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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- **`Star Check` CI workflow** (`.github/workflows/star-check.yml`) — runs on every PR and blocks merge if the author hasn't starred the repository. Auto-exempts maintainer (`@hoainho`), bots (Dependabot, gemini-code-assist, google-cla, github-actions, renovate), `tracked-plan`-labeled PRs (maintainer-driven milestone work), and `pre-star-rule`-labeled PRs (grandfathered pre-policy). Uses the public `GET /users/{login}/starred/{owner}/{repo}` API — no extra auth scope.
- **Detector registry foundation (M-B)** — pluggable `Detector<TIssue>` lifecycle interface (`id`, `category`, `budgetMs`, `confidence`, `prodCapable`, `init`, `onCommit`, `onIdle`, `drain`, `teardown`, `recover`). Per-detector try/catch isolation + staged-write transactionality + bounded LRU dedupe.
- **React version adapter** scaffolding for r17/r18/r19/r19.2 with version-aware fiber tag enums + `getDisplayName`. Handles `OffscreenComponent` / `LegacyHiddenComponent` / `IndeterminateComponent` landmines across React versions.
- **Settings storage** with zod schema validation, v0→v1 migration (from legacy `react_debugger_disabled_sites` array), and `chrome.storage.local` persistence under `react_debugger_settings_v1`.
- **Settings UI** — new panel tab with per-detector toggles + confidence badges + per-site override list.
- **Hero detector #1 — reconciler-keys**: detects `Math.random()` / `Date.now()` keys (emit on first commit) AND numeric-index keys with verified cross-commit reorder. Emits new `UNSTABLE_LIST_KEY` issue type. Confidence: high (defaults ON). Production-capable.
- **Registry `onIdle` driver** (`Registry.dispatchIdle`) — scheduled via `requestIdleCallback` after every commit, enables detectors to do deferred work off the hot path.

### Changed

- **Contributor claim policy hardened** — starring the repo is now a **hard precondition for merge**, enforced by CI (see Star Check workflow above). The previous "comment `I'll take this`" rule stays honor-system + reviewer-checked. See [CONTRIBUTING.md → How to claim](.github/CONTRIBUTING.md#-how-to-claim-an-issue-required-before-opening-a-pr).
- PR template "Claim confirmation" section updated to flag the star as CI-enforced.
- **Contributor claim policy hardened** — starring the repo is now a **hard precondition for merge**, enforced by CI. See [CONTRIBUTING.md → How to claim](.github/CONTRIBUTING.md#-how-to-claim-an-issue-required-before-opening-a-pr). The previous "comment `I'll take this`" rule stays honor-system + reviewer-checked.
- PR template adds a "Claim confirmation" section with checkboxes for the two required steps. Maintainer / tracked-plan PRs can delete this section.
- **closure-leak detector** migrated to registry pattern via Strategy A (thin adapter through `window.__REACT_DEBUGGER_CLOSURE_BRIDGE__`). Legacy `_installClosureTracking` body unchanged; existing behavior preserved end-to-end. Confidence: medium (defaults OFF).
- **scan-overlay detector** migrated to registry pattern. **`getBoundingClientRect()` moved from synchronous `onCommit` to deferred `onIdle`** — the biggest live perf-budget violation flagged by the M-A audit is now closed. Confidence: high (defaults ON). Behavior preserved with a one-idle-callback-tick delay.

### Fixed

- Periodic cleanup now drains the detector registry's per-detector buffers every 60s, preventing unbounded buffer growth if users opt in to medium/low-confidence detectors.

### Migration

- 4 PRs that were already open when this policy landed (#17, #36, #37, #38) labeled `pre-star-rule` and grandfathered through the check.
- First run after upgrade: existing per-site disabled list (`react_debugger_disabled_sites`) is migrated to the new `Settings.perSite` shape. Migration is idempotent; legacy key is removed after successful migration.
- Default-policy applied on first install: high-confidence detectors (reconciler-keys, scan-overlay) default ON; medium/low (closure-leak) default OFF.
- 4 PRs that were already open when the Star Check policy landed (#17, #36, #37, #38) labeled `pre-star-rule` and grandfathered through the check.

## [2.0.3] - 2026-02-28

Expand Down
183 changes: 183 additions & 0 deletions M_B_SMOKE_TEST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# M-B Manual Smoke-Test Plan

Tester runbook for someone with real Chrome + devtools extension loaded.
Extension must be built (`npm run build`) and loaded as an unpacked extension.

---

## Prerequisites

1. `npm run build` — exits 0.
2. Open `chrome://extensions`, enable **Developer mode**, load unpacked from `dist/`.
3. Open a test page running React (e.g. `http://localhost:3000` with any CRA/Vite app, or [react.dev](https://react.dev)).
4. Open Chrome DevTools → find the **React Debugger** panel tab.

---

## TC-01: Extension loads without errors

**Steps:**
1. Open a React page.
2. Open DevTools Console.
3. Check for errors from `react-debugger` or `chrome-extension://`.

**Expected:** No errors. Panel shows "React Debugger" tab.

---

## TC-02: Settings panel — detector toggles visible

**Steps:**
1. Click **Settings** tab in the React Debugger panel.
2. Observe detector list.

**Expected:**
- `reconciler-keys` listed — confidence badge `high` — toggle ON by default.
- `scan-overlay` listed — confidence badge `high` — toggle ON by default.
- `closure-leak` listed — confidence badge `medium` — toggle OFF by default.

---

## TC-03: Settings panel — toggle closure-leak ON

**Steps:**
1. In Settings, toggle `closure-leak` to ON.
2. Interact with the page (click buttons, navigate between views).
3. Wait 60 seconds.

**Expected:**
- No browser tab memory growth visible in Task Manager (drain prevents buffer from growing).
- No JS errors in Console.

---

## TC-04: Reconciler-keys detector — Math.random() key

**Steps:**
1. Load or create a React component that renders a list with `key={Math.random()}`.
Example: `items.map(item => <div key={Math.random()}>{item}</div>)`
2. Trigger a re-render.
3. Check the React Debugger **Issues** tab.

**Expected:**
- Issue of type `UNSTABLE_LIST_KEY` appears within ~1s of the commit.
- Issue description mentions "Math.random" or "unstable key".

---

## TC-05: Reconciler-keys detector — Date.now() key

**Steps:**
1. Render a list with `key={Date.now()}`.
2. Trigger a re-render.

**Expected:** Same as TC-04 — `UNSTABLE_LIST_KEY` issue appears.

---

## TC-06: Reconciler-keys detector — numeric index reorder

**Steps:**
1. Render a list with index keys: `items.map((item, i) => <div key={i}>{item}</div>)`.
2. Trigger a reorder of items (reverse the array, for example).
3. Check Issues tab.

**Expected:** `UNSTABLE_LIST_KEY` issue appears flagging numeric-index reorder.

---

## TC-07: Scan-overlay detector — bounding rect off commit path

**Steps:**
1. Enable Performance profiling in DevTools → record a few seconds of React activity.
2. Stop recording.
3. Inspect the flame chart for `onCommitFiberRoot`.

**Expected:**
- `getBoundingClientRect` calls do NOT appear inside `onCommitFiberRoot` stack frames.
- They appear inside idle callback frames (separate from the commit stack).
- No long tasks (>50ms) attributed to the extension commit handler.

---

## TC-08: Settings migration — legacy disabled sites preserved

**Steps:**
1. Before loading the extension, manually set chrome.storage.local:
```js
chrome.storage.local.set({ react_debugger_disabled_sites: ['example.com', 'foo.com'] })
```
2. Load the extension.
3. Go to Settings → per-site overrides.

**Expected:**
- `example.com` and `foo.com` appear in the per-site disabled list.
- No `react_debugger_disabled_sites` key remains in storage after migration
(verify: `chrome.storage.local.get(null, console.log)` in background console).
- New key `react_debugger_settings_v1` is present.

---

## TC-09: Settings migration is idempotent

**Steps:**
1. Reload the extension (disable + re-enable in chrome://extensions).
2. Check storage again.

**Expected:** Migration does not duplicate entries. Storage state identical to post-TC-08.

---

## TC-10: Per-site override — disable on current site

**Steps:**
1. Open React Debugger panel on `localhost:3000`.
2. In Settings, add `localhost` to per-site disabled list (or click the "Disable on this site" button if present).
3. Reload the page.

**Expected:**
- Panel shows debugger is disabled for this site.
- No issues emitted.
- Other sites remain unaffected.

---

## TC-11: Closure-leak detector — no false positives on clean closures

**Steps:**
1. Enable `closure-leak` in Settings.
2. Visit a React page with normal event handlers (onClick, useEffect cleanup, etc.).
3. Interact normally for 30 seconds.
4. Check Issues tab.

**Expected:** No closure-leak issues for normal, properly-cleaned-up closures.

---

## TC-12: drainAll periodic cleanup — no memory growth

**Steps:**
1. Enable ALL detectors in Settings.
2. Open Chrome Task Manager (Shift+Esc).
3. Note the extension's memory footprint.
4. Interact with the React app for 5 minutes (navigation, clicks, etc.).
5. Check memory every 60 seconds.

**Expected:** Extension memory stays stable (±5MB). Does not grow linearly over time.

---

## Sign-off checklist

- [ ] TC-01 passed
- [ ] TC-02 passed
- [ ] TC-03 passed (no errors, no memory growth)
- [ ] TC-04 passed (UNSTABLE_LIST_KEY emitted for Math.random)
- [ ] TC-05 passed (UNSTABLE_LIST_KEY emitted for Date.now)
- [ ] TC-06 passed (UNSTABLE_LIST_KEY emitted for index reorder)
- [ ] TC-07 passed (getBoundingClientRect off commit path)
- [ ] TC-08 passed (migration from legacy format)
- [ ] TC-09 passed (migration idempotent)
- [ ] TC-10 passed (per-site disable works)
- [ ] TC-11 passed (no false positives)
- [ ] TC-12 passed (no memory growth)
13 changes: 9 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 15 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,19 @@
"url": "https://github.com/sponsors/hoainho"
},
"scripts": {
"dev": "vite build --watch --mode development",
"build": "vite build --mode production",
"build:dev": "vite build --mode development",
"clean": "rm -rf dist",
"package": "npm run build && cd dist && zip -r ../react-debugger.zip .",
"test": "vitest",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"fixture:basic:dev": "npm --prefix test/fixtures/basic run dev",
"typecheck": "tsc --noEmit",
"typecheck:node": "tsc -p tsconfig.node.json --noEmit",
"bench": "vitest bench --run"
},
"dev": "vite build --watch --mode development",
"build": "vite build --mode production",
"build:dev": "vite build --mode development",
"clean": "rm -rf dist",
"package": "npm run build && cd dist && zip -r ../react-debugger.zip .",
"test": "vitest",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"fixture:basic:dev": "npm --prefix test/fixtures/basic run dev",
"typecheck": "tsc --noEmit",
"typecheck:node": "tsc -p tsconfig.node.json --noEmit",
"bench": "vitest bench --run"
},
"devDependencies": {
"@resvg/resvg-js": "^2.6.2",
"@testing-library/jest-dom": "^6.9.1",
Expand All @@ -62,6 +62,7 @@
"dependencies": {
"opencode-antigravity-auth": "^1.4.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"zod": "^4.4.3"
}
}
Loading
Loading