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.
This commit is contained in:
golem
2026-08-01 22:33:29 -06:00
parent 22fc754636
commit 6bedd700e8
3 changed files with 58 additions and 23 deletions
@@ -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**