// tests/build/dead-code-grep.test.ts — Plan 04-02 Wave 0 GREEN-on-arrival // regression pin (ROADMAP SC #4). // // ROADMAP SC #4 ("Dead-code grep returns no live references for // permissions.request + duplicate offscreen inline string") is verified // against the current src/ source tree (NOT against dist/). Both targets were // removed during Phase 1: // // - `permissions.request` was the broken runtime-permission flow under the // pre-D-01 `chrome.tabCapture` architecture; removed in Plan 01-05 as part // of the SW shrink (audit P0 #5 fix). Under D-01 (`getDisplayMedia` via // offscreen + `desktopCapture` permission), no runtime permission check is // meaningful — every user-gesture-initiated getDisplayMedia surfaces its // own picker UI as the implicit grant. Reintroducing `permissions.request` // would route start-of-recording back into the never-granted branch and // silently fail. // // - The duplicate offscreen inline string was the build-pipeline-side // manifestation of the same architecture: pre-01-06 vite.config.ts shipped // a 174-line inline copy-offscreen plugin that emitted an HTML literal of // the offscreen document for the `chrome.offscreen.createDocument` path. // Plan 01-06 collapsed vite.config.ts to 21 lines + relocated the // offscreen entry into `rollupOptions.input` under the crxjs plugin's // canonical multi-entry pattern. Reintroducing the inline-string emit // would defeat the build-pipeline collapse. // // Polarity at Wave 0 land: // - GREEN-on-arrival today (both targets are absent — verified by // `grep -rn 'permissions.request' src/` returning 0 hits + the vite.config.ts // review at Plan 04-02 RED time). This test acts as a regression pin: a // future commit reintroducing either offender breaks CI. // // Note on the offscreen-inline-string sub-test: the planner empirically // determined that no single literal HTML string from the pre-01-06 inline // plugin is uniquely pinnable post-collapse — the plugin emitted a templated // HTML body that included only generic ... markup with no // SUMMARY-distinguishable sentinel. The audit-side coverage for "duplicate // offscreen inline string absence" is delegated to: // - tests/build/no-remote-fonts.test.ts (Plan 01-12) — full dist/ walk for // `googleapis` etc. would catch any inline-HTML reintroduction with remote // URLs; AND // - vite.config.ts review at Plan 04-02 time confirms the file is still 21 // lines + 75 LOC including blanks (no inline plugin block re-added). // This file documents the delegation in the SUMMARY rather than asserting a // brittle sentinel that future minor formatting changes would invalidate. // // Implementation mirrors tests/build/no-remote-fonts.test.ts (recursive walk + // substring count + describe-block scaffold), but scopes the walk to `src/` // directly (no build step needed; this is a pure source-tree audit). // // References: // - .planning/phases/04-harden-clean-up-optional/04-RESEARCH.md §"Phase // Requirements" mapping (ROADMAP SC #4 ↔ this test) // - .planning/phases/04-harden-clean-up-optional/04-PATTERNS.md (this test // scaffold; analog at tests/build/no-remote-fonts.test.ts) // - .planning/phases/01-stabilize-video-pipeline/01-05-SUMMARY.md (Plan // 01-05 SW shrink, where permissions.request was removed) // - .planning/phases/01-stabilize-video-pipeline/01-06-SUMMARY.md (Plan // 01-06 build-pipeline collapse, where the inline-string plugin was // deleted) // - Plan 04-02 threat model T-04-02-03 (Information Disclosure via // leftover deleted-permission literal masking architecture) import { readdirSync, readFileSync, statSync } from 'node:fs'; import { resolve as resolvePath } from 'node:path'; import { describe, expect, it } from 'vitest'; interface DeadCodeEntry { readonly needle: string; readonly searchPaths: ReadonlyArray; readonly rationale: string; } /** Forbidden dead-code substrings — any occurrence in src/ is a regression. */ const FORBIDDEN_DEAD_CODE: ReadonlyArray = [ { needle: 'permissions.request', searchPaths: ['src'], rationale: 'Removed in Phase 1 Plan 01-05 SW shrink (audit P0 #5 fix). Under D-01 ' + '(getDisplayMedia via offscreen + desktopCapture manifest permission), no ' + 'runtime permission check is meaningful. Reintroducing permissions.request ' + 'would route start-of-recording back into the never-granted branch.', }, ]; interface ForbiddenMatch { readonly filePath: string; readonly count: number; } function listAllFilesRecursive(root: string): ReadonlyArray { const accumulator: string[] = []; const stack: string[] = [root]; while (stack.length > 0) { const dir = stack.pop()!; const entries = readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = resolvePath(dir, entry.name); // Filter-pipeline form: skip symlinks via short-circuit (no `continue` per // CLAUDE.md global instructions; we read `if (...) {} else if (...) { stack.push }`). if (entry.isSymbolicLink()) { // Symlinks within src/ should not exist in this project; defensive skip. } else if (entry.isDirectory()) { stack.push(fullPath); } else if (entry.isFile()) { accumulator.push(fullPath); } } } return accumulator.sort(); } function isTextLikeFile(filePath: string): boolean { const binaryExtensions = new Set([ '.png', '.jpg', '.jpeg', '.gif', '.ico', '.webp', '.woff', '.woff2', '.ttf', '.otf', ]); const dotIdx = filePath.lastIndexOf('.'); const ext = dotIdx >= 0 ? filePath.substring(dotIdx).toLowerCase() : ''; return !binaryExtensions.has(ext); } function countOccurrencesInFile(filePath: string, needle: string): number { if (!isTextLikeFile(filePath)) return 0; const stat = statSync(filePath); if (stat.size === 0) return 0; const text = readFileSync(filePath, 'utf8'); let count = 0; let from = 0; for (;;) { const idx = text.indexOf(needle, from); if (idx < 0) break; count += 1; from = idx + needle.length; } return count; } function findMatchesInPaths(needle: string, searchPaths: ReadonlyArray): ReadonlyArray { const accumulator: ForbiddenMatch[] = []; const cwd = process.cwd(); for (const searchPath of searchPaths) { const fullPath = resolvePath(cwd, searchPath); const stat = statSync(fullPath); const files = stat.isDirectory() ? listAllFilesRecursive(fullPath) : [fullPath]; for (const filePath of files) { const count = countOccurrencesInFile(filePath, needle); if (count > 0) { accumulator.push({ filePath, count }); } } } return accumulator; } describe('dead-code regression pin (ROADMAP SC #4 — Plan 04-02 T-04-02-03)', () => { for (const entry of FORBIDDEN_DEAD_CODE) { const pathsDescription = entry.searchPaths.join(' + '); it(`${pathsDescription} does not contain '${entry.needle}' (${entry.rationale.split('.')[0]})`, () => { const matches = findMatchesInPaths(entry.needle, entry.searchPaths); expect( matches.length, matches.length === 0 ? 'unreachable' : `${pathsDescription} contains dead-code '${entry.needle}' in ${matches.length} file(s) ` + `— REGRESSION. ${entry.rationale}\n` + `Offending files:\n` + matches .map((m) => ` - ${m.filePath} (${m.count} occurrence${m.count === 1 ? '' : 's'})`) .join('\n'), ).toBe(0); }); } });