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:
@@ -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)"
|
||||
- "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"
|
||||
- "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:
|
||||
- path: "tests/uat/extension-page-harness.ts"
|
||||
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
|
||||
const A33_IDLE_WAIT_MS = 5 * 60 * 1000; // 300_000 — real wall-clock
|
||||
const A33_NEW_SW_BOOT_MS = 500; // post-worker.close() settle
|
||||
@@ -153,8 +157,21 @@ export async function driveA33(
|
||||
): Promise<AssertionRecord> {
|
||||
const r: AssertionRecord = { name: 'A33', passed: false, checks: [], diagnostics: [] };
|
||||
|
||||
// Step 1: prime recording on the probe tab
|
||||
await page.evaluate(() => (window as any).__mokoshHarness.setupFreshRecording());
|
||||
// Step 1: prime recording on the probe tab via the existing harness primitive.
|
||||
// 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
|
||||
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
|
||||
await new Promise((res) => setTimeout(res, A33_NEW_SW_BOOT_MS));
|
||||
|
||||
// Step 5: dispatch SAVE_ARCHIVE — wakes SW back up as an event
|
||||
// (event-driven respawn is the canonical MV3 wakeup path)
|
||||
const saveResult = await page.evaluate(() => (window as any).__mokoshHarness.dispatchSaveArchive());
|
||||
// Step 5: dispatch SAVE_ARCHIVE via chrome.runtime.sendMessage from the harness
|
||||
// page realm — matches the established A5/A11/A12/A13/A26/A28/A29/A30/A31 pattern.
|
||||
// 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({
|
||||
name: 'A33.1: SAVE_ARCHIVE ack success after 5-min idle + SW kill',
|
||||
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">
|
||||
<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>
|
||||
<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>
|
||||
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:
|
||||
- Imports `launchHarnessBrowser` from `./lib/launch.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...')`
|
||||
- `await new Promise(r => setTimeout(r, 5 * 60 * 1000));`
|
||||
- `await stopServiceWorker(handles.browser, handles.extensionId);`
|
||||
- `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)
|
||||
- `const zipPath = findLatestZip(handles.downloadsDir);`
|
||||
- `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).
|
||||
- Spike script ran to completion (no Puppeteer throw).
|
||||
- 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 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).
|
||||
@@ -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">
|
||||
<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>
|
||||
<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>
|
||||
**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:
|
||||
|
||||
**File 1: tests/uat/extension-page-harness.ts**
|
||||
- Locate the existing `__mokoshHarness` registration block (~line 3971) and the `__mokoshHarness` Window interface declaration (~line 3950).
|
||||
- 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`.
|
||||
- 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.
|
||||
- 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 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.
|
||||
- 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).
|
||||
- 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.
|
||||
- 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).
|
||||
- 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.
|
||||
|
||||
**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).
|
||||
- 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.
|
||||
- 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**
|
||||
- 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).
|
||||
- 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").
|
||||
- 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>
|
||||
<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>
|
||||
<acceptance_criteria>
|
||||
- `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 '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).
|
||||
- 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>
|
||||
<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>
|
||||
@@ -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.
|
||||
- vitest baseline preserved (≥ 181 GREEN from Plans 04-01 + 04-02).
|
||||
- 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>
|
||||
|
||||
<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:
|
||||
- Spike outcome (videoSize value + interpretation; SPIKE PASSED/FAILED tag)
|
||||
- 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)
|
||||
- SKIP_LONG_UAT env-gate decision (default RUN; rationale)
|
||||
- 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)
|
||||
</output>
|
||||
</content>
|
||||
</invoke>
|
||||
Reference in New Issue
Block a user