Files
rclone-jav/verification.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

9.6 KiB

Verification — Phase 3 — 2026-05-25

Original snapshot: audit-snapshot-2026-05-24T15-55Z.md Final snapshot: same code-of-record + 13 manifest bumps (0.1.33 → 0.1.45 inclusive) + 1 CLI-only no-bump fix

Fix summary (all bugs in audit queue)

Severe (1/1 fixed)

  • S-1 (opts): Export silently drops keep_ranking → backup data loss. FIXED v0.1.33 at src/options/options.js:386-447. Export now blocks on get-keep-ranking RPC failure; success path writes _meta.host_config.keep_ranking. Verified: failure path shows clear block message + no file; success path produces JSON with full keep_ranking populated.

Moderate (7/7 fixed)

  • M-1 (opts): sanitizeImportedSettings element validation gap → content-script crash on malformed import. FIXED v0.1.34 at src/options/options.js:552-633. Added ARRAY_ELEMENT_VALIDATORS for siteAdapters / idNormalizers / partPatterns / knownSitePatterns / profiles. Verified: malformed import shows siteAdapters[0](malformed) in modal; good entry survives; runtime test confirmed.
  • M-2 (bg): Context menu missing after MV3 SW eviction. FIXED v0.1.36 at background.js:1193 (top-level ensureContextMenu() call). Verified: right-click on google.com after SW lifecycle shows full rclone-jav menu.
  • M-3 (host): handle_scan returned success before Popen could fail. FIXED v0.1.37 at host/rcjav-host.py:2053-2306. Per-invocation threading.Event + spawn_result dict; 500 ms wait; synchronous failure surfacing. Verified via instrumented raise FileNotFoundError("simulated spawn fail") runtime test — UI showed scan failed: FileNotFoundError: simulated spawn fail synchronously; instrumentation reverted.
  • M-4 (host): post_discord_alert blocked main loop 5 s on slow Discord. FIXED v0.1.39 at host/rcjav-host.py:174-289. Refactored to _discord_post_worker + _build_discord_body; real alerts threaded fire-and-forget; test RPC waits 6 s with explicit timeout error. Outcomes logged with alert_source. Verified runtime: Test (host) returned synchronous HTTP 401 for bogus token + HTTP 204 for valid; events.log has discord_post with all fields.
  • M-5 (popup): Profile selector race overwrites with stale results. FIXED v0.1.40 + 0.1.41 follow-up at src/popup/popup.js. Monotonic _currentSearchId gate in runCheck + runManualSearch; bumped BEFORE paused early-exit. Verified: unit tests 5/5 pass; stale callbacks bail before any UI write.
  • M-6 (bg): recordRpc race loses log entries. FIXED v0.1.42 at background.js:155-180. Promise-chain lock around the body. Verified via simulated-storage smoke test: unlocked 1/5 preserved, locked 5/5 preserved.
  • M-7 (CLI): save_config no retry — Windows AV lock crashes --save. FIXED (no manifest bump — CLI repo only) at rcjav/cli.py:186-194. Mirrored save_cache's retry. Verified 3/3 smoke tests.

Light (1/6 fixed; 5 deferred)

  • L-1 (bg): maybeNotifyHostError rate-limit race over-notification. FIXED v0.1.43 at background.js:191-247. Dedicated _hostAlertLock around rate-limit + notification + Discord paths. Verified: unlocked 5/5 fire (bug confirmed), locked 1/5 fire (correct), sequential locked still rate-limited.
  • L-2 → L-6 (deferred): cosmetic / UX polish — Discord visibility passive UI, stderr 5 s stale on rc-jav stall, expectedId state leak, history chip during modal, Clear button modal stays open. None block S/M user workflows; all have documented workarounds. Tracked in respective bugs-*.md files for a future polish pass.

Phase 3 re-audit: bug introduced by M-3 fix, caught and fixed

Re-audit of Phase 2 modified files (background.js, options.js, popup.js, rcjav-host.py, cli.py, manifest.json) by a fresh-context Explore agent surfaced one introduced bug:

  • M-3 spawn race: _scan_worker signaled spawn_event BEFORE assigning _scan_proc = proc under _scan_lock. A cancel arriving in the ~1-5 ms window between signal and assignment would read _scan_proc = None, return "no scan running", and never write the cancel flag — scan would run to completion uninterruptable.
  • FIXED v0.1.44 at host/rcjav-host.py:2186-2196. Reordered: _scan_proc = proc (under _scan_lock) now happens BEFORE spawn_event.set(). handle_scan still gets the spawn-ok signal; cancel handler now sees a live _scan_proc reference.

No other introduced bugs found. Phase 2 fix code passed scrutiny on:

  • Lock nesting (3 independent locks: _rpcLogLock, _hostAlertLock, _contextMenuLock, plus new _activityLogLock — no path holds two simultaneously)
  • Closure capture (each lock chain .then() captures its own entry/now/etc.)
  • Unhandled rejection paths (try/catch inside chains; one failure doesn't poison future calls)
  • Thread leaks (M-4 rate-limit check runs BEFORE thread spawn)
  • M-1 validator backward compat (v1 exports without source/target keys accepted via || [] consumer pattern)
  • M-5 popup counter (popup is short-lived; counter doesn't need cross-session persistence)
  • M-7 retry not infinite (single retry, then re-raises on persistent failure)
  • Manifest JSON validity (semver, no trailing commas)

Mirror checks resolved

Bug Mirror flagged Status
S-1 other RPC-sourced _meta.host_config data None exist beyond keep_ranking. Resolved (nothing to mirror).
M-1 profiles[] + partPatterns[] Both covered in same commit via ARRAY_ELEMENT_VALIDATORS. Resolved.
M-2 other Chrome APIs needing re-register per SW boot chrome.alarms persistent, chrome.commands manifest-declared. contextMenus is the outlier. Resolved.
M-3 none flagged n/a
M-4 extension-side postDiscordAlert parity Verified: extension-side already uses fetch(...).catch(...) fire-and-forget. Parity confirmed. Resolved.
M-5 other search entry points All 6 entry points (search-go, Enter, history chip, profile change, search-clear, pause-while-inflight) funnel through runCheck/runManualSearch. Covered. Resolved.
M-6 options.js settings save / options-library-issues.js / activity log / tabvault recordActivity had same race — FIXED v0.1.45 at background.js:613-635 with dedicated _activityLogLock. options.js settings save is user-triggered (single SAVE click), low race risk. options-library-issues.js only does set (no get-then-set). Tabvault out-of-scope (separate project). Resolved.
M-7 other os.replace callsites in rcjav/ Only save_cache and save_config use os.replace. Both now have retry. Resolved.
L-1 same as M-6 Covered via recordActivity mirror fix above. Resolved.

Residual risk

  1. Deferred Lights (5). Documented as cosmetic / UX polish. None block user workflows. Pass-through risk acceptable.
  2. M-3 timeout-path response shape change. Added startup_pending: true on Popen timeout. Backward-compatible — existing UI ignores unknown keys. If future UI work parses this field, behavior locked in.
  3. Phase 3 re-audit blind spot. Auditor instructed to focus on introduced bugs, not pre-existing. Pre-existing bugs in unmodified files (e.g. tabvault, rc-jav internals beyond cli.py) were not re-checked. Those remain in their respective audit-out-of-scope notes.
  4. Brave-specific divergence from Chrome contracts. Several REFUTED candidates noted that if Brave is observed diverging from documented Chrome behavior (SW lifecycle, connectNative keepalive), some refuted bugs could re-emerge as Brave-specific. Not currently verified; flagged in chunk-3 candidate notes.
  5. Manifest version chip semantics. Each fix bumped manifest per the project's reload-verification signal rule. Total 13 bumps (0.1.33 → 0.1.45 inclusive) covering: S-1, M-1, branding follow-up, M-2, M-3, M-2 follow-up (lock), M-4, M-5, M-5 follow-up (paused), M-6, L-1, M-3 follow-up (spawn race introduced + fixed in Phase 3), and M-6 mirror (recordActivity). M-7 had no bump (CLI repo only).

Final pass

  • Files modified during Phase 2 + 3:
    • D:\DEV\Extensions\Production\rclone-jav\background.js (M-2 + M-6 + L-1 + M-2 follow-up + M-6 mirror)
    • D:\DEV\Extensions\Production\rclone-jav\src\options\options.js (S-1 + M-1 + branding)
    • D:\DEV\Extensions\Production\rclone-jav\src\popup\popup.js (M-5 + M-5 follow-up)
    • D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py (M-3 + M-4 + M-3 fix-of-fix)
    • D:\DEV\Extensions\Production\rclone-jav\manifest.json (13 bumps: 0.1.33, 0.1.34, 0.1.35, 0.1.36, 0.1.37, 0.1.38, 0.1.39, 0.1.40, 0.1.41, 0.1.42, 0.1.43, 0.1.44, 0.1.45)
    • D:\DEV\Project\rclone-jav\rcjav\cli.py (M-7)
  • Independent re-audit by fresh Explore agent: 1 introduced bug found (M-3 spawn race) → fixed in v0.1.44. Final re-audit pass on the M-3 fix: trivial reorder of two adjacent blocks, no further issues.
  • All bugs-*.md files: zero entries with status open except deferred Lights (L-2 through L-6 — 5 entries; intentionally deferred per Phase 2 close decision).
  • Extension manifest.json version: 0.1.45 (was 0.1.32 at audit start).
  • Test instrumentation residue check: no simulated spawn fail / M-3 TEST / REMOVE markers remain in any source file.
  • JS syntax (node --check): background.js, options.js, popup.js, options/* all pass.
  • Python syntax (py_compile): rcjav-host.py, rcjav/cli.py pass.

Verification verdict

Phase 2 + 3 closed. All Severe + Moderate fixed and runtime-verified. 1 of 6 Lights fixed (L-1, same bug class as M-6). 1 introduced bug surfaced and fixed during Phase 3 re-audit. All mirror checks resolved or scoped out. 5 cosmetic Lights deferred.

Next polish session (out of audit scope): L-2 through L-6 if/when prioritized.