Files
rclone-jav/bugs-candidates-extension-popup.md
T
admin f7fc15b17c Sync working tree before initial Gitea push
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
2026-05-26 22:35:42 +02:00

7.2 KiB

Candidate Findings — Extension Popup + Bulk Check — audit-snapshot-2026-05-24T15-55Z.md

Scope: src/popup/* + src/bulk-check/* + src/shared/id-extract.js Required-reading: ext AGENTS.md / bug-audit-plan.md Auditor: fresh Explore agent (Phase 1 audit)

Candidate C-1: Popup closes before open-bulk-check message completes

  • File: D:\DEV\Extensions\Production\rclone-jav\src\popup\popup.js:563-565
  • Hunch: Popup window closes immediately after sending open-bulk-check message without callback, risking message loss if popup is killed before IPC serialization.
  • Trace: Line 564 sends message with NO callback, line 565 immediately closes popup.
  • Question for verifier: Does Chrome guarantee sendMessage() is queued before window.close() returns?
  • Contract refs needed: Chrome Runtime API message passing guarantees

Candidate C-2: Delete confirmation allows stale expectedId from prior modal session

  • File: D:\DEV\Extensions\Production\rclone-jav\src\popup\popup.js:318-372
  • Hunch: Global expectedId set when hit is selected. If modal closes without selection and reopens, old expectedId persists and could allow false-positive match.
  • Trace: expectedId is global line 316, set in selectHit() line 353, but NOT reset in openDeleteModal().
  • Question for verifier: Can modal open without selecting a hit, leaving stale expectedId that allows unintended validation?
  • Contract refs needed: Modal state management

Candidate C-3: Manual search captures t0 before SW eviction, causing misleading timings

  • File: D:\DEV\Extensions\Production\rclone-jav\src\popup\popup.js:452-470
  • Hunch: t0 = performance.now() captured at send time. If SW evicted/restarted during 90s timeout, callback fires with unbounded total_ms.
  • Trace: Lines 452 and 468 show t0 captured and used to synthesize total_ms after callback.
  • Question for verifier: When SW dies mid-request, can callback fire with unbounded total_ms contradicting host query time?
  • Contract refs needed: SW lifecycle, AGENTS.md timeout handling

Candidate C-4: History chip click executes search without checking modal state

  • File: D:\DEV\Extensions\Production\rclone-jav\src\popup\popup.js:423-425
  • Hunch: History chip click calls runManualSearch() unconditionally. If delete modal open with chosenHit, search executes while modal remains visible with stale state.
  • Trace: Line 425 calls runManualSearch() with no check for open modals.
  • Question for verifier: Should clicking history chip close delete modal first?
  • Contract refs needed: Modal lifecycle specification

Candidate C-5: Search Clear button does not close delete modal

  • File: D:\DEV\Extensions\Production\rclone-jav\src\popup\popup.js:479-484
  • Hunch: Clear button resets manualMode and calls runCheck() but does NOT close delete modal, leaving it open with stale chosenHit.
  • Trace: Lines 479-484 show no $overlay.style.display = "none"
  • Question for verifier: If user opens delete modal then clicks Clear, does modal remain open in invalid state?
  • Contract refs needed: Modal lifecycle specification

Candidate C-6: Bulk-check uses innerHTML with escaped fields (fragile pattern)

  • File: D:\DEV\Extensions\Production\rclone-jav\src\bulk-check\bulk-check.js:26-44
  • Hunch: All template fields are escaped currently, but innerHTML pattern is fragile. If future code adds unescaped response fields, XSS possible.
  • Trace: Lines 32-44 show escapeHtml() called on fields, but innerHTML assignment could miss new fields.
  • Question for verifier: Are all response fields (e.g., cache_meta, scanned_remotes) properly escaped?
  • Contract refs needed: XSS contract, host response schema

Candidate C-7: Profile selector change triggers search without canceling in-flight request

  • File: D:\DEV\Extensions\Production\rclone-jav\src\popup\popup.js:612-622
  • Hunch: Profile change triggers new search without AbortController. Old search callback could fire after new one, rendering stale (old-profile) results.
  • Trace: Lines 620-621 call runManualSearch/runCheck with no request ID or AbortController.
  • Question for verifier: If user changes profiles while search in-flight, can old callback render stale results?
  • Contract refs needed: Message passing race condition contract

Candidate C-8: Bulk-check does not warn when query count exceeds 250-query limit

  • File: D:\DEV\Extensions\Production\rclone-jav\src\bulk-check\bulk-check.js:13-18
  • Hunch: readBulkIds() deduplicates but does NOT enforce 250-query limit. User pastes 300 IDs, UI shows "300 unique IDs", host silently truncates to 250.
  • Trace: No limit enforcement in readBulkIds(). Host limit at rcjav-host.py line 818: queries[:250]
  • Question for verifier: Should UI warn when input exceeds 250 IDs?
  • Contract refs needed: Host bulk_search limit contract

Candidate C-9: Undo modal button success feedback only visible for 1.2 seconds

  • File: D:\DEV\Extensions\Production\rclone-jav\src\popup\popup.js:536-543
  • Hunch: Button text changes to "✓ restored" but modal auto-closes after 1.2s. May be too brief for user to see success state.
  • Trace: Line 536 sets button text to checkmark, line 541 closes modal after only 1200ms timeout.
  • Question for verifier: Is 1.2s timeout intentional, or should success state remain visible longer?
  • Contract refs needed: Undo UX specification

Candidate C-10: Cache banner age uses Math.round, hiding near-boundary staleness

  • File: D:\DEV\Extensions\Production\rclone-jav\src\popup\popup.js:604
  • Hunch: Math.round(24.4) = 24, making 24.4h cache appear as 24h old. Should use Math.ceil for conservative rounding.
  • Trace: Line 604 uses Math.round() on oldest.age_hours
  • Question for verifier: Should cache age always round up to conservatively display staleness?
  • Contract refs needed: Cache freshness display contract

Summary: 10 candidates found

Most critical: C-1 (message race), C-2 (stale state), C-7 (search race)


VERIFIER NOTES (Phase 1 Moderate verification, stricter prompt + UI-lifecycle rule + bulk-check window awareness)

  • C-1 (open-bulk-check race) — REFUTED. Chrome runtime guarantees fire-and-forget delivery before sender unload.
  • C-2 (stale expectedId) — PARTIAL → demoted M to L. Delete RPC uses chosenHit (reset every open); typing-validation just gates UI button; no wrong-delete possible. Promoted as L-1.
  • C-4 (history chip during modal) — PARTIAL → demoted M to L. chosenHit is reference; delete still correct file. Cosmetic UI confusion only. Promoted as L-2.
  • C-5 (Clear button modal) — CONFIRMED M, high confidence. Modal stays open; no Esc handler; delete still works but UX broken. Promoted as M-1.
  • C-7 (profile selector race) — CONFIRMED M, high confidence. Real race, stale results stick. Promoted as M-2.

CHUNK 5 CALIBRATION:

  • Severe: 0 (none flagged)
  • Moderate raw rejection: 1/5 pure REFUTED, 2/5 demoted = 60% downgrade rate
  • Combined: stop condition triggered
  • Auditor weaknesses: flagging timing races without checking (a) platform contracts, (b) object reference vs rebuilt-from-current-results, (c) self-correcting cosmetic-only effects
  • L candidates NOT verified per stop condition. Revisit only if needed.