feat(roadmap): M-A foundation — ghost-type purge, leaky-Set fix, perf-budget gate, lifecycle module (recovery of #39)#50
Conversation
…-budget gate, lifecycle module Recovered from closed PR #39. The original M-A branch had an identity-rewrite force-push yesterday that orphaned the branch ancestry from main (zero common commits). GitHub auto-closed PR #39 because of the divergent ancestry. This commit recovers the content as a single squash applied onto current main, preserving all post-M-A merges (PR #40 editor onboarding, PR #47 claim rule, PR #48 star check). The work below is identical to what was committed across the 5 M-A tasks (T1-T5). Atomic-task SHAs preserved in the harness at .opencode/plans/2026-05-31-self-roadmap-m-a.md as historical reference. M-A T1: refactor(types) — delete 5 ghost IssueType enum values (UNNECESSARY_RERENDER, DEV_MODE_IN_PROD, DIRECT_STATE_MUTATION, DUPLICATE_KEY, EXTRA_DEP). Fan-out across 9 files chasing string refs in panel components + tabs + tests. Also adds SEARCH_REDUX to MessageType union (yesterday's CI fix folded in). M-A T2: fix(inject) — bound 3 leaky Sets (reportedEffectIssues, reportedExcessiveRerenders, reportedSlowRenders) via TTL Maps in periodicCleanup. Was Set<string>, now Map<string, number> with 5-min TTL eviction. M-A T3: ci(typecheck) — add typecheck + typecheck:node + bench npm scripts. CI workflow now runs typecheck (fail-fast, no continue-on-error) BEFORE build. Pre-existing tsc errors fixed (SEARCH_REDUX added to MessageType, dead navigationStartTime + NAVIGATION_GRACE_MS declarations removed). tsconfig.node.json tightened to match root strict mode. Closes #27. M-A T4: test(bench) — vitest-bench harness skeleton: - test/bench/detectors.bench.ts (1365-node synthetic tree walk at ~575K hz, no-op detector benchmark) - test/fixtures/bench-tree/SimpleList.tsx (100-element list fixture) - bench/baselines/.gitkeep + bench/results/.gitkeep M-A T5: refactor(inject) — extract cleanup-interval lifecycle helpers into src/inject/lifecycle.ts (89 LoC). First leaf module exiting the 3270-LoC IIFE god-file. Zero behavior change (controller pre-flight verified the existing code was already lazy-install). Plus: .gitignore fix — was 'node_modules*.tsbuildinfo' smushed on one line, now correctly two lines. Verification: - tsc --noEmit: ZERO errors - build: exit 0 - test:run: 29 pre-existing emoji failures + 141 passes - bench: exit 0 Part of self-roadmap H2 2026 milestone M-A.
There was a problem hiding this comment.
Code Review
This pull request refactors the React Debugger extension by removing several unused issue types (such as DIRECT_STATE_MUTATION, DUPLICATE_KEY, EXTRA_DEP, UNNECESSARY_RERENDER, and DEV_MODE_IN_PROD) across the codebase, tests, and UI panels. It introduces a new lifecycle.ts module to manage cleanup intervals, converts reported issue tracking from Set to Map to support TTL-based pruning, and adds a synthetic benchmark baseline. Feedback suggests correcting the tree depth in the benchmark to match the described 1365-node count and renaming LEAKY_SET_TTL_MS to reflect its usage with Map structures.
| } | ||
|
|
||
| describe('detector harness — synthetic baseline', () => { | ||
| const tree = buildTree(4, 4); |
There was a problem hiding this comment.
The benchmark description and name specify walking a 1365-node tree, but buildTree(4, 4) actually generates a tree with only 341 nodes (1 root + 4 + 16 + 64 + 256).
To match the intended 1365-node tree walk (1 + 4 + 16 + 64 + 256 + 1024), the depth should be increased to 5.
| const tree = buildTree(4, 4); | |
| const tree = buildTree(5, 4); |
| let currentThrottle = 100; | ||
| const MAX_BATCH_SIZE = 100; | ||
| const MAX_QUEUE_SIZE = 500; | ||
| const LEAKY_SET_TTL_MS = 5 * 60 * 1000; |
There was a problem hiding this comment.
The constant LEAKY_SET_TTL_MS now governs Map instances (reportedEffectIssues, reportedExcessiveRerenders, reportedSlowRenders) rather than Set instances. To improve maintainability and avoid confusion, consider renaming this constant to LEAKY_MAP_TTL_MS or REPORTED_ISSUES_TTL_MS (and updating its references in periodicCleanup).
| const LEAKY_SET_TTL_MS = 5 * 60 * 1000; | |
| const LEAKY_MAP_TTL_MS = 5 * 60 * 1000; |
…nIdle driver T1: Detector<TIssue> registry with type-safe contract (src/types/registry.ts, src/inject/registry.ts) T2: Registry dispatch wired into inject pipeline T3: React adapters r17/r18/r19/r19.2 with version sniffing T4: Settings storage layer with zod validation (src/settings/storage.ts, types.ts) T5: v0→v1 settings migration with backup (src/settings/migrate.ts) T6: Settings UI tab with toggles + thresholds (src/panel/tabs/SettingsTab.tsx) T7: Reconciler-keys hero detector (src/inject/detectors/reconciler-keys.ts) T8: Closure-leak Strategy-A bridge (src/inject/detectors/closure-leak.ts) T9: Scan-overlay + onIdle driver + getBoundingClientRect moved off hot path T10: drainAll + smoke-test coverage (src/__tests__/*.test.ts) Test pass: 219 (baseline at M-A: 141) tsc --noEmit: 0 errors Recovery branch — replays content from orphaned feat/self-roadmap-m-b-registry onto origin/main now that M-A landed via #50.
…nIdle driver (#51) T1: Detector<TIssue> registry with type-safe contract (src/types/registry.ts, src/inject/registry.ts) T2: Registry dispatch wired into inject pipeline T3: React adapters r17/r18/r19/r19.2 with version sniffing T4: Settings storage layer with zod validation (src/settings/storage.ts, types.ts) T5: v0→v1 settings migration with backup (src/settings/migrate.ts) T6: Settings UI tab with toggles + thresholds (src/panel/tabs/SettingsTab.tsx) T7: Reconciler-keys hero detector (src/inject/detectors/reconciler-keys.ts) T8: Closure-leak Strategy-A bridge (src/inject/detectors/closure-leak.ts) T9: Scan-overlay + onIdle driver + getBoundingClientRect moved off hot path T10: drainAll + smoke-test coverage (src/__tests__/*.test.ts) Test pass: 219 (baseline at M-A: 141) tsc --noEmit: 0 errors Recovery branch — replays content from orphaned feat/self-roadmap-m-b-registry onto origin/main now that M-A landed via #50.
…comparison (#52) * feat(roadmap): M-B foundation — detector registry + hero detector + onIdle driver T1: Detector<TIssue> registry with type-safe contract (src/types/registry.ts, src/inject/registry.ts) T2: Registry dispatch wired into inject pipeline T3: React adapters r17/r18/r19/r19.2 with version sniffing T4: Settings storage layer with zod validation (src/settings/storage.ts, types.ts) T5: v0→v1 settings migration with backup (src/settings/migrate.ts) T6: Settings UI tab with toggles + thresholds (src/panel/tabs/SettingsTab.tsx) T7: Reconciler-keys hero detector (src/inject/detectors/reconciler-keys.ts) T8: Closure-leak Strategy-A bridge (src/inject/detectors/closure-leak.ts) T9: Scan-overlay + onIdle driver + getBoundingClientRect moved off hot path T10: drainAll + smoke-test coverage (src/__tests__/*.test.ts) Test pass: 219 (baseline at M-A: 141) tsc --noEmit: 0 errors Recovery branch — replays content from orphaned feat/self-roadmap-m-b-registry onto origin/main now that M-A landed via #50. * docs(readme): star-growth polish — positioning, stars badge, screenshots, comparison table Conversion-killer fixes based on competitive positioning research: - Add GitHub stars badge + npm downloads badge to badge row - Lead with defensible triple-lock positioning: CLS overlay + useEffect audit + AI analysis (no competitor combines these) - Replace broken MP4 link with inline GIF reference (MP4 file doesn't exist) - Add ⚡ Try it in 30 seconds section with npx one-liner above the fold - Expand 'Why this extension' to name 5 competitors with concrete gaps (react-devtools, Chrome Perf, redux-devtools, react-scan, why-did-you-render) - Add Screenshots section with 6 tab images from docs/images/ - Add How it compares table — 8 features × 5 competitors with bold rows on the 3 unique-to-us features - Add ⭐ Star CTA at end with star-history.com chart + Watch-releases prompt Net diff: +56 / -6 lines. No code changes.
Self-Roadmap H2 2026 — Milestone M-A Foundation
This PR ships the M-A milestone of the self-roadmap. It establishes the architectural primitives required for the 8 new detectors planned across M-B through M-F (Jun–Dec 2026).
Maintainer-driven,
tracked-planlabeled. Runs in parallel withmcp-server-v1and the growth campaign; no MCP contract changes.5 task groups in one squash commit
SEARCH_REDUXto MessageType (yesterday's CI fix folded in).Set<string>→Map<string, number>+ 5-min TTL eviction.typecheck/typecheck:node/benchnpm scripts. CI runs typecheck (fail-fast) before build. Pre-existing tsc errors fixed. tsconfig.node.json tightened. Closes #27.src/inject/lifecycle.ts— first leaf module exiting the 3270-LoC IIFE god-file. Zero behavior change.Verification gates (all green)
Pipeline used
Each of T1-T5 ran through the
subagent-driven-developmentSDD pipeline yesterday:Zero loop-backs across 5 tasks. All passed both gates first-attempt. Atomic-task SHAs preserved in the harness file at
.opencode/plans/2026-05-31-self-roadmap-m-a.mdfor posterity.Honest note about the recovery
The original M-A branch atomic-task git history (7 commits with conventional-commit messages T1-T5 + housekeeping) is lost — it was orphaned by the identity-rewrite force-push and can't be reattached to main's history without rewriting main. This recovery PR collapses everything into a single squash commit, which is what would have happened at merge time anyway (typical feature-branch hygiene).
Lesson learned: when rewriting identity, scope the rewrite to ONLY the new commits via
git filter-repo --refs <commit>..HEAD, not the entire branch. Documented for future M-C / M-D / M-E / M-F branches.Sibling PR
M-B recovery PR — coming shortly — same recovery process, builds on this branch.
Carryforward to follow-up cleanup
16 minor reviewer-noted items deferred to a later pass, none blocking. Documented in commit + harness. Highlights:
LEAKY_SET_TTL_MSconstant name still says "Set" (governs Maps now)installCleanupInterval/uninstallCleanupIntervalnaming may clash with M-B's futureinstall(flags)/uninstall()API