Skip to content

feat(roadmap): M-A foundation — ghost-type purge, leaky-Set fix, perf-budget gate, lifecycle module (recovery of #39)#50

Merged
hoainho merged 3 commits into
mainfrom
feat/m-a-recovery
Jun 1, 2026
Merged

feat(roadmap): M-A foundation — ghost-type purge, leaky-Set fix, perf-budget gate, lifecycle module (recovery of #39)#50
hoainho merged 3 commits into
mainfrom
feat/m-a-recovery

Conversation

@hoainho
Copy link
Copy Markdown
Owner

@hoainho hoainho commented Jun 1, 2026

Recovery PR. Original PR was #39.
#39 auto-closed when I force-pushed identity-rewrite commits yesterday (fixed author from nhonh@geargames.comnhoxtvt@gmail.com). The rewrite cascaded SHA changes through the entire branch history, leaving zero common ancestry with main. This PR recovers the work by cherry-picking file-level changes onto current main — a single squash commit that preserves all post-M-A merges (PR #40 editor onboarding, PR #47 claim rule, PR #48 star check).

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-plan labeled. Runs in parallel with mcp-server-v1 and the growth campaign; no MCP contract changes.

5 task groups in one squash commit

Task Headline
T1 refactor(types): delete 5 ghost IssueType enum values + fix Panel.tsx badge selectors. Also adds SEARCH_REDUX to MessageType (yesterday's CI fix folded in).
T2 fix(inject): bound 3 leaky Sets via TTL Maps in periodicCleanup. Set<string>Map<string, number> + 5-min TTL eviction.
T3 ci(typecheck): add typecheck / typecheck:node / bench npm scripts. CI runs typecheck (fail-fast) before build. Pre-existing tsc errors fixed. tsconfig.node.json tightened. Closes #27.
T4 test(bench): vitest-bench harness skeleton + first baseline at ~575K hz on synthetic 1365-node tree walk.
T5 refactor(inject): extract cleanup-interval lifecycle into src/inject/lifecycle.ts — first leaf module exiting the 3270-LoC IIFE god-file. Zero behavior change.

Verification gates (all green)

tsc --noEmit  → ZERO errors
build         → exit 0 (background.js 19.97 kB / gzip 4.20 kB)
test:run      → 29 pre-existing emoji-test failures + 141 passes
bench         → exit 0, ~575K hz baseline

Pipeline used

Each of T1-T5 ran through the subagent-driven-development SDD pipeline yesterday:

  1. Implementer subagent (atomic task brief)
  2. Spec-compliance reviewer (independent, reads code line-by-line)
  3. Code-quality reviewer (separate session)

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.md for 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:

  • T2: LEAKY_SET_TTL_MS constant name still says "Set" (governs Maps now)
  • T5: installCleanupInterval / uninstallCleanupInterval naming may clash with M-B's future install(flags) / uninstall() API

hoainho added 3 commits June 1, 2026 01:57
…-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.
@hoainho hoainho added the tracked-plan Maintainer-driven milestone PR (M-A, M-B, Self-Roadmap); exempt from Star Check CI label Jun 1, 2026
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
const tree = buildTree(4, 4);
const tree = buildTree(5, 4);

Comment thread src/inject/index.ts
let currentThrottle = 100;
const MAX_BATCH_SIZE = 100;
const MAX_QUEUE_SIZE = 500;
const LEAKY_SET_TTL_MS = 5 * 60 * 1000;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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).

Suggested change
const LEAKY_SET_TTL_MS = 5 * 60 * 1000;
const LEAKY_MAP_TTL_MS = 5 * 60 * 1000;

@hoainho hoainho merged commit 7017d01 into main Jun 1, 2026
3 checks passed
@hoainho hoainho deleted the feat/m-a-recovery branch June 1, 2026 14:04
hoainho added a commit that referenced this pull request Jun 2, 2026
…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.
hoainho added a commit that referenced this pull request Jun 2, 2026
…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.
hoainho added a commit that referenced this pull request Jun 2, 2026
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tracked-plan Maintainer-driven milestone PR (M-A, M-B, Self-Roadmap); exempt from Star Check CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dx: add 'typecheck' script + CI step to enforce strict TypeScript

1 participant