Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Preserve the Engine host module closure in the packed browser gate

## Product outcome

Make the adapter's existing fresh packed-browser consumer exercise the published Engine host exactly as a deployable browser bundle. The built consumer must serve `prepared-control.js` beside the raw Engine AudioWorklet host so its relative import resolves in Chromium.

## Bounded implementation

Change only `scripts/browser-packed.mjs`, this numbered issue spec, and a focused harness test only if the implementation cannot be directly proved by the existing browser gate. Preserve adapter and Engine package/runtime sources, public APIs, package identities, release workflow, and issue #117.

The harness may emit or copy the installed Engine host closure into its temporary Vite output. It must retain the Engine host and worklet asset observations and fail if the required relative companion is absent.

## Objective gates

From synchronized adapter main `1a97a7e2a5c8747996388fdf412d82e32156fa15`, reproduce the ordinary packed Chromium failure before the correction. Then prove `npm run test:browser`, the indexed-sparse Chromium gate, `npm run check`, and package/dry-run gates pass. Confirm no generated evidence or dependencies remain untracked. Record exact commands and outcomes below.

## Workflow

One bounded Sol implementation round owns this harness-only correction. Root owns checkpoint commit, push, PR, CI, merge, and any release integration. No publication or change to issue #117 is authorized here.

## Evidence

Starting source is clean synchronized adapter main `1a97a7e2a5c8747996388fdf412d82e32156fa15` in isolated worktree `/tmp/miso-adapter-packed-closure`. The primary checkout and `/tmp/miso-adapter-0511-release` are untouched.

### Bounded implementation and local acceptance

Baseline `CHROME_EXECUTABLE=/home/bl/.cache/ms-playwright/chromium-1243/chrome-linux64/chrome npm run test:browser` reproduced the defect on Chromium `153.0.8010.12`: Vite emitted the raw host at a hashed asset URL, the host requested its relative `/assets/prepared-control.js`, that request returned 404, and session open failed with `Engine host module could not load`.

The harness now writes a temporary consumer Vite config that derives a content-addressed directory from the installed SDK asset manifest, emits the host module and ABI layout there under their original filenames, and emits the installed `prepared-control.js` beside them. The ordinary browser lane explicitly requires requests for both relative companions. No adapter/Engine runtime source, public API, package identity, release workflow, or issue #117 changed.

Local acceptance on Node `22.23.2`, npm `10.9.8`, and Chromium `153.0.8010.12`:

- `npm ci --ignore-scripts`: PASS, 31 packages, zero vulnerabilities.
- `CHROME_EXECUTABLE=/home/bl/.cache/ms-playwright/chromium-1243/chrome-linux64/chrome npm run test:browser`: PASS, full packed playback/control/seek/fault assertions, 15 observed JS/Wasm assets, zero request failures and zero console errors.
- `CHROME_EXECUTABLE=/home/bl/.cache/ms-playwright/chromium-1243/chrome-linux64/chrome node scripts/browser-packed.mjs --indexed-sparse`: PASS, cold/warm/three-worker/serial/concurrent/all-silent/tail proofs, all physical workers terminated, zero request failures and zero console errors.
- `npm run check`: PASS, including format, reproducible SHA-256/BLAKE3 Wasm, types/source policy, decoder policy, the complete test suite, and package policy.
- `npm run check:package`: PASS, `247` files and `474766` packed bytes.
- `npm run publish:dry-run`: PASS for unpublished action only, `@misofm/engine-web-adapter@0.5.10`, `247` files, package SHA1 `39cb19c1f312af81c9905d4f50811107d093d3ee`.
- `git diff --check`: PASS. Generated `.adapter-71-evidence/` was removed; final status contains only this issue spec and `scripts/browser-packed.mjs`.

Verdict: **PASS** for the smallest packed-browser harness correction. Root retains ownership of checkpointing, remote delivery, review, and release sequencing.

### Fresh Sol HIGH adversarial review

PASS on frozen commit `2e982947d752a66e04b427066de6ebe79cabe003`. The reviewer confirmed exact two-path scope, the installed/current Engine host's only two relative companions, authoritative `BUNDLED_ENGINE_FILES` names, manifest-hashed directory construction, and byte-identical host/ABI/prepared-control output in both ordinary and indexed builds. Ordinary Chromium 153 passed full playback/control and observed the companion requests with correct JavaScript handling; indexed-sparse Chromium passed its complete matrix; both reported zero request and console failures. `npm run check` passed 380 tests, package policy remained 247 files/474766 bytes, dry-run package SHA1 remained `39cb19c1f312af81c9905d4f50811107d093d3ee`, and the worktree was clean. No blocker remains for remote delivery.
43 changes: 43 additions & 0 deletions scripts/browser-packed.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,47 @@ WebAssembly.validate = (() => false) as typeof WebAssembly.validate;
})();
`);
await writeFile(join(consumer, "package.json"), JSON.stringify({ type: "module" }));
await writeFile(join(consumer, "vite.config.mjs"), `
import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";
import { BUNDLED_ENGINE_ASSETS, BUNDLED_ENGINE_FILES } from "@misofm/engine/assets";

const manifestSha256 = createHash("sha256")
.update(readFileSync(BUNDLED_ENGINE_ASSETS.manifest))
.digest("hex");
const hostDirectory = "assets/engine-" + manifestSha256;
const hostClosure = new Set([
BUNDLED_ENGINE_FILES.hostModule,
BUNDLED_ENGINE_FILES.abiLayout,
]);

export default {
build: {
rollupOptions: {
output: {
assetFileNames: (asset) => hostClosure.has(asset.name ?? "")
? hostDirectory + "/[name][extname]"
: "assets/[name]-[hash][extname]",
},
},
},
plugins: [{
name: "packed-engine-host-closure",
generateBundle(_, bundle) {
for (const fileName of hostClosure) {
if (!Object.values(bundle).some((entry) => entry.type === "asset" && entry.name === fileName)) {
throw new Error("Vite did not emit Engine host asset " + fileName);
}
}
this.emitFile({
type: "asset",
fileName: hostDirectory + "/" + BUNDLED_ENGINE_FILES.preparedControl,
source: readFileSync(new URL(BUNDLED_ENGINE_FILES.preparedControl, BUNDLED_ENGINE_ASSETS.hostModule)),
});
},
}],
};
`);
await writeFile(join(consumer, "index.html"), '<div id="status">loading</div><script type="module" src="/src/main.ts"></script>\n');
await mkdir(join(consumer, "src"));
await writeFile(join(consumer, "src", "main.ts"), indexedSparse
Expand Down Expand Up @@ -380,6 +421,8 @@ try {
assert.ok(requested.some(([path, mime]) => path.includes("pcm-pump-worker") && mime.includes("javascript")), "pump Worker asset not observed");
assert.ok(requested.some(([path, mime]) => path.includes("feed-worklet") && mime.includes("javascript")), "feed worklet asset not observed");
assert.ok(requested.some(([path, mime]) => path.includes("audio-worklet-host") && mime.includes("javascript")), "Engine host asset not observed");
assert.ok(requested.some(([path, mime]) => path.endsWith("/prepared-control.js") && mime.includes("javascript")), "Engine prepared-control companion not observed");
assert.ok(requested.some(([path]) => path.endsWith("/miso-engine-v1-abi-layout.json")), "Engine ABI-layout companion not observed");
assert.ok(requested.some(([path, mime]) => path.includes("audio-worklet-") && !path.includes("host") && mime.includes("javascript")), "Engine worklet asset not observed");
console.log(JSON.stringify({ profile: profile.name, origin: `http://127.0.0.1:${address.port}`, ...result.result,
assets: requested.filter(([path]) => /\.(?:js|wasm)$/u.test(path)).length, root, requestFailures, consoleErrors }));
Expand Down
Loading