feat(02-03): meta.json — urls[] + schemaVersion (D-P2-02 + D-P2-03; replaces url:string)
- src/shared/types.ts SessionMetadata: REPLACE `url: string` with
`urls: string[]`; ADD `schemaVersion: string` as the first field.
Total 8 fields. Field-emission order follows source-declaration order
(TypeScript object-literal insertion order; JSON.stringify emits in
insertion order per ECMA-262). Docstring cites D-P2-02 + D-P2-03 +
Plan 02-01 Task 3 planner-resolved 8th field decision + F2 empty-array
permission.
- src/background/index.ts:
* Import { initTabUrlTracker, snapshotOpenTabs, getTabUrlsSeen } from
'./tab-url-tracker'.
* Register initTabUrlTracker() at module top-level alongside
chrome.downloads.onChanged (Plan 02-02 precedent for D-P2-* feature
registration). Defensive try/catch matches the surrounding chrome.*
listener pattern; tracker module has its own initialized flag for
idempotency.
* createArchive: snapshotOpenTabs() before reading getTabUrlsSeen()
(DEC-011 Amendment 1 capability — captures tabs opened but never
activated). Empty urls[] emitted faithfully per F2 (no fake
extension-origin sentinel; logger.warn for diagnostic visibility on
whole-desktop-no-tab sessions).
* metadata literal: schemaVersion: '2' first, urls (not url), 8 fields
total. ECMA-262 insertion-order guarantee + JSON.stringify deliver
the canonical wire shape.
- Always-on charter preserved: createArchive does NOT call
clearTabUrlsSeen() — tracker continues accumulating across saves
(Plan 01-09 Amendment 3 invariant).
Verification:
- npx tsc --noEmit → clean.
- npm run build → clean (dist/assets/index.ts-8LkXuqac.js 378.82 kB,
~+2 kB vs pre-Task-2 baseline for the new tab-url-tracker module).
- npx vitest run → 171/171 GREEN (was 163 GREEN / 8 RED; +8 GREEN net).
- Tier-1 grep gate: 13/13 GREEN unchanged.
Closes 8 RED tests:
- tests/background/meta-json-urls-schema.test.ts Tests 1+2 (Tests 3+4+5
flipped in Task 1).
- tests/build/strict-meta-json-validation.test.ts Tests 1+3+8 (Tests 2,
4, 5, 6, 7 remain GREEN regression guards).