Executor instructions: Follow this plan step by step. Run every verification command and confirm the expected result before moving to the next step. If anything in the “STOP conditions” section occurs, stop and report — do not improvise. When done, update the status row for this plan in
plans/README.md— unless a reviewer dispatched you and told you they maintain the index.Drift check (run first):
git diff --stat a6293e1..HEAD -- scripts/ src/rampart-worker.ts public/ort/Any drift inscripts/vendor-ort.mjsor the worker’s WASM configuration versus the excerpts below is a STOP condition.
node_modules, not public/ort/). A manual Chrome check
is a REQUIRED gate in this plan.a6293e1, 2026-07-17scripts/vendor-ort.mjs copies every .wasm/.mjs file from
node_modules/onnxruntime-web/dist into public/ort/ — currently 93 MB
across ~25 files (webgpu, webgl, jspi, asyncify, node, and bundle variants).
The runtime configuration pins a single execution path: WASM backend,
numThreads: 1, proxy: false, dtype: q4, device: "wasm" — which loads
exactly one WASM binary family (ort-wasm-simd-threaded.*). The release zip
is 39 MB and the repo carries ~93 MB of dead weight in git and in every
user’s unpacked extension directory. Trimming the keep-list roughly halves
the install size and shrinks CI checkout.
scripts/vendor-ort.mjs:9-13 — the copy-everything loop:
for (const item of await fs.readdir(sourceDir)) {
if (!/\.(wasm|mjs)$/.test(item)) continue;
await fs.copyFile(path.join(sourceDir, item), path.join(ortDir, item));
copied.push(item);
}
src/rampart-worker.ts:60-64 — the runtime constraint:
const wasm = env.backends.onnx.wasm;
if (!wasm) throw new Error("Transformers ONNX WASM backend is unavailable");
wasm.wasmPaths = ortBaseUrl; // -> chrome-extension://<id>/ort/
wasm.proxy = false;
wasm.numThreads = 1;
and src/rampart-worker.ts:175-177: pipeline(..., { dtype: "q4", device: "wasm", ... }).
public/ort/ currently contains (93 MB): ort-wasm-simd-threaded.{wasm,mjs},
.jsep.{wasm,mjs}, .asyncify.{wasm,mjs}, .jspi.{wasm,mjs}, plus ~17
ort.*.mjs loader bundles (ort.all.*, ort.webgpu.*, ort.node.min.mjs, …).wasmPaths is only
used to fetch the WASM-side artifacts at runtime. With numThreads: 1 and
no WebGPU, ORT dynamically imports ort-wasm-simd-threaded.mjs and fetches
ort-wasm-simd-threaded.wasm from wasmPaths. The jsep pair is the
WebGPU/WebNN build — unused (and plan 012 removes the dormant WebGPU
toggle). The asyncify/jspi pairs and all ort.*.mjs top-level bundles
are never requested.scripts/assets.mjs writeChecksums() regenerates
public/asset-manifest.json from whatever is on disk; npm run
verify:assets (also the first step of npm run build) fails on any
mismatch, missing checksum, or missing file. Both vendor scripts call
writeChecksums() at the end.console.debug + storage-backed
events) — a missing ORT file surfaces there as a failed fetch/import during
“Loading model”.| Purpose | Command | Expected on success |
|---|---|---|
| Re-vendor | npm run vendor:ort |
prints count + regenerates manifest |
| Asset check | npm run verify:assets |
Local model and ORT assets verified |
| Typecheck | npx tsc -p tsconfig.json --noEmit |
exit 0 |
| Tests | npm test |
all pass |
| Build | npm run build |
exit 0, dist/ populated |
| Package | npm run package |
writes packages/promptward-extension.zip |
| Size check | du -sh public/ort dist (Git Bash) |
see step targets |
In scope:
scripts/vendor-ort.mjsscripts/verify-assets.mjs (tighten the ORT existence check to the keep-list)public/ort/** (files removed by re-running the vendor script)public/asset-manifest.json (regenerated)README.md (one line, only if it mentions ORT file counts — at planning
time it does not, so likely no change)Out of scope:
src/rampart-worker.ts — do NOT change runtime configuration to match the
trim; the trim must match the existing configuration.public/models/** — model assets are all required..gitignore.advisor/007-trim-ortperf(assets): vendor only the ORT wasm variant the runtime loadsIn scripts/vendor-ort.mjs, replace the extension-based filter with an
explicit keep-list:
const KEEP = [
"ort-wasm-simd-threaded.wasm",
"ort-wasm-simd-threaded.mjs"
];
Copy only KEEP entries; throw listing any that are missing from
node_modules/onnxruntime-web/dist (fail loud, not partial). Keep the
writeChecksums() call.
Verify: node -e "console.log('syntax ok')" && node --check scripts/vendor-ort.mjs → no error.
Delete the current contents of public/ort/ (tracked files — use
git rm -r --cached semantics via plain deletion; git will stage the
removals), then run:
Verify: npm run vendor:ort → prints Vendored 2 ONNX Runtime Web assets into ....
Verify: ls public/ort → exactly ort-wasm-simd-threaded.wasm and ort-wasm-simd-threaded.mjs.
Verify: npm run verify:assets → Local model and ORT assets verified
(the manifest was regenerated, so removed files no longer have dangling
checksums — the verify script iterates actual files, so this passes).
Verify: du -sh public/ort → ~21 MB or less (was 93 MB).
In scripts/verify-assets.mjs, replace the loose “at least one .wasm and
one .mjs” check (lines 11–17) with an explicit required-file check
mirroring requiredModelFiles: import or declare the same keep-list and fail
if any keep-list file is missing from public/ort/. Export the keep-list
from scripts/assets.mjs (alongside requiredModelFiles) so the two scripts
share it.
Verify: npm run verify:assets → passes. Temporarily rename
public/ort/ort-wasm-simd-threaded.mjs, run again → fails naming that file;
rename back, passes.
Verify: npx tsc -p tsconfig.json --noEmit → exit 0.
Verify: npm test → all pass (the Node model test does not touch public/ort/).
Verify: npm run build → exit 0.
Verify: grep -rl "ort-wasm" dist/ | head → the worker bundle references
ort-wasm-simd-threaded only; grep -rl "jsep\|asyncify\|jspi" dist/*.js dist/assets 2>/dev/null
finding matches is fine (dead code strings inside the bundled ORT JS), but if
you can see a dynamic import or fetch path for a jsep/asyncify/jspi file
that would execute under device: "wasm", treat it as a STOP condition.
Verify: npm run package → zip written;
du -h packages/promptward-extension.zip → expected well under 20 MB (was 39 MB).
This step needs a human or a browser-capable agent; if you cannot perform it,
mark the plan BLOCKED (needs manual Chrome verification) in
plans/README.md and report — do NOT mark DONE.
dist/ as an unpacked extension in Chrome (chrome://extensions,
Developer mode, Load unpacked).Ready in <n> ms and Diagnostics shows model-load-progress
events ending in runtime-configured/prewarm-end with no errors.123-45-6789, press send. Expected: the review modal appears
with the SSN replaced by [SSN_1].ort/* file 404’d — add exactly that file
to the keep-list, re-run from step 2, and record the addition in the
commit message.No new unit tests — coverage is the tightened verify:assets (step 3), the
build greps (step 4), and the mandatory runtime gate (step 5).
public/ort/ contains exactly the keep-list filesnpm run verify:assets, npm test, npm run build, npm run package all exit 0packages/promptward-extension.zip is materially smaller than 39 MB (record the number in the commit message)git status shows only in-scope files + plans/README.mdplans/README.md status row updatedStop and report back if:
scripts/vendor-ort.mjs or the worker WASM config drifted from the excerpts.device: "wasm" configuration.onnxruntime-web’s dist layout has changed (keep-list files absent) —
the dependency was updated; the keep-list needs re-derivation, report.plans/README.md), the jsep pair
(ort-wasm-simd-threaded.jsep.{wasm,mjs}) must be added back to the
keep-list — the tightened verify:assets will force that to be explicit.onnxruntime-web is upgraded, re-run npm run vendor:ort and repeat
the step-5 runtime gate; file names have changed across ORT majors before.scripts/assets.mjs)
and both scripts import it.