···11# Phase 2.5 #3 Agent Report — createExtensionWindow migration audit
2233-## Triage stub (in progress)
33+## Audit (Phase A)
4455-Target: migrate `createExtensionWindow()` in `backend/electron/main.ts` from
66-v1 `preload.js` to v2 tile-preload, OR document why it stays.
55+Target: `createExtensionWindow()` in `backend/electron/main.ts` (line 1106).
66+Still uses v1 `preload.js` (`config.preloadPath`). Function creates a
77+BrowserWindow per extension and loads `peek://ext/{id}/background.html`.
7888-Initial scan complete. Full audit next — see later sections.
99+### Call sites (6 inside main.ts, 2 inside ipc.ts)
1010+1111+| Site | Caller | Runtime reachability | Bucket |
1212+|------|--------|----------------------|--------|
1313+| main.ts:1213 | `loadEnabledExtensions()` | **DEAD** — exported but never invoked. Replaced by `loadExtensions()` (entry.ts:741). | dead code |
1414+| main.ts:1458 | `loadExtensions()` — `externalBuiltinIds` loop | **EMPTY in practice.** Filter = `registered ∩ !CONSOLIDATED_EXTENSION_IDS ∩ enabled ∩ !v2FeatureIds`. All 35 features in `features/` are v2 (`manifestVersion: 2`) and get loaded by `loadV2Feature()` into `v2FeatureIds`, so this set is empty. | dead in practice |
1515+| main.ts:1467 | `loadExtensions()` — `enabledExternalExts` from `extensions` DB table | Empty under normal test / dev. The `extensions` table is populated by the legacy settings UI `api.extensions.add()` — superseded by features-manager (which installs into the v2 feature registry, not this table). | dead in practice |
1616+| main.ts:1672 | `loadDevExtension()` | Live when user passes `--load-extension` CLI flag. Dev-only. | v1 path, dev-only |
1717+| main.ts:1747 | `reloadExtension()` | **LIVE.** Called by `ipcMain.handle('extension-reload')` (ipc.ts:1374), which is invoked by `api.extensions.reload(id)` on trustedBuiltin tiles (features-manager, test fixtures). | v1 path, live |
1818+| ipc.ts:1287 | `ipcMain.handle('extension-window-load')` | **DEAD** — no renderer invokes this channel (grep). | dead code |
1919+| ipc.ts:1315 | `ipcMain.handle('extension-window-reload')` | **DEAD** — no renderer invokes this channel (grep). | dead code |
2020+2121+### Bucket summary
2222+2323+- **v2-migratable builtin externals:** 0. All features are already loaded through
2424+ `loadV2Tile()` / `launchTile()` today — `createExtensionWindow` is never
2525+ invoked for them at runtime.
2626+- **Chrome extensions:** 0 — Chrome extensions use a separate path
2727+ (`backend/electron/chrome-extensions.ts` + `session.loadExtension()`), not
2828+ `createExtensionWindow`. Out of scope as planned.
2929+- **v1-only live callers:** 2 — `reloadExtension` (features-manager) and
3030+ `loadDevExtension` (CLI). Both need a v2 "launch/relaunch a tile by id"
3131+ helper that doesn't exist yet (tile-launcher has `launchTile(opts)` but no
3232+ "find the manifest, revoke the old token, close the old window, relaunch"
3333+ convenience).
3434+- **Dead code:** 4 call sites (`loadEnabledExtensions`, two IPC handlers,
3535+ + the two startup branches that are empty in practice). Safe to drop.
3636+3737+### Implementation choice
3838+3939+**Exit at audit boundary.** Migrating `reloadExtension` and `loadDevExtension`
4040+requires:
4141+4242+1. A `relaunchTile(tileId)` helper in `tile-launcher.ts` that re-reads the
4343+ manifest from disk, revokes the old token, closes the old window, and
4444+ calls `launchTile` again.
4545+2. A "find the tile's resident/launch entry from manifest" utility (currently
4646+ only `loadV2Tile` does this, and it's tangled with eager/lazy branching).
4747+3. Handling the dev-extension case where the path is registered
4848+ transiently via `registerDevExtension` and not in the feature registry.
4949+5050+That's 1–2 commits of new infrastructure, not a "remove v1 call site" swap.
5151+Given the 60-minute budget and the audit finding that `createExtensionWindow`
5252+is effectively already replaced for the common path (startup loading), the
5353+correct move is to (a) remove the dead-code call sites cleanly in a follow-up
5454+and (b) defer the remaining two live v1 call sites to a dedicated Phase 2.5 #3b.
5555+5656+### Open items for Phase 3 / follow-up
5757+5858+- **Phase 2.5 #3b** — implement `relaunchTile(tileId)` in tile-launcher.ts;
5959+ rewrite `reloadExtension()` and `loadDevExtension()` to use it; delete
6060+ `createExtensionWindow`, `loadEnabledExtensions`, the dead IPC handlers,
6161+ and the dead `externalBuiltinIds` / `enabledExternalExts` branches.
6262+- Phase 3 can proceed for everything not behind `createExtensionWindow` —
6363+ features-manager reload and CLI dev extensions are the only surfaces
6464+ that still need v1 `preload.js`.
6565+6666+### Files read during audit
6767+6868+- `backend/electron/main.ts` — createExtensionWindow, loadExtensions, loadEnabledExtensions, reloadExtension, loadDevExtension, discoverBuiltinExtensions
6969+- `backend/electron/ipc.ts` — extension-window-* handlers, extension-reload
7070+- `backend/electron/tile-compat.ts` — loadV2Tile, ensureTileIpcHandlers
7171+- `backend/electron/tile-loader.ts` — loadV2Feature, loadFeaturesFromRegistry
7272+- `backend/electron/feature-startup.ts` — initializeFeatures
7373+- `backend/electron/feature-installer.ts` — syncBuiltinFeatures
7474+- `backend/electron/tile-launcher.ts` — launchTile
7575+- `backend/electron/extensions.ts` — getExternalExtensions (reads `extensions` DB table)
7676+- All `features/*/manifest.json` — confirmed 31 of 31 are `manifestVersion: 2`
7777+7878+## Validation
7979+8080+N/A at audit-commit. No code changes landed.