From 799c98aa1f021316302689ec9380a6e179870224 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Fri, 2 Oct 2026 06:56:50 +0700 Subject: [PATCH 01/12] docs: add extension roadmap --- ROADMAP.md | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 ROADMAP.md diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 00000000..c453776d --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,217 @@ +# Roadmap + +This roadmap describes the planned direction for **Google Cloud Skills Boost Helper** after v1.3.3. + +It is intentionally organized by outcome rather than fixed dates. GitHub issues and pull requests remain the source of truth for implementation status, and priorities may change when Google Cloud Skills Boost changes its UI or Arcade program behavior. + +## Status legend + +- **Now** — reliability and compatibility work that should be addressed first. +- **Next** — the next product-level capabilities after the current baseline is stable. +- **Later** — planned improvements that depend on the earlier foundations. +- **Continuous** — quality work that applies to every release. + +--- + +## Now — Platform reliability and compatibility + +### 1. Keep core features working across Skills Boost UI changes + +Google Cloud Skills Boost regularly changes routes, markup, and page structure. The extension should become less dependent on one exact DOM layout. + +Planned work: + +- [ ] Repair and harden the Solution button against the current `skills.google` UI ([#139](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/issues/139)). +- [ ] Repair score detection when assessment markup changes ([#140](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/issues/140)). +- [ ] Add representative HTML/DOM fixtures for supported lab and assessment layouts. +- [ ] Prefer small page adapters/selectors with explicit fallbacks instead of scattered DOM queries. +- [ ] Add regression tests for old and current Skills Boost layouts where practical. +- [ ] Fail gracefully when a page layout is unknown instead of rendering broken controls. + +**Done when:** the extension can detect supported lab/assessment pages through tested adapters, and a Google markup change can usually be fixed in one isolated place. + +### 2. Improve Solution matching accuracy + +Known search failures include incorrect prefix matches and pages whose title, lab code, or route shape differs from the indexed solution title. + +Planned work: + +- [ ] Prefer an exact lab code match before fuzzy title matching ([#30](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/issues/30)). +- [ ] Normalize alternate lab URL formats and route aliases ([#63](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/issues/63)). +- [ ] Prevent partial-code collisions such as `ARC120` matching `ARC1206`. +- [ ] Add deterministic ranking rules: exact code → normalized title → fuzzy title → external fallback. +- [ ] Add regression fixtures for known mismatches before changing ranking logic. +- [ ] Keep Google/YouTube fallback available when no trusted solution match exists. + +**Done when:** known lab-code collisions are covered by tests and the matching result can explain why a solution was selected. + +### 3. UI consistency + +- [ ] Fix remaining browser/theme dark-mode inconsistencies ([#104](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/issues/104)). +- [ ] Verify popup/options/changelog surfaces in both light and dark browser themes. +- [ ] Keep new user-facing strings in all 13 shipped locales. +- [ ] Preserve keyboard focus, tooltips, and disabled states for interactive controls. + +--- + +## Next — Arcade season/session architecture + +The extension currently has a working Arcade v3 flow, including Facilitator and Bonus Milestone support. The next major foundation is making Arcade data explicitly period-aware. + +Tracked in [#215 — Support multi-season/session Arcade scoring across Hub, Web, and Extension](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/issues/215). + +### 1. Hub-owned period metadata + +The extension must not hardcode future Arcade seasons or session dates. + +- [ ] Load available periods and the current period from Hub metadata. +- [ ] Support a stable period identifier such as `2027-s1`, `2027-s2`, etc. +- [ ] Treat the Hub current period as the source of truth. +- [ ] Keep old periods queryable after a new session starts. + +### 2. Current vs pinned period + +- [ ] Add a **Current season** mode that follows the Hub automatically. +- [ ] Add a manual period selector for users who want to inspect an older session. +- [ ] Persist the selected mode and explicit period. +- [ ] Do not silently move users who deliberately pinned an older period. + +### 3. Period-aware API and cache + +- [ ] Add optional `period` to the Arcade API v3 request. +- [ ] Keep existing v3 requests valid when `period` is omitted. +- [ ] Ensure HMAC signing remains correct when the new field is present. +- [ ] Make local Arcade cache/snapshots period-aware. +- [ ] Prevent data from one period from overwriting or appearing as another period. + +### 4. Transition regression coverage + +Required scenarios: + +- [ ] Existing clients with no period still resolve the current period. +- [ ] Current mode follows a Hub transition such as `2027-s1 → 2027-s2`. +- [ ] A pinned `2027-s1` selection stays on `2027-s1`. +- [ ] Historical snapshots remain separate. +- [ ] Opening a future period does not require an extension release just to hardcode its label/date. + +**Done when:** the Hub can open a new Arcade session and current-mode extension users follow it without an extension update, while historical sessions remain selectable and isolated. + +--- + +## Next — Safer automatic score refresh + +Tracked in [#38 — Auto check score](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/issues/38). + +The goal is useful freshness without creating noisy requests or bypassing Hub cache/rate-limit behavior. + +Planned work: + +- [ ] Add an explicit opt-in/opt-out control for automatic score refresh. +- [ ] Refresh only known profiles and only when the relevant period is selected. +- [ ] Use cached data for passive refresh where possible. +- [ ] Reserve force refresh for explicit user actions. +- [ ] Apply backoff after API/network failures. +- [ ] Expose last-updated/stale state so users know whether displayed points are fresh. +- [ ] Keep refresh state isolated per profile and per Arcade period. +- [ ] Add tests preventing duplicate concurrent refreshes. + +**Done when:** users can enable automatic freshness without excessive API traffic, and the UI clearly distinguishes cached, refreshed, and failed states. + +--- + +## Later — Productivity and account UX + +### 1. Keyboard shortcuts + +Tracked in [#126 — Thêm tính năng: tự cài đặt phím tắt](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/issues/126). + +- [ ] Define a small set of useful extension commands. +- [ ] Prefer browser-native command APIs instead of custom global key listeners. +- [ ] Provide a discoverable shortcut settings/help entry. +- [ ] Avoid conflicts with Google Cloud Skills Boost and browser shortcuts. +- [ ] Localize shortcut descriptions where supported by the browser. + +Potential commands: + +- Open/toggle the helper popup. +- Refresh the active profile score. +- Open the current lab solution when a confident match exists. +- Toggle selected optional UI surfaces. + +### 2. Multi-account improvements + +- [ ] Show clearer snapshot freshness per profile. +- [ ] Make active-profile switching resilient to stale/missing profile data. +- [ ] Keep profile settings, Arcade period selection, and cached results correctly scoped. +- [ ] Add import/export only if it can be done without exposing sensitive account/session data. + +--- + +## Later — Search and learning workflow + +### 1. Broader content detection + +- [ ] Support quiz/assessment solution discovery where the source data is reliable ([#58](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/issues/58)). +- [ ] Normalize course-template, game, path, lab, and quiz route variants into one internal page model. +- [ ] Keep matching logic independent from the content-script rendering layer. + +### 2. Search confidence and transparency + +- [ ] Attach an internal confidence/reason to solution matches. +- [ ] Prefer hiding a weak automatic match over presenting a confidently wrong result. +- [ ] Show external search fallbacks when confidence is below the trusted threshold. +- [ ] Add regression cases whenever a false-positive solution is reported. + +--- + +## Continuous — Engineering, security, and releases + +These requirements apply to every roadmap phase. + +### Test and build quality + +- [ ] Keep `yarn compile` passing. +- [ ] Keep `yarn test:coverage` passing the project coverage gate. +- [ ] Keep production Chrome and Firefox builds passing. +- [ ] Add regression tests for every fixed scoring/search bug when practical. +- [ ] Keep business logic in `services/` or `utils/` instead of page-specific UI code. + +### Cross-browser support + +- [ ] Validate Chrome and Firefox behavior for every release. +- [ ] Keep Edge/Opera manual packages compatible where the Chromium build supports them. +- [ ] Avoid adding browser permissions unless a feature clearly requires them. + +### Security and privacy + +- [ ] Never log API secrets, request signatures, profile session data, or sensitive payloads. +- [ ] Treat build-time extension secrets as inspectable public-client material. +- [ ] Keep server-side validation, rate limiting, replay protection, and key rotation as the real enforcement boundary. +- [ ] Keep telemetry best-effort and non-blocking for score calculation. + +### Internationalization + +- [ ] Keep all user-facing features compatible with the 13 shipped locales. +- [ ] Avoid introducing hardcoded English UI copy. +- [ ] Include localization regression coverage for important score/Arcade actions. + +### Release discipline + +- [ ] Develop feature/fix PRs against `dev`. +- [ ] Keep release PRs focused and reviewable. +- [ ] Update changelog/release notes for user-visible behavior. +- [ ] Preserve backward compatibility for older extension/API clients when feasible. + +--- + +## Prioritization principles + +When deciding what moves first, use this order: + +1. **Broken core behavior** — score calculation, profile handling, Solution detection, extension startup. +2. **Data correctness** — Arcade totals, period/session isolation, cache correctness. +3. **Compatibility** — Skills Boost markup changes, API contract changes, cross-browser behavior. +4. **User clarity** — stale state, match confidence, loading/error states, accessible interaction. +5. **Convenience features** — shortcuts, workflow acceleration, optional visual enhancements. + +A feature should not ship if it makes score correctness, privacy, or core page compatibility harder to reason about. From ae7f05c389057d9b635ea86cb2e27d6d86c5887a Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Fri, 2 Oct 2026 06:57:00 +0700 Subject: [PATCH 02/12] docs: link roadmap from readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index a101efdc..e491b1ab 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ - [Introduction](#introduction) - [Key Features](#key-features) +- [Roadmap](#roadmap) - [Installation](#installation) - [Development](#development) - [Contributing](#contributing) @@ -49,6 +50,10 @@ Google Cloud Skills Boost Helper is a browser extension that enhances your exper **🌐 13 Languages Supported** — Interface localized for English, Vietnamese, Japanese, Korean, Chinese (Simplified), French, German, Spanish, Portuguese (BR), Italian, Russian, Arabic, and Hindi. +## Roadmap + +See [ROADMAP.md](ROADMAP.md) for the planned direction of the extension, including Skills Boost UI resilience, multi-season Arcade scoring, automatic score refresh, keyboard shortcuts, solution matching, and cross-browser quality work. + ## Installation Install from an official store where available: From 5fe5077d928421197c9721c1414e40be4c2010e8 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Fri, 2 Oct 2026 07:00:27 +0700 Subject: [PATCH 03/12] docs: add AI agent roadmap for Arcade Calculator --- ROADMAP.md | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) diff --git a/ROADMAP.md b/ROADMAP.md index c453776d..c0c6b3e2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -98,6 +98,214 @@ Required scenarios: --- +## Next — AI / Agent for Arcade Calculator + +AI and Agent features should be built **on top of the existing Arcade Calculator**, not replace its scoring logic. The Calculator remains the deterministic source of truth for points, milestone rules, and API-derived status; AI is responsible for explanation and planning, while Agent actions orchestrate existing extension capabilities with explicit user intent. + +### Current Arcade Calculator foundation + +The extension already exposes the structured data needed for a useful AI/Agent layer: + +- Signed Arcade API v3 requests using the normalized public profile URL/profile ID. +- Total Arcade points plus structured point fields such as Game, Trivia, Skill, Special, and Completion points when returned by the API. +- Facilitator metadata, including current badge counts, milestone requirements, Regular Arcade/base points, and Facilitator bonus values. +- Milestone progress displayed as both percentage and completed/required badge counts. +- API-provided Facilitator rules as the primary source of truth, with local rules used only as compatibility fallback. +- Bonus Milestone availability and self-reported completion state, kept separate from the standard Facilitator milestone bonus. +- Per-account Arcade snapshots, active-account switching, and `lastUpdated` freshness metadata. +- Extension badge display using the active account's calculated total. +- Existing localization infrastructure for all 13 shipped locales. + +There is **no AI scoring engine today**. Current totals and milestone progress are calculated from deterministic API/rule data. The roadmap must preserve that behavior. + +### 1. AI Arcade Insights + +Add an optional AI explanation layer that consumes the normalized Calculator result. + +Example questions: + +- **Why do I have this many Arcade points?** +- **What contributes to my current total?** +- **How far am I from the next Facilitator milestone?** +- **Which requirement is currently blocking the next milestone?** +- **What changed since my previous score refresh?** +- **Is this result stale or incomplete?** + +Planned work: + +- [ ] Define a typed, read-only `ArcadeInsightContext` derived from the Calculator result. +- [ ] Include current total, point breakdown, badge counts, active Facilitator rules, milestone progress, Bonus Milestone state, selected period, and freshness metadata. +- [ ] Generate natural-language explanations from those facts without recalculating the authoritative total in the model. +- [ ] Calculate exact "remaining to milestone" values in deterministic code before passing them to AI. +- [ ] Clearly distinguish **official/API data**, **self-reported Bonus Milestone state**, **local fallback rules**, and **AI explanation**. +- [ ] Warn when data is stale, incomplete, using fallback rules, or missing fields required for a confident answer. +- [ ] Support the same 13 locales as the rest of the extension. + +**Example:** + +```text +User: How far am I from the next Facilitator milestone? + +Calculator: +- Games: 7 / 8 +- Skill Badges: 31 / 34 +- Current milestone progress: 38 / 42 + +AI: +You need 1 more Game badge and 3 more Skill Badges to satisfy the next +milestone requirements. This explanation is based on the active rules returned +by the Arcade API. +``` + +The arithmetic in the example must come from deterministic Calculator helpers, not from free-form model math. + +### 2. Goal planner + +Allow users to choose a target such as a Facilitator milestone and receive a plan grounded in the Calculator state. + +- [ ] Select a target milestone from the active API rules. +- [ ] Show exact remaining Games / Skill Badges / other active requirements. +- [ ] Show the Regular Arcade/base points and Facilitator bonus associated with that milestone when provided by the API. +- [ ] Build a simple ordered checklist from unmet requirements. +- [ ] Re-plan automatically after a score refresh. +- [ ] Keep recommendations descriptive; do not claim that future rewards or points are guaranteed until the authoritative data confirms them. + +Potential UI: + +```text +AI Arcade Advisor + +Target: Milestone 3 + +Current +Games 8 / 10 +Skill Badges 41 / 50 + +Remaining +2 Games +9 Skill Badges + +[Explain my score] [Refresh & re-plan] +``` + +### 3. Agent actions + +The Agent layer may orchestrate existing extension functions, but it should not bypass their validation, permissions, or confirmation flows. + +Initial actions: + +- [ ] **Refresh my Arcade score** — invoke the existing Calculator fetch flow for the active profile. +- [ ] **Explain the refreshed result** — compare the previous and new snapshots, then summarize the change. +- [ ] **Switch profile and inspect score** — use existing multi-account state. +- [ ] **Switch Arcade period** — after multi-season/session support from #215 is available. +- [ ] **Open the relevant Arcade/Facilitator information page** when the user asks for the official source. +- [ ] **Open a matching lab/solution search** only when the user explicitly requests help finding relevant learning content. +- [ ] Reuse existing loading/error/rate-limit behavior instead of creating a second network path. + +Agent actions that modify state must be explicit. In particular: + +- Never auto-confirm or auto-claim the self-reported Bonus Milestone. +- Never change profile settings, selected period, or account state silently. +- Never repeatedly force-refresh in the background to chase a target score. +- Never present a locally predicted point total as an official Arcade result. + +### 4. Calculator tools for AI/Agent + +Expose a small internal tool layer instead of letting AI read or mutate popup DOM directly. + +Suggested read tools: + +```text +get_active_arcade_snapshot() +get_arcade_breakdown() +get_facilitator_progress() +get_next_milestone_gap() +get_arcade_data_freshness() +get_available_arcade_periods() +``` + +Suggested user-triggered actions: + +```text +refresh_arcade_score() +select_arcade_period(period_id) +switch_active_profile(profile_id) +open_arcade_source(resource) +``` + +Implementation principles: + +- [ ] Tool outputs use typed JSON, not rendered HTML. +- [ ] Deterministic services perform all point/milestone arithmetic. +- [ ] AI receives the resulting facts and explains them. +- [ ] Read operations can be low-friction; state-changing operations require clear user intent/confirmation. +- [ ] Every Agent action returns a structured success/error result that can be shown without guessing. +- [ ] Keep tools reusable by popup UI, future side panel, and other approved assistant surfaces. + +### 5. Privacy and security + +AI/Agent integration must not expand the data boundary silently. + +- [ ] Make AI features opt-in until the data flow is clearly documented. +- [ ] Send only the minimum normalized Calculator context required for the requested explanation. +- [ ] Do not send browser cookies, Skills Boost session tokens, HMAC signing values, extension secrets, or unrelated account data to an AI provider. +- [ ] Do not expose signed Arcade request headers or raw authentication material to the model. +- [ ] Make it clear when an explanation is produced by AI versus returned by the Arcade API. +- [ ] Preserve existing server validation, rate limiting, and replay protection for Agent-triggered refreshes. +- [ ] Provide a non-AI Calculator experience with no feature loss for users who keep AI disabled. + +### 6. Acceptance scenarios + +#### Scenario A — Explain current total + +```text +User asks: "Why is my score 118?" +=> Agent reads the current Calculator snapshot. +=> Deterministic breakdown is used as source data. +=> AI explains the returned components. +=> AI does not invent missing point categories. +``` + +#### Scenario B — Plan for the next milestone + +```text +User asks: "What do I still need for the next milestone?" +=> Calculator helper resolves the next milestone from active API rules. +=> Deterministic code calculates remaining requirements. +=> AI converts the result into a short actionable explanation. +``` + +#### Scenario C — Refresh and compare + +```text +User asks: "Refresh my score and tell me what changed." +=> Agent performs one user-requested refresh through the existing Arcade flow. +=> Previous and new snapshots are compared deterministically. +=> AI summarizes added/removed points, progress, and freshness. +``` + +#### Scenario D — Stale or incomplete data + +```text +Calculator snapshot is old or required fields are missing. +=> AI explicitly reports the limitation. +=> Agent offers a refresh action. +=> No estimated official score is fabricated. +``` + +#### Scenario E — Bonus Milestone + +```text +Bonus Milestone is available but not confirmed. +=> AI may explain what the control means. +=> Agent may open the existing confirmation UI when requested. +=> Agent never checks/confirms the self-reported completion box automatically. +``` + +**Done when:** a user can ask natural-language questions about their Arcade Calculator state, receive explanations fully grounded in deterministic Calculator data, and request safe Agent actions without creating a second scoring implementation. + +--- + ## Next — Safer automatic score refresh Tracked in [#38 — Auto check score](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/issues/38). From b845d8fc8b36168cc7087492baa67ce20587dc4f Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Fri, 2 Oct 2026 07:00:29 +0700 Subject: [PATCH 04/12] docs: mention AI agent direction in roadmap summary --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e491b1ab..7f5aba0e 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Google Cloud Skills Boost Helper is a browser extension that enhances your exper ## Roadmap -See [ROADMAP.md](ROADMAP.md) for the planned direction of the extension, including Skills Boost UI resilience, multi-season Arcade scoring, automatic score refresh, keyboard shortcuts, solution matching, and cross-browser quality work. +See [ROADMAP.md](ROADMAP.md) for the planned direction of the extension, including Skills Boost UI resilience, multi-season Arcade scoring, an AI/Agent layer grounded in the Arcade Calculator, automatic score refresh, keyboard shortcuts, solution matching, and cross-browser quality work. ## Installation From cafd5a27d7bcf2555d698746bf3d6d6b8d79b6ea Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Fri, 2 Oct 2026 07:13:25 +0700 Subject: [PATCH 05/12] docs: document current architecture and capabilities --- ARCHITECTURE.md | 761 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 761 insertions(+) create mode 100644 ARCHITECTURE.md diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000..0f279435 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,761 @@ +# Architecture & Current Capabilities + +This document is the canonical overview of the **current implemented state** of Google Cloud Skills Boost Helper. + +Use it to answer: + +- What does the extension do today? +- Which part of the code owns each feature? +- How does data move between Skills Boost pages, the popup, storage, and external services? +- Which rules are authoritative and which are compatibility fallbacks? +- Where should a new feature be implemented? + +For planned work, see [ROADMAP.md](ROADMAP.md). A roadmap item is **not** a current feature unless it is also documented here and implemented in source. + +--- + +## 1. Project overview + +Google Cloud Skills Boost Helper is a browser extension built with: + +- **WXT Framework** +- **React 19** +- **TypeScript** +- **Tailwind CSS** +- **WXT Storage** +- **Vitest + jsdom** +- **Firebase Remote Config** +- **Fuse.js** for solution matching +- **Axios** for HTTP requests + +Supported browser targets include Chrome and Firefox, with Chromium builds also used for manual Edge/Opera installation. + +The extension has four main runtime surfaces: + +1. **Content script** on supported Skills Boost pages. +2. **Popup** for Arcade data, profiles, milestones, settings, and related UI. +3. **Options page** for account/settings/data management. +4. **Background service worker** for lifecycle events, badge updates, and cross-tab messages. + +--- + +## 2. Current feature inventory + +### 2.1 Arcade Points Calculator + +**Primary owners** + +- `services/arcadeApiService.ts` +- `services/popupService.ts` +- `services/popupUIService.ts` +- `services/storageService.ts` +- `types/popup.ts` +- `utils/arcadeRequestSignature.ts` + +The Arcade Calculator is the central scoring feature. + +Current behavior: + +- Reads the active Skills Boost public profile URL. +- Canonicalizes supported legacy/current profile hosts. +- Extracts the public profile ID. +- Calls the configured **Arcade API v3** endpoint. +- Builds the v3 request payload before signing. +- Adds request-signature headers when the signing configuration is available. +- Preserves successful API data even if non-critical post-processing fails. +- Stores a `lastUpdated` timestamp with the snapshot. +- Renders total Arcade points in the popup. +- Stores Arcade data per active account. +- Updates the extension action badge with the active account total. +- Falls back to legacy single-account storage where required for backward compatibility. + +The normalized Arcade response can contain: + +- total Arcade points +- Game points +- Trivia points +- Skill points +- Special points +- Completion points +- badge history +- user/profile details +- Facilitator metadata +- freshness metadata + +### Source-of-truth rule + +The extension does **not** use an AI model to calculate Arcade points. + +Authoritative score data comes from the Arcade API response plus deterministic extension logic required to combine supported local/account state. Future AI/Agent features described in the roadmap must consume Calculator results instead of implementing a second scoring engine. + +--- + +### 2.2 Facilitator Program support + +**Primary owners** + +- `services/facilitatorService.ts` +- `services/arcadeApiService.ts` +- `services/popupUIService.ts` + +Current behavior: + +- Supports Facilitator badge counts and milestone progress. +- Reads milestone definitions returned by the API. +- Uses API-provided milestone metadata as the preferred source of truth. +- Keeps local milestone values only as a compatibility fallback for old/incomplete responses. +- Shows active requirement counts such as Games and Skill Badges. +- Hides requirements whose active rule is zero. +- Shows milestone progress as percentage plus completed/required counts. +- Shows Regular Arcade/base points for a milestone. +- Shows the Facilitator bonus separately. +- Calculates/normalizes standard Facilitator bonus values through deterministic helpers. + +Important invariant: + +> A new API ruleset must not be duplicated as a second hardcoded UI ruleset when the API already supplies the rule data. + +--- + +### 2.3 Bonus Milestone + +**Primary owners** + +- `components/BonusMilestoneControl.tsx` +- `services/bonusMilestoneService.ts` +- `entrypoints/popup/bonusMilestoneControl.tsx` + +Current behavior: + +- Shows the Bonus Milestone control when the active season/API state allows it. +- Uses a fixed self-reported **+10** claim flow in the current implementation. +- Opens a confirmation dialog before applying local self-reported completion. +- Links users to the official Bonus Milestone page. +- Requires explicit user confirmation. +- Keeps Bonus Milestone separate from the normal Facilitator milestone bonus. +- Avoids double counting when the API says the bonus is already included. +- Persists confirmation using a profile/period-scoped storage key. +- Supports undo. +- Ignores stale confirmation for periods where the bonus is unavailable. + +Important invariant: + +> Bonus Milestone completion is self-reported extension state unless explicitly verified by an authoritative upstream source. The extension must not describe local confirmation as Google verification. + +--- + +### 2.4 Multi-account management + +**Primary owners** + +- `services/accountService.ts` +- `services/storageService.ts` +- `services/popupService.ts` +- `entrypoints/options/` +- `types/popup.ts` + +Current behavior: + +- Stores multiple Skills Boost public profiles. +- Tracks one `activeAccountId`. +- Supports account names and optional nicknames. +- Keeps an Arcade snapshot on each account. +- Supports account switching from the popup. +- Supports account management from the options page. +- Stores whether an account participates in the Facilitator Program. +- Migrates legacy single-account data into the multi-account structure. +- Keeps compatibility reads for legacy storage when necessary. + +Primary storage namespace: + +```text +local:accountsData +``` + +Conceptual shape: + +```text +accountsData +├── activeAccountId +├── accounts +│ └── +│ ├── id +│ ├── name +│ ├── nickname +│ ├── profileUrl +│ ├── facilitatorProgram +│ ├── arcadeData +│ ├── createdAt +│ └── lastUsed +└── settings +``` + +--- + +### 2.5 Extension badge + +**Primary owners** + +- `services/storageService.ts` +- `entrypoints/background.ts` + +Current behavior: + +- Displays the active account's current calculated total on the extension action badge. +- Supports disabling badge display. +- Uses compact text for large values. +- Refreshes after account/data changes and browser startup. +- Uses background messaging first, with direct browser action APIs as fallback. + +--- + +### 2.6 Arcade / Facilitator countdown and dynamic config + +**Primary owner** + +- `services/firebaseService.ts` + +Firebase Remote Config currently supports runtime-configurable values such as: + +- Arcade countdown deadline +- Facilitator countdown deadline +- countdown enabled/disabled state +- Arcade milestone configuration + +Behavior: + +- Remote values can update without publishing a new extension version. +- Development can use local/default values. +- Production gracefully falls back to configured defaults if Firebase is unavailable. +- Fetches are memoized/throttled to avoid unnecessary Remote Config traffic. + +--- + +### 2.7 Leaderboard / scoreboard UI + +**Primary owners** + +- Popup HTML/UI services +- related popup rendering code + +Current behavior includes leaderboard/scoreboard surfaces in the popup and visibility controls used by the extension UI. + +This feature is presentation-oriented; Arcade point correctness remains owned by Calculator/services rather than leaderboard rendering. + +--- + +### 2.8 Lab Solution Search + +**Primary owners** + +- `entrypoints/content.ts` +- `services/labService.ts` +- `services/searchService.ts` +- `services/apiClient.ts` +- `components/uiComponents.ts` + +Supported content-script routes include: + +```text +/games/*/labs/* +/course_templates/*/labs/* +/focuses/* +/paths/*/course_templates/*/labs/* +/my_account/profile* +``` + +Main flow: + +```text +Skills Boost lab page + ↓ +content.ts + ↓ +LabService.isLabPage() + ↓ +SearchService extracts/normalizes current lab text + ↓ +ApiClient requests solution content + ↓ +SearchService ranks matches + ↓ +UIComponents renders the Solution action +``` + +Current behavior: + +- Detects supported lab pages. +- Extracts the lab title/query from the page. +- Queries the configured solutions API. +- Uses exact/normalized/fuzzy matching logic. +- Uses Fuse.js where fuzzy matching is appropriate. +- Renders an in-page Solution action. +- Provides Google/YouTube fallback search when needed. +- Supports configurable preferred search engine behavior. + +Known matching/layout edge cases are tracked in the roadmap/issues and should not be confused with fully solved behavior. + +--- + +### 2.9 Skills Boost profile helper + +**Primary owners** + +- `services/profileService.ts` +- `entrypoints/content.ts` + +On the Skills Boost profile page the extension initializes profile-related helper behavior, including public-profile setup assistance used by the rest of the extension. + +Supported profile hosts are canonicalized through `utils/profileUrl.ts`. + +Current canonical target: + +```text +www.skills.google +``` + +Legacy/current accepted hosts include: + +- `www.skills.google` +- `www.cloudskillsboost.google` +- `www.qwiklabs.com` + +--- + +### 2.10 Back to Top + +**Primary owner** + +- `services/backToTopService.ts` + +The content script initializes a Back to Top helper on supported pages. It is designed to work with Skills Boost pages that use dynamic/internal scroll containers rather than assuming only `window` scroll. + +--- + +### 2.11 Themes, custom Theme Studio, and compact popup + +**Primary owners** + +- `entrypoints/popup/main.tsx` +- `entrypoints/popup/index.html` +- `entrypoints/theme-studio/` +- `wxt.config.ts` + +Current UI capabilities include: + +- built-in popup themes +- custom theme palette +- Theme Studio +- live popup preview +- custom color controls +- compact popup mode +- early compact-mode bootstrap to reduce layout flash + +Popup compact mode hides selected non-essential sections before normal app startup when compact mode is active. + +--- + +### 2.12 Data export + +**Primary owners** + +- `services/exportService.ts` +- `services/optionsService.ts` +- `entrypoints/options/` + +Current export capabilities include: + +- Arcade data as **JSON** +- badge data as **CSV** + +Exports operate on the active account's stored/current data. + +--- + +### 2.13 Settings + +Account/global settings currently include or support concepts such as: + +- enable/disable Solution search +- enable/disable ePlus search action +- preferred search engine +- extension action badge visibility +- notification preference/state + +Settings are stored through the account/storage service layer rather than directly coupling every UI control to raw browser storage. + +--- + +### 2.14 Update / changelog flow + +**Primary owners** + +- `entrypoints/background.ts` +- `services/updateNotificationService.ts` +- changelog entrypoint/page + +Current behavior: + +- Opens the options page after first install. +- Can open the extension changelog after an update. +- Respects the update-notification preference. +- Refreshes the extension action badge on install/update/startup. +- Configures an uninstall feedback URL. + +--- + +### 2.15 Internationalization + +Locales live under: + +```text +public/_locales//messages.json +``` + +The extension currently ships 13 locales: + +- English +- Vietnamese +- Japanese +- Korean +- Simplified Chinese +- French +- German +- Spanish +- Portuguese (Brazil) +- Italian +- Russian +- Arabic +- Hindi + +Rule: + +> New user-facing extension text should use `browser.i18n.getMessage()` / existing localization helpers rather than introducing hardcoded English UI. + +--- + +## 3. Runtime architecture + +### 3.1 High-level view + +```text +┌───────────────────────────────────────────────────────────────┐ +│ Google Cloud Skills Boost │ +└─────────────────────────────┬─────────────────────────────────┘ + │ + content script injection + │ + ┌────────────▼────────────┐ + │ entrypoints/content.ts │ + └───────┬─────────┬──────┘ + │ │ + LabService ProfileService + │ + Search/API/UI components + +┌───────────────────────────────────────────────────────────────┐ +│ Extension Popup │ +│ │ +│ PopupService → Account/Storage → ArcadeApiService │ +│ │ │ │ +│ └────────────→ PopupUIService│ │ +│ ▼ │ +│ Arcade API v3 │ +└───────────────────────────────────────────────────────────────┘ + + Shared local extension storage + │ + ┌────────────▼────────────┐ + │ WXT/browser.storage │ + └────────────┬────────────┘ + │ + background service worker + │ + badge / lifecycle / cross-tab messages + + Firebase Remote Config + │ + countdown / dynamic config +``` + +--- + +## 4. Project structure + +### Core directories + +| Path | Responsibility | +| --- | --- | +| `entrypoints/` | WXT runtime entrypoints and extension pages | +| `services/` | Business/domain logic | +| `components/` | UI components and injected UI helpers | +| `utils/` | Pure/shared utilities | +| `types/` | Shared TypeScript contracts | +| `assets/` | CSS and static styling assets | +| `public/` | Public files and browser locale catalogs | +| `tests/` | Vitest regression/unit tests | +| `.github/` | CI/release/dependency automation | +| `.claude/` | Claude-specific development skills/instructions | + +### Important entrypoints + +| Path | Role | +| --- | --- | +| `entrypoints/background.ts` | service worker, lifecycle, badge/message handling | +| `entrypoints/content.ts` | Skills Boost page integration | +| `entrypoints/popup/` | main popup UI | +| `entrypoints/options/` | settings/account/data management | +| `entrypoints/theme-studio/` | custom popup-theme editor | +| changelog entrypoint | update/release information | + +### Important services + +| Service | Responsibility | +| --- | --- | +| `arcadeApiService.ts` | Arcade v3 request and Arcade/Facilitator metadata sync | +| `facilitatorService.ts` | Facilitator rules/progress/bonus helpers | +| `bonusMilestoneService.ts` | self-reported Bonus Milestone state | +| `accountService.ts` | account CRUD, switching, migration | +| `storageService.ts` | account-aware storage compatibility layer and badge refresh | +| `popupService.ts` | popup orchestration | +| `popupUIService.ts` | popup rendering/update logic | +| `searchService.ts` | lab solution matching | +| `labService.ts` | lab-page workflow | +| `apiClient.ts` | solution-content API client | +| `profileService.ts` | Skills Boost profile-page helpers | +| `firebaseService.ts` | Remote Config | +| `exportService.ts` | JSON/CSV export | +| `browserService.ts` | browser detection/compatibility helpers | +| `backToTopService.ts` | page scroll helper | +| `updateNotificationService.ts` | changelog/update notification preference | + +--- + +## 5. Main data flows + +### 5.1 Arcade refresh + +```text +User opens popup / presses refresh + ↓ +PopupService + ↓ +active Account + profile URL + ↓ +ArcadeApiService.fetchArcadeData() + ↓ +canonicalize profile URL + ↓ +build API v3 payload + ↓ +build signature headers + ↓ +Arcade API v3 + ↓ +validate successful response + ↓ +sync Facilitator rules from API + ↓ +StorageService.saveArcadeData() + ↓ +active account Arcade snapshot + ↓ +PopupUIService + BadgeService + ↓ +popup total / milestones / badges / extension action badge +``` + +Failure behavior: + +- request/invalid response → return no new snapshot +- cached data can remain available +- Facilitator metadata sync failure must not discard an otherwise successful Arcade response +- extension badge failure is non-fatal + +--- + +### 5.2 Bonus Milestone + +```text +Arcade snapshot + active account + ↓ +BonusMilestoneService + ↓ +check participating + enabled + available points + period + ↓ +read profile/period-scoped local confirmation + ↓ +BonusMilestoneControl + ↓ +explicit user confirmation + ↓ +persist local self-reported state + ↓ +next Arcade v3 request includes completion flag +``` + +--- + +### 5.3 Lab solution + +```text +Supported Skills Boost lab route + ↓ +content.ts + ↓ +LabService + ↓ +SearchService.extractQueryText() + ↓ +ApiClient + ↓ +SearchService ranking + ↓ +matched solution or fallback + ↓ +UIComponents injected into page +``` + +--- + +### 5.4 Account switching + +```text +User selects account + ↓ +AccountService changes activeAccountId + ↓ +Popup reloads account snapshot/profile + ↓ +Popup UI rerenders + ↓ +StorageService refreshes action badge +``` + +--- + +## 6. Storage model + +Primary modern storage: + +```text +local:accountsData +``` + +Other storage namespaces exist for compatibility and feature-specific state, including: + +- legacy Arcade/profile storage +- popup theme/custom theme state +- Bonus Milestone profile/period-scoped confirmation +- feature/settings values + +Rules: + +1. New account-specific data should normally live with or be keyed by the account/profile. +2. Period-specific Arcade state must also include period identity when multi-season support lands. +3. Do not silently overwrite historical period data with current-period data. +4. Backward compatibility should be handled in the service layer, not duplicated throughout UI code. + +--- + +## 7. External systems + +### Arcade API + +Used for current Arcade scoring and Facilitator metadata. + +The extension should treat API data as the preferred source for season/rule-specific score metadata. + +### Solutions API + +Used to retrieve candidate lab solution content for SearchService matching. + +### Firebase Remote Config + +Used for remotely adjustable countdown/config values. + +### Google Cloud Skills Boost pages + +The content script integrates with supported `skills.google` routes and therefore must be resilient to upstream DOM changes. + +--- + +## 8. Security and privacy boundaries + +Current architecture principles: + +- Do not log secrets/signature values. +- Do not treat extension-embedded build-time values as truly confidential. +- Keep server validation/rate limiting/replay protection on the trusted server side. +- Sanitize untrusted profile/display data before injecting HTML. +- Restrict browser permissions to what a feature actually requires. +- Notifications remain an optional permission. +- A failure to update the action badge, telemetry-like metadata, or secondary UI must not corrupt/block score data. + +### Future AI/Agent boundary + +AI/Agent is currently a **roadmap direction**, not a current scoring/runtime subsystem. + +When implemented: + +- Calculator remains authoritative for points. +- AI consumes normalized read-only Calculator facts. +- deterministic code performs score/milestone arithmetic. +- AI explains/plans from those facts. +- state-changing Agent actions require explicit user intent. +- cookies, session tokens, HMAC secrets/signatures, and unrelated account data must not be exposed to a model. + +See [ROADMAP.md](ROADMAP.md#next--ai--agent-for-arcade-calculator). + +--- + +## 9. Testing and release contract + +Before merging code changes: + +```bash +yarn compile +yarn test:coverage +yarn build +``` + +Also build Firefox for release validation when relevant: + +```bash +yarn build:firefox +``` + +Current test stack: + +- Vitest +- jsdom +- fake browser/WXT state +- service/util-focused regression tests +- coverage gate configured by the project + +Changes to scoring, Facilitator rules, Bonus Milestone, solution matching, storage migration, or request signing should include regression coverage. + +--- + +## 10. Documentation ownership + +Use these files for different purposes: + +| File | Purpose | +| --- | --- | +| `README.md` | public project introduction and installation | +| `ARCHITECTURE.md` | **current features, structure, ownership, and runtime flows** | +| `ROADMAP.md` | planned/future work | +| `CONTRIBUTING.md` | contribution workflow and PR requirements | +| `CLAUDE.md` | Claude Code-specific working instructions | +| `CHANGELOG.md` | released changes by version | + +When a feature becomes real: + +1. implement it, +2. test it, +3. update `ARCHITECTURE.md` if ownership/flow/current capabilities changed, +4. remove or mark completed roadmap wording as appropriate, +5. include it in release notes/changelog. + +This keeps **current state** and **future state** from drifting into the same document. From d55bf8be33ec2936c5a640a763f9f0eefc0025f6 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Fri, 2 Oct 2026 07:13:34 +0700 Subject: [PATCH 06/12] docs: link current architecture overview --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 7f5aba0e..d92903f3 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ - [Introduction](#introduction) - [Key Features](#key-features) +- [Architecture](#architecture) - [Roadmap](#roadmap) - [Installation](#installation) - [Development](#development) @@ -50,6 +51,10 @@ Google Cloud Skills Boost Helper is a browser extension that enhances your exper **🌐 13 Languages Supported** — Interface localized for English, Vietnamese, Japanese, Korean, Chinese (Simplified), French, German, Spanish, Portuguese (BR), Italian, Russian, Arabic, and Hindi. +## Architecture + +See [ARCHITECTURE.md](ARCHITECTURE.md) for the current implemented feature inventory, project structure, service ownership, storage model, and main runtime/data flows. + ## Roadmap See [ROADMAP.md](ROADMAP.md) for the planned direction of the extension, including Skills Boost UI resilience, multi-season Arcade scoring, an AI/Agent layer grounded in the Arcade Calculator, automatic score refresh, keyboard shortcuts, solution matching, and cross-browser quality work. From 3c42cc556b356fd1dd1bc51fa8b6500f3d533a37 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Fri, 2 Oct 2026 07:13:37 +0700 Subject: [PATCH 07/12] docs: point Claude guidance to canonical architecture --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 300bbcd1..de2a9456 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,6 @@ # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +> **Canonical project documentation:** read [ARCHITECTURE.md](ARCHITECTURE.md) for the current implemented features, ownership, structure, and data flows. Read [ROADMAP.md](ROADMAP.md) for future/planned work. This file contains Claude Code-specific working instructions and should not duplicate the full product architecture.\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Commands From 751e9506a60030e00c30a5609f79a9200a47ad08 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:13:45 +0000 Subject: [PATCH 08/12] style: format code with Prettier This commit fixes the style issues introduced in cafd5a2 according to the output from Prettier. Details: https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/pull/236 --- ARCHITECTURE.md | 88 ++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 0f279435..4b4a9d67 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -484,50 +484,50 @@ Rule: ### Core directories -| Path | Responsibility | -| --- | --- | -| `entrypoints/` | WXT runtime entrypoints and extension pages | -| `services/` | Business/domain logic | -| `components/` | UI components and injected UI helpers | -| `utils/` | Pure/shared utilities | -| `types/` | Shared TypeScript contracts | -| `assets/` | CSS and static styling assets | -| `public/` | Public files and browser locale catalogs | -| `tests/` | Vitest regression/unit tests | -| `.github/` | CI/release/dependency automation | -| `.claude/` | Claude-specific development skills/instructions | +| Path | Responsibility | +| -------------- | ----------------------------------------------- | +| `entrypoints/` | WXT runtime entrypoints and extension pages | +| `services/` | Business/domain logic | +| `components/` | UI components and injected UI helpers | +| `utils/` | Pure/shared utilities | +| `types/` | Shared TypeScript contracts | +| `assets/` | CSS and static styling assets | +| `public/` | Public files and browser locale catalogs | +| `tests/` | Vitest regression/unit tests | +| `.github/` | CI/release/dependency automation | +| `.claude/` | Claude-specific development skills/instructions | ### Important entrypoints -| Path | Role | -| --- | --- | +| Path | Role | +| --------------------------- | ------------------------------------------------- | | `entrypoints/background.ts` | service worker, lifecycle, badge/message handling | -| `entrypoints/content.ts` | Skills Boost page integration | -| `entrypoints/popup/` | main popup UI | -| `entrypoints/options/` | settings/account/data management | -| `entrypoints/theme-studio/` | custom popup-theme editor | -| changelog entrypoint | update/release information | +| `entrypoints/content.ts` | Skills Boost page integration | +| `entrypoints/popup/` | main popup UI | +| `entrypoints/options/` | settings/account/data management | +| `entrypoints/theme-studio/` | custom popup-theme editor | +| changelog entrypoint | update/release information | ### Important services -| Service | Responsibility | -| --- | --- | -| `arcadeApiService.ts` | Arcade v3 request and Arcade/Facilitator metadata sync | -| `facilitatorService.ts` | Facilitator rules/progress/bonus helpers | -| `bonusMilestoneService.ts` | self-reported Bonus Milestone state | -| `accountService.ts` | account CRUD, switching, migration | -| `storageService.ts` | account-aware storage compatibility layer and badge refresh | -| `popupService.ts` | popup orchestration | -| `popupUIService.ts` | popup rendering/update logic | -| `searchService.ts` | lab solution matching | -| `labService.ts` | lab-page workflow | -| `apiClient.ts` | solution-content API client | -| `profileService.ts` | Skills Boost profile-page helpers | -| `firebaseService.ts` | Remote Config | -| `exportService.ts` | JSON/CSV export | -| `browserService.ts` | browser detection/compatibility helpers | -| `backToTopService.ts` | page scroll helper | -| `updateNotificationService.ts` | changelog/update notification preference | +| Service | Responsibility | +| ------------------------------ | ----------------------------------------------------------- | +| `arcadeApiService.ts` | Arcade v3 request and Arcade/Facilitator metadata sync | +| `facilitatorService.ts` | Facilitator rules/progress/bonus helpers | +| `bonusMilestoneService.ts` | self-reported Bonus Milestone state | +| `accountService.ts` | account CRUD, switching, migration | +| `storageService.ts` | account-aware storage compatibility layer and badge refresh | +| `popupService.ts` | popup orchestration | +| `popupUIService.ts` | popup rendering/update logic | +| `searchService.ts` | lab solution matching | +| `labService.ts` | lab-page workflow | +| `apiClient.ts` | solution-content API client | +| `profileService.ts` | Skills Boost profile-page helpers | +| `firebaseService.ts` | Remote Config | +| `exportService.ts` | JSON/CSV export | +| `browserService.ts` | browser detection/compatibility helpers | +| `backToTopService.ts` | page scroll helper | +| `updateNotificationService.ts` | changelog/update notification preference | --- @@ -741,14 +741,14 @@ Changes to scoring, Facilitator rules, Bonus Milestone, solution matching, stora Use these files for different purposes: -| File | Purpose | -| --- | --- | -| `README.md` | public project introduction and installation | +| File | Purpose | +| ----------------- | ------------------------------------------------------------- | +| `README.md` | public project introduction and installation | | `ARCHITECTURE.md` | **current features, structure, ownership, and runtime flows** | -| `ROADMAP.md` | planned/future work | -| `CONTRIBUTING.md` | contribution workflow and PR requirements | -| `CLAUDE.md` | Claude Code-specific working instructions | -| `CHANGELOG.md` | released changes by version | +| `ROADMAP.md` | planned/future work | +| `CONTRIBUTING.md` | contribution workflow and PR requirements | +| `CLAUDE.md` | Claude Code-specific working instructions | +| `CHANGELOG.md` | released changes by version | When a feature becomes real: From 5085e57de39db27a46f75d14fed060a37cad5c59 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Fri, 2 Oct 2026 07:14:09 +0700 Subject: [PATCH 09/12] docs: add repository agent guidance --- AGENTS.md | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..b2845966 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,123 @@ +# AGENTS.md + +Instructions for coding agents working in this repository. + +## Read first + +Before making a non-trivial change, read: + +1. [ARCHITECTURE.md](ARCHITECTURE.md) — current implemented features, ownership, structure, storage, and runtime flows. +2. [ROADMAP.md](ROADMAP.md) — planned/future work. Do not treat roadmap items as already implemented. +3. [CONTRIBUTING.md](CONTRIBUTING.md) — branch, test, and PR requirements. +4. [CLAUDE.md](CLAUDE.md) only when Claude-specific workflow details are relevant. + +## Branch and PR rules + +- Target `dev`, not `main`, for normal feature/fix PRs. +- Keep one focused feature/fix per PR. +- Use Conventional Commits. +- Do not mix dependency churn or unrelated cleanup into a feature PR. + +## Required validation + +For code changes, run: + +```bash +yarn compile +yarn test:coverage +yarn build +``` + +Run the Firefox build when the change can affect browser compatibility or release packaging: + +```bash +yarn build:firefox +``` + +## Architecture boundaries + +- `entrypoints/` owns WXT/browser entrypoints and page bootstrapping. +- `services/` owns business/domain logic. +- `components/` owns reusable/injected UI. +- `utils/` owns pure/shared helpers. +- `types/` owns shared TypeScript contracts. +- UI code should not become a second implementation of business rules already owned by services/API metadata. + +## Arcade Calculator invariants + +The Arcade Calculator is deterministic and is the source of truth for score-related extension behavior. + +- Do not add a second scoring implementation in UI or AI code. +- Prefer API-provided Arcade/Facilitator metadata when available. +- Keep local Facilitator rules only as compatibility fallback. +- Do not double count Facilitator or Bonus Milestone points. +- A successful Arcade API response must not be discarded because optional UI/metadata synchronization fails. +- Cached/account data should remain usable when a non-critical badge/UI update fails. +- Future period/session state must be scoped so one period cannot overwrite another. + +## Bonus Milestone invariants + +- Current claim flow is self-reported extension state. +- Do not describe a local confirmation as Google verification. +- Do not auto-check, auto-confirm, or silently claim Bonus Milestone. +- Keep Bonus Milestone separate from the normal Facilitator milestone bonus. +- Respect profile/period scoping and API `bonusIncludedInTotal`-style protections against double counting. + +## AI / Agent invariants + +AI/Agent is a roadmap direction unless corresponding runtime code has actually landed. + +When implementing it: + +- Calculator/services perform all point and milestone arithmetic. +- AI consumes normalized Calculator facts and explains/plans from them. +- Never let a model invent an official score or missing point category. +- State-changing Agent actions require explicit user intent. +- Never send cookies, Skills Boost session tokens, HMAC secrets/signatures, or unrelated account data to a model/provider. +- Preserve a fully functional non-AI Calculator path. + +## Solution search invariants + +- Keep matching logic in services rather than DOM rendering code. +- Prefer exact/normalized identifiers before fuzzy title matching when available. +- Add a regression case for reported false-positive/false-negative matches. +- Preserve Google/YouTube fallback behavior when no trusted match exists. +- Treat upstream Skills Boost DOM as unstable and isolate selector/layout assumptions. + +## Storage and account rules + +- Use account-aware service APIs instead of raw storage from unrelated UI code. +- Preserve legacy reads/migrations only through compatibility layers. +- Scope account-specific data to the active/profile account. +- Scope period-specific data to a period identity when that feature is implemented. +- Do not silently migrate or overwrite unrelated historical data. + +## Security and privacy + +- Do not log API secrets, signature values, cookies, session data, or sensitive payloads. +- Treat extension-embedded build-time values as inspectable by users. +- Keep trusted enforcement (validation, rate limiting, replay protection) server-side. +- Sanitize untrusted strings/URLs before HTML injection. +- Avoid new browser permissions unless a feature clearly requires them. + +## Internationalization + +The extension ships 13 locales. + +- Do not introduce hardcoded user-facing English when an i18n key is appropriate. +- Use `browser.i18n.getMessage()` / existing localization helpers. +- New important user-facing flows should be represented in all shipped locale catalogs. + +## Documentation maintenance + +When a change modifies current capabilities, ownership, storage, or data flow: + +- update [ARCHITECTURE.md](ARCHITECTURE.md). + +When a planned item becomes implemented: + +- update [ROADMAP.md](ROADMAP.md) so future-state text does not contradict current state, +- update [ARCHITECTURE.md](ARCHITECTURE.md), +- include user-visible behavior in changelog/release notes. + +Do not document planned behavior as current behavior. From 2697a73f64eb7c0f95c88ed19105ff857b59083b Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Fri, 2 Oct 2026 07:14:17 +0700 Subject: [PATCH 10/12] docs: link agent guidance from architecture From 60265318f42344f2f82bf167c48b28c9a417403e Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Tue, 6 Oct 2026 08:19:52 +0700 Subject: [PATCH 11/12] release: v1.3.4 security hardening * chore: bump version to 1.3.4 * chore: route dependency updates through dev * security: pin CI actions to immutable SHAs * security: pin release actions to immutable SHAs * docs: add v1.3.4 release notes --- .github/dependabot.yml | 2 ++ .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- CHANGELOG.md | 16 ++++++++++++++++ package.json | 2 +- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5c772cc0..4eb633c4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,6 +2,7 @@ version: 2 updates: - package-ecosystem: "npm" directory: "/" + target-branch: "dev" schedule: interval: "weekly" day: "monday" @@ -14,6 +15,7 @@ updates: - package-ecosystem: "github-actions" directory: "/" + target-branch: "dev" schedule: interval: "weekly" day: "monday" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a0fe3fb1..17022e44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0 - name: Validate GitHub Actions workflows env: @@ -36,7 +36,7 @@ jobs: ./actionlint -shellcheck= -pyflakes= -color - name: Setup Node.js - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x cache: yarn diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e030bb1..5e032fdb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -70,7 +70,7 @@ jobs: fi - name: Checkout release tag - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.0 with: ref: ${{ env.RELEASE_TAG }} fetch-depth: 0 @@ -103,7 +103,7 @@ jobs: fi - name: Setup Node.js - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x diff --git a/CHANGELOG.md b/CHANGELOG.md index ae3d7344..df8a55fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.3.4] - 2026-10-06 + +### :lock: Security +- Update transitive `undici` to 7.30.0, including the upstream security fixes shipped in 7.29.1. +- Update transitive `brace-expansion` to 1.1.21. +- Pin `actions/checkout` and `actions/setup-node` to immutable v7.0.0 commit SHAs in CI and release workflows. + +### :wrench: Chores +- Refresh production dependency patches already validated on `main` (`dompurify` 3.4.16, `intro.js` 8.6.0, `marked` 18.0.14). +- Route Dependabot npm and GitHub Actions updates to `dev` so dependency/security changes follow the `dev → main` release flow. +- Bump extension version to 1.3.4. + +### :memo: Documentation +- Ship the architecture, agent guidance, and roadmap documentation prepared on `dev`. + ## [1.3.3] - 2026-09-14 ### :sparkles: New Features - [`6e34f7b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/6e34f7b034e5c682863d0e5ff12837988dfd3f9f) - add localized Bonus Milestone disclaimer *(commit by [@hoangsvit](https://github.com/hoangsvit))* @@ -1411,3 +1426,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [1.3.1]: https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/compare/1.3.0...1.3.1 [1.3.2]: https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/compare/1.3.1...1.3.2 [1.3.3]: https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/compare/1.3.2...1.3.3 +[1.3.4]: https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/compare/1.3.3...1.3.4 diff --git a/package.json b/package.json index 6cb184c2..9ef5ee50 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "google-cloud-skills-boost-helper", "description": "__MSG_extDescription__", "private": true, - "version": "1.3.3", + "version": "1.3.4", "author": "dev@eplus.dev", "license": "MIT", "homepage_url": "https://eplus.dev", From d41c7003b510b070d477a6c1bebbf597e098cf69 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Tue, 6 Oct 2026 01:20:57 +0000 Subject: [PATCH 12/12] style: format code with Prettier This commit fixes the style issues introduced in 6026531 according to the output from Prettier. Details: https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/pull/242 --- CHANGELOG.md | 160 +++++++++++++++++++++++++++------------------------ 1 file changed, 84 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df8a55fc..53d1af98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,105 +8,113 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.3.4] - 2026-10-06 ### :lock: Security + - Update transitive `undici` to 7.30.0, including the upstream security fixes shipped in 7.29.1. - Update transitive `brace-expansion` to 1.1.21. - Pin `actions/checkout` and `actions/setup-node` to immutable v7.0.0 commit SHAs in CI and release workflows. ### :wrench: Chores + - Refresh production dependency patches already validated on `main` (`dompurify` 3.4.16, `intro.js` 8.6.0, `marked` 18.0.14). - Route Dependabot npm and GitHub Actions updates to `dev` so dependency/security changes follow the `dev → main` release flow. - Bump extension version to 1.3.4. ### :memo: Documentation + - Ship the architecture, agent guidance, and roadmap documentation prepared on `dev`. ## [1.3.3] - 2026-09-14 + ### :sparkles: New Features -- [`6e34f7b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/6e34f7b034e5c682863d0e5ff12837988dfd3f9f) - add localized Bonus Milestone disclaimer *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`78063ab`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/78063abd8867eb1ac62660c59095a8110143d7a7) - show self-reported disclaimer in Bonus Milestone modal *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`83e2272`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/83e227236d5c182d77a93c4dccce6045ec94765a) - localize official Bonus Milestone link *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`6e209f4`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/6e209f4592d3884766f56d78a5ffa9c2fea7889c) - link official Bonus Milestone page *(commit by [@hoangsvit](https://github.com/hoangsvit))* + +- [`6e34f7b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/6e34f7b034e5c682863d0e5ff12837988dfd3f9f) - add localized Bonus Milestone disclaimer _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`78063ab`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/78063abd8867eb1ac62660c59095a8110143d7a7) - show self-reported disclaimer in Bonus Milestone modal _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`83e2272`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/83e227236d5c182d77a93c4dccce6045ec94765a) - localize official Bonus Milestone link _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`6e209f4`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/6e209f4592d3884766f56d78a5ffa9c2fea7889c) - link official Bonus Milestone page _(commit by [@hoangsvit](https://github.com/hoangsvit))_ ### :bug: Bug Fixes -- [`ce62481`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/ce62481596c0636da7fca7cb9137c9109088f2ad) - preserve successful Arcade v3 responses *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`a4bf101`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/a4bf1015eff6df7bd20fcdbb685ec0bdb3622b88) - rebase Bonus Milestone UX onto dev *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`f5fc978`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/f5fc9782733d2790169dd8c4d6e08332f35d8629) - address DeepSource bonus milestone findings *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`a716fa2`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/a716fa23c6e7f2eb7e57e9d379dde3bf7ae914c1) - document Bonus Milestone service helpers *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`4f7f215`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/4f7f21561f4f088f3efbd0860f78ce8c240f06fe) - document Bonus Milestone i18n helpers *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`290bfb4`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/290bfb4177dc4989d3f4bf67db22d393f2f1a6cf) - guard bonus milestone across periods *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`5a51194`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/5a51194eac80a974c0fb1209917ac12523268203) - submit bonus milestone confirmation to hub *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`fa8f344`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/fa8f344daecdaf946159668f34efa5493a2fcd5b) - restore Bonus Milestone toggle control *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`32bc96e`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/32bc96e4c902d0f5a844c78601e290a315e83d71) - preserve existing Bonus Milestone UI *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`639501f`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/639501fd9af210f778482ed3765f980a94f78539) - restore approved Bonus Milestone UX *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`7e7d70d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/7e7d70df657d79bab50cac18e5645c9b5d8a957f) - restore Bonus Milestone localization helper *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`f268059`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/f268059b9cbadd9504c901ec3daece22df8b5489) - bootstrap bonus milestone control in popup *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`176756d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/176756dc83cd85b387029adc0f2c5232e2967341) - satisfy popup bootstrap static analysis *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`b610a9e`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/b610a9e11f757e44b8d37153b6ae624118772d20) - show only self-reported bonus in claim chip *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`3fc7cea`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/3fc7cea61d568a2c23dca489bbee8d41b61038c9) - keep Bonus Milestone claim at +10 *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`550b906`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/550b90617a7b666f3c87293fc6368a40136b8070) - let undo override stale bonus confirmation *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`30d8d7c`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/30d8d7c59e788917aba6d25c0c4cf3fb7063c761) - correct Arabic Bonus Milestone tooltip *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`7734360`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/77343608661b428e19f844dda94425c86a6c5546) - show pointer cursor on Bonus Milestone claim *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`a347e41`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/a347e4100ed66fd68f5afdd38a813b0b6d88c6fc) - use extension tooltip for Bonus Milestone claim *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`33fe4f3`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/33fe4f32576d7b5752e84cc19e62eb08e8e309f1) - move Bonus Milestone tooltip below claim *(commit by [@hoangsvit](https://github.com/hoangsvit))* + +- [`ce62481`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/ce62481596c0636da7fca7cb9137c9109088f2ad) - preserve successful Arcade v3 responses _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`a4bf101`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/a4bf1015eff6df7bd20fcdbb685ec0bdb3622b88) - rebase Bonus Milestone UX onto dev _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`f5fc978`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/f5fc9782733d2790169dd8c4d6e08332f35d8629) - address DeepSource bonus milestone findings _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`a716fa2`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/a716fa23c6e7f2eb7e57e9d379dde3bf7ae914c1) - document Bonus Milestone service helpers _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`4f7f215`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/4f7f21561f4f088f3efbd0860f78ce8c240f06fe) - document Bonus Milestone i18n helpers _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`290bfb4`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/290bfb4177dc4989d3f4bf67db22d393f2f1a6cf) - guard bonus milestone across periods _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`5a51194`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/5a51194eac80a974c0fb1209917ac12523268203) - submit bonus milestone confirmation to hub _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`fa8f344`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/fa8f344daecdaf946159668f34efa5493a2fcd5b) - restore Bonus Milestone toggle control _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`32bc96e`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/32bc96e4c902d0f5a844c78601e290a315e83d71) - preserve existing Bonus Milestone UI _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`639501f`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/639501fd9af210f778482ed3765f980a94f78539) - restore approved Bonus Milestone UX _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`7e7d70d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/7e7d70df657d79bab50cac18e5645c9b5d8a957f) - restore Bonus Milestone localization helper _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`f268059`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/f268059b9cbadd9504c901ec3daece22df8b5489) - bootstrap bonus milestone control in popup _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`176756d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/176756dc83cd85b387029adc0f2c5232e2967341) - satisfy popup bootstrap static analysis _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`b610a9e`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/b610a9e11f757e44b8d37153b6ae624118772d20) - show only self-reported bonus in claim chip _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`3fc7cea`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/3fc7cea61d568a2c23dca489bbee8d41b61038c9) - keep Bonus Milestone claim at +10 _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`550b906`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/550b90617a7b666f3c87293fc6368a40136b8070) - let undo override stale bonus confirmation _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`30d8d7c`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/30d8d7c59e788917aba6d25c0c4cf3fb7063c761) - correct Arabic Bonus Milestone tooltip _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`7734360`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/77343608661b428e19f844dda94425c86a6c5546) - show pointer cursor on Bonus Milestone claim _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`a347e41`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/a347e4100ed66fd68f5afdd38a813b0b6d88c6fc) - use extension tooltip for Bonus Milestone claim _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`33fe4f3`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/33fe4f32576d7b5752e84cc19e62eb08e8e309f1) - move Bonus Milestone tooltip below claim _(commit by [@hoangsvit](https://github.com/hoangsvit))_ ### :recycle: Refactors -- [`dc8744f`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/dc8744fc0b3b3e0e9819d5aa8879d5212cb48e3e) - consolidate Bonus Milestone i18n copy *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`2e54d85`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/2e54d85e79f1d6541a50bd34616e01d85708d14a) - use unified Bonus Milestone i18n *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`4e03d30`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/4e03d302972813b7ef6360bbd99bdbf969c8287f) - test unified Bonus Milestone i18n *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`d09fcf1`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/d09fcf11b939675c6c05218c96836991369a9ffd) - remove duplicate Bonus Milestone i18n helper *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`58e7442`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/58e74420b0c78c74fe6c2e48f7512286862ba2bb) - isolate Bonus Milestone info panel *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`c5f807d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/c5f807d40a6f8ac9db5fc9a59fe026f4bde0f77e) - move Bonus Milestone copy to browser i18n *(commit by [@github-actions[bot]](https://github.com/apps/github-actions))* -- [`3b84f6f`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/3b84f6fa1e10a255e587c8afc6e7fa2faeff12f0) - use native browser i18n for Bonus Milestone *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`d8dd150`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/d8dd15005c5dfb065cd495f8fe84713628b62278) - remove duplicate Bonus Milestone i18n service *(commit by [@hoangsvit](https://github.com/hoangsvit))* + +- [`dc8744f`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/dc8744fc0b3b3e0e9819d5aa8879d5212cb48e3e) - consolidate Bonus Milestone i18n copy _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`2e54d85`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/2e54d85e79f1d6541a50bd34616e01d85708d14a) - use unified Bonus Milestone i18n _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`4e03d30`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/4e03d302972813b7ef6360bbd99bdbf969c8287f) - test unified Bonus Milestone i18n _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`d09fcf1`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/d09fcf11b939675c6c05218c96836991369a9ffd) - remove duplicate Bonus Milestone i18n helper _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`58e7442`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/58e74420b0c78c74fe6c2e48f7512286862ba2bb) - isolate Bonus Milestone info panel _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`c5f807d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/c5f807d40a6f8ac9db5fc9a59fe026f4bde0f77e) - move Bonus Milestone copy to browser i18n _(commit by [@github-actions[bot]](https://github.com/apps/github-actions))_ +- [`3b84f6f`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/3b84f6fa1e10a255e587c8afc6e7fa2faeff12f0) - use native browser i18n for Bonus Milestone _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`d8dd150`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/d8dd15005c5dfb065cd495f8fe84713628b62278) - remove duplicate Bonus Milestone i18n service _(commit by [@hoangsvit](https://github.com/hoangsvit))_ ### :white_check_mark: Tests -- [`781037b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/781037b3a77cabb2fafe4e225cf9e835674d3927) - cover bonus milestone period safety *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`acd91a2`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/acd91a28b289fb5b07fc604414abb2d1354ba474) - cover bonus milestone request payload *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`3b4deb1`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/3b4deb1ce3e3bbcb7b19c0c8999a0e68e6e2dadf) - relax bonus request payload assertion *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`c28d309`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/c28d309c010791abf36d5c0ef91016ec1dd32364) - document bonus milestone test helpers *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`3299c94`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/3299c94765807fb2a3dc59796a8ba43101e8d9a2) - avoid async mock warnings *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`9f9c583`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/9f9c5834461e1836f08c9af767fc487794b3ad2b) - keep Bonus Milestone toggle visible *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`e38a58b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/e38a58bc62e9c677b1a8e5bf499742b6202a972c) - avoid stale React root between toggle cases *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`2424a28`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/2424a28e14661df783a9a3efde4be702ec587f7b) - keep toggle regression coverage *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`47c490d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/47c490d9766a61c6eef867438e034f2ec6c44727) - document no-bonus toggle behavior *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`eb9bb6c`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/eb9bb6c317da623b5e0939302af6017291d7e4ac) - preserve existing Bonus Milestone design *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`4880bd2`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/4880bd2ae622522fd06eaa0fd6f8f0ef464a4487) - remove unintended toggle UI regression test *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`5e9d2fc`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/5e9d2fc441d4fbb9e9724231317f0afae1fdd740) - cover bonus milestone popup bootstrap *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`bebfdf6`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/bebfdf618cca3c7ec04faed3dd4db12f18a7db1c) - keep claim action visible before confirmation *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`9ef8391`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/9ef839106f9860fc70d639e10e1a8efdfb179589) - keep standard milestone bonus out of claim chip *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`12ea18b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/12ea18b41b2eb85d8d2ede4557e7d23339a98baf) - lock Bonus Milestone claim copy to +10 *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`54445e3`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/54445e342805d194e4e20d33735c6b323eb8bcb0) - cover bonus milestone undo precedence *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`6d9a1c4`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/6d9a1c466d33e5116793a7bf4e715a35b14d5fdc) - ensure undo removes self-reported bonus *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`b0d46b0`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/b0d46b0d7c29813022b42c85f8ee8858feed462c) - require self-reported disclaimer in Bonus Milestone modal *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`ed4c2ec`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/ed4c2ecc96462533180f2b3d82d40332a663e19f) - cover official Bonus Milestone link *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`465d543`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/465d543b495a8d6b60e1d8fb1de402f5ed7c088b) - use browser locale messages for Bonus Milestone UI *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`58f982c`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/58f982c6f5d6da78b1a2ec58dfd9532ddf857773) - require Bonus Milestone messages in every locale catalog *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`f2dd60d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/f2dd60d994ac4c6c661809771b0625b2f221f6c2) - require pointer cursor on claim action *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`e088a88`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/e088a8874238b3487ff109cddd41bdd9d103322d) - cover extension tooltip on Bonus Milestone claim *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`dc24935`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/dc24935eabb1bbe1e5a39eb5da2ee36e89c2d9a0) - keep Bonus Milestone tooltip below claim *(commit by [@hoangsvit](https://github.com/hoangsvit))* + +- [`781037b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/781037b3a77cabb2fafe4e225cf9e835674d3927) - cover bonus milestone period safety _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`acd91a2`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/acd91a28b289fb5b07fc604414abb2d1354ba474) - cover bonus milestone request payload _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`3b4deb1`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/3b4deb1ce3e3bbcb7b19c0c8999a0e68e6e2dadf) - relax bonus request payload assertion _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`c28d309`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/c28d309c010791abf36d5c0ef91016ec1dd32364) - document bonus milestone test helpers _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`3299c94`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/3299c94765807fb2a3dc59796a8ba43101e8d9a2) - avoid async mock warnings _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`9f9c583`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/9f9c5834461e1836f08c9af767fc487794b3ad2b) - keep Bonus Milestone toggle visible _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`e38a58b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/e38a58bc62e9c677b1a8e5bf499742b6202a972c) - avoid stale React root between toggle cases _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`2424a28`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/2424a28e14661df783a9a3efde4be702ec587f7b) - keep toggle regression coverage _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`47c490d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/47c490d9766a61c6eef867438e034f2ec6c44727) - document no-bonus toggle behavior _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`eb9bb6c`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/eb9bb6c317da623b5e0939302af6017291d7e4ac) - preserve existing Bonus Milestone design _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`4880bd2`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/4880bd2ae622522fd06eaa0fd6f8f0ef464a4487) - remove unintended toggle UI regression test _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`5e9d2fc`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/5e9d2fc441d4fbb9e9724231317f0afae1fdd740) - cover bonus milestone popup bootstrap _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`bebfdf6`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/bebfdf618cca3c7ec04faed3dd4db12f18a7db1c) - keep claim action visible before confirmation _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`9ef8391`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/9ef839106f9860fc70d639e10e1a8efdfb179589) - keep standard milestone bonus out of claim chip _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`12ea18b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/12ea18b41b2eb85d8d2ede4557e7d23339a98baf) - lock Bonus Milestone claim copy to +10 _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`54445e3`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/54445e342805d194e4e20d33735c6b323eb8bcb0) - cover bonus milestone undo precedence _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`6d9a1c4`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/6d9a1c466d33e5116793a7bf4e715a35b14d5fdc) - ensure undo removes self-reported bonus _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`b0d46b0`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/b0d46b0d7c29813022b42c85f8ee8858feed462c) - require self-reported disclaimer in Bonus Milestone modal _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`ed4c2ec`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/ed4c2ecc96462533180f2b3d82d40332a663e19f) - cover official Bonus Milestone link _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`465d543`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/465d543b495a8d6b60e1d8fb1de402f5ed7c088b) - use browser locale messages for Bonus Milestone UI _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`58f982c`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/58f982c6f5d6da78b1a2ec58dfd9532ddf857773) - require Bonus Milestone messages in every locale catalog _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`f2dd60d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/f2dd60d994ac4c6c661809771b0625b2f221f6c2) - require pointer cursor on claim action _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`e088a88`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/e088a8874238b3487ff109cddd41bdd9d103322d) - cover extension tooltip on Bonus Milestone claim _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`dc24935`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/dc24935eabb1bbe1e5a39eb5da2ee36e89c2d9a0) - keep Bonus Milestone tooltip below claim _(commit by [@hoangsvit](https://github.com/hoangsvit))_ ### :wrench: Chores -- [`920c49b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/920c49bee2ed80f9fd9871b5762f5f3df89ac915) - **deps**: bump the production-dependencies group with 3 updates *(commit by [@dependabot[bot]](https://github.com/apps/dependabot))* -- [`ac08f82`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/ac08f82d4ff54626e333b6d5530acb1f278ffd56) - **deps**: bump the production-dependencies group with 2 updates *(commit by [@dependabot[bot]](https://github.com/apps/dependabot))* -- [`d4411fe`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/d4411fedacb1e0659f44ce4add95783671ce3bd6) - **deps-dev**: bump vitest from 4.1.5 to 4.1.11 *(commit by [@dependabot[bot]](https://github.com/apps/dependabot))* -- [`21e1482`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/21e1482c775030a56eca35ad4315b2c70a6d4f9a) - remove unused Bonus Milestone copy overrides *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`4bfd0ea`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/4bfd0eab5e3598e8894f809f4cec3afb8c09221b) - remove accidental empty file *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`ce50e97`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/ce50e97ac8041bc115e2e6aeb91550fb5b86ea76) - no-op *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`cb1d140`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/cb1d14080ed4de00e0ce40d59510c5ac9957f61c) - remove accidental empty file *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`b124cdd`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/b124cdd75de6f83faa7f81e2f60bfe5f1c7f7f59) - keep localized official link copy *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`7dd642c`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/7dd642c22ae898c84007c1b20afbfe9402c3232a) - ensure no accidental file *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`f6d7e1f`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/f6d7e1feb03c42686b95d75b976a1b44b728a946) - remove accidental empty file *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`3206624`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/32066244cdf3fb0c230e48427d8b5836f5d74ca7) - no content change *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`0b1c3af`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/0b1c3afa238896bbf053c9e8c22bf13b8d58697b) - preserve current link copy *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`931c03a`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/931c03a79633919cde9d71a7e240aca8e0f86208) - retain localized Bonus Milestone link label *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`78b2de7`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/78b2de7b2332fd822d2c72acd2ad97fbe7b0c5cb) - **deps**: bump the production-dependencies group with 5 updates *(commit by [@dependabot[bot]](https://github.com/apps/dependabot))* -- [`8c81e40`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/8c81e40b49d27373bec4dbca5116d44bacce57af) - bump version to 1.3.3 *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`9484b2f`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/9484b2fb99b649e0843ac49d38c334022b70ee52) - add one-time Bonus Milestone i18n migration *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`2995b3d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/2995b3d2fc5e8c3d13ec48c91b0c01686b1d7278) - run one-time Bonus Milestone i18n migration *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`e09fdd1`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/e09fdd1376d6f6ccff6e42afa5101d94f1a8decd) - remove one-time i18n migration workflow *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`87178c5`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/87178c52bf2f94ab80465a1206290a5a62973b36) - remove one-time i18n migration script *(commit by [@hoangsvit](https://github.com/hoangsvit))* -- [`afaa946`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/afaa9467673c979c38d7d0c01af98fe21ab4c264) - remove accidental empty file *(commit by [@hoangsvit](https://github.com/hoangsvit))* +- [`920c49b`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/920c49bee2ed80f9fd9871b5762f5f3df89ac915) - **deps**: bump the production-dependencies group with 3 updates _(commit by [@dependabot[bot]](https://github.com/apps/dependabot))_ +- [`ac08f82`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/ac08f82d4ff54626e333b6d5530acb1f278ffd56) - **deps**: bump the production-dependencies group with 2 updates _(commit by [@dependabot[bot]](https://github.com/apps/dependabot))_ +- [`d4411fe`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/d4411fedacb1e0659f44ce4add95783671ce3bd6) - **deps-dev**: bump vitest from 4.1.5 to 4.1.11 _(commit by [@dependabot[bot]](https://github.com/apps/dependabot))_ +- [`21e1482`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/21e1482c775030a56eca35ad4315b2c70a6d4f9a) - remove unused Bonus Milestone copy overrides _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`4bfd0ea`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/4bfd0eab5e3598e8894f809f4cec3afb8c09221b) - remove accidental empty file _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`ce50e97`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/ce50e97ac8041bc115e2e6aeb91550fb5b86ea76) - no-op _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`cb1d140`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/cb1d14080ed4de00e0ce40d59510c5ac9957f61c) - remove accidental empty file _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`b124cdd`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/b124cdd75de6f83faa7f81e2f60bfe5f1c7f7f59) - keep localized official link copy _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`7dd642c`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/7dd642c22ae898c84007c1b20afbfe9402c3232a) - ensure no accidental file _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`f6d7e1f`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/f6d7e1feb03c42686b95d75b976a1b44b728a946) - remove accidental empty file _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`3206624`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/32066244cdf3fb0c230e48427d8b5836f5d74ca7) - no content change _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`0b1c3af`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/0b1c3afa238896bbf053c9e8c22bf13b8d58697b) - preserve current link copy _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`931c03a`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/931c03a79633919cde9d71a7e240aca8e0f86208) - retain localized Bonus Milestone link label _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`78b2de7`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/78b2de7b2332fd822d2c72acd2ad97fbe7b0c5cb) - **deps**: bump the production-dependencies group with 5 updates _(commit by [@dependabot[bot]](https://github.com/apps/dependabot))_ +- [`8c81e40`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/8c81e40b49d27373bec4dbca5116d44bacce57af) - bump version to 1.3.3 _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`9484b2f`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/9484b2fb99b649e0843ac49d38c334022b70ee52) - add one-time Bonus Milestone i18n migration _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`2995b3d`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/2995b3d2fc5e8c3d13ec48c91b0c01686b1d7278) - run one-time Bonus Milestone i18n migration _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`e09fdd1`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/e09fdd1376d6f6ccff6e42afa5101d94f1a8decd) - remove one-time i18n migration workflow _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`87178c5`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/87178c52bf2f94ab80465a1206290a5a62973b36) - remove one-time i18n migration script _(commit by [@hoangsvit](https://github.com/hoangsvit))_ +- [`afaa946`](https://github.com/ePlus-DEV/google-cloud-skills-boost-helper/commit/afaa9467673c979c38d7d0c01af98fe21ab4c264) - remove accidental empty file _(commit by [@hoangsvit](https://github.com/hoangsvit))_ ## [1.3.2] - 2026-08-11