Conversation
- WDYR (`wdyr.js`, `useSelector` diff tracking) as the live cascade tracer - input-unstable vs output-unstable tool selection (`resultEqualityCheck`) - a live cascade nullifies downstream memo/virtualization/compiler wins - plain-function selector sweep; span quota guardrail; redux-persist caveat
- WDYR (`wdyr.js`, `useSelector` diff tracking) as the live cascade tracer - input-unstable vs output-unstable tool selection (`resultEqualityCheck`) - a live cascade nullifies downstream memo/virtualization/compiler wins - plain-function selector sweep; span quota guardrail; redux-persist caveat
The three files this PR adds each restated a pattern that also exists generically. Rather than duplicate, each now opens with a scope note naming the knowledge file that owns the definition — `effect-anti-patterns` for the lifecycle patterns, `render-cascade` and `selector-anti-patterns` for the cascade and shape ones — and keeps what only it can say: the verified Mobile instances, this store's real dependency graph, and the fix recipes. Citations are by name rather than relative link: `install` copies domain knowledge/ and a skill's references/ as siblings under the installed skill directory, so a repo-correct relative path breaks once installed. The knowledge files themselves land in the performance-skills PR (#43); until that merges these notes name a file that is not yet present, which is why they are names and not links.
Context budgetWhat this PR costs an agent, measured from an install rather than read from the diff. Three tiers, and only the first is unavoidable.
Frontmatter is the only tier paid unconditionally — every agent loads it on every run once the skill is installed, used or not, because it is what the agent reads to decide relevance. The 28 skills across the eleven open skill PRs sit at a median of ~1,716 tokens selected and ~1,860 with references followed. All are within the 1,536-character description budget. Selected is paid only when the agent picks the skill. + refs & knowledge is the ceiling if every bundled reference is then read; it is a worst case, not an expectation. Method
These figures are pinned to the commit above and drift on every push; #96 tracks automating them. |
The selector and effect anti-pattern definitions existed in two places: these knowledge files, and the `performance` skill's own mm-* references already on main. Same patterns, same worked examples, two homes that would drift. knowledge/selector-anti-patterns.md and knowledge/effect-anti-patterns.md are now the canonical, platform-agnostic taxonomy — the union of both sides. The selector file absorbs mutation-in-result and over-broad-input from mm-selector-memoization; the effect file absorbs the dependency-side patterns from mm-hook-dependency-arrays and the lifecycle-side patterns (derived state, effect chains, uncancelled async). mm-selector-memoization.md keeps everything only it can say — the codebase's own selector creators, the verified instance table with file:line, the fix recipes, the scoped greps, the don't-over-correct caveats — and maps each generic pattern onto this codebase instead of redefining it. mm-hook-dependency-arrays.md keeps its richer JSON.stringify treatment and gains a scope note. Citations are by NAME, not by relative link. `install` copies domain knowledge/ and a skill's references/ as siblings under the installed skill directory, so `../../../knowledge/x.md` resolves in the repo and breaks once installed, and `../knowledge/x.md` does the reverse. Section anchors are dropped for the same reason — they broke the moment the taxonomy was renumbered. Also drops the CHANGELOG entry: that file tracks the @metamask/skills CLI package, no merged skill-only PR adds one, and it was this branch's sole conflict with main.
Folds in the react-render-proof skill (was MetaMask#82) and the mobile reference-library additions (was MetaMask#49). All three were the same effort seen from different ends — moving performance work earlier in the loop — and they share a substrate, so reviewing them apart meant reviewing the substrate three times. The loop this domain now covers: - catch it at review — effect/selector anti-pattern review skills, driven by the knowledge taxonomy - prove it moved — react-render-proof, with a delivery gate so an arm whose treatment never reached the bundle cannot report as a null - measure it honestly — data-analysis, benchmark hygiene, web-vitals framing - know the codebase — the mm-* reference library and its audit playbook Also neutralizes five references to private planning tickets, which do not belong on a public repository — they named internal epic and audit-ticket numbers. The surrounding guidance is unchanged; only the identifiers are gone.
These name MetaMask-org planning epics and audit tickets. The audience for this repo is the MetaMask org, for whom those identifiers are load-bearing context — they are where the guidance came from and where the follow-up lives. The scrub line is personal references, not org-internal ones.
`benchmark-design` and `browser-extension-profiling` are the capture half of the measurement work already here: `data-analysis` turns raw numbers into a defensible before/after, and `react-render-proof` proves a specific change moved work. Both arrived from the platform PR, which shipped them alongside unrelated extension-runtime skills. `benchmark-design` stays in `testing` — that domain already owns benchmark methodology (`performance-testing`) — and brings its `benchmark-statistical-hygiene` knowledge with it. The PR spans two domains because the subject does, not because it is a grab bag.
`metamask-extension` moved its default branch to `main`; `develop` still exists but its last commit is 2026-01-15, so six links in the extension overlays resolved to code roughly six months stale. They loaded, which is why nothing caught it — a frozen branch is worse than a dead one here, since the reader gets plausible but outdated source. All five cited paths verified present on `main` (HTTP 200): `ui/`, `ui/hooks/`, `ui/selectors/`, `shared/lib/selectors/selector-creators.ts`, and `app/scripts/metamask-controller.js`.
`browser-extension-profiling` drops `browser-`, which distinguishes nothing: an extension is a browser extension, and the `extension-` half is what separates it from the mobile work this domain also covers. `anti-pattern` loses its hyphen in identifiers, matching what `main` already ships in `review-antipatterns.md` and `mm-redux-antipatterns.md`. Both skills and both knowledge files move together, since a skill and its knowledge sharing a stem is what makes the by-name citation convention resolvable. Prose inside the two renamed skills is normalised with them so each file agrees with its own name; hyphenated prose elsewhere is left alone as pre-existing and outside this change.
`scan` says what they do. Both walk a diff looking for a known set of shapes and report what they find; `review` implied a judgement they do not make and overlapped with the correctness review these deliberately are not. The suffix still carries its original job of keeping each skill distinct from the knowledge file it cites — `selector-antipatterns.md` and `effect-antipatterns.md` — which the by-name citation resolver needs, since it matches on filename. Installed as `mms-selector-antipattern-scan` and `mms-effect-antipattern-scan`.
…g it `C4` is an address into `evidence-catalog.md`. A reader who has not opened the catalog cannot resolve it, and the frontmatter `description` cannot link out to one. Both sites now name the category and link the catalog by URL — a relative path would not survive installation, which flattens skills to `mms-<name>/`. Also updates two sibling names that no longer resolve: `pr-validate` is now `evidence`, and `memory-leak-hunt` is now `memory-leak`.
`-proof` as a noun suffix reads as "immune to", so the old name parsed as "immune to React renders". `-delta` names what the skill actually produces, and matches the skill's own insistence that its output is a measured quantity rather than a boolean.
Found by running the skill against real merged PRs: the §3 detection matched
only named collection constructors, so a result function returning an object
literal directly went undetected.
`(metamask) => ({ userRegion: ..., ... })` builds a new object on every
recompute and matches none of `new Set`, `new Map`, `Object.values`, `?? {}`,
or `?? []`. Adds `=> ({` and `=> [` as alternates, with the reason recorded
beside the table so the next person does not narrow it again.
The installer emits `mms-react-render-delta`; the description advertised `/react-render-delta`, which resolves to nothing. Caught by the check MetaMask#99 adds — this branch predates it and only fails once combined.
34b935c to
9999888
Compare
performance domain - anti-pattern scans, render delta, profiling, data analysis skills
performance domain - anti-pattern scans, render delta, profiling, data analysis skillsperformance domain - /effect-antipattern-scan, /selector-antipattern-scan, /react-render-delta, /extension-profiling, /benchmark-design, /data-analysis skills
performance domain - /effect-antipattern-scan, /selector-antipattern-scan, /react-render-delta, /extension-profiling, /benchmark-design, /data-analysis skillsperformance domain - cross-client learnings from performance audit and "shift-left" initiative
performance domain - cross-client learnings from performance audit and "shift-left" initiativeperformance domain - Extension performance audit learnings applied to cross-client skills, knowledges
performance domain - Extension performance audit learnings applied to cross-client skills, knowledgesperformance domain with performance audit, benchmark gate learnings
The symptom table and the description both named `react-render-proof`. No skill of that name exists on `main` or in any open pull request; the render engine is `react-render-delta`, added by #43 and carried by #84 and #108, and installed locally as `mms-react-render-delta`. The other six engines this skill routes to all resolve to skills in open pull requests, so this was the only wrong name rather than one of three. Checked against the repository rather than against an install: none of the seven is on `main` yet, which is a merge-ordering fact and not a defect here. Nothing validates this today. #103, which would have checked cross-skill references, was closed as superseded by #87, and #87 is not merged — so this name would have shipped unflagged.
…audit here `react-render-delta`, `extension-profiling`, `data-analysis` and `benchmark-design` measure; the two scans and the mobile reference updates review. Verified disjoint — no citation crosses the split.
performance domain with performance audit, benchmark gate learningsperformance domain with antipattern scan skills
performance domain with antipattern scan skillsperformance domain - /effect-antipattern-scan, /selector-antipattern-scan skills
performance domain - /effect-antipattern-scan, /selector-antipattern-scan skillsperformance domain with anti-pattern scanning skills
Compiler adoption is a different subject from the render antipattern scans, and neither scan cites it. The three inbound links go with it, so nothing here points at a file this branch no longer carries. Also removes five `MetaMask-planning` epic and audit-ticket ids from four files. They are a private repo's numbers and this repo is public; none of them is on `main`, so this branch introduced all five. Provenance now reads "the extension performance audit". The public `metamask-extension` PR references are kept.
…he single-entry cache BaseController v2 state is Immer-produced, so an unchanged path keeps its reference, and the PR's own cascade reference already said so. reselect 5's `createSelector` defaults to `weakMapMemoize`, which caches per argument and only thrashes on an unstable one. React Strict Mode does not amplify through a cascade by a clean factor of 2. The skills also no longer contradict themselves: mobile runs the React Compiler, the taxonomy has eight patterns, a cold-path `JSON.stringify` is allowed, a cancelled flag is as good as `AbortController`, and the mobile citation points at line 183.
…ch reaches A span that fires once per transaction still fans out when the transaction fires at high volume, and its failures stay fully sampled. A kill-switch reaches only the builds that contain it.
Motivation
domains/performanceis four extension pattern guides (perf-hooks-effects,perf-rendering,perf-state-management,perf-react-compiler) and one mobile advisory skill. The patterns are documented. What none of them does is fire without being sought.A selector returning a fresh object reference each call produces no build error, no failing test and no user report. It produces a component that renders 178 times instead of 61. Nobody searches for a guide to a problem they do not know they have, which is what makes a review-time scan a different thing from a better-written guide.
The guides are also one platform each: the four
perf-*skills install intometamask-extensiononly, theperformanceskill intometamask-mobileonly. The same antipattern had two unlinked treatments and no shared definition.Overview
Two review-time scans for the React and Redux antipatterns that cause render cascades, plus the shared definitions both scans cite. Supersedes #82 and #49. Profiling, render deltas and benchmark design are in #144.
effect-antipattern-scanandselector-antipattern-scan: grep-driven checklists over a PR diff. Both carrymetamask-extensionandmetamask-mobileoverlays.knowledge/:effect-antipatterns,selector-antipatterns,render-cascade.performanceskill'smm-*references map each pattern onto the codebase instead of redefining it. No mobile-specific content was removed.Coverage gap this surfaced: no skill here detects
renderItemidentity instability, and no overlay mentionsFlatListorFlashList.Showcase
A render-cascade epic in
metamask-extension, both arms measured with WDYR:1d6d1811b8178 re-renders →0d37542a0861. Its two constituent fixes, #39312 and #37147, are both selectors returning a fresh reference per call, which is the pattern these scans look for.Trial runs against merged PRs nobody flagged, each posted beside its diff. #39310 "149 consumers" counts call sites, not renders · #40859 deep-equal to reference-equal, recomputations may rise · #44392
?? {}fresh object, unmemoized, intouseSelector· mobile#33578 per-renderconstfeeding a FlashList.The same epic counted by selector evaluations rather than renders: 49 → 2, and a single transition a timer cannot resolve, at #39314.
What I could not check: the per-slice reference-stability framing in the cascade file, against the store's actual behavior.
Sources:
frontend-performance.md.