Skip to content

fix: v3.5.6 production hotfixes — 6 audit-surfaced bugs + drop tabs permission#92

Merged
heznpc merged 1 commit intomainfrom
fix/v3.5.6-hotfix
Apr 26, 2026
Merged

fix: v3.5.6 production hotfixes — 6 audit-surfaced bugs + drop tabs permission#92
heznpc merged 1 commit intomainfrom
fix/v3.5.6-hotfix

Conversation

@heznpc
Copy link
Copy Markdown
Owner

@heznpc heznpc commented Apr 26, 2026

Summary

Deep production-readiness audit (delegated + four direct re-reads to verify) surfaced six bugs that get worse as user count grows. Two are user-visible now; the rest amplify with traffic. Plus one preventative permission cleanup.

# Severity What broke Impact
1 CRITICAL Bridge timeout silently resolves with isReady=false (translator.js:683) Tutor + Gemini block-translation fail invisibly until reload
2 CRITICAL history.pushState wrapper stacks across extension reloads (content.js:1259) After auto-update, every SPA nav doubles onRouteChange → 2× GT load
3 HIGH Cache-cleanup alarm sends type:, content.js switches on action: (background.js:145) 24h cleanup alarm dead in long-pinned tabs (page-load fallback masked it)
4 HIGH GT rate-limit returns original English text (background.js:298) On large lessons (>120 strings/min) users get half-translated pages
5 HIGH processGTQueue early-returns skip cleanup (content.js:805) Progress bar + verify spinners stuck on screen after language switch
6 MEDIUM pruneOldHistory doesn't retry failed add() (sidebar-chat.js:527) Chat conversation silently dropped on QuotaExceededError
7 CHORE tabs permission unused (manifest.json:11) CWS shows "read browsing history" warning in install prompt

Notable design choices

Verification (local)

  • Tests: 309/309 pass across 12 suites
  • npm run lint / format:check / check:selectors / check:dicts / check:sync / glossary / validate — all green
  • npm run build:firefox / build:bundle — both pass; bundle 198.8 KB → 113.9 KB (43% reduction)
  • Manifest lint clean after tabs removal; both chrome.tabs.query and chrome.tabs.sendMessage confirmed to work via host_permissions alone (Chrome docs + popup.js code path)

Test plan

  • CI: validate + build + test all pass
  • Manual on a Skilljar course page: confirm the bridge banner shows when Puter.js is throttled (block the script in DevTools to simulate)
  • Manual: change language mid-translation, confirm the progress bar disappears
  • Manual: install the dev build and confirm the CWS install prompt no longer mentions "read browsing history"

🤖 Generated with Claude Code

A deep production-readiness audit (and four direct re-reads to verify) found
six bugs that get worse at scale. Two are user-visible right now; the rest
amplify with traffic.

1. Bridge timeout silent fail (CRITICAL)
   `_injectPageBridge` resolved the readiness promise even on timeout, with
   `isReady` left false. Every later `_sendRequest` rejected "Bridge not
   ready" forever — tutor and Gemini block translation died until reload, no
   UI signal. Now flips a `bridgeFailed` flag and dispatches
   `skillbridge:bridgeunavailable`; content.js renders a persistent banner
   asking the user to refresh.

2. pushState/replaceState wrapper stacking (CRITICAL)
   The history monkey-patches had no idempotency guard, so an extension
   reload (auto-update, dev refresh) captured the previous wrapper as the
   "original" and stacked. Each reload doubled `onRouteChange` per nav,
   amplifying GT load. Guard with `__sb_wrapped__`.

3. Cache-cleanup alarm dead code (HIGH)
   Background sent `{ type: 'CACHE_CLEANUP' }` but the content-script
   handler keys on `request.action`. The 24h alarm reached the default
   "Unknown action" branch and silently no-op'd in long-pinned tabs. The
   page-load fallback still ran, so the bug was hidden — but the alarm
   itself is now unified on `{ action: 'cacheCleanup' }` with a real case.

4. GT rate-limit dropped translations (HIGH)
   `googleTranslateBatch` returned the original English text on rate-limit,
   which content.js silently skipped because `translated === source` looks
   like a no-op. On large lessons over 120 strings/min users got a
   half-translated page. Replaced with a polling `_rateLimiter.acquire()`
   that paces the batch instead. Failed items now return `null` for
   consistent skip-and-retry semantics.

5. Progress UI stuck on language switch (HIGH)
   Mid-batch `gtGeneration` mismatches early-returned past
   `hideTranslationProgress` and `pruneDetachedEntries`, leaving the
   progress bar and verify spinners on screen. Wrapped the loop in
   try/finally so cleanup always runs. Term-preview only fires when the
   generation is still current.

6. Chat history quota silently dropped messages (MEDIUM)
   `pruneOldHistory` deleted the oldest 20 entries on `QuotaExceededError`
   but never retried the failed `add()`, losing the conversation. Now
   `saveConversation` retries once after pruning, and `pruneOldHistory`
   resolves on `tx.oncomplete` so the retry sees the freed space.

Plus one preventative cleanup:
- Drop the `tabs` permission from manifest. Both `chrome.tabs.query` and
  `chrome.tabs.sendMessage` work via `host_permissions` matching the active
  tab. The broader `tabs` permission was unused and triggered the "read
  your browsing history" string in the CWS install prompt.

Version 3.5.5 → 3.5.6. Tests 309/309 pass; lint, format, selector health,
dicts, bg-sync, glossary, translate validate, firefox build, bundle build
all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@heznpc heznpc merged commit 3ca94d1 into main Apr 26, 2026
3 checks passed
@heznpc heznpc deleted the fix/v3.5.6-hotfix branch April 26, 2026 13:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant