From 6bedd700e8180234ae4e0992a7266a2ffdcdba4d Mon Sep 17 00:00:00 2001 From: golem Date: Sat, 1 Aug 2026 22:33:29 -0600 Subject: [PATCH] doc: record the omitted strict_min_version and rejection guards The plan pinned strict_min_version to 112.0 for the ES-module background floor, but the existing data_collection_permissions key requires Firefox 140 desktop / 142 Android, so addons-linter warned and warningsAsErrors failed the build. Measured: 112.0 -> 2 warnings, 140.0 -> 1, 142.0 -> clean, omitted -> clean. 142.0 was rejected because it locks out ESR 140. Omitting excludes nobody and degrades gracefully below 112. Also syncs the plan's background.js block with the rejection guards added in 22fc754, and reworks two of those comments for clarity. --- background/background.js | 10 ++-- .../2026-07-30-extension-options-panel.md | 48 +++++++++++++------ .../2026-07-29-extension-options-design.md | 23 +++++++-- 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/background/background.js b/background/background.js index 575b88a..8d473a4 100644 --- a/background/background.js +++ b/background/background.js @@ -67,8 +67,9 @@ async function openChatGpt(query) { await browser.tabs.create({ url, active: settings.openIn !== "background-tab" }); } catch { - // Silence rejections silently — the user expects either a tab to open or - // nothing, not an error log. Every failure path must degrade gracefully. + // Nothing useful to say and nowhere useful to say it: the user expects a + // tab or nothing at all. Both call sites invoke this without awaiting, so + // without this catch a failure would log an unhandled rejection. } } @@ -102,6 +103,7 @@ if (browser.commands) { } registerMenu().catch(() => { - // Silence rejections from menus.removeAll() — it cannot prevent menu creation - // on retry, so degrade gracefully with no unhandled rejection logged. + // menus.removeAll() is promise-based and can reject; a failed re-registration + // cannot be retried usefully from here. (menus.create() is callback-based and + // cannot reject, so it needs no guard.) }); diff --git a/docs/superpowers/plans/2026-07-30-extension-options-panel.md b/docs/superpowers/plans/2026-07-30-extension-options-panel.md index b3673f7..3881717 100644 --- a/docs/superpowers/plans/2026-07-30-extension-options-panel.md +++ b/docs/superpowers/plans/2026-07-30-extension-options-panel.md @@ -20,7 +20,13 @@ Every task's requirements implicitly include this section. Values are copied ver - **Manifest stays V2.** Do not migrate to MV3. Keep the code MV3-portable: ES-module background, `persistent: false`, never `browser_style: true`. - **Permissions are exactly `["storage", "menus", "activeTab"]`.** Do not add host permissions, `optional_permissions`, `tabs`, `webNavigation`, `notifications`, or `contentScripts`. All three chosen permissions add no install-prompt line; `tabs` and `notifications` do. - **Never read `tab.url`, `tab.title`, or `tab.favIconUrl`.** Reading them requires the `tabs` permission. Only `tab.id` may be read. -- **`strict_min_version` is `"112.0"`.** +- **`strict_min_version` is omitted.** Corrected during execution: the plan + originally pinned `"112.0"` (the ES-module background floor), but the existing + `data_collection_permissions` key requires Firefox 140 / Android 142, so + `addons-linter` warns on any lower value and `warningsAsErrors: true` fails the + build. Measured: `112.0` → 2 warnings, `140.0` → 1, `142.0` → clean, omitted → + clean. `142.0` was rejected because it locks out ESR 140. Below Firefox 112 the + `gpt` keyword still works and only the two new entry points are inert. - **No new runtime or dev dependencies.** `node:test` is built in. - **`lint.warningsAsErrors: true`** — a single addons-linter warning fails the build. `npx web-ext lint` must stay at 0 errors / 0 warnings / 0 notices. - **Two-space indentation** in JSON, YAML, and JavaScript. Lowercase, hyphenated filenames. @@ -48,7 +54,7 @@ Every task's requirements implicitly include this section. Values are copied ver | `options/options.js` | **Create.** Renders settings, debounced auto-save, live re-sync on `storage.onChanged`. | | `test/build-url.test.js` | **Create.** Unit tests for the URL builder. | | `test/settings.test.js` | **Create.** Unit tests for `mergeSettings`. | -| `manifest.json` | **Modify.** Add `permissions`, `background`, `options_ui`, `commands`, `strict_min_version`; bump version. | +| `manifest.json` | **Modify.** Add `permissions`, `background`, `options_ui`, `commands`; bump version. | | `package.json` | **Modify.** Add `"type": "module"`, a `test:unit` script; bump version. | | `README.md` | **Modify.** Options section, the double-Enter limitation, revised privacy wording. | | `AGENTS.md` | **Modify.** Project structure, commands, manual test checklist. | @@ -614,7 +620,6 @@ Replace the whole file. `browser_style: false` is set **explicitly** — omittin "browser_specific_settings": { "gecko": { "id": "{24644f0c-bfcb-4ebd-a16b-bc8a7d154288}", - "strict_min_version": "112.0", "data_collection_permissions": { "required": [ "none" @@ -718,20 +723,30 @@ async function readSelection() { return ""; } +// Corrected during execution: the whole body is wrapped, because both call +// sites invoke this without awaiting. Without the outer catch a rejection from +// the final tabs.create surfaces as an unhandled promise rejection, which the +// "degrade silently" constraint above forbids. The inner catch stays nested so +// a windows.create failure still falls through to a tab. async function openChatGpt(query) { - const settings = await load(); - const url = buildChatGptUrl(settings, query); + try { + const settings = await load(); + const url = buildChatGptUrl(settings, query); - if (settings.openIn === "new-window") { - try { - await browser.windows.create({ url }); - return; - } catch { - // Fall through to a tab rather than doing nothing. + if (settings.openIn === "new-window") { + try { + await browser.windows.create({ url }); + return; + } catch { + // Fall through to a tab rather than doing nothing. + } } - } - await browser.tabs.create({ url, active: settings.openIn !== "background-tab" }); + await browser.tabs.create({ url, active: settings.openIn !== "background-tab" }); + } catch { + // Nothing useful to say and nowhere useful to say it: the user expects a + // tab or nothing at all. + } } // removeAll() first, so a background event page waking up and re-running this @@ -763,7 +778,12 @@ if (browser.commands) { }); } -registerMenu(); +// Corrected during execution: menus.removeAll() is promise-based in Firefox, so +// an unguarded call here can log an unhandled rejection. (menus.create() is +// callback-based and cannot reject.) +registerMenu().catch(() => { + // A failed re-registration cannot be retried usefully from here. +}); ``` - [ ] **Step 3: Verify lint and packaging still pass** diff --git a/docs/superpowers/specs/2026-07-29-extension-options-design.md b/docs/superpowers/specs/2026-07-29-extension-options-design.md index d9e8c64..4ffcfc4 100644 --- a/docs/superpowers/specs/2026-07-29-extension-options-design.md +++ b/docs/superpowers/specs/2026-07-29-extension-options-design.md @@ -115,9 +115,21 @@ ES modules work in an MV2 background script via needed. The options page is a normal extension page and can use `