fix(04): revise plans per checker iter-1 — 2 BLOCKERS + 2 WARNINGS fixed
Plan-checker iter-1 found 2 BLOCKERS + 4 WARNINGS. Iter-2 revision applies
surgical fixes to 4 plans + VALIDATION:
BLOCKER 1 (Plan 04-06 Task 4): wrong SW chunk glob `dist/assets/index*-bg.js`
matched zero files → Gates 2/3/4 silently PASSED. Replaced with canonical
`dist/assets/index.ts-*.js` (verified empirically: index.ts-8LkXuqac.js
on disk; RESEARCH Q1). Added glob-existence pre-gate `ls | wc -l >= 1`
to fail-loudly on future Vite chunk-naming shift.
BLOCKER 2 (Plan 04-04 Task 1): spike called non-existent
__mokoshHarness.dispatchSaveArchive (verified: harness surface is
assertA1..A31 + getManifestVersion only). Applied Option B — spike
+ driveA33 now dispatch SAVE_ARCHIVE via chrome.runtime.sendMessage
inline in page.evaluate (matches 9 existing assertA* methods:
A5/A11/A12/A13/A26/A28/A29/A30/A31). No new harness helper introduced.
WARNING 1 (Plan 04-02 Task 2): verify omitted UAT harness run. Added
`HEADLESS=1 SKIP_PROD_REBUILD=0 npm run test:uat 2>&1 | grep -c 'UAT
harness: 33/33 assertions passed'` to verify command (stdout format
confirmed at tests/uat/harness.test.ts:537).
WARNING 4 (Plan 04-07 Task 1): weak operator-ack gate (placeholder would
pass). Added `grep -cE 'approved|All good|APPROVED|approved by|operator
ack|all good' 04-VERIFICATION.md` to verify command. Covers both
canonical Plan 04-06 resume-signal ("approved" lowercase) AND prior-art
Plan 01-10 cycle-2 ack ("All good" titlecase).
WARNINGS 2 + 3 left as-is (truly advisory: scope-sanity threshold +
conservative dependency without file overlap).
04-VALIDATION.md per-task map rows updated for the 5 revised task entries
(04-02 T2 + 04-04 T1 + 04-04 T2 + 04-06 T4 + 04-07 T1). Frontmatter
adds `revised: 2026-05-21` + iter-2 notes block.
3 plans unchanged on disk (04-01, 04-03, 04-05).
Empirical confirmations used in revision:
- Harness surface: grep extension-page-harness.ts:4018 confirms
__mokoshHarness.{assertA1..A31, getManifestVersion}; no dispatchSaveArchive
- SW chunk filename: ls dist/assets/ shows index.ts-8LkXuqac.js;
no index*-bg.js matches
- SAVE_ARCHIVE precedent count: 9 existing assertA* methods use the
chrome.runtime.sendMessage pattern
- UAT harness stdout format: harness.test.ts:537 emits canonical
"UAT harness: N/N assertions passed"
Ready for plan-checker iter-3 re-verification.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@ must_haves:
|
||||
- "node generate-icons.cjs exits 0 under package.json type: module (CJS-explicit via .cjs extension)"
|
||||
- "vitest baseline +2 (no-new-function-in-sw-chunk + dead-code-grep tests) GREEN"
|
||||
- "Pre-checkpoint bundle Gate 2 polarity flipped (1 hit → 0 hits for 'new Function' in dist/assets/index.ts-*.js)"
|
||||
- "UAT harness 33/33 GREEN preserved post-polyfill-replacement (REVISION iter-2 WARNING 1 — JSZip's MessageChannel/postMessage/setTimeout fallback chain verified empirically end-to-end at the SAVE→zip layer)"
|
||||
artifacts:
|
||||
- path: "tests/build/no-new-function-in-sw-chunk.test.ts"
|
||||
provides: "Wave 0 RED — grep gate pinning 0 hits of 'new Function' in SW chunk after Plan 04-02 polyfill replacement"
|
||||
@@ -181,6 +182,9 @@ From tests/build/no-remote-fonts.test.ts (existing test scaffold — full 145 li
|
||||
- `runProductionBuild()`: `execFileAsync('npm', ['run', 'build'], { timeout: 90_000 })`
|
||||
- Skip gate: `if (process.env.SKIP_BUILD !== '1') { await runProductionBuild(); }` — re-uses existing built dist/ when SKIP_BUILD=1 (developer-velocity escape hatch)
|
||||
- The Plan 04-02 RED test inherits the same scaffold; SCOPES the walk to `dist/assets/` filtered by `^index\\.ts-.*\\.js$` regex (the SW chunk only).
|
||||
|
||||
UAT harness stdout format (REVISION iter-2 — WARNING 1 mitigation):
|
||||
- The orchestrator at tests/uat/harness.test.ts:537 emits exactly `UAT harness: 33/33 assertions passed\n` (verified 2026-05-21 via grep). Task 2 `<verify><automated>` greps for this canonical line to confirm post-polyfill JSZip behavior is preserved end-to-end at the SAVE→zip layer.
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
@@ -273,7 +277,7 @@ From tests/build/no-remote-fonts.test.ts (existing test scaffold — full 145 li
|
||||
Run the focused test: `npm test -- tests/build/no-new-function-in-sw-chunk.test.ts tests/build/dead-code-grep.test.ts --run` — expect 100% GREEN. Run the full vitest: `npm test -- --run` — expect 181 GREEN (or post-Plan-04-01 baseline + 2). Run the UAT harness: `HEADLESS=1 SKIP_PROD_REBUILD=0 npm run test:uat` — expect 33/33 GREEN (the SKIP_PROD_REBUILD=0 forces a rebuild against the new vite config + prelude so the UAT runs against the post-fix bundle).
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npm run build && grep -c 'new Function' dist/assets/index.ts-*.js | head -1; node generate-icons.cjs; npm test -- tests/build/no-new-function-in-sw-chunk.test.ts tests/build/dead-code-grep.test.ts --run; npx tsc --noEmit</automated>
|
||||
<automated>npm run build && grep -c 'new Function' dist/assets/index.ts-*.js | head -1; node generate-icons.cjs; npm test -- tests/build/no-new-function-in-sw-chunk.test.ts tests/build/dead-code-grep.test.ts --run; npx tsc --noEmit && HEADLESS=1 SKIP_PROD_REBUILD=0 npm run test:uat 2>&1 | tee /tmp/04-02-task-2-uat.log | tail -3; grep -c 'UAT harness: 33/33 assertions passed' /tmp/04-02-task-2-uat.log</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `npm run build` exits 0; `grep -c 'new Function' dist/assets/index.ts-*.js` returns 0 (was 1).
|
||||
@@ -284,7 +288,7 @@ From tests/build/no-remote-fonts.test.ts (existing test scaffold — full 145 li
|
||||
- `grep -c "queueMicrotask" src/background/index.ts | head -1` returns ≥ 1 (the polyfill assignment).
|
||||
- `grep -c "Resolved in Phase 4 Plan 04-02" .planning/phases/01-stabilize-video-pipeline/deferred-items.md` returns ≥ 1.
|
||||
- Full vitest passes: `npm test -- --run` exits 0 (Plan 04-01 baseline +2 from this plan = ≥ 181 GREEN).
|
||||
- UAT harness 33/33 GREEN preserved: `HEADLESS=1 SKIP_PROD_REBUILD=0 npm run test:uat` exits 0 (verifies JSZip fallback works correctly post-polyfill-removal).
|
||||
- UAT harness 33/33 GREEN preserved (REVISION iter-2 — WARNING 1): `HEADLESS=1 SKIP_PROD_REBUILD=0 npm run test:uat` exits 0 AND stdout contains `UAT harness: 33/33 assertions passed`; verified by `grep -c 'UAT harness: 33/33 assertions passed' /tmp/04-02-task-2-uat.log` returning 1. This confirms JSZip fallback (MessageChannel/postMessage/setTimeout) works correctly post-polyfill-removal at the empirical SAVE→zip layer.
|
||||
</acceptance_criteria>
|
||||
<done>Polyfill replacement landed; SW chunk grep flipped 1 → 0; generate-icons CJS-renamed; deferred-items.md closure-flipped. Atomic commit: `feat(04-02): Wave 1 — setimmediate polyfill replaced + generate-icons.cjs + deferred-items closure`.</done>
|
||||
</task>
|
||||
@@ -304,7 +308,7 @@ From tests/build/no-remote-fonts.test.ts (existing test scaffold — full 145 li
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|-------------|-----------------|
|
||||
| T-04-02-01 | Elevation of Privilege | SW chunk `new Function(string)` literal — a static-analysis red flag for tighter future CSP and a security-audit eyebrow-raiser even under current MV3 CSP defaults | mitigate | Replace transitive `setimmediate` polyfill with explicit `queueMicrotask`-based polyfill in SW entry; verifiable by grep against built dist/. Reversible by git revert. |
|
||||
| T-04-02-02 | DoS (functional) | JSZip relies on setImmediate to yield between zip-entry writes; if our explicit polyfill `(fn, ...args) => queueMicrotask(() => fn(...args))` is incompatible with JSZip's internal use, the zip-assembly could starve or deadlock | accept (verified by UAT) | The polyfill matches JSZip's signature expectation (function + variadic args); UAT harness 33/33 GREEN under the new bundle confirms behavior preserved (A24 specifically tests SAVE→zip; A28/A29/A30/A31 all exercise the zip-assembly path empirically) |
|
||||
| T-04-02-02 | DoS (functional) | JSZip relies on setImmediate to yield between zip-entry writes; if our explicit polyfill `(fn, ...args) => queueMicrotask(() => fn(...args))` is incompatible with JSZip's internal use, the zip-assembly could starve or deadlock | accept (verified by UAT) | The polyfill matches JSZip's signature expectation (function + variadic args); UAT harness 33/33 GREEN under the new bundle confirms behavior preserved (A24 specifically tests SAVE→zip; A28/A29/A30/A31 all exercise the zip-assembly path empirically). REVISION iter-2 WARNING 1: Task 2 `<verify><automated>` now greps for `UAT harness: 33/33 assertions passed` in stdout so the gate is empirically pinned, not merely asserted in `<acceptance_criteria>`. |
|
||||
| T-04-02-03 | Information Disclosure | leftover `permissions.request` literal in src/ could give a future audit the impression the codebase still relies on the deleted permission flow, masking the post-01-05 architecture | mitigate (regression pin) | dead-code-grep.test.ts pins absence — re-introduction breaks CI |
|
||||
| T-04-02-04 | Tampering | `.cjs` extension override applies only to the renamed file; future contributors writing `.js` files under the same project type:module would re-introduce the ESM/CJS error | accept | Convention is documented in the SUMMARY; CI catches future `require(` in `.js` files via `npx tsc --noEmit` at build time + the explicit `node generate-icons.cjs` invocation in any future ROADMAP backfill |
|
||||
</threat_model>
|
||||
@@ -316,7 +320,7 @@ From tests/build/no-remote-fonts.test.ts (existing test scaffold — full 145 li
|
||||
- `node generate-icons.cjs` exits 0.
|
||||
- vitest baseline +2 to ≥ 181 (Plan 04-01 baseline + 2 new build-gate tests).
|
||||
- tsc-clean.
|
||||
- UAT harness 33/33 GREEN preserved (validates JSZip fallback under the new polyfill regime).
|
||||
- UAT harness 33/33 GREEN preserved (validates JSZip fallback under the new polyfill regime) — REVISION iter-2 WARNING 1: grep `UAT harness: 33/33 assertions passed` in `<verify><automated>` confirms empirically.
|
||||
- Pre-checkpoint bundle Gate 2 (SW CSP-safety: `grep -rn "new Function\\|eval(" dist/assets/`) returns 0 hits (was 1 documented exception).
|
||||
</verification>
|
||||
|
||||
@@ -326,7 +330,7 @@ From tests/build/no-remote-fonts.test.ts (existing test scaffold — full 145 li
|
||||
- ROADMAP SC #3 (generate-icons ESM/CJS) GREEN — `node generate-icons.cjs` exits 0.
|
||||
- ROADMAP SC #4 (dead-code grep) GREEN — regression pinned in vitest.
|
||||
- setimmediate polyfill replacement GREEN — `new Function` count in SW chunk = 0.
|
||||
- UAT harness 33/33 GREEN preserved.
|
||||
- UAT harness 33/33 GREEN preserved (REVISION iter-2 — empirically pinned in Task 2 verify).
|
||||
- Pre-checkpoint bundle Gate 2 polarity flipped (1 → 0).
|
||||
</success_criteria>
|
||||
|
||||
@@ -339,9 +343,8 @@ After completion, create `.planning/phases/04-harden-clean-up-optional/04-02-SUM
|
||||
- deferred-items.md closure-flip block
|
||||
- Pre-fix vs post-fix `grep -c 'new Function' dist/assets/index.ts-*.js` (1 → 0)
|
||||
- vitest baseline before/after
|
||||
- UAT harness GREEN preservation evidence
|
||||
- UAT harness GREEN preservation evidence (REVISION iter-2 — grep `UAT harness: 33/33 assertions passed` count = 1 from `<verify><automated>` output)
|
||||
- RED→GREEN flip for the no-new-function test (Task 1 RED → Task 2 GREEN)
|
||||
- Commit refs (Task 1 + Task 2)
|
||||
</output>
|
||||
</content>
|
||||
</invoke>
|
||||
Reference in New Issue
Block a user