experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs(phase3): 3.11-pre audit — preload.js deletion blockers

Audit of all api.invoke/api.send/api.on/window.app.invoke callers in
app/ and features/ to identify which renderers still run under preload.js
and block 3.11b (preload.js deletion).

Key findings:

- Zero legacy IPC callers in features/**
- 21 api.invoke() call sites in app/ across 5 files
- 3 true blockers (renderers receiving preload.js at window-open time):
app/settings/settings.js (3491 LOC, broadest API surface)
app/diagnostic.html (232 LOC, 4 backup/shell channels)
app/page/page.js (~3788 LOC, canvas page host)
- 2 non-blockers already on tile-preload trustedBuiltin:
app/index.js (core background renderer via core-glue.ts)
app/cmd/commands/page.js (cmd tile via cmd-glue.ts)
- 3.4 audit correction: 10 channels were classified "likely dead" but
have live callers in app/ scripts that were outside the original grep
scope. Removes them from the 3.11a deletion list.

Recommends 4 pre-3.11b packages (~115 min total): 3.11b-settings (45),
3.11b-diagnostic (20), 3.11b-page (30), 3.11b-nav-session (20).

+259
+259
docs/v1-removal-phase3-tasks.md
··· 1666 1666 page trustedBuiltin capability grant in the relevant glue files, delete 1667 1667 the six `contextCompat` compat branches from `tile-preload.cts`, and 1668 1668 delete the five legacy `context-*` handlers from `ipc.ts`. 1669 + 1670 + --- 1671 + 1672 + ### phase3.11-pre — preload.js deletion blockers (2026-04-18) 1673 + 1674 + This audit answers the question: after Wave 2 (3.5–3.10) completes, what 1675 + prevents `preload.js` from being deleted in 3.11b? The 3.7a audit found 1676 + 23 channels with live `api.invoke('<channel>', …)` callers in `app/` 1677 + files. This audit identifies those callers precisely, classifies each by 1678 + renderer context (tile-preload vs preload.js), and determines which ones 1679 + are true blockers. 1680 + 1681 + #### Methodology 1682 + 1683 + Searched all `.js` and `.html` files under `app/` and `features/` for: 1684 + - `api.invoke(` (direct channel invocation) 1685 + - `api.send(` / `api.on(` (IPC send/receive) 1686 + - `window.app.invoke(` (DOM-based passthrough) 1687 + - `ipcRenderer.invoke(` (renderer-side raw IPC) 1688 + 1689 + Results: **zero hits in `features/**`**. All live callers are in `app/`. 1690 + 1691 + --- 1692 + 1693 + #### Section 1 — Complete `api.invoke(...)` call inventory in `app/` 1694 + 1695 + | File | Line | Channel | Context (-1 line) | 1696 + |------|------|---------|-------------------| 1697 + | `app/index.js` | 489 | `session-save` | `execute: async () => {` | 1698 + | `app/index.js` | 501 | `session-restore-interactive` | `execute: async () => {` | 1699 + | `app/index.js` | 528 | `web-nav-back` | `execute: () =>` | 1700 + | `app/index.js` | 534 | `web-nav-forward` | `execute: () =>` | 1701 + | `app/index.js` | 540 | `web-nav-reload` | `execute: () =>` | 1702 + | `app/index.js` | 547 | `web-nav-state` | `execute: async () => {` | 1703 + | `app/index.js` | 684 | `window-reopen-last-closed` | `api.subscribe('cmd:execute:reopen closed window', …)` | 1704 + | `app/index.js` | 701 | `frontend-ready` | `// Signal to main process that frontend subscribers are ready.` | 1705 + | `app/index.js` | 710 | `session-restore-pending` | `if (p.restoreSession !== false) {` | 1706 + | `app/settings/settings.js` | 281 | `default-browser-status` | `(async () => {` | 1707 + | `app/settings/settings.js` | 296 | `set-default-browser` | `defaultBrowserBtn.textContent = 'Setting...';` | 1708 + | `app/settings/settings.js` | 3147 | `backup-create` | `backupOutput.textContent = 'Creating backup...';` | 1709 + | `app/settings/settings.js` | 3159 | `backup-list` | `backupOutput.textContent = 'Loading...';` | 1710 + | `app/settings/settings.js` | 3186 | `backup-get-config` | `backupBtnRow.appendChild(makeBtn('Open Backup Folder', async () => {` | 1711 + | `app/settings/settings.js` | 3196 | `shell-open-path` | `await api.invoke('backup-get-config'); …` | 1712 + | `app/page/page.js` | 847 | `get-app-prefs` | `(async () => {` | 1713 + | `app/diagnostic.html` | 155 | `backup-create` | `logBackup('Creating Backup', 'Please wait...');` | 1714 + | `app/diagnostic.html` | 169 | `backup-list` | `logBackup('Loading', 'Fetching backup list...');` | 1715 + | `app/diagnostic.html` | 205 | `backup-get-config` | `window.openBackupFolder = async function() {` | 1716 + | `app/diagnostic.html` | 217 | `shell-open-path` | `const configResult = await api.invoke('backup-get-config');` | 1717 + | `app/cmd/commands/page.js` | 148 | `window-devtools` | `// DevTools is handled via IPC directly, not via page.js` | 1718 + 1719 + No `api.send(...)`, `api.on(...)`, `window.app.invoke(...)`, or 1720 + `ipcRenderer.invoke(...)` calls found in any `app/` or `features/` file. 1721 + 1722 + --- 1723 + 1724 + #### Section 2 — Channel table 1725 + 1726 + For each unique channel, the table records: 1727 + 1728 + - **Legacy handler in `ipc.ts`?** — `Y` = yes, `entry.ts` = in `entry.ts` not `ipc.ts`. 1729 + - **`tile:*` equivalent in `tile-ipc.ts`?** — `Y` = yes, `N` = no. 1730 + - **Caller files** — where invoked. 1731 + - **Preload used by caller** — `tile-preload` or `preload.js`. 1732 + - **Recommended action.** 1733 + 1734 + | Channel | ipc.ts? | tile:* equiv? | Caller file(s) | Caller preload | Action | 1735 + |---------|---------|---------------|----------------|----------------|--------| 1736 + | `frontend-ready` | entry.ts | N | `app/index.js:701` | tile-preload | **No action needed.** Core renderer uses tile-preload's `api.invoke` trustedBuiltin passthrough. `frontend-ready` lives in `entry.ts` (not ipc.ts); it is NOT in the preload.js legacy surface being deleted. | 1737 + | `session-restore-pending` | entry.ts | N | `app/index.js:710` | tile-preload | **No action needed.** Same reason as `frontend-ready` — `entry.ts` handler, tile-preload trustedBuiltin passthrough. | 1738 + | `session-save` | Y | N | `app/index.js:489` | tile-preload | **Build `tile:session:save` shim.** Caller is core background renderer (tile-preload, trustedBuiltin). Direct preload.js removal unblocks this channel's deletion, but to KEEP the feature working we need either a strict shim or keep the legacy handler. Since core renderer will use trustedBuiltin passthrough, keeping the legacy handler as a named channel is fine until a `tile:session:*` namespace is built out. | 1739 + | `session-restore-interactive` | Y | N | `app/index.js:501` | tile-preload | Same as `session-save`. | 1740 + | `web-nav-back` | Y | N | `app/index.js:528` | tile-preload | **Legacy handler can stay.** Caller is tile-preload trustedBuiltin passthrough — not blocked by preload.js deletion. These are in the "suspected dead in 3.4 audit" bucket (grep found no pl/tp callers). The `app/index.js` callers were missed by the 3.4 grep because that grep only scanned preload.js and tile-preload.cts, not `app/` scripts. These channels are LIVE, not dead. | 1741 + | `web-nav-forward` | Y | N | `app/index.js:534` | tile-preload | Same as `web-nav-back`. LIVE via trustedBuiltin. | 1742 + | `web-nav-reload` | Y | N | `app/index.js:540` | tile-preload | Same. LIVE. | 1743 + | `web-nav-state` | Y | N | `app/index.js:547` | tile-preload | Same. LIVE. | 1744 + | `window-reopen-last-closed` | Y | N | `app/index.js:684` | tile-preload | Same — LIVE via trustedBuiltin. (3.4 audit: "no caller found in pl/tp" — missed this.) | 1745 + | `default-browser-status` | Y | N | `app/settings/settings.js:281` | **preload.js** | **BLOCKER.** `app/settings` has no v2 manifest; settings window gets `preload.js`. | 1746 + | `set-default-browser` | Y | N | `app/settings/settings.js:296` | **preload.js** | **BLOCKER.** Same. | 1747 + | `backup-create` | Y | N | `app/settings/settings.js:3147`, `app/diagnostic.html:155` | **preload.js** | **BLOCKER.** Both files use preload.js. (3.4 audit: "likely dead" — missed these.) | 1748 + | `backup-list` | Y | N | `app/settings/settings.js:3159`, `app/diagnostic.html:169` | **preload.js** | **BLOCKER.** Same. | 1749 + | `backup-get-config` | Y | N | `app/settings/settings.js:3186`, `app/diagnostic.html:205` | **preload.js** | **BLOCKER.** Same. | 1750 + | `shell-open-path` | Y | N | `app/settings/settings.js:3196`, `app/diagnostic.html:217` | **preload.js** | **BLOCKER.** Same. (3.4 audit: "no caller — likely dead" — missed these.) | 1751 + | `get-app-prefs` | Y | N | `app/page/page.js:847` | **preload.js** | **BLOCKER.** Canvas page windows have no tile manifest → get `preload.js`. | 1752 + | `window-devtools` | Y | N | `app/cmd/commands/page.js:148` | tile-preload | **No action needed.** cmd is trustedBuiltin. Channel stays in ipc.ts until cmd migrates to strict `tile:extensions:windowDevtools` path (already exists). | 1753 + 1754 + **3.4 audit correction:** six channels were incorrectly classified as 1755 + "no caller — likely dead" (`backup-get-config`, `backup-create`, 1756 + `backup-list`, `shell-open-path`, `web-nav-back/forward/reload/state`, 1757 + `window-reopen-last-closed`). The 3.4 grep only searched `preload.js` 1758 + and `tile-preload.cts`. Actual callers live in `app/*.js` and 1759 + `app/settings/settings.js` which were NOT grepped. These channels must 1760 + NOT be deleted in 3.11a without first migrating the callers. 1761 + 1762 + Additionally, `frontend-ready` and `session-restore-pending` are NOT in 1763 + `ipc.ts` — they live in `entry.ts` and are outside the v1-removal scope 1764 + entirely. No action needed. 1765 + 1766 + --- 1767 + 1768 + #### Section 3 — Renderer context per blocker file 1769 + 1770 + For each file with legacy-preload callers, this section identifies HOW 1771 + the renderer is loaded and why it receives `preload.js`. 1772 + 1773 + The `window-open` handler in `ipc.ts:1022` calls 1774 + `getTileWebPreferencesForUrl(url, …)` to decide which preload to assign 1775 + a new BrowserWindow. That function returns `null` for any URL whose 1776 + `peek://` host is not a registered v2 tile manifest. A `null` result 1777 + falls back to `getPreloadPath()` = `preload.js`. 1778 + 1779 + ##### `app/settings/settings.html` + `app/settings/settings.js` 1780 + 1781 + - **Entry point:** opened via `windowManager.createWindow(url, …)` in 1782 + `app/index.js:58`, which calls `api.window.open(settingsAddress, …)` 1783 + → `window-open` IPC with url = `peek://app/settings/settings.html`. 1784 + - **URL host:** `app` — not a registered v2 tile (`app/settings/` has no 1785 + `manifest.json`, no tile registration in `tile-launcher.ts`). 1786 + - **`getTileWebPreferencesForUrl` result:** `null`. 1787 + - **Preload assigned:** `getPreloadPath()` = **`preload.js`**. 1788 + - **Consequence:** All `api.*` calls in `settings.js` come from 1789 + `preload.js`. The file uses: `api.invoke` (5 direct channels), 1790 + `api.extensions.*`, `api.theme.*`, `api.adblocker.*`, 1791 + `api.chromeExtensions.*`, `api.darkMode.*`, `api.sync.*`, 1792 + `api.profiles.*`, `api.publish`, `api.scopes`. 1793 + - **LOC:** `settings.js` 3491 + `settings.html` 30 = **3521 LOC**. 1794 + - **Blocker classification:** BLOCKER. Cannot delete `preload.js` while 1795 + this window uses it. 1796 + - **Migration path:** Convert `app/settings/` to a v2 tile. Add 1797 + `manifest.json` declaring `app/settings/settings.html` as its home 1798 + entry, add capability grants covering every `api.*` namespace used 1799 + (window, extensions, theme, adblocker, chromeExtensions, darkMode, 1800 + sync, profiles, datastore, pubsub). Register via `tile-launcher.ts`. 1801 + Replace all `api.invoke(...)` calls with structured `api.<ns>.<method>` 1802 + calls through tile-preload. Estimated budget: 30–45 min (large file). 1803 + Can be split into 3.11b-settings (manifest + registration) + 3.11b-settings2 1804 + (port api.* calls). 1805 + 1806 + ##### `app/diagnostic.html` 1807 + 1808 + - **Entry point:** `api.window.open('peek://app/diagnostic.html', …)` in 1809 + `app/index.js:268` → `window-open` IPC with url = `peek://app/diagnostic.html`. 1810 + - **URL host:** `app` — not a registered v2 tile. 1811 + - **Preload assigned:** **`preload.js`**. 1812 + - **API surface:** `api.invoke` (4 direct channels: `backup-create`, 1813 + `backup-list`, `backup-get-config`, `shell-open-path`), 1814 + `api.datastore.getTable`. 1815 + - **LOC:** 232 LOC. 1816 + - **Blocker classification:** BLOCKER. However, this is a developer-only 1817 + diagnostic tool. Lowest-risk migration option: either (a) convert to a 1818 + minimal v2 tile with `backup` + `datastore` capabilities, or (b) wrap 1819 + the 4 `api.invoke` calls into proper `api.backup.*` tile methods and 1820 + add a `tile:backup:*` namespace, then add a manifest. Budget: 20 min. 1821 + 1822 + ##### `app/page/page.js` (canvas page host) 1823 + 1824 + - **Entry point:** canvas page windows are created by `window-open` with 1825 + a WEB URL (e.g. `https://example.com`). `getTileWebPreferencesForUrl` 1826 + returns `null` for non-`peek://` URLs. The window then loads 1827 + `peek://app/page/index.html?url=...` as `loadUrl` (ipc.ts:1225), but 1828 + the preload was already determined against the original `https://` URL 1829 + — so `preload.js` is used. 1830 + - **Preload assigned:** **`preload.js`** (all canvas page windows). 1831 + - **API surface used by `page.js`:** 1832 + - `api.invoke('get-app-prefs')` (line 847) 1833 + - `api.window.*` (getWindowId, setBounds, getBounds, getDisplayInfo, 1834 + setScrollPosition, openerPostMessage, openerClose, openerFocus) 1835 + - `api.profiles.getPartition` (line 630) 1836 + - `api.context.get` / `api.context.setMode` / `api.context.watchMode` 1837 + (lines 2109, 2119, 2133, 2140) 1838 + - `api.datastore.*` (updateItemTitle, trackNavigation, queryItems, 1839 + getItemTags, getTagsByFrecency, getOrCreateTag, tagItem, untagItem) 1840 + - `api.chromeExtensions.list` / `getUiEntries` (line 3543-3544) 1841 + - `api.subscribe` / `api.publish` / `api.scopes` 1842 + - **LOC:** `page.js` 3788 + `app/page/index.html` (canvas host) — 1843 + combined **~4000+ LOC** of preload.js-dependent renderer code. 1844 + - **Blocker classification:** BLOCKER — the largest single blocker. 1845 + - **Migration path:** There is no straightforward v2 tile manifest path 1846 + for canvas page windows because they are created dynamically with web 1847 + URLs as their identity. The correct migration is one of: 1848 + - **(a) Dedicated `page` tile** — register `app/page/index.html` as a 1849 + v2 tile entry under a `page` tile manifest (`peek://page/page-host.html` 1850 + or similar), and in the `window-open` handler, use that tile's preload 1851 + for any canvas window instead of the web URL. This keeps the existing 1852 + canvas architecture but routes `page.js`'s `api.*` calls through 1853 + tile-preload. The token would carry `window`, `datastore`, `context`, 1854 + `profiles`, `chromeExtensions` capabilities + trustedBuiltin. 1855 + Estimated budget: 30 min (manifest + glue change in ipc.ts:1041-1042). 1856 + - **(b) Unconditional tile-preload for `peek://app/*`** — in the 1857 + `window-open` handler, for URLs that will `loadUrl` into 1858 + `peek://app/page/index.html`, assign a hardcoded tile-preload path + 1859 + `core` trustedBuiltin token (same as core background). Simpler but 1860 + gives the canvas window the full trustedBuiltin surface (same risk as 1861 + current `preload.js` isCore). 1862 + - **(c) Port `get-app-prefs` to a proper `tile:*` channel** and register 1863 + `app/page/` as a v2 tile. Requires addressing the full `api.*` surface 1864 + used by `page.js` — essentially same as option (a) but scoped to the 1865 + canvas page tile manifest. 1866 + Option (a) is cleanest architecturally. 1867 + 1868 + --- 1869 + 1870 + #### Section 4 — Path-forward recommendation 1871 + 1872 + **True blockers** (renderers running under `preload.js`): 3 renderer 1873 + contexts, ~3753 LOC of consumer code. 1874 + 1875 + **Non-blockers** (callers already on tile-preload trustedBuiltin 1876 + passthrough): `app/index.js` (9 channels), `app/cmd/commands/page.js` 1877 + (1 channel). These do NOT block preload.js deletion but do require the 1878 + corresponding legacy channels to remain in `ipc.ts` until a `tile:*` 1879 + shim is built for each. They represent channels the 3.4 audit 1880 + incorrectly classified as "dead" — they must be removed from the 3.11a 1881 + deletion list. 1882 + 1883 + ##### Corrected 3.11a channel list 1884 + 1885 + Remove from the "suspected dead, delete in 3.11a" list: 1886 + - `web-nav-back`, `web-nav-forward`, `web-nav-reload`, `web-nav-state` 1887 + (live callers: `app/index.js:528, 534, 540, 547` via trustedBuiltin) 1888 + - `window-reopen-last-closed` (live caller: `app/index.js:684` via 1889 + trustedBuiltin) 1890 + - `backup-get-config`, `backup-create`, `backup-list`, `shell-open-path` 1891 + (live callers: `app/settings/settings.js` + `app/diagnostic.html`) 1892 + - `default-browser-status`, `set-default-browser` (live callers: 1893 + `app/settings/settings.js`) 1894 + 1895 + Keep these channels in `ipc.ts` until their callers migrate. 1896 + 1897 + ##### Packages needed before 3.11b can execute 1898 + 1899 + | Package | Scope | Budget | 1900 + |---------|-------|--------| 1901 + | **3.11b-settings** | Convert `app/settings/settings.html` to v2 tile: add `manifest.json`, register in `tile-launcher.ts`, add `tile:backup:*` and `tile:shell:open` shims, add `tile:app:default-browser-*` shims, port all `api.invoke()` calls to structured `api.<ns>.*`. Replace remaining preload.js surface with tile-preload equivalents (most already exist: theme, extensions, chromeExtensions, sync, profiles, adblocker all have tile:* channels from Waves 2a–2b). | 45 min — split into 3.11b-settings1 (manifest + registration) + 3.11b-settings2 (api migration) | 1902 + | **3.11b-diagnostic** | Convert `app/diagnostic.html` to v2 tile OR add `tile:backup:create/list/get-config` + `tile:shell:open-path` shims and keep as a core utility with trustedBuiltin. The file is only 232 LOC with 4 direct `api.invoke` calls and 1 `api.datastore.getTable` call — simplest path is option (b): give it a minimal `app` tile entry + trustedBuiltin grant in the window-open handler for `peek://app/diagnostic.html`. | 20 min | 1903 + | **3.11b-page** | Convert canvas page host (`app/page/index.html` → `page.js`) to tile-preload. Add a `page-host` tile manifest or modify the `window-open` handler (ipc.ts:1041) to assign `tile-preload.cjs` with a trustedBuiltin page-host token for all canvas windows. Port `api.invoke('get-app-prefs')` to a `tile:app:get-prefs` shim. The rest of `page.js`'s `api.*` calls already have tile:* equivalents (window, datastore, context, profiles, chromeExtensions, pubsub). | 30 min | 1904 + | **3.11b-nav-session** | Build `tile:nav:*` shims for `web-nav-back/forward/reload/state` and `tile:session:save` + `tile:session:restore-interactive` + `tile:session:reopen-last-closed`. These are called from `app/index.js` via trustedBuiltin passthrough — the channels still need to exist in ipc.ts until tile-preload has strict equivalents, but they do NOT block preload.js deletion (only block the legacy handler deletion in 3.7/3.11c). | 20 min | 1905 + | **3.11b-prefs** | Build `tile:app:get-prefs` shim. Needed by `app/page/page.js:847`. Pairs with 3.11b-page. | (fold into 3.11b-page) | 1906 + 1907 + ##### Summary of additional work before 3.11b 1908 + 1909 + 1. **Build 3 missing `tile:*` namespaces:** `tile:backup:*` (3 methods), 1910 + `tile:shell:open-path` (1 method), `tile:app:get-prefs` (1 method). 1911 + Optionally `tile:nav:*` (4 methods) and `tile:app:default-browser-*` 1912 + (2 methods) for clean channel removal in 3.11c. 1913 + 2. **Migrate 3 renderer contexts** to tile-preload: `app/settings/`, 1914 + `app/diagnostic.html`, `app/page/` (canvas host). 1915 + 3. **Do NOT delete** these 10 channels in 3.11a: `backup-*` (3), 1916 + `shell-open-path`, `default-browser-*` (2), `web-nav-*` (4), 1917 + `window-reopen-last-closed`, `get-app-prefs`, `session-save`, 1918 + `session-restore-interactive`. 1919 + 4. **Fastest unblocking path:** 3.11b-diagnostic (20 min) + 3.11b-page 1920 + (30 min) + the `tile:backup:*` shims (15 min folded into 3.11b-settings1) 1921 + clear the majority of the surface. `settings.js` at 3491 LOC is the 1922 + largest single item but can be staged across two spawns. 1923 + 1924 + **Total additional budget before 3.11b:** ~115 min across 4–5 packages. 1925 + Biggest single blocker: `app/settings/settings.js` (3491 LOC, broadest 1926 + API surface, most new tile:* shims needed). 1927 +