f7fc15b17c
Includes: - cli.py path fix (parents[1]) for config/catalog resolution - Library cleanup feature design docs (TODO.md, mockup) - Audit + bug-queue markdowns from May 2026 reliability pass - .gitignore expanded for transient artifacts
8.6 KiB
8.6 KiB
Candidate Findings — Extension Options pages — audit-snapshot-2026-05-24T15-55Z.md
Scope: src/options/* (+ src/shared/* if referenced)
Required-reading: ext AGENTS.md / mockup / bug-audit-plan.md / project memory
Auditor: fresh Explore agent
Candidate C-1
- File:
src/options/options.js:492-525(SETTINGS_SCHEMA definition) - Hunch: SETTINGS_SCHEMA includes all load/save keys; no asymmetry.
- Trace: Lines 191-192 in
load()readsettings.siteAdaptersandsettings.idNormalizers, and lines 234-235 insave()write them back. SETTINGS_SCHEMA at lines 518, 520 includes both keys. Schema is complete. - Question for verifier: Confirm SETTINGS_SCHEMA includes all keys that load/save cycle uses.
- Contract refs needed: none
Candidate C-2
- File:
src/options/options-dupe-review.js:561-628(loadKeepRanking and save) - Hunch:
loadKeepRanking()runs once at module load (line 628), not when pane is activated. External changes to keep-ranking won't appear until page reload. - Trace: Line 628 calls loadKeepRanking() at module top level. No listener on pane activation (options.js line 37) calls it again. If another tab changes keep-ranking via RPC, this pane won't refresh until reload.
- Question for verifier: Should pane activation re-fetch keep-ranking to catch external changes?
- Contract refs needed: none
Candidate C-3
- File:
src/options/options.js:110-122(openModal / closeModal) - Hunch: No coordination between modals. Two rapid opens could show two modals simultaneously.
- Trace:
openModal(id)adds "open" class and sets aria-hidden=false. No check if another modal is already open. Multiple modals could be marked "open" at the same time. - Question for verifier: Should only one modal be visible at a time, or is simultaneous open allowed?
- Contract refs needed: none
Candidate C-4
- File:
src/options/options.js:300(setNote function) - Hunch:
setNote()callsel.innerHTML = htmlwithout sanitization. Assumes caller sanitizes before passing. - Trace: All current callers (lines 308–337) build HTML with escapeHtml() before inserting. So current usage is safe. But setNote() is not a safe setter — it's a raw innerHTML setter.
- Question for verifier: Is setNote intended as a safe reescaper, or a raw setter expecting pre-sanitized input?
- Contract refs needed: none
Candidate C-5
- File:
src/options/options.js:533-546(sanitizeImportedSettings) - Hunch: Array elements are not recursively validated. Example:
siteAdapters: [{ host: 123, selector: [] }]would pass because the outer type is "array". - Trace: SETTINGS_SCHEMA checks outer type (line 542) but not inner element types. Comment at line 491 says nested objects get recursive validation, but code doesn't implement it for arrays.
- Question for verifier: Should imported arrays validate element types, or is current lenient behavior acceptable?
- Contract refs needed: none
Candidate C-6
- File:
src/options/options.js:210-286(save function) - Hunch: Save persists to chrome.storage but messages to background.js are fire-and-forget. No confirmation that background applied the settings.
- Trace: Line 256 awaits chrome.storage.sync (safe). Lines 261, 278 send messages without waiting for response. If background crashes, settings persist but running extension uses stale config.
- Question for verifier: Should save() wait for background.js acknowledgment?
- Contract refs needed: none
Candidate C-7
- File:
src/options/options-cache.js:113-137(renderCacheContractBanner) - Hunch: Unrecognized cache_state values silently return empty string instead of showing error.
- Trace: Lines 118, 121, 131 test cache_state against known literals. If host sends unexpected state (e.g.,
"unknown_state"), no if matches and line 136 returns "". No error banner shown. - Question for verifier: Should unrecognized cache_state trigger an error banner?
- Contract refs needed: none
Candidate C-8
- File:
src/options/options.js:386-416(export/import keep-ranking) - Hunch: Export fails silently if keep-ranking RPC fails. Exported file has empty
_meta.host_config.keep_ranking. On import, user gets warning but import proceeds anyway. Asymmetric: backup loses data without obvious indication. - Trace: Lines 391-395 try-catch the RPC silently. If it fails, hostConfig.keep_ranking is never set. Export completes anyway (line 405-414). On import, user sees warning at line 560 but can proceed. Keep-ranking is lost in backup/restore cycle.
- Question for verifier: Should export fail or warn prominently if keep-ranking cannot be fetched?
- Contract refs needed: none
Candidate C-9
- File:
src/options/options.js:351-372(delete-enable-modal flow) - Hunch: If user checks enableDelete and navigates away before confirming modal, box stays unchecked with no way to retry except page reload.
- Trace: Line 352-353 check→uncheck→open-modal. If user closes modal without confirming, checkbox is false and no path to re-open the modal exists. Would need page reload or clicking box again.
- Question for verifier: Should modal be re-openable from checked state without page reload?
- Contract refs needed: none
Candidate C-10
- File:
src/options/options-library-issues.js:134-143(makeReportRow rendering) - Hunch:
entry.path.split("/")could throw if entry.path is null or not a string. - Trace: Line 134
fname = entry.filename || entry.path.split("/").pop(). If entry.filename is falsy and entry.path is null, .split() throws. Entry.path comes from RPC; malformed response could crash render. - Question for verifier: Should there be null/type check for entry.path before .split()?
- Contract refs needed: none
Candidate C-11
- File:
src/options/options.js:374-382(input/change listeners) - Hunch: Event listeners call updateSectionSummaries() which reads from DOM. If multiple panes render simultaneously and input fires from hidden pane, stale element reads could occur.
- Trace: Lines 374-375 listen for "input" and "change" on panes. Delegated check at line 378 ensures only active pane events fire, but race condition possible if multiple panes render concurrently.
- Question for verifier: Is there a render race if load() initializes all panes and events fire before page ready?
- Contract refs needed: none
Candidate C-12
- File:
src/options/options-library-issues.js:120-131(makeRow - library issues) - Hunch: The makeRow function for bracket_id and nohyphen_id rows sets data-issue at line 123, which is later checked by _canRenameIdFixRow() line 60. If makeRow is called with malformed entry data, the row might be created but with missing data attributes, making it silently non-renamable.
- Trace: Line 120-131 creates row HTML and sets data-issue to entry.issue at line 123. The entry.issue comes from the response. If rendering bracket entries with undefined entry.issue, the row would be created but unclickable (no rename).
- Question for verifier: Should missing entry.issue in bracket/nohyphen entries trigger an error, or is silent disable acceptable?
- Contract refs needed: none
Summary Stats
- Total candidates: 12
- Severity breakdown: L (7), M (4), N (1)
- Areas affected: stale state (1), modal visibility (1), HTML safety (2), validation (2), error handling (3), RPC failures (1), null safety (1), concurrency (1), missing attributes (1)
VERIFIER NOTES (Phase 1 Moderate verification, stricter prompt + UI-inconvenience rule + storage-quota awareness)
- C-5 (array element validation) — CONFIRMED M. Auditor right; downstream crash in tryAdapters confirmed via content.js read. Promoted as M-1.
- C-6 (save fire-and-forget) — REFUTED. getSettings reads fresh from storage every call; no in-memory cache to invalidate. sendMessage wakes SW per MV3 spec.
- C-8 (export silent fail) — CONFIRMED M, high confidence. Backup→restore cycle silently loses user-typed config. Promoted as M-2.
- C-10 (entry.path crash) — REFUTED. Host's _cache_entry contract guarantees path always non-null string. Unreachable in normal operation.
CHUNK 4 CALIBRATION:
- Severe: 0 (none flagged)
- Moderate rejection: 2/4 = 50% (stop condition >30% triggered)
- Combined: 2/4 = 50%
- Auditor weaknesses: (1) flagging fire-and-forget message patterns without checking if downstream caches, (2) ignoring host-side schema contracts that prevent null/malformed data reaching JS
- L candidates NOT verified per stop condition. Revisit only if needed.