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

98 lines
7.2 KiB
Markdown

# 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.