Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- **Protected-term restoration corrupted correct CJK prose.** Across ko/ja/zh-CN/zh-TW, common words were mapped as brand "wrong-forms" (클라우드→Claude, 인류→Anthropic, 企业→Enterprise, …), so `restoreProtectedTerms` rewrote correct translations into wrong English (e.g. "클라우드 컴퓨팅" → "Claude 컴퓨팅"). Removed the ambiguous common-word wrong-forms; intended brand restoration (클로드→Claude, etc.) still works. (#172)
- **AI tutor spinner could hang forever** when the Puter bridge wasn't ready — `chatStream` resolved to a discarded error string instead of throwing, so the caller never rendered the error+retry. It now rejects on bridge-not-ready. (#174)
- **Gemini verify could render a non-translation as the translation.** A short affirmation ("Okay", "OK입니다", "OK?") or whitespace reply fell through and was cached/shown in place of the correct translation (an empty reply blanked the element). Added a length guard so anything far shorter than the source keeps the Google translation. (#175, #176)
- **The AI-Tutor floating button rendered as a blank circle.** The host page's SVG sizing reset collapsed the chat-bubble icon to 0px wide (presentation attributes have specificity 0). Pinned an explicit icon size; the FAB now also lives in the shadow root (see Added), which makes this whole leak class impossible. (#182, #183)
- **The flashcards "Reset Progress" button rendered in Skilljar's blue.** `.si18n-history-clear` had no base rule, so the host's `button { background: #0164cc }` leaked through. Grouped it with the sibling header icon-button rules (transparent, brand-neutral). (#185)
- **Translated brand terms could render as "Claude(Claude)".** Google Translate appends an English gloss in parens for proper nouns; protected-term restoration then turned the transliteration back to English, duplicating it. Exact self-duplicates now collapse via a backreference (ASCII + fullwidth parens); legitimate parentheticals and code are untouched. (#187)
- **Tutor suggestion chips were misaligned with the greeting bubble** — the chip row sat flush to the messages gutter while the bubble is indented past the avatar. Indented the chips by the same 36px (logical property, RTL-safe). (#191)

### Added
- **Locale cross-contamination guard** (`scripts/check-locale-contamination.js`, `npm run check:locales`, wired into CI). Fails when any locale shares >8% of its long strings with another — the bug class the key/shape checks (`check-i18n`, `check-dict-coverage`) cannot see because they only verify structure, not language. Clean locales sit at ≤2.1%; the contaminated Italian file was 51%. (#166)
- **`skillbridge-academy-terms` companion Claude Code plugin** (`claude-plugin/`) re-exposing the curated Academy terminology dictionary for Claude Code / Cowork. Its data is generated from `src/data/*.json` and kept in sync by CI (`npm run check:plugin`). (#170)
- **Shadow-root style isolation for injected overlay UI.** The floating tutor button, the tutor sidebar, and the reading-aid TOC now live in an open shadow root (`#skillbridge-root`) the host page's stylesheet cannot reach — making the host-CSS-leak bug class (the FAB icon and reset-button bugs above) structurally impossible. `content.css` is fetched once, its ancestor theme selectors are rewritten to `:host(...)` form, and the result is adopted into the root; dark/locale state is mirrored onto the shadow host. Header controls (language selector, dark toggle) stay in the light DOM **by design** — they borrow Skilljar's own header classes to blend in. A new E2E suite injects hostile host CSS and proves it cannot reach the shadowed UI. (#188, #189, #190, #192)

### Changed
- **build-plugin generator** now reads `FLASHCARD_COURSE_MAP` via the same evaluation the sibling checkers use (was a fragile regex parse of the source); `--check` also detects orphan output files. (#171)
- **jest** no longer warns about a Haste name collision from `dist/` builds (`modulePathIgnorePatterns`). (#179)
- **Privacy policy** permission table realigned with the manifest (removed the stale `tabs` entry, disclosed `api.github.com`); language count corrected to 32. (#180)
- **README telemetry wording aligned with reality** — nothing is collected, not even opt-in error reports (the old line implied an opt-in error reporter exists; none is implemented). (#186)
- **`npm run capture:store` repoints at `@starter-series/shotkit`**, the extracted store-asset generator, after the in-repo harness copy was removed. (#192)

## [3.5.39] - 2026-06-01

Expand Down
9 changes: 9 additions & 0 deletions src/content/header-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@
const linksContainer = headerRight.querySelector(SKILLJAR_SELECTORS.headerLinks);
if (!linksContainer) return;

// Header controls are *blend-in* components and stay in the light DOM by
// design (decided during the 2026-06 shadow migration, #188–#192): this
// wrapper deliberately borrows Skilljar's own `headerheight align-vertical`
// classes so the selector sits exactly like a native header item. Shadow-
// isolating it would cut off those borrowed styles and force us to
// replicate the host header's metrics by hand — brittle against Skilljar
// header changes, for no benefit (no host-CSS leak ever observed here).
// Overlay components with their own visual identity (FAB, sidebar, TOC)
// are the ones that live in the #skillbridge-root shadow root.
const wrapper = document.createElement('div');
wrapper.id = 'si18n-header-lang';
wrapper.className = 'headerheight align-vertical';
Expand Down
Loading