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)"
|
- "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"
|
- "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)"
|
- "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:
|
artifacts:
|
||||||
- path: "tests/build/no-new-function-in-sw-chunk.test.ts"
|
- 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"
|
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 })`
|
- `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)
|
- 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).
|
- 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>
|
</interfaces>
|
||||||
</context>
|
</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).
|
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>
|
</action>
|
||||||
<verify>
|
<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>
|
</verify>
|
||||||
<acceptance_criteria>
|
<acceptance_criteria>
|
||||||
- `npm run build` exits 0; `grep -c 'new Function' dist/assets/index.ts-*.js` returns 0 (was 1).
|
- `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 "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.
|
- `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).
|
- 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>
|
</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>
|
<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>
|
</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 |
|
| 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-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-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 |
|
| 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>
|
</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.
|
- `node generate-icons.cjs` exits 0.
|
||||||
- vitest baseline +2 to ≥ 181 (Plan 04-01 baseline + 2 new build-gate tests).
|
- vitest baseline +2 to ≥ 181 (Plan 04-01 baseline + 2 new build-gate tests).
|
||||||
- tsc-clean.
|
- 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).
|
- Pre-checkpoint bundle Gate 2 (SW CSP-safety: `grep -rn "new Function\\|eval(" dist/assets/`) returns 0 hits (was 1 documented exception).
|
||||||
</verification>
|
</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 #3 (generate-icons ESM/CJS) GREEN — `node generate-icons.cjs` exits 0.
|
||||||
- ROADMAP SC #4 (dead-code grep) GREEN — regression pinned in vitest.
|
- ROADMAP SC #4 (dead-code grep) GREEN — regression pinned in vitest.
|
||||||
- setimmediate polyfill replacement GREEN — `new Function` count in SW chunk = 0.
|
- 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).
|
- Pre-checkpoint bundle Gate 2 polarity flipped (1 → 0).
|
||||||
</success_criteria>
|
</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
|
- deferred-items.md closure-flip block
|
||||||
- Pre-fix vs post-fix `grep -c 'new Function' dist/assets/index.ts-*.js` (1 → 0)
|
- Pre-fix vs post-fix `grep -c 'new Function' dist/assets/index.ts-*.js` (1 → 0)
|
||||||
- vitest baseline before/after
|
- 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)
|
- RED→GREEN flip for the no-new-function test (Task 1 RED → Task 2 GREEN)
|
||||||
- Commit refs (Task 1 + Task 2)
|
- Commit refs (Task 1 + Task 2)
|
||||||
</output>
|
</output>
|
||||||
</content>
|
</content>
|
||||||
</invoke>
|
|
||||||
@@ -32,6 +32,7 @@ must_haves:
|
|||||||
- "A33 is env-gated by SKIP_LONG_UAT (default: RUN for closure + alpha gate; SKIP_LONG_UAT=1 to skip for per-commit iteration)"
|
- "A33 is env-gated by SKIP_LONG_UAT (default: RUN for closure + alpha gate; SKIP_LONG_UAT=1 to skip for per-commit iteration)"
|
||||||
- "UAT harness count flips from 33 → 34 (A33 added); 34/34 GREEN when SKIP_LONG_UAT unset"
|
- "UAT harness count flips from 33 → 34 (A33 added); 34/34 GREEN when SKIP_LONG_UAT unset"
|
||||||
- "ROADMAP SC #1 (SW state persistence) GREEN — A33 empirical evidence that a real-world 5-min idle + SAVE produces a non-empty video buffer"
|
- "ROADMAP SC #1 (SW state persistence) GREEN — A33 empirical evidence that a real-world 5-min idle + SAVE produces a non-empty video buffer"
|
||||||
|
- "SAVE_ARCHIVE dispatch reuses the canonical chrome.runtime.sendMessage({type: 'SAVE_ARCHIVE'}, ...) pattern from the harness page realm (NOT a new __mokoshHarness helper); matches the established assertA5/A11/A12/A13/A26/A28/A29/A30/A31 precedent"
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: "tests/uat/extension-page-harness.ts"
|
- path: "tests/uat/extension-page-harness.ts"
|
||||||
provides: "assertA33 page-side stub (or thin driver) for SAVE_ARCHIVE dispatch after host-side SW kill"
|
provides: "assertA33 page-side stub (or thin driver) for SAVE_ARCHIVE dispatch after host-side SW kill"
|
||||||
@@ -138,7 +139,10 @@ async function stopServiceWorker(browser: Browser, extensionId: string): Promise
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
From RESEARCH Q2 Code Example Pattern 4 (driveA33 — host-side body):
|
SAVE_ARCHIVE dispatch (REVISION iter-2 — Option B per plan-checker BLOCKER 2):
|
||||||
|
The harness page realm has `chrome.runtime` available (it's an extension-page realm — `chrome-extension://<id>/tests/uat/extension-page-harness.html`). The canonical SAVE_ARCHIVE dispatch is `chrome.runtime.sendMessage({type: 'SAVE_ARCHIVE'}, callback)` — used by 9 existing assertions (A5/A11/A12/A13/A26/A28/A29/A30/A31; verified via `grep "type: 'SAVE_ARCHIVE'" tests/uat/extension-page-harness.ts`). The `__mokoshHarness` surface is `assertA1..A31 + getManifestVersion`; there is NO `dispatchSaveArchive` helper. We do NOT add one — driveA33 dispatches SAVE_ARCHIVE directly via `page.evaluate` + a promise-wrapped `chrome.runtime.sendMessage` callback. This matches Plan 04-05's approach (which dispatches SAVE_ARCHIVE from inside an existing assertA34 method that runs in the harness page realm).
|
||||||
|
|
||||||
|
From RESEARCH Q2 Code Example Pattern 4 (driveA33 — host-side body; REVISION iter-2 inline-dispatched SAVE):
|
||||||
```typescript
|
```typescript
|
||||||
const A33_IDLE_WAIT_MS = 5 * 60 * 1000; // 300_000 — real wall-clock
|
const A33_IDLE_WAIT_MS = 5 * 60 * 1000; // 300_000 — real wall-clock
|
||||||
const A33_NEW_SW_BOOT_MS = 500; // post-worker.close() settle
|
const A33_NEW_SW_BOOT_MS = 500; // post-worker.close() settle
|
||||||
@@ -153,8 +157,21 @@ export async function driveA33(
|
|||||||
): Promise<AssertionRecord> {
|
): Promise<AssertionRecord> {
|
||||||
const r: AssertionRecord = { name: 'A33', passed: false, checks: [], diagnostics: [] };
|
const r: AssertionRecord = { name: 'A33', passed: false, checks: [], diagnostics: [] };
|
||||||
|
|
||||||
// Step 1: prime recording on the probe tab
|
// Step 1: prime recording on the probe tab via the existing harness primitive.
|
||||||
await page.evaluate(() => (window as any).__mokoshHarness.setupFreshRecording());
|
// setupFreshRecording is a module-internal helper inside extension-page-harness.ts
|
||||||
|
// and is reachable from page.evaluate only if exposed; in practice driveA33 calls
|
||||||
|
// assertA1 (or an equivalent existing harness method that primes a fresh recording)
|
||||||
|
// OR a thin Plan-04-04 page-side wrapper if the prior arts don't suffice. Verify
|
||||||
|
// in Task 2 read_first which existing assertA* method delivers a fresh-recording
|
||||||
|
// SUT and reuse it directly (no new harness method needed).
|
||||||
|
await page.evaluate(async () => {
|
||||||
|
// Reuse the same fresh-recording primitive that A5/A26/A30/A31 use as their Step 1.
|
||||||
|
// The exact call depends on whether setupFreshRecording is exposed; if not, A33's
|
||||||
|
// first step calls __mokoshHarness.assertA1 (which is the canonical "fresh
|
||||||
|
// recording bootstrap" assertion in the harness surface).
|
||||||
|
const harness = (window as { __mokoshHarness: { assertA1: () => Promise<unknown> } }).__mokoshHarness;
|
||||||
|
await harness.assertA1();
|
||||||
|
});
|
||||||
|
|
||||||
// Step 2: 5-min wall-clock idle
|
// Step 2: 5-min wall-clock idle
|
||||||
r.diagnostics.push(`waiting ${A33_IDLE_WAIT_MS}ms for SW idle window`);
|
r.diagnostics.push(`waiting ${A33_IDLE_WAIT_MS}ms for SW idle window`);
|
||||||
@@ -167,9 +184,27 @@ export async function driveA33(
|
|||||||
// Step 4: brief settle for SW teardown
|
// Step 4: brief settle for SW teardown
|
||||||
await new Promise((res) => setTimeout(res, A33_NEW_SW_BOOT_MS));
|
await new Promise((res) => setTimeout(res, A33_NEW_SW_BOOT_MS));
|
||||||
|
|
||||||
// Step 5: dispatch SAVE_ARCHIVE — wakes SW back up as an event
|
// Step 5: dispatch SAVE_ARCHIVE via chrome.runtime.sendMessage from the harness
|
||||||
// (event-driven respawn is the canonical MV3 wakeup path)
|
// page realm — matches the established A5/A11/A12/A13/A26/A28/A29/A30/A31 pattern.
|
||||||
const saveResult = await page.evaluate(() => (window as any).__mokoshHarness.dispatchSaveArchive());
|
// Wakes SW back up as an event (event-driven respawn is the canonical MV3 wakeup path).
|
||||||
|
const saveResult = await page.evaluate(
|
||||||
|
(timeoutMs: number) =>
|
||||||
|
new Promise<{ success: boolean; error?: string }>((resolve) => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
resolve({ success: false, error: `SAVE_ARCHIVE timed out after ${timeoutMs}ms` });
|
||||||
|
}, timeoutMs);
|
||||||
|
chrome.runtime.sendMessage({ type: 'SAVE_ARCHIVE' }, (response: unknown) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
if (chrome.runtime.lastError !== undefined) {
|
||||||
|
resolve({ success: false, error: String(chrome.runtime.lastError.message) });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(response as { success: boolean; error?: string });
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
A33_SAVE_ARCHIVE_TIMEOUT_MS,
|
||||||
|
);
|
||||||
|
|
||||||
r.checks.push({
|
r.checks.push({
|
||||||
name: 'A33.1: SAVE_ARCHIVE ack success after 5-min idle + SW kill',
|
name: 'A33.1: SAVE_ARCHIVE ack success after 5-min idle + SW kill',
|
||||||
expected: true,
|
expected: true,
|
||||||
@@ -239,19 +274,40 @@ The spike's job: verify this RAM-only design survives a 5-min SW idle. If it doe
|
|||||||
<task type="auto">
|
<task type="auto">
|
||||||
<name>Task 1: Wave 0 SPIKE — empirical verification that offscreen survives 5-min SW idle</name>
|
<name>Task 1: Wave 0 SPIKE — empirical verification that offscreen survives 5-min SW idle</name>
|
||||||
<files>tests/uat/lib/harness-page-driver.ts</files>
|
<files>tests/uat/lib/harness-page-driver.ts</files>
|
||||||
<read_first>tests/uat/lib/harness-page-driver.ts (full; ~2200 lines — read selectively: imports lines 1-40, findLatestZip ~1395, driveA30 host-side filter ~2039-2148), tests/uat/extension-page-harness.ts:600-700 (setupFreshRecording helper), src/offscreen/recorder.ts:80-100 (segments array context), .planning/phases/04-harden-clean-up-optional/04-RESEARCH.md Q2 sub-question (b), .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md (Plan 07 spike precedent)</read_first>
|
<read_first>tests/uat/lib/harness-page-driver.ts (full; ~2200 lines — read selectively: imports lines 1-40, findLatestZip ~1395, driveA30 host-side filter ~2039-2148), tests/uat/extension-page-harness.ts:3932-4021 (__mokoshHarness global registration block — confirm available surface BEFORE writing spike), tests/uat/extension-page-harness.ts:600-700 (setupFreshRecording helper context), src/offscreen/recorder.ts:80-100 (segments array context), .planning/phases/04-harden-clean-up-optional/04-RESEARCH.md Q2 sub-question (b), .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md (Plan 07 spike precedent)</read_first>
|
||||||
<action>
|
<action>
|
||||||
1. Add the `stopServiceWorker(browser, extensionId)` helper to `tests/uat/lib/harness-page-driver.ts` per the Code Example in `<interfaces>` above. Place it near the top of the file (after existing imports + before existing driveA-* functions). Add the `import type { Browser } from 'puppeteer';` if not already present.
|
1. Add the `stopServiceWorker(browser, extensionId)` helper to `tests/uat/lib/harness-page-driver.ts` per the Code Example in `<interfaces>` above. Place it near the top of the file (after existing imports + before existing driveA-* functions). Add the `import type { Browser } from 'puppeteer';` if not already present.
|
||||||
|
|
||||||
2. Create a one-shot spike script `tests/uat/spike-a33-sw-persistence.ts` (NEW; treat as scratch file for this spike — delete after spike concludes; record outcome in plan SUMMARY). The script:
|
2. Create a one-shot spike script `tests/uat/spike-a33-sw-persistence.ts` (NEW; treat as scratch file for this spike — delete after spike concludes; record outcome in plan SUMMARY). The script:
|
||||||
- Imports `launchHarnessBrowser` from `./lib/launch.ts`.
|
- Imports `launchHarnessBrowser` from `./lib/launch.ts`.
|
||||||
- Imports `stopServiceWorker` + `findLatestZip` from `./lib/harness-page-driver.ts`.
|
- Imports `stopServiceWorker` + `findLatestZip` from `./lib/harness-page-driver.ts`.
|
||||||
- Launches the harness browser, primes recording via the harness page's setupFreshRecording method.
|
- Launches the harness browser.
|
||||||
|
- **Prime recording (REVISION iter-2 — Option B; no `dispatchSaveArchive` helper exists on `__mokoshHarness`):** call the existing fresh-recording primitive via `await handles.harnessPage.evaluate(() => (window as { __mokoshHarness: { assertA1: () => Promise<unknown> } }).__mokoshHarness.assertA1());`. The Task 1 read_first MUST verify that `__mokoshHarness.assertA1` is the canonical fresh-recording bootstrap (it is per the existing harness — `Harness ready. window.__mokoshHarness.{assertA1..A31, getManifestVersion} available.`); if a different assertA* method is more direct for "prime + leave recording active for 5 min", choose that instead and document in the spike script comment.
|
||||||
- `console.log('SPIKE: waiting 5 minutes for SW idle window...')`
|
- `console.log('SPIKE: waiting 5 minutes for SW idle window...')`
|
||||||
- `await new Promise(r => setTimeout(r, 5 * 60 * 1000));`
|
- `await new Promise(r => setTimeout(r, 5 * 60 * 1000));`
|
||||||
- `await stopServiceWorker(handles.browser, handles.extensionId);`
|
- `await stopServiceWorker(handles.browser, handles.extensionId);`
|
||||||
- `await new Promise(r => setTimeout(r, 500));` (settle)
|
- `await new Promise(r => setTimeout(r, 500));` (settle)
|
||||||
- Dispatch SAVE_ARCHIVE via `await handles.harnessPage.evaluate(() => (window as any).__mokoshHarness.dispatchSaveArchive());`
|
- **Dispatch SAVE_ARCHIVE (REVISION iter-2 — Option B; canonical chrome.runtime.sendMessage from harness page realm):**
|
||||||
|
```typescript
|
||||||
|
const saveResult = await handles.harnessPage.evaluate(
|
||||||
|
(timeoutMs: number) =>
|
||||||
|
new Promise<{ success: boolean; error?: string }>((resolve) => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
resolve({ success: false, error: `SAVE_ARCHIVE timed out after ${timeoutMs}ms` });
|
||||||
|
}, timeoutMs);
|
||||||
|
chrome.runtime.sendMessage({ type: 'SAVE_ARCHIVE' }, (response: unknown) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
if (chrome.runtime.lastError !== undefined) {
|
||||||
|
resolve({ success: false, error: String(chrome.runtime.lastError.message) });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(response as { success: boolean; error?: string });
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
15_000,
|
||||||
|
);
|
||||||
|
console.log(`SPIKE: SAVE_ARCHIVE ack -> ${JSON.stringify(saveResult)}`);
|
||||||
|
```
|
||||||
- `await new Promise(r => setTimeout(r, 5000));` (let download complete)
|
- `await new Promise(r => setTimeout(r, 5000));` (let download complete)
|
||||||
- `const zipPath = findLatestZip(handles.downloadsDir);`
|
- `const zipPath = findLatestZip(handles.downloadsDir);`
|
||||||
- `const zip = await JSZip.loadAsync(readFileSync(zipPath));`
|
- `const zip = await JSZip.loadAsync(readFileSync(zipPath));`
|
||||||
@@ -273,6 +329,7 @@ The spike's job: verify this RAM-only design survives a 5-min SW idle. If it doe
|
|||||||
- `stopServiceWorker(browser, extensionId)` helper exists at `tests/uat/lib/harness-page-driver.ts` with the canonical Chrome devrel signature (`Browser` + extensionId args; `target.worker()?.close()` body).
|
- `stopServiceWorker(browser, extensionId)` helper exists at `tests/uat/lib/harness-page-driver.ts` with the canonical Chrome devrel signature (`Browser` + extensionId args; `target.worker()?.close()` body).
|
||||||
- Spike script ran to completion (no Puppeteer throw).
|
- Spike script ran to completion (no Puppeteer throw).
|
||||||
- Spike result logged with explicit `videoSize=<N> bytes` line.
|
- Spike result logged with explicit `videoSize=<N> bytes` line.
|
||||||
|
- Spike SAVE_ARCHIVE dispatch uses `chrome.runtime.sendMessage({type: 'SAVE_ARCHIVE'}, ...)` directly (NOT a non-existent `__mokoshHarness.dispatchSaveArchive()` call); verify by `grep -c 'dispatchSaveArchive' tests/uat/spike-a33-sw-persistence.ts` returns 0 AND `grep -c "type: 'SAVE_ARCHIVE'" tests/uat/spike-a33-sw-persistence.ts` returns ≥ 1.
|
||||||
- If videoSize > 100_000: spike PASSED; proceed to Task 2 with verification-only path.
|
- If videoSize > 100_000: spike PASSED; proceed to Task 2 with verification-only path.
|
||||||
- If videoSize ≤ 100_000: spike FAILED; pause plan + flag to plan-checker for re-planning (out of scope for this task to escalate, but SUMMARY documents).
|
- If videoSize ≤ 100_000: spike FAILED; pause plan + flag to plan-checker for re-planning (out of scope for this task to escalate, but SUMMARY documents).
|
||||||
- Total spike wall-clock: ~6-7 minutes (5 min idle + ~1-2 min orchestration).
|
- Total spike wall-clock: ~6-7 minutes (5 min idle + ~1-2 min orchestration).
|
||||||
@@ -283,26 +340,25 @@ The spike's job: verify this RAM-only design survives a 5-min SW idle. If it doe
|
|||||||
<task type="auto">
|
<task type="auto">
|
||||||
<name>Task 2: Wave 1 — A33 assertion + driveA33 + orchestrator wiring (assumes spike PASSED)</name>
|
<name>Task 2: Wave 1 — A33 assertion + driveA33 + orchestrator wiring (assumes spike PASSED)</name>
|
||||||
<files>tests/uat/extension-page-harness.ts, tests/uat/lib/harness-page-driver.ts, tests/uat/harness.test.ts</files>
|
<files>tests/uat/extension-page-harness.ts, tests/uat/lib/harness-page-driver.ts, tests/uat/harness.test.ts</files>
|
||||||
<read_first>tests/uat/extension-page-harness.ts:3517-3636 (assertA30 — canonical setupFreshRecording + SAVE pattern), tests/uat/extension-page-harness.ts:3971-4000 (__mokoshHarness global registration block), tests/uat/lib/harness-page-driver.ts:2039-2148 (driveA30 — host-side filter pattern), tests/uat/harness.test.ts:100-110 (import block), tests/uat/harness.test.ts:340-360 (wrapped-driver block), tests/uat/harness.test.ts:459-486 (drivers-array push block), tests/uat/harness.test.ts:225-240 (SKIP_PROD_REBUILD env-gate pattern)</read_first>
|
<read_first>tests/uat/extension-page-harness.ts:3517-3636 (assertA30 — canonical setupFreshRecording + SAVE pattern), tests/uat/extension-page-harness.ts:3878-3917 (assertA31 — most-recent chrome.runtime.sendMessage SAVE_ARCHIVE pattern; copy this), tests/uat/extension-page-harness.ts:3932-4021 (__mokoshHarness global registration block — confirm NO new method added per REVISION iter-2), tests/uat/lib/harness-page-driver.ts:2039-2148 (driveA30 — host-side filter pattern), tests/uat/harness.test.ts:100-110 (import block), tests/uat/harness.test.ts:340-360 (wrapped-driver block), tests/uat/harness.test.ts:459-486 (drivers-array push block), tests/uat/harness.test.ts:225-240 (SKIP_PROD_REBUILD env-gate pattern)</read_first>
|
||||||
<action>
|
<action>
|
||||||
**GATING CONDITION:** Task 1 spike produced videoSize > 100_000. (If FAILED, this task is BLOCKED and the plan must be re-planned to add IndexedDB persistence work.)
|
**GATING CONDITION:** Task 1 spike produced videoSize > 100_000. (If FAILED, this task is BLOCKED and the plan must be re-planned to add IndexedDB persistence work.)
|
||||||
|
|
||||||
3-file lockstep update per the Approach B harness extension pattern:
|
3-file lockstep update per the Approach B harness extension pattern:
|
||||||
|
|
||||||
**File 1: tests/uat/extension-page-harness.ts**
|
**File 1: tests/uat/extension-page-harness.ts**
|
||||||
- Locate the existing `__mokoshHarness` registration block (~line 3971) and the `__mokoshHarness` Window interface declaration (~line 3950).
|
- REVISION iter-2 — Option B per plan-checker BLOCKER 2: the existing `__mokoshHarness` surface is `assertA1..A31 + getManifestVersion`; `dispatchSaveArchive` does NOT exist and we do NOT add it. SAVE_ARCHIVE dispatch happens directly via `chrome.runtime.sendMessage` inside driveA33's `page.evaluate` (matches the established assertA31 pattern at lines 3886-3890).
|
||||||
- Add a thin `dispatchSaveArchive()` helper to `__mokoshHarness` if not already present (it may exist as `dispatchSaveArchiveForA33` or similar; reuse the existing SAVE_ARCHIVE dispatch). If the existing `setupFreshRecording` already covers Step 1 (priming the recording), no new page-side helper is needed — driveA33 calls it directly via `page.evaluate`.
|
- Decision: NO new page-side function. driveA33 (host-side) drives Step 1 (prime) by calling an existing `__mokoshHarness.assertA<N>` method that bootstraps a fresh recording (confirm in read_first which existing assertA* is the canonical "prime fresh recording" entrypoint — `assertA1` is the leading candidate; falling back to `assertA5`/`assertA26` if a more direct method matches the spike's actual call site). Step 5 (SAVE) uses inline `chrome.runtime.sendMessage` per the `<interfaces>` block above.
|
||||||
- If a Step-1 page-side helper IS needed for driveA33: add a thin wrapper `setupFreshRecordingForA33` that's a 1-line forwarder to existing `setupFreshRecording`. Per RESEARCH note (FORBIDDEN_HOOK_STRINGS stays at 12): NO new test-only symbol needed — the new helper calls existing production-surface APIs.
|
- Verify no edits needed to `__mokoshHarness` registration block (lines 3932-4015): the surface stays at 31 assertA* + getManifestVersion. The Tier-1 FORBIDDEN_HOOK_STRINGS inventory stays at 12 entries (no new test-only symbol).
|
||||||
- Add `assertA33` ENTRY to the `__mokoshHarness` window interface declaration (`assertA33: () => Promise<AssertionResult>;`) IF a page-side assertA33 is needed. Per RESEARCH driveA33 pattern: the host-side driveA33 owns the 5-min wait + SW kill + SAVE dispatch via the existing harness methods — likely NO new `assertA33` page-side function is needed; the host-side drives everything via existing primitives.
|
- If, during read_first, the planner determines that NONE of the existing assertA* methods deliver "prime + leave recording active for ≥5 min", THEN add a thin page-side primer `primeForA33` that calls existing production-surface APIs (REQUEST_PERMISSIONS → START_RECORDING via chrome.runtime.sendMessage); this is a deviation from Option B and must be flagged in the SUMMARY. Per RESEARCH note (FORBIDDEN_HOOK_STRINGS stays at 12): NO new test-only `__MOKOSH_UAT__`-gated symbol; any new page-side helper uses production APIs only.
|
||||||
- If page-side function is NOT needed: just verify orchestrator uses host-only driveA33 (Step 1's setupFreshRecording is already there; Step 5's dispatchSaveArchive call uses existing SAVE_ARCHIVE messaging).
|
|
||||||
- Decision recorded in plan SUMMARY.
|
|
||||||
|
|
||||||
**File 2: tests/uat/lib/harness-page-driver.ts**
|
**File 2: tests/uat/lib/harness-page-driver.ts**
|
||||||
- Append `driveA33` function per RESEARCH Code Example Pattern 4 (full body in `<interfaces>` above).
|
- Append `driveA33` function per RESEARCH Code Example Pattern 4 (full body in `<interfaces>` above; REVISION iter-2 inline-dispatched SAVE).
|
||||||
- Place it after the existing driveA32 (which is the most-recent Phase 3 addition).
|
- Place it after the existing driveA32 (which is the most-recent Phase 3 addition).
|
||||||
- Verify the `stopServiceWorker` helper from Task 1 is in scope (same file).
|
- Verify the `stopServiceWorker` helper from Task 1 is in scope (same file).
|
||||||
- Filter-pipeline form; no `continue`; typed function signature `(page, browser, extensionId, downloadsDir) => Promise<AssertionRecord>` per the new 4-arg shape.
|
- Filter-pipeline form; no `continue`; typed function signature `(page, browser, extensionId, downloadsDir) => Promise<AssertionRecord>` per the new 4-arg shape.
|
||||||
- Add `import { readFileSync } from 'node:fs';` + `import JSZip from 'jszip';` if not already present (they should be — these are reused from driveA29/30/31).
|
- Add `import { readFileSync } from 'node:fs';` + `import JSZip from 'jszip';` if not already present (they should be — these are reused from driveA29/30/31).
|
||||||
|
- The Step-5 SAVE_ARCHIVE inline `page.evaluate` block uses `chrome.runtime.sendMessage({type: 'SAVE_ARCHIVE'}, callback)` per the `<interfaces>` Code Example; verify by `grep -c "type: 'SAVE_ARCHIVE'" tests/uat/lib/harness-page-driver.ts` increases by ≥ 1 vs pre-edit baseline (was 0 in driveA29/30/31 because those call sites are inside extension-page-harness.ts assertA* methods; A33 is unique in dispatching from the host-side via page.evaluate).
|
||||||
|
|
||||||
**File 3: tests/uat/harness.test.ts**
|
**File 3: tests/uat/harness.test.ts**
|
||||||
- Import: add `driveA33,` to the import block at ~line 101 (alongside `driveA29`-`driveA32`).
|
- Import: add `driveA33,` to the import block at ~line 101 (alongside `driveA29`-`driveA32`).
|
||||||
@@ -339,9 +395,10 @@ The spike's job: verify this RAM-only design survives a 5-min SW idle. If it doe
|
|||||||
- Quick UAT: `HEADLESS=1 SKIP_PROD_REBUILD=1 SKIP_LONG_UAT=1 npm run test:uat` exits 0 with 34/34 GREEN (A33 SKIPPED message visible; preserves baseline + adds A33 skip placeholder).
|
- Quick UAT: `HEADLESS=1 SKIP_PROD_REBUILD=1 SKIP_LONG_UAT=1 npm run test:uat` exits 0 with 34/34 GREEN (A33 SKIPPED message visible; preserves baseline + adds A33 skip placeholder).
|
||||||
- Full UAT: `HEADLESS=1 SKIP_PROD_REBUILD=1 npm run test:uat` exits 0 with 34/34 GREEN (A33 actually runs ~6 min wall-clock; A33.1 SAVE ack + A33.2 size > 0 + A33.3 size > 100 KB all PASS).
|
- Full UAT: `HEADLESS=1 SKIP_PROD_REBUILD=1 npm run test:uat` exits 0 with 34/34 GREEN (A33 actually runs ~6 min wall-clock; A33.1 SAVE ack + A33.2 size > 0 + A33.3 size > 100 KB all PASS).
|
||||||
- Tier-1 FORBIDDEN_HOOK_STRINGS check: `grep -c 'FORBIDDEN_HOOK_STRINGS' tests/uat/harness.test.ts tests/background/no-test-hooks-in-prod-bundle.test.ts` — verify the inventory count in both files unchanged (preserves the 12-entry invariant per CONTEXT §"Claude's Discretion").
|
- Tier-1 FORBIDDEN_HOOK_STRINGS check: `grep -c 'FORBIDDEN_HOOK_STRINGS' tests/uat/harness.test.ts tests/background/no-test-hooks-in-prod-bundle.test.ts` — verify the inventory count in both files unchanged (preserves the 12-entry invariant per CONTEXT §"Claude's Discretion").
|
||||||
|
- REVISION iter-2 gate: `grep -c 'dispatchSaveArchive' tests/uat/lib/harness-page-driver.ts tests/uat/extension-page-harness.ts tests/uat/harness.test.ts` returns 0 (the non-existent helper is NOT introduced).
|
||||||
</action>
|
</action>
|
||||||
<verify>
|
<verify>
|
||||||
<automated>npx tsc --noEmit && npm run build:test && HEADLESS=1 SKIP_PROD_REBUILD=1 SKIP_LONG_UAT=1 npm run test:uat 2>&1 | tail -5 | tee /tmp/04-04-task-2-skip.log; grep -c '34/34' /tmp/04-04-task-2-skip.log</automated>
|
<automated>npx tsc --noEmit && npm run build:test && HEADLESS=1 SKIP_PROD_REBUILD=1 SKIP_LONG_UAT=1 npm run test:uat 2>&1 | tail -5 | tee /tmp/04-04-task-2-skip.log; grep -c '34/34' /tmp/04-04-task-2-skip.log; grep -c 'dispatchSaveArchive' tests/uat/lib/harness-page-driver.ts tests/uat/extension-page-harness.ts tests/uat/harness.test.ts</automated>
|
||||||
</verify>
|
</verify>
|
||||||
<acceptance_criteria>
|
<acceptance_criteria>
|
||||||
- `npx tsc --noEmit` exits 0.
|
- `npx tsc --noEmit` exits 0.
|
||||||
@@ -352,6 +409,7 @@ The spike's job: verify this RAM-only design survives a 5-min SW idle. If it doe
|
|||||||
- `grep -c 'A33' tests/uat/harness.test.ts` returns ≥ 4 (import + wrapped + push + comment banner).
|
- `grep -c 'A33' tests/uat/harness.test.ts` returns ≥ 4 (import + wrapped + push + comment banner).
|
||||||
- `grep -c 'SKIP_LONG_UAT' tests/uat/harness.test.ts` returns ≥ 2 (env-gate + comment).
|
- `grep -c 'SKIP_LONG_UAT' tests/uat/harness.test.ts` returns ≥ 2 (env-gate + comment).
|
||||||
- FORBIDDEN_HOOK_STRINGS count unchanged at 12 (no new test-only symbols introduced per CONTEXT §"Claude's Discretion"; verify by `wc -l` of the inventory arrays).
|
- FORBIDDEN_HOOK_STRINGS count unchanged at 12 (no new test-only symbols introduced per CONTEXT §"Claude's Discretion"; verify by `wc -l` of the inventory arrays).
|
||||||
|
- REVISION iter-2 gate (Option B): `grep -c 'dispatchSaveArchive' tests/uat/` returns 0 across all harness files; SAVE_ARCHIVE dispatched via `chrome.runtime.sendMessage({type: 'SAVE_ARCHIVE'}, ...)` only.
|
||||||
</acceptance_criteria>
|
</acceptance_criteria>
|
||||||
<done>A33 lands; UAT 33→34 GREEN; SW persistence empirically verified at 5-min idle scale. Atomic commit: `feat(04-04): Wave 1 — A33 SW state persistence harness assertion (34/34 GREEN)`.</done>
|
<done>A33 lands; UAT 33→34 GREEN; SW persistence empirically verified at 5-min idle scale. Atomic commit: `feat(04-04): Wave 1 — A33 SW state persistence harness assertion (34/34 GREEN)`.</done>
|
||||||
</task>
|
</task>
|
||||||
@@ -386,6 +444,7 @@ The spike's job: verify this RAM-only design survives a 5-min SW idle. If it doe
|
|||||||
- FORBIDDEN_HOOK_STRINGS count unchanged at 12.
|
- FORBIDDEN_HOOK_STRINGS count unchanged at 12.
|
||||||
- vitest baseline preserved (≥ 181 GREEN from Plans 04-01 + 04-02).
|
- vitest baseline preserved (≥ 181 GREEN from Plans 04-01 + 04-02).
|
||||||
- A29 + A30 + A31 + A32 unchanged (no regression to existing assertions).
|
- A29 + A30 + A31 + A32 unchanged (no regression to existing assertions).
|
||||||
|
- REVISION iter-2 invariant: `grep -c 'dispatchSaveArchive' tests/uat/` returns 0 across spike script + harness files.
|
||||||
</verification>
|
</verification>
|
||||||
|
|
||||||
<success_criteria>
|
<success_criteria>
|
||||||
@@ -401,7 +460,7 @@ The spike's job: verify this RAM-only design survives a 5-min SW idle. If it doe
|
|||||||
After completion, create `.planning/phases/04-harden-clean-up-optional/04-04-SUMMARY.md` capturing:
|
After completion, create `.planning/phases/04-harden-clean-up-optional/04-04-SUMMARY.md` capturing:
|
||||||
- Spike outcome (videoSize value + interpretation; SPIKE PASSED/FAILED tag)
|
- Spike outcome (videoSize value + interpretation; SPIKE PASSED/FAILED tag)
|
||||||
- stopServiceWorker helper diff (full body)
|
- stopServiceWorker helper diff (full body)
|
||||||
- driveA33 diff (full body)
|
- driveA33 diff (full body; inline chrome.runtime.sendMessage SAVE per REVISION iter-2 Option B)
|
||||||
- Orchestrator wiring diff (3 sites in harness.test.ts)
|
- Orchestrator wiring diff (3 sites in harness.test.ts)
|
||||||
- SKIP_LONG_UAT env-gate decision (default RUN; rationale)
|
- SKIP_LONG_UAT env-gate decision (default RUN; rationale)
|
||||||
- UAT before/after (33/33 → 34/34)
|
- UAT before/after (33/33 → 34/34)
|
||||||
@@ -411,4 +470,3 @@ After completion, create `.planning/phases/04-harden-clean-up-optional/04-04-SUM
|
|||||||
- If spike FAILED: detailed failure mode + flag for re-planning (this branch is unlikely per RESEARCH MEDIUM-confidence; document as ALPHA-PATH-NOT-TAKEN)
|
- If spike FAILED: detailed failure mode + flag for re-planning (this branch is unlikely per RESEARCH MEDIUM-confidence; document as ALPHA-PATH-NOT-TAKEN)
|
||||||
</output>
|
</output>
|
||||||
</content>
|
</content>
|
||||||
</invoke>
|
|
||||||
@@ -253,6 +253,9 @@ No change strictly required; the bare class selector matches both `<img class="w
|
|||||||
From tests/uat/extension-page-harness.ts:2249-2294 (current A17.8 — Plan 01-10 mark-bundling invariant):
|
From tests/uat/extension-page-harness.ts:2249-2294 (current A17.8 — Plan 01-10 mark-bundling invariant):
|
||||||
- Current: asserts welcome chunk JS contains `data:image/svg+xml,...` data URL + canonical viewBox.
|
- Current: asserts welcome chunk JS contains `data:image/svg+xml,...` data URL + canonical viewBox.
|
||||||
- Post-Plan-04-06: assert welcome chunk JS contains raw SVG source as string literal with `currentColor` + canonical viewBox. May split into A17.8a (raw bundling) + A17.8b (runtime inline <svg> injection check via DOM query).
|
- Post-Plan-04-06: assert welcome chunk JS contains raw SVG source as string literal with `currentColor` + canonical viewBox. May split into A17.8a (raw bundling) + A17.8b (runtime inline <svg> injection check via DOM query).
|
||||||
|
|
||||||
|
SW chunk canonical glob (REVISION iter-2 — plan-checker BLOCKER 1):
|
||||||
|
The Vite SW chunk is `dist/assets/index.ts-<hash>.js` (verified empirically — `dist/assets/index.ts-8LkXuqac.js` confirmed on disk; also pinned by RESEARCH Q1 finding lines 142/180/196). All Phase 4 bundle gates MUST use the `dist/assets/index.ts-*.js` glob, NOT `dist/assets/index*-bg.js` (which matches no files and would silently return 0 on grep — spurious PASS). Task 4 pre-checkpoint gates use this canonical glob for Gates 2/3/4.
|
||||||
</interfaces>
|
</interfaces>
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
@@ -396,28 +399,31 @@ From tests/uat/extension-page-harness.ts:2249-2294 (current A17.8 — Plan 01-10
|
|||||||
<action>
|
<action>
|
||||||
Step 1 — Pre-checkpoint bundle gates (orchestrator-driven; per saved memory `feedback-pre-checkpoint-bundle-gates.md`; MUST PASS before surfacing Step 2 to operator):
|
Step 1 — Pre-checkpoint bundle gates (orchestrator-driven; per saved memory `feedback-pre-checkpoint-bundle-gates.md`; MUST PASS before surfacing Step 2 to operator):
|
||||||
1. `npm run build` -> exit 0; dist/ populated.
|
1. `npm run build` -> exit 0; dist/ populated.
|
||||||
2. SW CSP-safety grep: `grep -rE 'new Function\(|eval\(' dist/assets/index*-bg.js` -> 0 hits (Plan 04-02 effect preserved).
|
2. SW CSP-safety grep (REVISION iter-2 — canonical SW chunk glob per RESEARCH Q1; was `index*-bg.js` which matches no files): `grep -cE 'new Function\(|eval\(' dist/assets/index.ts-*.js` -> 0 hits (Plan 04-02 effect preserved). The pipe-counted form ensures a SPURIOUS-PASS-PROOF gate — if the glob ever matches zero files, the gate registers as missing rather than silent 0.
|
||||||
3. SW Node-globals grep: `grep -rE 'Buffer\.from|Buffer\.alloc|process\.|require\(' dist/assets/index*-bg.js` -> 0 hits.
|
3. SW Node-globals grep (REVISION iter-2 — canonical SW chunk glob): `grep -cE 'Buffer\.from|Buffer\.alloc|process\.|require\(' dist/assets/index.ts-*.js` -> 0 hits.
|
||||||
4. DOM-globals grep: `grep -rE '(window\.|document\.)' dist/assets/index*-bg.js | grep -vE '^//|globalThis|^$'` -> 0 hits in SW chunk.
|
4. DOM-globals grep (REVISION iter-2 — canonical SW chunk glob): `grep -E '(window\.|document\.)' dist/assets/index.ts-*.js | grep -vE '^//|globalThis|^$' | wc -l` -> 0 hits in SW chunk.
|
||||||
5. Tier-1 SW-bundle-import gate: `npx vitest run tests/background/sw-bundle-import.test.ts` -> GREEN.
|
5. Tier-1 SW-bundle-import gate: `npx vitest run tests/background/sw-bundle-import.test.ts` -> GREEN.
|
||||||
6. Tier-1 FORBIDDEN_HOOK_STRINGS gate: `npx vitest run tests/background/no-test-hooks-in-prod-bundle.test.ts` -> 12 strings, 0 hits each -> GREEN.
|
6. Tier-1 FORBIDDEN_HOOK_STRINGS gate: `npx vitest run tests/background/no-test-hooks-in-prod-bundle.test.ts` -> 12 strings, 0 hits each -> GREEN.
|
||||||
|
|
||||||
|
**REVISION iter-2 — Glob existence pre-gate (BLOCKER 1 mitigation):** before running Gates 2/3/4, verify the glob actually matches at least one file: `ls dist/assets/index.ts-*.js 2>/dev/null | wc -l` MUST return >= 1. If 0, the build is broken (SW chunk missing) OR the canonical filename pattern shifted — fail loudly rather than silently 0-grep.
|
||||||
|
|
||||||
Step 2 — Operator-driven empirical UAT cycle (manual; ~3-5 min): See `<how-to-verify>` block below for the operator-facing instructions.
|
Step 2 — Operator-driven empirical UAT cycle (manual; ~3-5 min): See `<how-to-verify>` block below for the operator-facing instructions.
|
||||||
|
|
||||||
Step 3 — Resume signal handling: orchestrator waits for operator response per `<resume-signal>` block below.
|
Step 3 — Resume signal handling: orchestrator waits for operator response per `<resume-signal>` block below.
|
||||||
</action>
|
</action>
|
||||||
<verify>
|
<verify>
|
||||||
<automated>npm run build && grep -c 'new Function' dist/assets/index*-bg.js | head -1; HEADLESS=1 SKIP_PROD_REBUILD=1 SKIP_LONG_UAT=1 npm run test:uat 2>&1 | tail -3</automated>
|
<automated>npm run build && ls dist/assets/index.ts-*.js | wc -l; grep -cE 'new Function\(|eval\(' dist/assets/index.ts-*.js; HEADLESS=1 SKIP_PROD_REBUILD=1 SKIP_LONG_UAT=1 npm run test:uat 2>&1 | tail -3</automated>
|
||||||
</verify>
|
</verify>
|
||||||
<done>Operator returns "approved" verbatim OR describes a specific issue; if issue, route via `/gsd-debug` per `feedback-gsd-ceremony-for-fixes.md`.</done>
|
<done>Operator returns "approved" verbatim OR describes a specific issue; if issue, route via `/gsd-debug` per `feedback-gsd-ceremony-for-fixes.md`.</done>
|
||||||
<what-built>
|
<what-built>
|
||||||
UI-SPEC dark-logo contrast strategy: SVG stroke recolor + inline-SVG injection + ambient module decl + harness update + cursor-visibility regression pin + docs back-patch. Pre-checkpoint bundle gates 6/6 PASS:
|
UI-SPEC dark-logo contrast strategy: SVG stroke recolor + inline-SVG injection + ambient module decl + harness update + cursor-visibility regression pin + docs back-patch. Pre-checkpoint bundle gates 6/6 PASS:
|
||||||
- Gate 1: `npm run build` exit 0
|
- Gate 1: `npm run build` exit 0
|
||||||
- Gate 2: `grep -c 'new Function' dist/assets/index.ts-*.js` returns 0 (Plan 04-02 effect preserved)
|
- Gate 2: `grep -c 'new Function' dist/assets/index.ts-*.js` returns 0 (Plan 04-02 effect preserved; canonical SW chunk glob)
|
||||||
- Gate 3: SW Node-globals grep clean
|
- Gate 3: SW Node-globals grep clean against `dist/assets/index.ts-*.js`
|
||||||
- Gate 4: DOM-globals bundled-lib idiom (typeof-guarded)
|
- Gate 4: DOM-globals bundled-lib idiom (typeof-guarded) against `dist/assets/index.ts-*.js`
|
||||||
- Gate 5: Tier-1 SW-bundle-import unit gate GREEN
|
- Gate 5: Tier-1 SW-bundle-import unit gate GREEN
|
||||||
- Gate 6: FORBIDDEN_HOOK_STRINGS at 12 (no change)
|
- Gate 6: FORBIDDEN_HOOK_STRINGS at 12 (no change)
|
||||||
|
- Glob-existence pre-gate: `ls dist/assets/index.ts-*.js | wc -l` returns >= 1 (prevents silent 0-hit pass on mis-glob)
|
||||||
- Plus pre-checkpoint vitest baseline >=185 GREEN; UAT harness 35/35 GREEN.
|
- Plus pre-checkpoint vitest baseline >=185 GREEN; UAT harness 35/35 GREEN.
|
||||||
|
|
||||||
Auto-confirms:
|
Auto-confirms:
|
||||||
@@ -462,6 +468,7 @@ From tests/uat/extension-page-harness.ts:2249-2294 (current A17.8 — Plan 01-10
|
|||||||
| T-04-06-01 | Tampering | a future developer might switch DOMParser to innerHTML for "simplicity" — innerHTML in a content script context is unsafe (CSP risk + script-execution surface) | mitigate | Inline code comment + executor-pattern in the action: "NEVER use innerHTML — DOMParser + appendChild only (MV3 CSP discipline)"; A17.8 harness check verifies the inline-SVG DOM shape (defense in depth) |
|
| T-04-06-01 | Tampering | a future developer might switch DOMParser to innerHTML for "simplicity" — innerHTML in a content script context is unsafe (CSP risk + script-execution surface) | mitigate | Inline code comment + executor-pattern in the action: "NEVER use innerHTML — DOMParser + appendChild only (MV3 CSP discipline)"; A17.8 harness check verifies the inline-SVG DOM shape (defense in depth) |
|
||||||
| T-04-06-02 | Information Disclosure | the inline SVG has no PII or secret; it's the canonical Mokosh brand mark | accept | Static brand asset; out-of-tree threat surface |
|
| T-04-06-02 | Information Disclosure | the inline SVG has no PII or secret; it's the canonical Mokosh brand mark | accept | Static brand asset; out-of-tree threat surface |
|
||||||
| T-04-06-03 | Spoofing | cursor visibility in captured frames could leak sensitive UI overlay state (e.g., 2FA OTP digit operator was about to type) — but this is a known and intended diagnostic feature per Plan 01-07 obs; out of scope for password masking per D-P3-02 charter | accept | Operator-side responsibility per CONTEXT charter; v2 candidate per CONTEXT Deferred Ideas |
|
| T-04-06-03 | Spoofing | cursor visibility in captured frames could leak sensitive UI overlay state (e.g., 2FA OTP digit operator was about to type) — but this is a known and intended diagnostic feature per Plan 01-07 obs; out of scope for password masking per D-P3-02 charter | accept | Operator-side responsibility per CONTEXT charter; v2 candidate per CONTEXT Deferred Ideas |
|
||||||
|
| T-04-06-04 | Repudiation (REVISION iter-2 — BLOCKER 1) | A mis-globbed `dist/assets/index*-bg.js` matches no files; `grep -c new Function` returns 0; Gate 2 spuriously PASSES even if the setimmediate polyfill never landed | mitigate | Canonical SW chunk glob `dist/assets/index.ts-*.js` verified empirically (file `index.ts-8LkXuqac.js` exists on disk; pinned by RESEARCH Q1 lines 142/180/196); pre-gate `ls dist/assets/index.ts-*.js \| wc -l >= 1` validates the glob matches BEFORE running the grep gates |
|
||||||
</threat_model>
|
</threat_model>
|
||||||
|
|
||||||
<verification>
|
<verification>
|
||||||
@@ -474,7 +481,7 @@ From tests/uat/extension-page-harness.ts:2249-2294 (current A17.8 — Plan 01-10
|
|||||||
- UAT harness 35/35 GREEN with updated A17.8 (no harness count change; assertion quality changes).
|
- UAT harness 35/35 GREEN with updated A17.8 (no harness count change; assertion quality changes).
|
||||||
- 01-07-SUMMARY.md back-patched.
|
- 01-07-SUMMARY.md back-patched.
|
||||||
- Operator empirical ack received (Task 4 resume signal "approved").
|
- Operator empirical ack received (Task 4 resume signal "approved").
|
||||||
- Pre-checkpoint bundle gates 6/6 PASS.
|
- Pre-checkpoint bundle gates 6/6 PASS (REVISION iter-2 — canonical SW chunk glob `dist/assets/index.ts-*.js` used across Gates 2/3/4; glob-existence pre-gate `ls dist/assets/index.ts-*.js | wc -l >= 1` validates).
|
||||||
- PNG toolbar icons byte-identical (no change to scripts/rasterize-icons.sh or icons/*.png).
|
- PNG toolbar icons byte-identical (no change to scripts/rasterize-icons.sh or icons/*.png).
|
||||||
</verification>
|
</verification>
|
||||||
|
|
||||||
@@ -485,7 +492,7 @@ From tests/uat/extension-page-harness.ts:2249-2294 (current A17.8 — Plan 01-10
|
|||||||
- ROADMAP cursor visibility item GREEN.
|
- ROADMAP cursor visibility item GREEN.
|
||||||
- ROADMAP dark-surface logo contrast item GREEN.
|
- ROADMAP dark-surface logo contrast item GREEN.
|
||||||
- Operator empirical ack received on dark-mode visual aesthetic.
|
- Operator empirical ack received on dark-mode visual aesthetic.
|
||||||
- Pre-checkpoint bundle gates 6/6 PASS preserved.
|
- Pre-checkpoint bundle gates 6/6 PASS preserved (REVISION iter-2 — canonical glob).
|
||||||
- UAT harness 35/35 GREEN preserved.
|
- UAT harness 35/35 GREEN preserved.
|
||||||
- vitest baseline +4 (Plan 04-05 baseline 181 -> Plan 04-06 baseline >= 185).
|
- vitest baseline +4 (Plan 04-05 baseline 181 -> Plan 04-06 baseline >= 185).
|
||||||
</success_criteria>
|
</success_criteria>
|
||||||
@@ -499,10 +506,9 @@ After completion, create `.planning/phases/04-harden-clean-up-optional/04-06-SUM
|
|||||||
- 01-07-SUMMARY.md back-patch (5 stale Phase-5 lines flipped)
|
- 01-07-SUMMARY.md back-patch (5 stale Phase-5 lines flipped)
|
||||||
- 2 new test files (inline-svg + cursor-visibility) with RED->GREEN cycle commits
|
- 2 new test files (inline-svg + cursor-visibility) with RED->GREEN cycle commits
|
||||||
- Operator empirical UAT verbatim ack (e.g., "approved", "all good", or specific issues)
|
- Operator empirical UAT verbatim ack (e.g., "approved", "all good", or specific issues)
|
||||||
- Pre-checkpoint bundle gates 6/6 PASS evidence (grep outputs)
|
- Pre-checkpoint bundle gates 6/6 PASS evidence (grep outputs against canonical `dist/assets/index.ts-*.js` glob per REVISION iter-2)
|
||||||
- vitest before/after (181 -> >=185)
|
- vitest before/after (181 -> >=185)
|
||||||
- UAT 35/35 GREEN preservation
|
- UAT 35/35 GREEN preservation
|
||||||
- Commit refs (Tasks 1 + 2 + 3 + 4 ack)
|
- Commit refs (Tasks 1 + 2 + 3 + 4 ack)
|
||||||
</output>
|
</output>
|
||||||
</content>
|
</content>
|
||||||
</invoke>
|
|
||||||
@@ -35,7 +35,7 @@ must_haves:
|
|||||||
- "All P1 polish items (#11 + #14 + #15) cited as GREEN with Plan 04-01 evidence"
|
- "All P1 polish items (#11 + #14 + #15) cited as GREEN with Plan 04-01 evidence"
|
||||||
- "All Phase 4 hardening items (setimmediate + dead-code + generate-icons + A29 race fix + cursor verification + dark-logo + ROADMAP backfill) cited as GREEN with their plan + commit refs"
|
- "All Phase 4 hardening items (setimmediate + dead-code + generate-icons + A29 race fix + cursor verification + dark-logo + ROADMAP backfill) cited as GREEN with their plan + commit refs"
|
||||||
- "Pre-checkpoint bundle gates 6/6 PASS evidence (per saved memory feedback-pre-checkpoint-bundle-gates.md)"
|
- "Pre-checkpoint bundle gates 6/6 PASS evidence (per saved memory feedback-pre-checkpoint-bundle-gates.md)"
|
||||||
- "Operator empirical ack from Plan 04-06 cited verbatim with date stamp"
|
- "Operator empirical ack from Plan 04-06 cited verbatim with date stamp (REVISION iter-2 WARNING 4 — Task 1 verify greps the ack literal from 04-VERIFICATION.md to confirm it's a REAL ack, not a placeholder)"
|
||||||
- "Deferred Items table carries forward the v1.1/v2 items: rrweb v2 upgrade + programmatic SW-RAM measurement + REQ-password-confidentiality v2 candidate"
|
- "Deferred Items table carries forward the v1.1/v2 items: rrweb v2 upgrade + programmatic SW-RAM measurement + REQ-password-confidentiality v2 candidate"
|
||||||
- "ROADMAP.md Phase 4 row flipped [x] with closure date; harness count updated from 33 to 35 (Plans 04-04 + 04-05 added A33 + A34)"
|
- "ROADMAP.md Phase 4 row flipped [x] with closure date; harness count updated from 33 to 35 (Plans 04-04 + 04-05 added A33 + A34)"
|
||||||
- "ROADMAP.md Plans 01-08..01-13 rows verified per D-P4-05 backfill (per plan-checker flag #4)"
|
- "ROADMAP.md Plans 01-08..01-13 rows verified per D-P4-05 backfill (per plan-checker flag #4)"
|
||||||
@@ -133,6 +133,9 @@ Per CONTEXT §"Deferred Ideas" — v1.1/v2 items to carry forward in 04-VERIFICA
|
|||||||
- REQ-password-confidentiality v2 candidate (D-P3-02; only if charter reverses)
|
- REQ-password-confidentiality v2 candidate (D-P3-02; only if charter reverses)
|
||||||
- Alpha-tester findings integration (D-P4-04; routed via separate maintenance window)
|
- Alpha-tester findings integration (D-P4-04; routed via separate maintenance window)
|
||||||
|
|
||||||
|
Operator empirical ack format (REVISION iter-2 — WARNING 4 mitigation):
|
||||||
|
Plan 04-06 Task 4's `<resume-signal>` is canonically: `Type "approved" or describe issues (e.g., "stroke too thin", ...)`. The Phase 4 prior-art ack pattern from Plan 01-10 cycle-2 was `"All good" 2026-05-20`. The 04-VERIFICATION.md `human_verification[0].evidence` field MUST contain the verbatim operator ack from the 04-06 Task 4 SUMMARY — matching ONE of: `approved`, `All good`, `APPROVED`, `approved by`, `operator ack`, `all good`. The Task 1 `<verify><automated>` greps the file for these patterns to ensure the field is a REAL ack, not a placeholder string like "TBD" or "TODO" or "<verbatim>".
|
||||||
|
|
||||||
Frontmatter sketch for 04-VERIFICATION.md:
|
Frontmatter sketch for 04-VERIFICATION.md:
|
||||||
```yaml
|
```yaml
|
||||||
# (yaml document marker omitted for parser-compat)
|
# (yaml document marker omitted for parser-compat)
|
||||||
@@ -166,7 +169,7 @@ human_verification:
|
|||||||
- test: "dark-mode operator visual aesthetic on welcome hero"
|
- test: "dark-mode operator visual aesthetic on welcome hero"
|
||||||
expected: "mark legible on OS dark-mode rendering surface"
|
expected: "mark legible on OS dark-mode rendering surface"
|
||||||
why_human: "Aesthetic contrast judgment — UI-SPEC §'Manual-Only Verifications' acceptance criterion #6; canonical operator-empirical case per feedback-trust-harness-over-manual-uat.md"
|
why_human: "Aesthetic contrast judgment — UI-SPEC §'Manual-Only Verifications' acceptance criterion #6; canonical operator-empirical case per feedback-trust-harness-over-manual-uat.md"
|
||||||
evidence: "Plan 04-06 Task 4 operator ack <verbatim>"
|
evidence: "Plan 04-06 Task 4 operator ack <VERBATIM_ACK_FROM_PLAN_04_06_SUMMARY>"
|
||||||
deferred:
|
deferred:
|
||||||
- truth: "rrweb 2.0.0-alpha.4 -> stable v2 upgrade"
|
- truth: "rrweb 2.0.0-alpha.4 -> stable v2 upgrade"
|
||||||
addressed_in: "v1.1 / v2 maintenance milestone"
|
addressed_in: "v1.1 / v2 maintenance milestone"
|
||||||
@@ -182,6 +185,7 @@ deferred:
|
|||||||
evidence: "D-P4-04 charter — operator handles alpha signal out-of-band"
|
evidence: "D-P4-04 charter — operator handles alpha signal out-of-band"
|
||||||
# (yaml document marker omitted for parser-compat)
|
# (yaml document marker omitted for parser-compat)
|
||||||
```
|
```
|
||||||
|
The placeholder `<VERBATIM_ACK_FROM_PLAN_04_06_SUMMARY>` MUST be replaced with the actual operator response captured in 04-06-SUMMARY.md (e.g., "approved 2026-05-21" or "All good 2026-05-21" or longer verbatim quote). The Task 1 verify-gate greps for the ack literal to ensure the placeholder is NOT left intact.
|
||||||
</interfaces>
|
</interfaces>
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
@@ -190,16 +194,16 @@ deferred:
|
|||||||
<task type="auto">
|
<task type="auto">
|
||||||
<name>Task 1: Write 04-VERIFICATION.md aggregator (NEW)</name>
|
<name>Task 1: Write 04-VERIFICATION.md aggregator (NEW)</name>
|
||||||
<files>.planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md</files>
|
<files>.planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md</files>
|
||||||
<read_first>.planning/phases/01-stabilize-video-pipeline/01-VERIFICATION.md, .planning/phases/02-stabilize-export-pipeline/02-VERIFICATION.md, .planning/phases/03-spec-10-smoke-verification-dom-event-log-verification/03-VERIFICATION.md, all Plan 04-01..04-06 SUMMARY files (.planning/phases/04-harden-clean-up-optional/04-0?-SUMMARY.md — produced by the prior plans)</read_first>
|
<read_first>.planning/phases/01-stabilize-video-pipeline/01-VERIFICATION.md, .planning/phases/02-stabilize-export-pipeline/02-VERIFICATION.md, .planning/phases/03-spec-10-smoke-verification-dom-event-log-verification/03-VERIFICATION.md, all Plan 04-01..04-06 SUMMARY files (.planning/phases/04-harden-clean-up-optional/04-0?-SUMMARY.md — produced by the prior plans), specifically Plan 04-06 SUMMARY for the verbatim operator ack quote (REVISION iter-2 WARNING 4 — required for human_verification[0].evidence)</read_first>
|
||||||
<action>
|
<action>
|
||||||
1. Read the 3 precedent VERIFICATION.md files (Phase 1 + 2 + 3) ONCE each to extract the canonical frontmatter shape + body section structure. Read each Plan 04-01..04-06 SUMMARY.md once to extract evidence (commit refs, test counts, harness assertion numbers, pre/post measurements).
|
1. Read the 3 precedent VERIFICATION.md files (Phase 1 + 2 + 3) ONCE each to extract the canonical frontmatter shape + body section structure. Read each Plan 04-01..04-06 SUMMARY.md once to extract evidence (commit refs, test counts, harness assertion numbers, pre/post measurements). **Specifically extract the verbatim operator ack quote from Plan 04-06 Task 4 SUMMARY** — Task 1 verify-gate requires the ack literal to be present in human_verification[0].evidence.
|
||||||
|
|
||||||
2. Create `.planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md` with frontmatter per the sketch in `<interfaces>` above. Replace placeholder fields with actual values from the Plan 04-01..04-06 SUMMARYs:
|
2. Create `.planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md` with frontmatter per the sketch in `<interfaces>` above. Replace placeholder fields with actual values from the Plan 04-01..04-06 SUMMARYs:
|
||||||
- `verified:` — current ISO timestamp (`date -u +%Y-%m-%dT%H:%M:%SZ`)
|
- `verified:` — current ISO timestamp (`date -u +%Y-%m-%dT%H:%M:%SZ`)
|
||||||
- `score:` — fill in actual counts from SUMMARYs
|
- `score:` — fill in actual counts from SUMMARYs
|
||||||
- `re_verification.gaps_closed[*]` — bullet per closed gap with Plan + commit citation
|
- `re_verification.gaps_closed[*]` — bullet per closed gap with Plan + commit citation
|
||||||
- `override_notes` — populate if any T5 override applied to a Phase 4 criterion (e.g., the operator-empirical UAT for dark-logo can be cited as harness-coverage-augmented rather than override; depends on Plan 04-06 outcome).
|
- `override_notes` — populate if any T5 override applied to a Phase 4 criterion (e.g., the operator-empirical UAT for dark-logo can be cited as harness-coverage-augmented rather than override; depends on Plan 04-06 outcome).
|
||||||
- `human_verification[0].evidence` — verbatim operator ack quote from Plan 04-06 Task 4 SUMMARY.
|
- `human_verification[0].evidence` — verbatim operator ack quote from Plan 04-06 Task 4 SUMMARY (REVISION iter-2 WARNING 4 — MUST contain one of: `approved`, `All good`, `APPROVED`, `approved by`, `operator ack`, `all good` — verified by Task 1 verify-gate grep).
|
||||||
- `deferred[]` — 4 v1.1/v2 items per CONTEXT Deferred Ideas + the alpha-distribution item per D-P4-04.
|
- `deferred[]` — 4 v1.1/v2 items per CONTEXT Deferred Ideas + the alpha-distribution item per D-P4-04.
|
||||||
|
|
||||||
3. Body sections (after frontmatter):
|
3. Body sections (after frontmatter):
|
||||||
@@ -208,16 +212,16 @@ deferred:
|
|||||||
- vitest count: 171 (Phase 3 baseline) -> 171 + new Wave 0 tests from Plans 04-01 + 04-02 + 04-06 = approximately 171 + 8 + 2 + 4 = 185 GREEN (verify exact count via final `npm test -- --run` invocation).
|
- vitest count: 171 (Phase 3 baseline) -> 171 + new Wave 0 tests from Plans 04-01 + 04-02 + 04-06 = approximately 171 + 8 + 2 + 4 = 185 GREEN (verify exact count via final `npm test -- --run` invocation).
|
||||||
- UAT harness count: 33 -> 35 GREEN (Plans 04-04 A33 + 04-05 A34 added; Plan 04-03 rewrote A29 in-place, count unchanged).
|
- UAT harness count: 33 -> 35 GREEN (Plans 04-04 A33 + 04-05 A34 added; Plan 04-03 rewrote A29 in-place, count unchanged).
|
||||||
- Tier-1 FORBIDDEN_HOOK_STRINGS: 12 unchanged (Phase 4 introduced no new __MOKOSH_UAT__-gated symbols per CONTEXT Claude's Discretion).
|
- Tier-1 FORBIDDEN_HOOK_STRINGS: 12 unchanged (Phase 4 introduced no new __MOKOSH_UAT__-gated symbols per CONTEXT Claude's Discretion).
|
||||||
- Pre-checkpoint bundle gates: 6/6 PASS (Plan 04-02 flipped Gate 2 polarity 1 -> 0 hits `new Function`).
|
- Pre-checkpoint bundle gates: 6/6 PASS (Plan 04-02 flipped Gate 2 polarity 1 -> 0 hits `new Function` in canonical `dist/assets/index.ts-*.js` glob — REVISION iter-2 BLOCKER 1 mitigation in Plan 04-06).
|
||||||
- `## Operator-Empirical Acks (verbatim + commit refs)`:
|
- `## Operator-Empirical Acks (verbatim + commit refs)`:
|
||||||
- Append the Plan 04-06 Task 4 ack from the SUMMARY (verbatim quote + date + commit hash).
|
- Append the Plan 04-06 Task 4 ack from the SUMMARY (verbatim quote + date + commit hash). REVISION iter-2 WARNING 4: this line MUST contain the actual operator response (e.g., `> approved 2026-05-21` or `> All good 2026-05-21`) — NOT a placeholder.
|
||||||
- `## Deferred Items` — table mirroring frontmatter `deferred:`.
|
- `## Deferred Items` — table mirroring frontmatter `deferred:`.
|
||||||
- `## ROADMAP backfill verification (D-P4-05)` — list of Plans 01-08..01-13 row presence + any newly-added rows. If all rows are already present (per PATTERNS.md noting lines 90-95 exist), this section's content is "Verified — no row additions needed; plan-checker flag #4 closed".
|
- `## ROADMAP backfill verification (D-P4-05)` — list of Plans 01-08..01-13 row presence + any newly-added rows. If all rows are already present (per PATTERNS.md noting lines 90-95 exist), this section's content is "Verified — no row additions needed; plan-checker flag #4 closed".
|
||||||
|
|
||||||
4. Commit: `docs(04-07): Phase 4 closure — 04-VERIFICATION.md aggregator (4/4 ROADMAP SCs + N/N hardening items)`.
|
4. Commit: `docs(04-07): Phase 4 closure — 04-VERIFICATION.md aggregator (4/4 ROADMAP SCs + N/N hardening items)`.
|
||||||
</action>
|
</action>
|
||||||
<verify>
|
<verify>
|
||||||
<automated>test -f .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md && grep -cE '^## ' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md; grep -c 'Plan 04-0' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md</automated>
|
<automated>test -f .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md && grep -cE '^## ' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md; grep -c 'Plan 04-0' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md; grep -cE 'approved|All good|APPROVED|approved by|operator ack|all good' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md</automated>
|
||||||
</verify>
|
</verify>
|
||||||
<acceptance_criteria>
|
<acceptance_criteria>
|
||||||
- File exists at `.planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md`.
|
- File exists at `.planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md`.
|
||||||
@@ -226,8 +230,9 @@ deferred:
|
|||||||
- File >= 120 lines.
|
- File >= 120 lines.
|
||||||
- `grep -c 'Plan 04-0' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md` returns >= 6 (one per Plan 04-01..04-06 evidence citation).
|
- `grep -c 'Plan 04-0' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md` returns >= 6 (one per Plan 04-01..04-06 evidence citation).
|
||||||
- `grep -c 'commit' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md` returns >= 6.
|
- `grep -c 'commit' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md` returns >= 6.
|
||||||
|
- REVISION iter-2 WARNING 4 — Operator ack gate: `grep -cE 'approved|All good|APPROVED|approved by|operator ack|all good' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md` returns >= 1. This proves the `human_verification[0].evidence` field contains a real operator ack literal (not the `<VERBATIM_ACK_FROM_PLAN_04_06_SUMMARY>` placeholder or "TBD"). The pattern set matches both lowercase ("approved", "all good") and titlecase/uppercase ("All good", "APPROVED") variants per the prior-art ack format from Plan 01-10 cycle-2 ("All good" 2026-05-20) AND the canonical 04-06 Task 4 `<resume-signal>` expectation ("approved" verbatim).
|
||||||
</acceptance_criteria>
|
</acceptance_criteria>
|
||||||
<done>04-VERIFICATION.md created with frontmatter + 5+ body sections + 6+ plan citations + deferred items. Commit: `docs(04-07): Phase 4 closure — 04-VERIFICATION.md aggregator`.</done>
|
<done>04-VERIFICATION.md created with frontmatter + 5+ body sections + 6+ plan citations + verbatim operator ack + deferred items. Commit: `docs(04-07): Phase 4 closure — 04-VERIFICATION.md aggregator`.</done>
|
||||||
</task>
|
</task>
|
||||||
|
|
||||||
<task type="auto">
|
<task type="auto">
|
||||||
@@ -309,6 +314,7 @@ deferred:
|
|||||||
| T-04-07-01 | Repudiation | aggregator could over-claim closure (e.g., mark ROADMAP SC #2 GREEN when only fetch is empirically verified but XHR is not) | mitigate | Each scorecard row MUST cite specific UAT assertion ID (e.g., "A34.3 XHR 404 -> network_error" or "A34.5 XHR meta.status === 404") + commit hash; absence of an assertion = row marked PARTIAL or YELLOW with explanation |
|
| T-04-07-01 | Repudiation | aggregator could over-claim closure (e.g., mark ROADMAP SC #2 GREEN when only fetch is empirically verified but XHR is not) | mitigate | Each scorecard row MUST cite specific UAT assertion ID (e.g., "A34.3 XHR 404 -> network_error" or "A34.5 XHR meta.status === 404") + commit hash; absence of an assertion = row marked PARTIAL or YELLOW with explanation |
|
||||||
| T-04-07-02 | Tampering | a docs-only commit could in theory be conflated with a code commit; the closure ceremony must be docs-pure | accept | Verification gate `git diff --stat HEAD~1 HEAD` on closure commits should show only `.planning/` files dirty; pre-commit check |
|
| T-04-07-02 | Tampering | a docs-only commit could in theory be conflated with a code commit; the closure ceremony must be docs-pure | accept | Verification gate `git diff --stat HEAD~1 HEAD` on closure commits should show only `.planning/` files dirty; pre-commit check |
|
||||||
| T-04-07-03 | Repudiation | alpha redistribution decision is non-automated (per D-P4-04 user handles out-of-band); 04-VERIFICATION.md is advisory not gating | accept | Documented in scorecard + STATE.md status field clarifies v1 close vs CLOSED-PENDING-ALPHA distinction |
|
| T-04-07-03 | Repudiation | alpha redistribution decision is non-automated (per D-P4-04 user handles out-of-band); 04-VERIFICATION.md is advisory not gating | accept | Documented in scorecard + STATE.md status field clarifies v1 close vs CLOSED-PENDING-ALPHA distinction |
|
||||||
|
| T-04-07-04 | Repudiation (REVISION iter-2 — WARNING 4) | `human_verification[0].evidence` field could be left as a placeholder (e.g., `<verbatim>` or `TBD`) — the 04-VERIFICATION.md "passes" gates but contains no real operator ack, masking a missing closure step | mitigate | Task 1 `<verify><automated>` greps for the ack literal (`approved`, `All good`, `APPROVED`, `approved by`, `operator ack`, `all good`) in the file; count >= 1 required to pass the gate. The pattern set covers both the canonical Plan 04-06 `<resume-signal>` expectation ("approved" lowercase) AND the historical Plan 01-10 cycle-2 ack format ("All good" titlecase). If the operator response uses a non-canonical phrasing, the SUMMARY for 04-06 still records it verbatim; the executor extends the grep alternation to match. |
|
||||||
</threat_model>
|
</threat_model>
|
||||||
|
|
||||||
<verification>
|
<verification>
|
||||||
@@ -320,6 +326,7 @@ deferred:
|
|||||||
- PROJECT.md: Validated section updated for Phase 4 hardening closure.
|
- PROJECT.md: Validated section updated for Phase 4 hardening closure.
|
||||||
- No code or test changes in this plan; `git diff --stat HEAD~1 HEAD` shows only `.planning/` files modified.
|
- No code or test changes in this plan; `git diff --stat HEAD~1 HEAD` shows only `.planning/` files modified.
|
||||||
- All Phase 4 plan SUMMARY files exist (Plans 04-01..04-06; this plan creates its own SUMMARY at completion).
|
- All Phase 4 plan SUMMARY files exist (Plans 04-01..04-06; this plan creates its own SUMMARY at completion).
|
||||||
|
- REVISION iter-2 WARNING 4: 04-VERIFICATION.md contains a verbatim operator ack literal (one of `approved`, `All good`, `APPROVED`, `approved by`, `operator ack`, `all good`); verified by Task 1 `<verify><automated>` grep count >= 1.
|
||||||
</verification>
|
</verification>
|
||||||
|
|
||||||
<success_criteria>
|
<success_criteria>
|
||||||
@@ -328,7 +335,7 @@ deferred:
|
|||||||
- Plans 01-08..01-13 ROADMAP backfill verified (D-P4-05).
|
- Plans 01-08..01-13 ROADMAP backfill verified (D-P4-05).
|
||||||
- v1 milestone status updated: CLOSED-PENDING-ALPHA OR CLOSED.
|
- v1 milestone status updated: CLOSED-PENDING-ALPHA OR CLOSED.
|
||||||
- All Phase 4 success criteria from the ROADMAP cited as GREEN with evidence.
|
- All Phase 4 success criteria from the ROADMAP cited as GREEN with evidence.
|
||||||
- Operator empirical ack from Plan 04-06 cited verbatim in 04-VERIFICATION.md.
|
- Operator empirical ack from Plan 04-06 cited verbatim in 04-VERIFICATION.md (REVISION iter-2 WARNING 4 — grep-pinned).
|
||||||
- Deferred items table carries forward v1.1/v2 items per CONTEXT.
|
- Deferred items table carries forward v1.1/v2 items per CONTEXT.
|
||||||
- No code/test changes (docs-only ceremony).
|
- No code/test changes (docs-only ceremony).
|
||||||
</success_criteria>
|
</success_criteria>
|
||||||
@@ -341,7 +348,7 @@ After completion, create `.planning/phases/04-harden-clean-up-optional/04-07-SUM
|
|||||||
- v1 milestone status flip (CLOSED-PENDING-ALPHA OR CLOSED — depending on alpha redistribution sequencing)
|
- v1 milestone status flip (CLOSED-PENDING-ALPHA OR CLOSED — depending on alpha redistribution sequencing)
|
||||||
- Closure commit refs
|
- Closure commit refs
|
||||||
- Final tally: UAT 35/35 GREEN; vitest >=185 GREEN; pre-checkpoint bundle gates 6/6 PASS; FORBIDDEN_HOOK_STRINGS at 12.
|
- Final tally: UAT 35/35 GREEN; vitest >=185 GREEN; pre-checkpoint bundle gates 6/6 PASS; FORBIDDEN_HOOK_STRINGS at 12.
|
||||||
|
- Verbatim operator ack from Plan 04-06 Task 4 (REVISION iter-2 WARNING 4 — grep-verified at Task 1 closure).
|
||||||
- Next steps for the operator: alpha redistribution + v1.0 tag + release notes (separate workstream per D-P4-04).
|
- Next steps for the operator: alpha redistribution + v1.0 tag + release notes (separate workstream per D-P4-04).
|
||||||
</output>
|
</output>
|
||||||
</content>
|
</content>
|
||||||
</invoke>
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ status: draft
|
|||||||
nyquist_compliant: false
|
nyquist_compliant: false
|
||||||
wave_0_complete: false
|
wave_0_complete: false
|
||||||
created: 2026-05-21
|
created: 2026-05-21
|
||||||
|
revised: 2026-05-21
|
||||||
|
revision_notes: "iter-2 revision — per-task map updated for 4 revised tasks (04-02 T2 UAT grep gate; 04-04 T1 Option B chrome.runtime.sendMessage; 04-06 T4 canonical SW chunk glob; 04-07 T1 ack-grep gate)"
|
||||||
---
|
---
|
||||||
|
|
||||||
# Phase 04 — Validation Strategy
|
# Phase 04 — Validation Strategy
|
||||||
@@ -44,24 +46,30 @@ created: 2026-05-21
|
|||||||
| 04-01 T1 RED 3 tests | 04-01 | 1 | Audit P1 #11/#14/#15 | T-04-01-01..03 | URL extraction + previousUrl + epoch normalization | unit (vitest jsdom) | `npm test -- tests/content/ --run` | ❌ NEW (Wave 0) | ⬜ pending |
|
| 04-01 T1 RED 3 tests | 04-01 | 1 | Audit P1 #11/#14/#15 | T-04-01-01..03 | URL extraction + previousUrl + epoch normalization | unit (vitest jsdom) | `npm test -- tests/content/ --run` | ❌ NEW (Wave 0) | ⬜ pending |
|
||||||
| 04-01 T2 GREEN edits | 04-01 | 1 | Audit P1 #11/#14/#15 | T-04-01-01..03 | Same; src/content/index.ts edits | unit (vitest) | `npm test -- tests/content/ --run` (+8 GREEN) + `npx tsc --noEmit` | ✗ EXISTS (modify) | ⬜ pending |
|
| 04-01 T2 GREEN edits | 04-01 | 1 | Audit P1 #11/#14/#15 | T-04-01-01..03 | Same; src/content/index.ts edits | unit (vitest) | `npm test -- tests/content/ --run` (+8 GREEN) + `npx tsc --noEmit` | ✗ EXISTS (modify) | ⬜ pending |
|
||||||
| 04-02 T1 RED build gates | 04-02 | 1 | SC #4 dead-code + setimmediate hygiene | T-04-02-01/03 | grep gate | unit (vitest + execFile build) | `npm test -- tests/build/no-new-function-in-sw-chunk.test.ts tests/build/dead-code-grep.test.ts --run` | ❌ NEW (Wave 0) | ⬜ pending |
|
| 04-02 T1 RED build gates | 04-02 | 1 | SC #4 dead-code + setimmediate hygiene | T-04-02-01/03 | grep gate | unit (vitest + execFile build) | `npm test -- tests/build/no-new-function-in-sw-chunk.test.ts tests/build/dead-code-grep.test.ts --run` | ❌ NEW (Wave 0) | ⬜ pending |
|
||||||
| 04-02 T2 GREEN polyfill + rename + flip | 04-02 | 1 | SC #3 generate-icons + setimmediate Q1 | T-04-02-01/02/04 | queueMicrotask polyfill; .cjs rename | build-gate + unit | `npm run build && grep -c 'new Function' dist/assets/index.ts-*.js` -> 0 + `node generate-icons.cjs` exit 0 | ✗ EXISTS (modify + rename) | ⬜ pending |
|
| 04-02 T2 GREEN polyfill + rename + flip (REVISION iter-2 WARNING 1) | 04-02 | 1 | SC #3 generate-icons + setimmediate Q1 + UAT preserved | T-04-02-01/02/04 | queueMicrotask polyfill; .cjs rename; JSZip fallback verified empirically | build-gate + unit + UAT | `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` -> 0 hits + cjs exit 0 + tests GREEN + tsc-clean + 1 ack-line | ✗ EXISTS (modify + rename) | ⬜ pending |
|
||||||
| 04-03 T1 assertA29 rewrite | 04-03 | 2 | A29 flake stabilization | T-04-03-01/02 | cs-injection-world ISOLATED + sentinel | UAT (page-side) | `npx tsc --noEmit && npm run build:test` | ✗ EXISTS (modify) | ⬜ pending |
|
| 04-03 T1 assertA29 rewrite | 04-03 | 2 | A29 flake stabilization | T-04-03-01/02 | cs-injection-world ISOLATED + sentinel | UAT (page-side) | `npx tsc --noEmit && npm run build:test` | ✗ EXISTS (modify) | ⬜ pending |
|
||||||
| 04-03 T2 driveA29 strict-sentinel | 04-03 | 2 | A29 sentinel filter | T-04-03-01 | rrweb IncrementalSource.Mutation filter | UAT (host-side) | `HEADLESS=1 SKIP_PROD_REBUILD=1 npm run test:uat` 33/33 GREEN; 5/5 stress | ✗ EXISTS (modify) | ⬜ pending |
|
| 04-03 T2 driveA29 strict-sentinel | 04-03 | 2 | A29 sentinel filter | T-04-03-01 | rrweb IncrementalSource.Mutation filter | UAT (host-side) | `HEADLESS=1 SKIP_PROD_REBUILD=1 npm run test:uat` 33/33 GREEN; 5/5 stress | ✗ EXISTS (modify) | ⬜ pending |
|
||||||
| 04-04 T1 SPIKE | 04-04 | 3 | SC #1 SW state persistence empirical | T-04-04-01 | offscreen survives SW idle | spike script | `HEADLESS=1 tsx tests/uat/spike-a33-sw-persistence.ts` -> videoSize > 100_000 | ❌ NEW (Wave 0 spike) | ⬜ pending |
|
| 04-04 T1 SPIKE (REVISION iter-2 BLOCKER 2 — Option B chrome.runtime.sendMessage) | 04-04 | 3 | SC #1 SW state persistence empirical | T-04-04-01 | offscreen survives SW idle; SAVE_ARCHIVE via canonical chrome.runtime.sendMessage (NOT non-existent __mokoshHarness.dispatchSaveArchive) | spike script | `npx tsc --noEmit && HEADLESS=1 tsx tests/uat/spike-a33-sw-persistence.ts 2>&1 \| tee /tmp/04-04-spike.log; grep -c 'SPIKE RESULT' /tmp/04-04-spike.log; grep -c "type: 'SAVE_ARCHIVE'" tests/uat/spike-a33-sw-persistence.ts; grep -c 'dispatchSaveArchive' tests/uat/spike-a33-sw-persistence.ts` -> SPIKE RESULT line + SAVE_ARCHIVE >= 1 + dispatchSaveArchive == 0 + videoSize > 100_000 | ❌ NEW (Wave 0 spike) | ⬜ pending |
|
||||||
| 04-04 T2 A33 + stopServiceWorker + orchestrator | 04-04 | 3 | SC #1 5-min idle harness | T-04-04-02/03/04 | CDP worker.close() + 5-min wait + SAVE | UAT | `HEADLESS=1 SKIP_LONG_UAT=1 npm run test:uat` 34/34 GREEN (skip-mode); full-mode 34/34 ~6.5 min | ✗ EXISTS (modify) | ⬜ pending |
|
| 04-04 T2 A33 + stopServiceWorker + orchestrator (REVISION iter-2 BLOCKER 2 — Option B) | 04-04 | 3 | SC #1 5-min idle harness | T-04-04-02/03/04 | CDP worker.close() + 5-min wait + SAVE via chrome.runtime.sendMessage inline page.evaluate | UAT | `npx tsc --noEmit && npm run build:test && HEADLESS=1 SKIP_PROD_REBUILD=1 SKIP_LONG_UAT=1 npm run test:uat 2>&1 \| tail -5 \| tee /tmp/04-04-task-2-skip.log; grep -c '34/34' /tmp/04-04-task-2-skip.log; grep -c 'dispatchSaveArchive' tests/uat/lib/harness-page-driver.ts tests/uat/extension-page-harness.ts tests/uat/harness.test.ts` -> 34/34 skip-mode + dispatchSaveArchive == 0 + full-mode 34/34 ~6.5 min | ✗ EXISTS (modify) | ⬜ pending |
|
||||||
| 04-05 T1 assertA34 fetch+XHR | 04-05 | 4 | SC #2 fetch+XHR network_error | T-04-05-01 | cs-injection-world dual-trigger | UAT (page-side) | `npx tsc --noEmit && npm run build:test` | ✗ EXISTS (modify) | ⬜ pending |
|
| 04-05 T1 assertA34 fetch+XHR | 04-05 | 4 | SC #2 fetch+XHR network_error | T-04-05-01 | cs-injection-world dual-trigger | UAT (page-side) | `npx tsc --noEmit && npm run build:test` | ✗ EXISTS (modify) | ⬜ pending |
|
||||||
| 04-05 T2 driveA34 + orchestrator | 04-05 | 4 | SC #2 + P1 #11 end-to-end empirical | T-04-05-01 | 2 network_error entries with status===404 | UAT | `HEADLESS=1 SKIP_LONG_UAT=1 npm run test:uat` 35/35 GREEN; full-mode ~7 min | ✗ EXISTS (modify) | ⬜ pending |
|
| 04-05 T2 driveA34 + orchestrator | 04-05 | 4 | SC #2 + P1 #11 end-to-end empirical | T-04-05-01 | 2 network_error entries with status===404 | UAT | `HEADLESS=1 SKIP_LONG_UAT=1 npm run test:uat` 35/35 GREEN; full-mode ~7 min | ✗ EXISTS (modify) | ⬜ pending |
|
||||||
| 04-06 T1 RED inline-SVG + cursor-pin | 04-06 | 5 | UI-SPEC dark-logo + RESEARCH Finding 4 | T-04-06-01 | DOMParser inline injection (no innerHTML); cursor: 'always' literal | unit (vitest jsdom + build-grep) | `npm test -- tests/welcome/ tests/build/cursor-visibility.test.ts --run` | ❌ NEW (Wave 0) | ⬜ pending |
|
| 04-06 T1 RED inline-SVG + cursor-pin | 04-06 | 5 | UI-SPEC dark-logo + RESEARCH Finding 4 | T-04-06-01 | DOMParser inline injection (no innerHTML); cursor: 'always' literal | unit (vitest jsdom + build-grep) | `npm test -- tests/welcome/ tests/build/cursor-visibility.test.ts --run` | ❌ NEW (Wave 0) | ⬜ pending |
|
||||||
| 04-06 T2 GREEN SVG + welcome.ts + globals | 04-06 | 5 | UI-SPEC stroke recolor + ?raw import | T-04-06-01 | currentColor + DOMParser inline | unit | `npm test -- tests/welcome/inline-svg.test.ts --run` 3/3 GREEN | ✗ EXISTS (modify) | ⬜ pending |
|
| 04-06 T2 GREEN SVG + welcome.ts + globals | 04-06 | 5 | UI-SPEC stroke recolor + ?raw import | T-04-06-01 | currentColor + DOMParser inline | unit | `npm test -- tests/welcome/inline-svg.test.ts --run` 3/3 GREEN | ✗ EXISTS (modify) | ⬜ pending |
|
||||||
| 04-06 T3 A17.8 + 01-07 back-patch | 04-06 | 5 | UI-SPEC harness invariant + docs hygiene | T-04-06-01 | A17.8 raw-source grep | UAT + docs | `HEADLESS=1 SKIP_LONG_UAT=1 npm run test:uat` 35/35 + grep verify | ✗ EXISTS (modify) | ⬜ pending |
|
| 04-06 T3 A17.8 + 01-07 back-patch | 04-06 | 5 | UI-SPEC harness invariant + docs hygiene | T-04-06-01 | A17.8 raw-source grep | UAT + docs | `HEADLESS=1 SKIP_LONG_UAT=1 npm run test:uat` 35/35 + grep verify | ✗ EXISTS (modify) | ⬜ pending |
|
||||||
| 04-06 T4 Operator empirical | 04-06 | 5 | UI-SPEC AC #6 aesthetic judgment | T-04-06-01 | dark-mode visual contrast | manual | operator returns "approved" or describes issue | n/a | ⬜ pending |
|
| 04-06 T4 Operator empirical (REVISION iter-2 BLOCKER 1 — canonical SW chunk glob) | 04-06 | 5 | UI-SPEC AC #6 aesthetic judgment | T-04-06-01/04 | dark-mode visual contrast; canonical `dist/assets/index.ts-*.js` glob (NOT non-matching `index*-bg.js`) | manual + pre-checkpoint bundle gates | `npm run build && ls dist/assets/index.ts-*.js \| wc -l; grep -cE 'new Function\(\|eval\(' dist/assets/index.ts-*.js; HEADLESS=1 SKIP_PROD_REBUILD=1 SKIP_LONG_UAT=1 npm run test:uat 2>&1 \| tail -3` -> glob match >= 1 + 0 hits + UAT 35/35 + operator returns "approved" | n/a (verification + operator) | ⬜ pending |
|
||||||
| 04-07 T1 04-VERIFICATION.md | 04-07 | 6 | Phase 4 closure aggregator | T-04-07-01 | scorecard + override notes + deferred items | docs aggregator | `test -f .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md && grep -cE '^## '` >= 5 | ❌ NEW | ⬜ pending |
|
| 04-07 T1 04-VERIFICATION.md (REVISION iter-2 WARNING 4 — ack-grep gate) | 04-07 | 6 | Phase 4 closure aggregator + verbatim operator ack | T-04-07-01/04 | scorecard + override notes + deferred items + verbatim operator ack from Plan 04-06 | docs aggregator | `test -f .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md && grep -cE '^## ' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md; grep -c 'Plan 04-0' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md; grep -cE 'approved\|All good\|APPROVED\|approved by\|operator ack\|all good' .planning/phases/04-harden-clean-up-optional/04-VERIFICATION.md` -> sections >= 5 + Plan-04 citations >= 6 + ack-literal >= 1 | ❌ NEW | ⬜ pending |
|
||||||
| 04-07 T2 Marker flips | 04-07 | 6 | D-P4-05 + ROADMAP/STATE flips | T-04-07-02/03 | Phase 4 [x] + completed_phases: 4 | docs | `grep -c '\[x\] \*\*Phase 4' .planning/ROADMAP.md` >= 1 | ✗ EXISTS (modify) | ⬜ pending |
|
| 04-07 T2 Marker flips | 04-07 | 6 | D-P4-05 + ROADMAP/STATE flips | T-04-07-02/03 | Phase 4 [x] + completed_phases: 4 | docs | `grep -c '\[x\] \*\*Phase 4' .planning/ROADMAP.md` >= 1 | ✗ EXISTS (modify) | ⬜ pending |
|
||||||
|
|
||||||
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
|
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
|
||||||
|
|
||||||
**Planner instructions:** Populate one row per task. Per RESEARCH finding 5 (6 new Wave-0 test files anticipated), expect ~6 unit-test rows + ~4 harness-A33+ rows + ~4 bundle-gate rows + ~3 docs rows. Format per Phase 3 03-VALIDATION precedent.
|
**Planner instructions:** Populate one row per task. Per RESEARCH finding 5 (6 new Wave-0 test files anticipated), expect ~6 unit-test rows + ~4 harness-A33+ rows + ~4 bundle-gate rows + ~3 docs rows. Format per Phase 3 03-VALIDATION precedent.
|
||||||
|
|
||||||
|
**REVISION iter-2 notes (2026-05-21):**
|
||||||
|
- **04-02 T2 (WARNING 1):** `<automated>` now includes `HEADLESS=1 SKIP_PROD_REBUILD=0 npm run test:uat` + `grep -c 'UAT harness: 33/33 assertions passed'` to empirically verify JSZip fallback works at the SAVE→zip layer post-polyfill-removal.
|
||||||
|
- **04-04 T1 + T2 (BLOCKER 2):** Option B applied — SAVE_ARCHIVE dispatched via `chrome.runtime.sendMessage({type: 'SAVE_ARCHIVE'}, ...)` directly from the harness page realm (matches established A5/A11/A12/A13/A26/A28/A29/A30/A31 precedent). The non-existent `window.__mokoshHarness.dispatchSaveArchive` is NOT introduced; gates verify `grep -c 'dispatchSaveArchive'` returns 0 across all harness files + spike script.
|
||||||
|
- **04-06 T4 (BLOCKER 1):** Canonical SW chunk glob `dist/assets/index.ts-*.js` used for all bundle gates (Gates 2/3/4) — replaces the misquoted `dist/assets/index*-bg.js` which matched no files (silent 0-grep = spurious PASS). New glob-existence pre-gate `ls dist/assets/index.ts-*.js | wc -l >= 1` validates the glob matches BEFORE running grep gates.
|
||||||
|
- **04-07 T1 (WARNING 4):** Ack-literal grep added — `grep -cE 'approved|All good|APPROVED|approved by|operator ack|all good' 04-VERIFICATION.md >= 1` ensures `human_verification[0].evidence` contains a real operator ack (not a placeholder).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Wave 0 Requirements
|
## Wave 0 Requirements
|
||||||
@@ -107,5 +115,6 @@ Existing infrastructure already in place (inherited from Phases 1-3):
|
|||||||
- [ ] No watch-mode flags — verify in planner output (focused commands use `--run`)
|
- [ ] No watch-mode flags — verify in planner output (focused commands use `--run`)
|
||||||
- [ ] Feedback latency < ~2.5 min default (5-min idle test on dedicated lane) — confirmed by RESEARCH
|
- [ ] Feedback latency < ~2.5 min default (5-min idle test on dedicated lane) — confirmed by RESEARCH
|
||||||
- [ ] `nyquist_compliant: true` set in frontmatter — pending sign-off after planner completes
|
- [ ] `nyquist_compliant: true` set in frontmatter — pending sign-off after planner completes
|
||||||
|
- [ ] REVISION iter-2 gates applied to 4 revised tasks (04-02 T2, 04-04 T1, 04-04 T2, 04-06 T4, 04-07 T1)
|
||||||
|
|
||||||
**Approval:** pending (planner fills per-task map; checker validates)
|
**Approval:** pending (planner fills per-task map; checker validates)
|
||||||
|
|||||||
Reference in New Issue
Block a user