promptward

Plan 013: Fix the debugSettingsPromise temporal-dead-zone crash on content-script init

Executor instructions: Follow this plan step by step. Run every verification command and confirm the expected result before moving to the next step. If anything in the “STOP conditions” section occurs, stop and report — do not improvise. When done, update the status row for this plan in plans/README.md — unless a reviewer dispatched you and told you they maintain the index.

Drift check (run first): git diff --stat a6293e1..HEAD -- src/content.ts Plans 001 and 002 are expected predecessors (001 added no src/content.ts changes; 002 added a 2-line composition guard inside onKeydownCapture at the top of the file). If debugSettingsPromise, getDebugSettings, or the module-init block have moved beyond what’s shown below, re-verify the “Current state” excerpt before proceeding — the exact line numbers below assume plans 001+002 are merged but 003/004 are not yet.

Status

Why this matters

src/content.ts throws an unhandled ReferenceError: Cannot access 'debugSettingsPromise' before initialization on every single import of the module — i.e. on every real page load on every supported site, and in every test file that imports src/content.ts. This was discovered during plan 001’s execution and independently reproduced during plan 002’s review: npm test exits with code 1 even though every individual test passes, because Vitest counts the unhandled rejection as an error and reflects it in the process exit code. This is a genuine temporal-dead-zone (TDZ) bug, not a test-environment artifact — confirmed with a bare await import("../src/content") and nothing else in a minimal repro. It is currently masked because the error is caught nowhere and simply logged as an unhandled rejection rather than crashing the content script (module evaluation of the rest of the file completes fine since the throwing call is wrapped in void logDebug(...), not awaited at the top level) — but it means the very first debug-settings lookup silently fails and falls back to { rawDiagnosticsEnabled: false } on every page load, and it currently blocks plan 006 (CI): a CI job that runs npm test would report every green test run as a failed job because of the exit code.

Current state

Commands you will need

Purpose Command Expected on success
Typecheck npx tsc -p tsconfig.json --noEmit exit 0
Tests npm test exit 0 (no “Errors” line, no unhandled rejection)
One file npx vitest run tests/content-flow.test.ts exit 0, no errors section

Scope

In scope:

Out of scope:

Git workflow

Steps

Step 1: Move the declaration

In src/content.ts:

  1. Delete the line let debugSettingsPromise: Promise<DebugSettings> | undefined; from its current position (directly above getDebugSettings, near the bottom of the file).
  2. Add it near the top of the file, directly after the existing const replaying = new WeakSet<HTMLElement>(); / const inFlight = new WeakSet<HTMLElement>(); pair (i.e. before the document.addEventListener(...) calls and the module-init void logDebug(...) call). Result:

    const replaying = new WeakSet<HTMLElement>();
    const inFlight = new WeakSet<HTMLElement>();
    let debugSettingsPromise: Promise<DebugSettings> | undefined;
    
    document.addEventListener("click", onClickCapture, true);
    ...
    
  3. getDebugSettings’s body is unchanged — it still reads/writes the module-scope debugSettingsPromise binding, just declared earlier now.

Do not change var/let/const, do not add a default value, do not wrap in a function — this is purely relocating one declaration statement so it executes before the first possible read.

Verify: npx tsc -p tsconfig.json --noEmit → exit 0.

Step 2: Confirm the crash is gone

Verify: npx vitest run tests/content-flow.test.ts 2>&1 | grep -i "ReferenceError\|debugSettingsPromise before initialization" → no output (previously printed the ReferenceError). Verify: npx vitest run tests/content-flow.test.ts → exit code $? is 0 (check explicitly: npx vitest run tests/content-flow.test.ts; echo "exit: $?"exit: 0).

Step 3: Full suite

Verify: npm test; echo "exit: $?"exit: 0, and the output contains NO Errors summary line (compare against before the fix, which printed Errors 1 error).

Test plan

No new test file — this is a crash fix in module-init ordering, and plan 001’s existing tests/content-flow.test.ts already imports src/content.ts at the top of the file (beforeAll), so its mere presence is the regression test: if the TDZ bug ever comes back, that import throws again and the exit code goes non-zero. Do not add a redundant standalone test for this.

Done criteria

STOP conditions

Stop and report back if:

Maintenance notes