mustflow 2.114.0 → 2.114.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -1
- package/templates/default/i18n.toml +12 -12
- package/templates/default/locales/en/.mustflow/skills/async-timing-boundary-review/SKILL.md +6 -1
- package/templates/default/locales/en/.mustflow/skills/client-bundle-pruning-review/SKILL.md +40 -34
- package/templates/default/locales/en/.mustflow/skills/frame-render-performance-review/SKILL.md +28 -22
- package/templates/default/locales/en/.mustflow/skills/hot-path-performance-review/SKILL.md +22 -10
- package/templates/default/locales/en/.mustflow/skills/javascript-code-change/SKILL.md +29 -11
- package/templates/default/locales/en/.mustflow/skills/memory-lifetime-review/SKILL.md +8 -2
- package/templates/default/locales/en/.mustflow/skills/node-code-change/SKILL.md +19 -5
- package/templates/default/locales/en/.mustflow/skills/performance-budget-check/SKILL.md +15 -7
- package/templates/default/locales/en/.mustflow/skills/quadratic-scan-review/SKILL.md +25 -22
- package/templates/default/locales/en/.mustflow/skills/web-render-performance-review/SKILL.md +18 -17
- package/templates/default/manifest.toml +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mustflow",
|
|
3
|
-
"version": "2.114.
|
|
3
|
+
"version": "2.114.5",
|
|
4
4
|
"description": "Agent workflow documents and CLI for mustflow repository roots.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT-0",
|
|
@@ -35,6 +35,8 @@
|
|
|
35
35
|
"test:cli": "node scripts/run-cli-tests.mjs --build cli",
|
|
36
36
|
"test:coverage": "node scripts/run-cli-tests.mjs --build coverage",
|
|
37
37
|
"test:audit": "node scripts/audit-tests.mjs --json",
|
|
38
|
+
"test:audit:related": "node scripts/audit-related-selection.mjs",
|
|
39
|
+
"test:ops": "node scripts/analyze-test-ops.mjs",
|
|
38
40
|
"test:release": "node scripts/run-cli-tests.mjs --build release",
|
|
39
41
|
"test:fast:node": "node scripts/run-cli-tests.mjs --build-runner=npm fast",
|
|
40
42
|
"test:release:node": "node scripts/run-cli-tests.mjs --build-runner=npm release",
|
|
@@ -50,13 +50,13 @@ translations.hi = { path = "locales/hi/.mustflow/docs/agent-workflow.md", source
|
|
|
50
50
|
[documents."config.preferences"]
|
|
51
51
|
source = "common/.mustflow/config/preferences.toml"
|
|
52
52
|
source_locale = "en"
|
|
53
|
-
revision =
|
|
53
|
+
revision = 5
|
|
54
54
|
translations = {}
|
|
55
55
|
|
|
56
56
|
[documents."config.technology"]
|
|
57
57
|
source = "common/.mustflow/config/technology.toml"
|
|
58
58
|
source_locale = "en"
|
|
59
|
-
revision =
|
|
59
|
+
revision = 2
|
|
60
60
|
translations = {}
|
|
61
61
|
|
|
62
62
|
[documents."skills.index"]
|
|
@@ -224,7 +224,7 @@ translations = {}
|
|
|
224
224
|
[documents."skill.memory-lifetime-review"]
|
|
225
225
|
source = "locales/en/.mustflow/skills/memory-lifetime-review/SKILL.md"
|
|
226
226
|
source_locale = "en"
|
|
227
|
-
revision =
|
|
227
|
+
revision = 3
|
|
228
228
|
translations = {}
|
|
229
229
|
|
|
230
230
|
[documents."skill.desktop-memory-footprint-review"]
|
|
@@ -236,7 +236,7 @@ translations = {}
|
|
|
236
236
|
[documents."skill.hot-path-performance-review"]
|
|
237
237
|
source = "locales/en/.mustflow/skills/hot-path-performance-review/SKILL.md"
|
|
238
238
|
source_locale = "en"
|
|
239
|
-
revision =
|
|
239
|
+
revision = 6
|
|
240
240
|
translations = {}
|
|
241
241
|
|
|
242
242
|
[documents."skill.api-request-performance-review"]
|
|
@@ -272,7 +272,7 @@ translations = {}
|
|
|
272
272
|
[documents."skill.web-render-performance-review"]
|
|
273
273
|
source = "locales/en/.mustflow/skills/web-render-performance-review/SKILL.md"
|
|
274
274
|
source_locale = "en"
|
|
275
|
-
revision =
|
|
275
|
+
revision = 2
|
|
276
276
|
translations = {}
|
|
277
277
|
|
|
278
278
|
[documents."skill.core-web-vitals-field-review"]
|
|
@@ -290,13 +290,13 @@ translations = {}
|
|
|
290
290
|
[documents."skill.client-bundle-pruning-review"]
|
|
291
291
|
source = "locales/en/.mustflow/skills/client-bundle-pruning-review/SKILL.md"
|
|
292
292
|
source_locale = "en"
|
|
293
|
-
revision =
|
|
293
|
+
revision = 2
|
|
294
294
|
translations = {}
|
|
295
295
|
|
|
296
296
|
[documents."skill.frame-render-performance-review"]
|
|
297
297
|
source = "locales/en/.mustflow/skills/frame-render-performance-review/SKILL.md"
|
|
298
298
|
source_locale = "en"
|
|
299
|
-
revision =
|
|
299
|
+
revision = 2
|
|
300
300
|
translations = {}
|
|
301
301
|
|
|
302
302
|
[documents."skill.motion-system-contract-review"]
|
|
@@ -386,7 +386,7 @@ translations = {}
|
|
|
386
386
|
[documents."skill.quadratic-scan-review"]
|
|
387
387
|
source = "locales/en/.mustflow/skills/quadratic-scan-review/SKILL.md"
|
|
388
388
|
source_locale = "en"
|
|
389
|
-
revision =
|
|
389
|
+
revision = 4
|
|
390
390
|
translations = {}
|
|
391
391
|
|
|
392
392
|
[documents."skill.type-state-modeling-review"]
|
|
@@ -404,7 +404,7 @@ translations = {}
|
|
|
404
404
|
[documents."skill.async-timing-boundary-review"]
|
|
405
405
|
source = "locales/en/.mustflow/skills/async-timing-boundary-review/SKILL.md"
|
|
406
406
|
source_locale = "en"
|
|
407
|
-
revision =
|
|
407
|
+
revision = 3
|
|
408
408
|
translations = {}
|
|
409
409
|
|
|
410
410
|
[documents."skill.concurrency-invariant-review"]
|
|
@@ -763,7 +763,7 @@ translations = {}
|
|
|
763
763
|
[documents."skill.javascript-code-change"]
|
|
764
764
|
source = "locales/en/.mustflow/skills/javascript-code-change/SKILL.md"
|
|
765
765
|
source_locale = "en"
|
|
766
|
-
revision =
|
|
766
|
+
revision = 6
|
|
767
767
|
translations = {}
|
|
768
768
|
|
|
769
769
|
[documents."skill.java-code-change"]
|
|
@@ -775,7 +775,7 @@ translations = {}
|
|
|
775
775
|
[documents."skill.node-code-change"]
|
|
776
776
|
source = "locales/en/.mustflow/skills/node-code-change/SKILL.md"
|
|
777
777
|
source_locale = "en"
|
|
778
|
-
revision =
|
|
778
|
+
revision = 4
|
|
779
779
|
translations = {}
|
|
780
780
|
|
|
781
781
|
[documents."skill.react-code-change"]
|
|
@@ -1056,7 +1056,7 @@ translations = {}
|
|
|
1056
1056
|
[documents."skill.performance-budget-check"]
|
|
1057
1057
|
source = "locales/en/.mustflow/skills/performance-budget-check/SKILL.md"
|
|
1058
1058
|
source_locale = "en"
|
|
1059
|
-
revision =
|
|
1059
|
+
revision = 24
|
|
1060
1060
|
translations = {}
|
|
1061
1061
|
|
|
1062
1062
|
[documents."skill.pattern-scout"]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: skill.async-timing-boundary-review
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 3
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: procedure
|
|
8
8
|
name: async-timing-boundary-review
|
|
@@ -63,6 +63,7 @@ The review question is not "how many milliseconds are safe?" It is "is the code
|
|
|
63
63
|
- Completion signal available in the codebase: event, callback, listener, promise that resolves on real completion, `finish`, `close`, `fsync`, atomic rename, health check, listen callback, ack, status endpoint, observer, transition event, cancellation token, latch, barrier, fake clock, or deterministic scheduler.
|
|
64
64
|
- Caller ownership: whether every caller awaits the returned Promise or whether the async work is fire-and-forget, debounced, event-handler-owned, framework-owned, or lifecycle-owned.
|
|
65
65
|
- Operation identity and ordering model: operation id, entity id, attempt, causation id, generation, version, sequence, cancellation reason, idempotency key, and whether the apply step checks that the result still belongs to the current state.
|
|
66
|
+
- Scheduling and backpressure model: task, microtask, `process.nextTick`, timer, `requestAnimationFrame`, idle callback, `scheduler.yield`, worker message, bounded concurrency, debounce, throttle, and whether producers can outrun consumers.
|
|
66
67
|
- Test evidence: current tests, fake timers, controlled promises, barriers, polling utilities, readiness probes, stress tests, CI logs, or missing configured verification.
|
|
67
68
|
|
|
68
69
|
<!-- mustflow-section: preconditions -->
|
|
@@ -109,6 +110,9 @@ The review question is not "how many milliseconds are safe?" It is "is the code
|
|
|
109
110
|
- The awaited Promise must represent the real work, not only scheduling the work.
|
|
110
111
|
- Catch async `forEach`, `map` without `Promise.all`, missing `return` in `.then`, unawaited callers, swallowed catches, async event handlers whose business flow is not awaited, debounced promises, and event APIs that need explicit `load`, `error`, `finish`, or `close` wrapping.
|
|
111
112
|
- In UI code, do not treat state setters, microtasks, or Promise resolution as proof that DOM layout or paint has happened.
|
|
113
|
+
- Do not use recursive `Promise.resolve().then(...)`, `queueMicrotask(...)`, or `process.nextTick(...)` loops as a general scheduler. They can starve rendering, input, timers, I/O, and shutdown work because the runtime drains those queues before moving on.
|
|
114
|
+
- Yield long work at the right boundary. Use `requestAnimationFrame` for visual writes, bounded tasks or feature-detected `scheduler.yield` for cooperative main-thread work, idle callbacks for non-urgent browser work, and worker offload when CPU work is too large to share the UI thread.
|
|
115
|
+
- Treat `Promise.all` as a failure-policy choice, not as automatic cancellation. If one failure should stop sibling work, wire cancellation to the underlying operations; if all outcomes matter, collect them with `allSettled`; if first success is enough, use the local `any` or fallback pattern.
|
|
112
116
|
6. Define "once" by scope.
|
|
113
117
|
- Name the scope: call, component mount, route lifetime, tab, process, deployment, worker, queue message, transaction retry, cron tick, or durable resource.
|
|
114
118
|
- Make side effects idempotent when retries, remounts, StrictMode, HMR, reconnects, queue redelivery, transaction retries, multiple tabs, serverless cold starts, or rolling deploys can repeat them.
|
|
@@ -140,6 +144,7 @@ The review question is not "how many milliseconds are safe?" It is "is the code
|
|
|
140
144
|
- Every fixed wait is classified as a true time contract, replaced with a completion signal, converted to bounded polling, or reported as residual risk.
|
|
141
145
|
- The exact completion condition and boundary crossed by the old delay are named.
|
|
142
146
|
- Promise, "once", event-loop, render, filesystem, process, worker, database, queue, external consistency, and test claims are checked where relevant.
|
|
147
|
+
- Microtask, next-tick, timer, frame, idle, bounded-concurrency, debounce, throttle, and cancellation scheduling claims are checked where relevant.
|
|
143
148
|
- Latest-request-wins, generation or version guards, cancellation states, duplicate delivery, late success, outbox or inbox handoffs, and per-key ordering are checked where relevant.
|
|
144
149
|
- Remaining waits have explicit reason, bound, cancellation, and diagnostic behavior when possible.
|
|
145
150
|
- Verification covers the changed timing boundary or reports the missing configured intent.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: skill.client-bundle-pruning-review
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 2
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: procedure
|
|
8
8
|
name: client-bundle-pruning-review
|
|
@@ -29,9 +29,9 @@ metadata:
|
|
|
29
29
|
<!-- mustflow-section: purpose -->
|
|
30
30
|
## Purpose
|
|
31
31
|
|
|
32
|
-
Review frontend bundle weight by finding code shapes that keep bundlers from deleting unused client code, not by repeating generic advice about compression, images, or code splitting.
|
|
32
|
+
Review frontend bundle weight by finding code shapes that keep bundlers from deleting unused client code, not by repeating generic advice about compression, images, or code splitting. Treat compressed transfer size as only one receipt; the browser pays again when JavaScript is decompressed, parsed, compiled, evaluated, and run on the main thread.
|
|
33
33
|
|
|
34
|
-
The review question is not "is code splitting enabled?" It is "which imports, package entrypoints, module formats, side-effect claims, client boundaries, polyfills, and chunk rules force unused code into the first route or shared vendor bundle?"
|
|
34
|
+
The review question is not "is code splitting enabled?" It is "which imports, package entrypoints, module formats, side-effect claims, client boundaries, polyfills, coverage gaps, and chunk rules force unused or late-use code into the first route or shared vendor bundle?"
|
|
35
35
|
|
|
36
36
|
<!-- mustflow-section: use-when -->
|
|
37
37
|
## Use When
|
|
@@ -60,6 +60,7 @@ The review question is not "is code splitting enabled?" It is "which imports, pa
|
|
|
60
60
|
- Framework boundary ledger: Next.js Server/Client Component boundary, `next/dynamic`, `optimizePackageImports`, React `lazy`, Angular `@defer`, Vue route lazy loading, Svelte/Astro island or hydration boundary, and whether code is required for first interaction.
|
|
61
61
|
- Heavy-feature ledger: icons, UI component libraries, date locales, syntax highlighters, markdown, editors, charts, maps, PDF viewers, search/fuzzy libraries, Node polyfills, dev-only tools, logs, and CSS utility extraction.
|
|
62
62
|
- Polyfill and target ledger: browser support target, Babel or TypeScript output target, `core-js` usage, Node polyfills, `process` or `Buffer` shims, Vite modulepreload polyfill, and esbuild/Webpack/Rollup define or drop settings.
|
|
63
|
+
- Measurement ledger: initial JavaScript transfer, decompressed size, parse, compile, evaluate, bootup or long-task time, route-specific Chrome Coverage or equivalent unused-code evidence, Resource Timing for preload or prefetch changes, manifest or chunk hash stability, and whether the evidence is flow-specific or a single refresh snapshot.
|
|
63
64
|
- Existing tests, build output, bundle budgets, analyzer screenshots or reports, package metadata checks, and configured command-intent evidence.
|
|
64
65
|
|
|
65
66
|
<!-- mustflow-section: preconditions -->
|
|
@@ -83,42 +84,47 @@ The review question is not "is code splitting enabled?" It is "which imports, pa
|
|
|
83
84
|
## Procedure
|
|
84
85
|
|
|
85
86
|
1. Review first-route JavaScript separately from total build output. Name the route or entry users actually load first, then separate initial JS, route JS, shared vendor JS, CSS, and lazy chunks when evidence exists.
|
|
86
|
-
2.
|
|
87
|
-
3.
|
|
88
|
-
4.
|
|
89
|
-
5.
|
|
90
|
-
6.
|
|
91
|
-
7.
|
|
92
|
-
8.
|
|
93
|
-
9.
|
|
94
|
-
10.
|
|
95
|
-
11.
|
|
96
|
-
12.
|
|
97
|
-
13.
|
|
98
|
-
14.
|
|
99
|
-
15.
|
|
100
|
-
16.
|
|
101
|
-
17.
|
|
102
|
-
18.
|
|
103
|
-
19.
|
|
104
|
-
20.
|
|
105
|
-
21.
|
|
106
|
-
22.
|
|
107
|
-
23.
|
|
108
|
-
24.
|
|
109
|
-
25.
|
|
110
|
-
26.
|
|
111
|
-
27.
|
|
112
|
-
28.
|
|
113
|
-
29.
|
|
114
|
-
30.
|
|
87
|
+
2. Budget execution, not only gzip. Prefer initial JavaScript parse, compile, evaluate, bootup, and long-task budgets over compressed KB-only claims. Treat gzip or brotli size as transfer evidence, not proof that the main thread got faster.
|
|
88
|
+
3. Compare analyzer receipts with coverage evidence. Bundle analyzers show what entered the build; route-specific Coverage or equivalent evidence shows what was unused in the flow. Check first entry, logged-in state, key route, checkout or save path, and heavy feature entry separately when those flows matter.
|
|
89
|
+
4. Prefer a failing bundle budget over human memory. If the repository has a budget pattern, enforce initial route JS, shared vendor growth, evaluate time, or long-task growth with configured tests or release checks. If no configured budget exists, report the gap instead of inventing analyzer commands.
|
|
90
|
+
5. Suspect non-ESM packages first. Tree shaking depends on static imports and exports; CommonJS `require`, mixed module packages, dynamic require patterns, or ambiguous package entrypoints often keep unused code alive.
|
|
91
|
+
6. Replace broad utility imports. Avoid `import _ from 'lodash'`, broad date imports, or whole-library namespace imports on client paths when ESM or function-level imports preserve behavior.
|
|
92
|
+
7. Audit barrel files on hot client paths. `export *` design-system or icon barrels can force bundlers to inspect or include too much. Prefer direct subpath imports when the package owns that contract.
|
|
93
|
+
8. Split internal package exports by feature. Provide stable subpath exports such as component, icon, or helper entrypoints when `@scope/ui` as a single entry drags unrelated modules into client bundles.
|
|
94
|
+
9. Set `sideEffects` metadata carefully. Use `false` only when modules are truly side-effect-free, and preserve CSS imports, polyfills, global registrations, telemetry setup, and plugin initialization through an allowlist.
|
|
95
|
+
10. Treat Rollup or Vite `moduleSideEffects: false` as dangerous by default. Use a function or allowlist when CSS, polyfills, custom elements, plugin registration, or global patches exist.
|
|
96
|
+
11. Add PURE annotations only for pure wrapper calls. React `memo`, `forwardRef`, higher-order component factories, icon factories, and generated component wrappers may need `/* @__PURE__ */`, but never mark a call pure unless its arguments and call have no required side effects.
|
|
97
|
+
12. Move client boundaries inward. In Next.js style apps, avoid putting `'use client'` on pages, layouts, or broad shells when only a small search box, menu, chart, or control needs browser state.
|
|
98
|
+
13. Use Server Components or server-only code as a deletion boundary. Keep markdown parsing, CMS transforms, price formatting, permission checks, data shaping, and server-safe library use out of Client Components when interactivity does not require them.
|
|
99
|
+
14. Keep dynamic imports statically analyzable and outside the initial static graph. `next/dynamic` and similar APIs need explicit import strings at module top level when preloading or chunk naming depends on static analysis; `import()` does not help when the same module is statically imported by the first route, shell, barrel, or shared vendor path.
|
|
100
|
+
15. Declare `React.lazy` and similar lazy components outside render functions. Recreating lazy definitions during render can reset state and blur split boundaries.
|
|
101
|
+
16. Split by "the user can wait here," not by arbitrary component size. Route transitions, modal first open, editor mode, chart tab, map reveal, admin panel entry, or preview mode are stronger boundaries than small components that are needed together.
|
|
102
|
+
17. Lazy-load optional heavy widgets. Modals, charts, editors, maps, search, PDF viewers, markdown preview, syntax highlighting, and admin-only panels should not enter initial JS unless they are visible and necessary at first load.
|
|
103
|
+
18. Move external library imports to the event or visibility point when safe. Search libraries can load on focus or input, charts on tab open, maps on section reveal, markdown preview on preview mode, and editors on edit intent.
|
|
104
|
+
19. Use Angular `@defer`, Vue route lazy loading, Svelte/Astro islands, or framework-native deferral when that framework is present. Confirm the dependencies are not also imported eagerly outside the deferred boundary.
|
|
105
|
+
20. Use import modularization options cautiously. Next.js `optimizePackageImports` or equivalent compiler transforms can help large export surfaces, but verify the actual output and do not treat an experimental option as proof.
|
|
106
|
+
21. Audit icon imports. Prefer per-icon imports, stable subpath imports, or build-time SVG sprites over package roots or barrels that can pull an icon catalog into client JS.
|
|
107
|
+
22. Audit date locales. Import only needed locales, prefer platform `Intl` when it is enough, and keep server-format-able date work off the client path.
|
|
108
|
+
23. Split syntax highlighters, markdown processors, and code editors by language, mode, or worker boundary. Do not ship every grammar, theme, plugin, or editor worker for one small code block.
|
|
109
|
+
24. Avoid accidental Node polyfills in browser bundles. Do not fix `crypto`, `stream`, `buffer`, `process`, or `path` resolution errors by adding browser shims unless the browser feature truly needs them; prefer false fallbacks or server-only boundaries when possible.
|
|
110
|
+
25. Modernize browser targets only with product support evidence. Too-low Babel or TypeScript targets can inject helper and polyfill overhead; too-high targets can break real users.
|
|
111
|
+
26. Replace broad Babel polyfill imports. Avoid whole `core-js/stable` or blanket polyfill entrypoints when target-aware `preset-env` or explicit feature polyfills can cover the supported browsers.
|
|
112
|
+
27. Ensure dev-only branches fold at build time. `process.env.NODE_ENV`, `__DEV__`, `import.meta.env.DEV`, feature labels, and debug helpers must become constants for dead-code elimination to remove dev tooling.
|
|
113
|
+
28. Remove console calls safely. Do not blindly drop all console calls when arguments may have side effects. Prefer logging wrappers or pure-log configuration that preserves required argument behavior.
|
|
114
|
+
29. Avoid one giant vendor chunk. Manual chunk rules that put all `node_modules` in one vendor bundle can pull charts, editors, maps, and admin-only code into the first route and can change side-effect timing.
|
|
115
|
+
30. Check Vite and Rollup version semantics before copying old chunk advice. Confirm whether the project uses current `build.rollupOptions`, newer Rolldown aliases, `cssCodeSplit`, framework wrappers, and modulepreload behavior before changing chunk rules.
|
|
116
|
+
31. Check Vite modulepreload, preload, and prefetch behavior with timing evidence. Disable the modulepreload polyfill only when supported browser targets make that safe; avoid preloading or prefetching lazy route or widget chunks that are not needed soon, and use Resource Timing or configured evidence when priority changes are claimed.
|
|
117
|
+
32. Keep Tailwind and utility extraction finite. Avoid dynamic class string construction that production extraction cannot see, and avoid broad safelists that inflate CSS. Prefer complete static class strings or constrained maps.
|
|
118
|
+
33. Check inline asset thresholds. Large SVGs, fonts, or images inlined into JavaScript increase parse and transfer cost, couple cache lifetimes, and can force re-downloads when an app chunk changes; use separate resources unless the asset is small and truly critical.
|
|
119
|
+
34. Check long-term chunk cache stability. One source edit should not churn every chunk hash unless the graph contract requires it. Inspect manifest use, stable vendor or route chunks, and rarely-used heavy chunks when deployment cache behavior is part of the claim.
|
|
120
|
+
35. Label evidence honestly. If no configured bundle analyzer, coverage report, Resource Timing, budget, build output, or package-size proof exists, report the result as static import-graph risk or missing measurement, not a measured bundle reduction.
|
|
115
121
|
|
|
116
122
|
<!-- mustflow-section: postconditions -->
|
|
117
123
|
## Postconditions
|
|
118
124
|
|
|
119
125
|
- First-route JS, route chunks, shared vendor chunks, package entrypoints, imports, barrels, side effects, client/server boundaries, dynamic imports, heavy optional features, polyfills, targets, chunk rules, CSS extraction, and inline assets are explicit where relevant.
|
|
120
126
|
- CJS-heavy imports, broad package roots, hot-path barrels, missing subpath exports, unsafe side-effect metadata, missing PURE hints, broad client boundaries, eager heavy widgets, event-time libraries, icon catalogs, date locale packs, highlighter/editor language packs, Node polyfills, old browser targets, broad polyfills, un-folded dev code, unsafe console drops, giant vendor chunks, modulepreload spam, dynamic Tailwind classes, broad safelists, and large inline assets are fixed or reported.
|
|
121
|
-
- Bundle-size claims are backed by current configured evidence or labeled as static import-graph risk, manual-only measurement, or missing evidence.
|
|
127
|
+
- Bundle-size, unused-code, initial-JS, evaluate-time, long-task, preload, prefetch, and cache-stability claims are backed by current configured evidence or labeled as static import-graph risk, manual-only measurement, or missing evidence.
|
|
122
128
|
- Public import compatibility, CSS, polyfills, localization, accessibility, logging semantics, and framework behavior remain intact or are reported as tradeoffs.
|
|
123
129
|
|
|
124
130
|
<!-- mustflow-section: verification -->
|
|
@@ -152,7 +158,7 @@ Use the narrowest configured test, build, docs, release, or mustflow intent that
|
|
|
152
158
|
|
|
153
159
|
- Client bundle surface reviewed
|
|
154
160
|
- First-route JS, route chunk, and shared vendor evidence
|
|
155
|
-
- Import graph, package entry, side-effect, client boundary, lazy-loading, polyfill, target, chunk, CSS extraction,
|
|
161
|
+
- Import graph, package entry, side-effect, client boundary, coverage, lazy-loading, polyfill, target, chunk, CSS extraction, preload or prefetch, inline asset, and cache-stability ledgers
|
|
156
162
|
- Findings or fixes
|
|
157
163
|
- Evidence level: measured, configured-test evidence, static import-graph risk, manual-only, missing, or not applicable
|
|
158
164
|
- Command intents run
|
package/templates/default/locales/en/.mustflow/skills/frame-render-performance-review/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: skill.frame-render-performance-review
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 2
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: procedure
|
|
8
8
|
name: frame-render-performance-review
|
|
@@ -56,6 +56,7 @@ The review question is not "did we add `useMemo`?" It is "what work does the bro
|
|
|
56
56
|
|
|
57
57
|
- Interaction and frame ledger: affected interaction, route, viewport, target frame rate, user-visible symptom, expected INP or next-paint boundary, and whether the path runs during startup, scroll, input, animation, resize, or idle.
|
|
58
58
|
- DOM and layout ledger: node count, tree depth, affected subtree, list size, virtualization boundary, layout containment, geometry reads, geometry writes, reserved media slots, and layout-shift evidence.
|
|
59
|
+
- DOM update ledger: node attach count, observable mutation count, keyed update behavior, fragment or template usage, `innerHTML`, `replaceChildren`, focus, selection, scroll position, listener ownership, and event delegation.
|
|
59
60
|
- Style and CSS ledger: class or attribute toggles, selector complexity, global state classes, CSS custom property scope, runtime style injection, CSS animations, transitions, `will-change`, `contain`, `content-visibility`, and stacking or containing block side effects.
|
|
60
61
|
- Paint and compositing ledger: animated properties, repaint area, layer promotion, transform and opacity usage, canvas or SVG drawing, image/video/ad slots, shadows, filters, clipping, and expensive visual effects.
|
|
61
62
|
- Event and scheduling ledger: scroll, wheel, touch, pointer, resize, observer, timer, `requestAnimationFrame`, long task, worker, `OffscreenCanvas`, `scheduler.yield`, debounce, throttle, and cancellation behavior.
|
|
@@ -92,32 +93,37 @@ The review question is not "did we add `useMemo`?" It is "what work does the bro
|
|
|
92
93
|
8. Stop offscreen work, not only offscreen rendering. For skipped or hidden charts, maps, canvas, or media widgets, pause redraws, resize loops, observers, polling, and expensive updates while the widget is not visible.
|
|
93
94
|
9. Virtualize long lists. Large tables, chat logs, feeds, option lists, and grids should keep only the visible window plus buffer in the DOM when item count can grow.
|
|
94
95
|
10. Reduce DOM depth and breadth where it affects a hot render path. Deep wrapper chains and wide repeated structures increase style and layout propagation even when no single node looks expensive.
|
|
95
|
-
11.
|
|
96
|
-
12. Avoid
|
|
97
|
-
13.
|
|
98
|
-
14.
|
|
99
|
-
15.
|
|
100
|
-
16.
|
|
101
|
-
17.
|
|
102
|
-
18.
|
|
103
|
-
19.
|
|
104
|
-
20.
|
|
105
|
-
21.
|
|
106
|
-
22.
|
|
107
|
-
23.
|
|
108
|
-
24. Use `
|
|
109
|
-
25.
|
|
110
|
-
26.
|
|
111
|
-
27.
|
|
112
|
-
28.
|
|
113
|
-
29.
|
|
114
|
-
30.
|
|
96
|
+
11. Reduce DOM attachment and observable mutation count. `DocumentFragment` can make batch assembly cleaner, but it is not magic by itself; the win is fewer live DOM attachments, fewer layout-visible changes, and a narrower subtree to reconcile.
|
|
97
|
+
12. Avoid repeated hot-path `innerHTML` replacement. Replacing a large parent destroys node identity, focus, selection, scroll position, listener ownership, and browser reuse. Prefer keyed patching, targeted `replaceChildren`, template clones, or virtualization when only part of the subtree changed.
|
|
98
|
+
13. Use event delegation for large repeated regions. Lists, grids, tables, menus, and icon rows should usually attach one container listener and resolve the target with `closest()` instead of attaching thousands of per-node listeners.
|
|
99
|
+
14. Simplify selectors on hot or broad subtrees. Prefer simple class selectors over selectors that depend on deep descendants, complex siblings, expensive pseudo-classes, or global ancestor state.
|
|
100
|
+
15. Focus on invalidation scope, not selector folklore alone. Ask how many elements a class, attribute, CSS variable, or DOM mutation invalidates before spending time on cosmetic selector rewrites.
|
|
101
|
+
16. Avoid broad global class toggles. `body` or `html` state changes force wide style invalidation. Use the narrowest subtree root unless the state is truly global, such as theme.
|
|
102
|
+
17. Scope frequently changing CSS variables close to the affected subtree. Avoid changing `:root` custom properties on pointer move, scroll, drag, or animation. Use non-inheriting registered properties when project support and browser targets allow it.
|
|
103
|
+
18. Reserve media, ad, and embed geometry. Use width, height, `aspect-ratio`, or stable placeholders so image, video, iframe, and ad loads do not trigger layout shifts and repeated paint.
|
|
104
|
+
19. Keep LCP media and first-render discovery concerns routed to `web-render-performance-review`. In this skill, focus on whether loaded media shifts layout, repaints broad regions, or forces per-frame work.
|
|
105
|
+
20. Prefer native lazy loading for below-fold images and iframes when it covers the case. Avoid JS lazy loaders that add scroll handlers, observers, state churn, and rerenders without a project reason.
|
|
106
|
+
21. Use `IntersectionObserver` for visibility and infinite-scroll triggers. Do not calculate viewport intersection manually on every scroll event unless a browser limitation forces it.
|
|
107
|
+
22. Debounce or throttle high-frequency input only after deciding the interaction contract. Scroll, resize, pointermove, mousemove, and text input can flood async work, state updates, layout reads, and network calls; keep urgent visual feedback separate from delayed heavy work.
|
|
108
|
+
23. Use passive wheel, touch, and scroll listeners when the handler does not call `preventDefault()`. Do not mark listeners passive when the gesture intentionally cancels scrolling.
|
|
109
|
+
24. Use CSS `overscroll-behavior` before JavaScript scroll blocking for modals, drawers, and nested scroll containers. Keep JS scroll locks as the narrow fallback for focus and body-lock requirements.
|
|
110
|
+
25. Schedule visual writes with `requestAnimationFrame`. Do not use fixed `setTimeout(..., 16)` as a frame clock. Use the animation timestamp so high-refresh displays do not speed up motion.
|
|
111
|
+
26. Split long tasks. Work longer than one frame or around 50ms should yield between chunks, show urgent UI first, and move non-urgent analytics, cache cleanup, validation, or transformation out of the immediate interaction path.
|
|
112
|
+
27. Move DOM-free heavy computation off the main thread when the boundary cost is worth it. Filtering, sorting, diffing, crypto, markdown parsing, image preprocessing, and search indexing can move to a worker when data transfer and cancellation are defined.
|
|
113
|
+
28. Consider `OffscreenCanvas` for heavy canvas rendering when browser targets and architecture support it. Charts, whiteboards, maps, and image editors should not block input and paint if a worker boundary is practical.
|
|
114
|
+
29. Use `ResizeObserver` for element size changes. Avoid window resize handlers that read every card and write layout back in the same pass.
|
|
115
|
+
30. Avoid runtime CSS rule churn. Do not inject new style tags or rules during click, hover, drag, pointer move, or repeated list rendering. Use static classes and narrow CSS variables where dynamic values are needed.
|
|
116
|
+
31. Treat React `memo` as a rerender scope tool, not a cure. It fails when props are fresh objects, arrays, or functions each render. Prefer smaller component boundaries and stable primitive props.
|
|
117
|
+
32. Split React context by change frequency and audience. A fresh provider object rerenders all consumers of that context; do not put theme, auth, permissions, feature flags, and editor state into one object unless they change together.
|
|
118
|
+
33. Keep input updates urgent and heavy results deferred. Use deferred rendering or transitions for large filtered lists, charts, panels, or route changes when immediate input feedback matters more than full result freshness.
|
|
119
|
+
34. Narrow hydration. SSR can still hurt INP when the client hydrates too much at once. Hydrate only interactive islands early and defer low-priority regions by visibility, idle time, or route intent when the framework supports it.
|
|
120
|
+
35. Verify with the right evidence. Prefer DevTools Performance, paint flashing, layout shift regions, Selector Stats, Long Tasks API or `PerformanceObserver`, and INP flame evidence when configured or provided. If unavailable, report static risks and skipped measurement reasons.
|
|
115
121
|
|
|
116
122
|
<!-- mustflow-section: postconditions -->
|
|
117
123
|
## Postconditions
|
|
118
124
|
|
|
119
125
|
- The affected interaction, frame phase, DOM scope, style scope, layout reads/writes, paint or compositing cost, scheduling path, and framework render boundary are explicit where relevant.
|
|
120
|
-
- Forced synchronous layout, layout thrashing, layout-affecting animations, stale `will-change`, missing containment, unsafe `content-visibility`, offscreen background work, oversized DOM, complex selectors, broad global class toggles, root CSS variable churn, unreserved media geometry, JS scroll polling, non-passive listeners, JS scroll blocking, timer-based animation, long tasks, main-thread heavy computation, canvas main-thread cost, resize measurement loops, runtime CSS injection, ineffective memo, broad context rerenders, urgent heavy results, and full hydration cost are fixed or reported.
|
|
126
|
+
- Forced synchronous layout, layout thrashing, layout-affecting animations, stale `will-change`, missing containment, unsafe `content-visibility`, offscreen background work, oversized DOM, high mutation count, hot-path `innerHTML`, missing event delegation, complex selectors, broad style invalidation, broad global class toggles, root CSS variable churn, unreserved media geometry, JS scroll polling, high-frequency event floods, non-passive listeners, JS scroll blocking, timer-based animation, long tasks, main-thread heavy computation, canvas main-thread cost, resize measurement loops, runtime CSS injection, ineffective memo, broad context rerenders, urgent heavy results, and full hydration cost are fixed or reported.
|
|
121
127
|
- Rendering performance claims are backed by current configured evidence or labeled as static frame-risk, manual-only measurement, or missing evidence.
|
|
122
128
|
- Accessibility, focus, scroll intent, reduced motion, layout stability, privacy, and framework semantics remain intact or are reported as tradeoffs.
|
|
123
129
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: skill.hot-path-performance-review
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 6
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: procedure
|
|
8
8
|
name: hot-path-performance-review
|
|
@@ -57,6 +57,7 @@ The review question is not only "which line looks slow?" It is "how often does t
|
|
|
57
57
|
- Per-iteration cost: external calls, queries, filesystem reads, temporary arrays, object spreads, array spreads, concat copies, clones, DTO conversions, JSON parse/stringify, string splitting, logging, formatting, regex, sorting, hashing, image or crypto work, and lock hold time.
|
|
58
58
|
- Boundary ledger: DB, network, cache, filesystem, IPC, provider SDK, queue, logger, metrics sink, transaction, pool, mutex, thread, goroutine, task, or UI main thread crossed by the path.
|
|
59
59
|
- Data-size and tail-latency evidence when available: p50, p95, p99, row count, payload size, allocation count, query count, round-trip count, queue depth, pool wait, lock wait, cache hit rate, retry count, or timeout behavior.
|
|
60
|
+
- Runtime-pressure evidence when available: CPU profile, flame graph, browser DevTools Performance or Memory output, event-loop utilization, p95 or p99 event-loop delay, libuv worker-pool wait, stream backpressure, GC pause, heap growth, request-level I/O timing, or equivalent runtime metrics.
|
|
60
61
|
- Correctness boundaries: order, duplicates, idempotency, authorization, tenant isolation, consistency, partial failure, stale data, cancellation, retry semantics, and error behavior.
|
|
61
62
|
- Relevant command-intent contract entries for build, tests, docs, release checks, and mustflow validation.
|
|
62
63
|
|
|
@@ -85,18 +86,21 @@ The review question is not only "which line looks slow?" It is "how often does t
|
|
|
85
86
|
|
|
86
87
|
1. Count the path before judging it. State how many times the code can run after multiplying by requests, rows, items, retries, renders, jobs, pages, tenants, and nested loops.
|
|
87
88
|
2. Build a cost ledger with five columns: iteration count, data size, round-trip count, wait time, and copy or allocation count.
|
|
89
|
+
- For JavaScript hot paths, start from flame graph, DevTools Performance, Memory, Node CPU profile, event-loop delay, or GC evidence when it exists. Do not turn `for` versus `map` or syntax preference into the first fight while JSON parsing, sort comparators, DOM layout, GC, sync APIs, or external calls are unmeasured.
|
|
88
90
|
3. Check repeated external access first.
|
|
89
91
|
- A loop around DB, ORM, Redis, HTTP, RPC, filesystem, object storage, IPC, provider SDK, logging sink, or child process is the first suspect.
|
|
90
92
|
- ORM relation access can be a query even when it looks like a property read; treat lazy loading as guilty until query count evidence says otherwise.
|
|
91
93
|
4. Check multi-pass collection code. `map`, `filter`, `reduce`, `forEach`, LINQ, streams, iterator chains, and comprehensions can traverse data several times. Count passes and intermediate arrays before admiring the one-liner.
|
|
92
|
-
5. Check hidden quadratic lookup. A loop containing `includes`, `contains`, `find`, `indexOf`, `some`, `filter`, list membership, row-wise DataFrame work, or another linear scan is often `O(n^2)`. Prefer `Set`, `Map`, lookup tables, sorted merge, or database-side join when semantics match.
|
|
93
|
-
6. Preserve semantics when changing data structures. State order, duplicates, first or last winner, missing IDs, stable sort, tie-breakers, and authorization visibility before replacing arrays with maps or sets.
|
|
94
|
+
5. Check hidden quadratic lookup. A loop containing `includes`, `contains`, `find`, `indexOf`, `some`, `filter`, list membership, row-wise DataFrame work, or another linear scan is often `O(n^2)`. Prefer `Set`, `Map`, lookup tables, sorted merge, or database-side join when semantics match. For JavaScript, do not claim `Map` or `Set` is guaranteed O(1); treat keyed collections as average sublinear and still account for setup, memory, hashing, equality, and resize cost.
|
|
95
|
+
6. Preserve semantics when changing data structures. State order, duplicates, first or last winner, missing IDs, stable sort, tie-breakers, and authorization visibility before replacing arrays with maps or sets. Use `Set` for membership or insertion-order scalar dedupe, `Map` for key-to-latest or grouping, arrays for hard-capped ordered data, and sorted arrays for range or merge work.
|
|
94
96
|
7. Check database shape.
|
|
95
97
|
- Avoid unbounded `SELECT *`, full entity hydration, large JSON/TEXT/BLOB columns, `findAll`, row-by-row saves, and per-item relation access.
|
|
96
98
|
- Check whether predicates can use indexes. Functions around indexed columns, leading wildcard search, unselective filters, implicit casts, and mismatched sort order often defeat indexes.
|
|
97
99
|
- Treat large `OFFSET ... LIMIT ...` pages as linearly expensive unless the product truly needs arbitrary jumps. Prefer stable keyset or cursor pagination when possible.
|
|
98
100
|
8. Check transaction and lock hold time. Do not hold DB transactions, mutexes, synchronized blocks, distributed locks, or global locks across network calls, file uploads, JSON conversion, logs, long computation, or user-controlled waits.
|
|
99
101
|
9. Check async shape. Sequential `await` in a loop is still serial work. Independent I/O usually needs bounded concurrency, while `Promise.all` over thousands of items, unbounded goroutines, unbounded futures, or thread-pool bypasses can melt the shared resource.
|
|
102
|
+
- In browser and Node JavaScript, `async` does not make CPU work free. Large `response.json()` parsing, JSON stringify, diffing, markdown parsing, syntax highlighting, compression, crypto, sorting, and chart preparation still occupy the main thread or event loop unless streamed, chunked, or moved to a worker or backend.
|
|
103
|
+
- Pick a Promise aggregation strategy that matches failure behavior. `Promise.all` fails fast without cancelling siblings, so first-failure-stop behavior needs abort propagation, while partial-result workflows usually need `allSettled` or a project-specific result collector.
|
|
100
104
|
10. Reuse expensive clients and sessions. Per-request or per-item HTTP clients, DB clients, ORM clients, SDK clients, connection pools, TLS handshakes, regexes, date formatters, and thread pools are performance traps unless the API requires that lifecycle.
|
|
101
105
|
11. Check cache honesty. A cache needs a bounded key space, invalidation or TTL, max size, authorization dimensions, negative-cache policy, stale behavior, and cache stampede protection such as locking, singleflight, early refresh, or request coalescing.
|
|
102
106
|
12. Check logging and telemetry in hot paths. Repeated debug logs, eager log-string creation, whole-object serialization, high-cardinality metrics, and JSON formatting for discarded logs can dominate CPU and I/O during incidents.
|
|
@@ -105,22 +109,29 @@ The review question is not only "which line looks slow?" It is "how often does t
|
|
|
105
109
|
- Spread accumulation, `concat` in loops, repeated object spread while building indexes, and `cloneDeep` can copy growing data many times.
|
|
106
110
|
- `JSON.stringify` or `JSON.parse(JSON.stringify(...))` used for comparison, cloning, cache keys, or logging can dominate CPU and allocation while losing type semantics.
|
|
107
111
|
- Repeated `RegExp`, `Date`, `Intl`, formatter, `Set`, or `Map` construction inside hot loops should move outside the loop or become request-scoped only when ownership and memory bounds are clear.
|
|
112
|
+
- Repeated Array built-in borrowing on `arguments`, `NodeList`, `HTMLCollection`, or other array-like objects should convert once to a real array when the path repeatedly maps, filters, iterates, or indexes the same values.
|
|
113
|
+
- JavaScript hot arrays should stay dense and type-stable. Avoid holes, far-out index writes, out-of-bounds reads, mixed numeric and object values, repeated `shift()` or `unshift()`, and repeated middle `splice()` when a head index, typed array, or unordered swap-and-pop fits the semantics.
|
|
114
|
+
- Hot JavaScript objects should keep stable field order and avoid `delete`; use `Map` for dynamic keys and fixed-shape records for known fields.
|
|
115
|
+
- Object pooling is not a default allocation fix. Pool heavy buffers or large reusable arrays only after allocation evidence; ordinary short-lived objects may be cheaper for the generational collector.
|
|
108
116
|
14. Check string, JSON, DTO, and clone churn. Repeated string concatenation, `JSON.parse(JSON.stringify(...))`, `cloneDeep`, broad object spread, deep copy, repeated DTO-to-DTO conversion, and repeated serialization can move the bottleneck into "clean" mapping code.
|
|
109
117
|
15. Check large value passing and materialization. In value-copy languages or APIs, large structs, arrays, buffers, spread copies, full file reads, full JSON loads, all-pages accumulation, and eager `collect` calls can turn neat code into memory traffic.
|
|
110
118
|
16. Check regex, parsing, formatting, and locale work. Nested or ambiguous regexes, repeated date parsing, timezone conversion, numeric or locale formatting, and per-row formatter creation should be reviewed with worst-case input in mind.
|
|
119
|
+
- Check `Array.prototype.sort` comparators for repeated expensive work. `new Date`, `localeCompare` with options, normalization, derived score calculation, JSON serialization, path reads, or lookup-key construction inside a comparator can run many times per item; precompute keys before sorting when data size can grow.
|
|
111
120
|
17. Check CPU-heavy work in request or UI paths. Image resizing, compression, encryption, hashing, diffing, report generation, spreadsheet export, and search indexing may need batching, worker offload, queueing, or streaming, but only with clear backpressure and failure behavior.
|
|
112
|
-
18.
|
|
113
|
-
19.
|
|
114
|
-
20.
|
|
115
|
-
21.
|
|
116
|
-
22.
|
|
117
|
-
23.
|
|
121
|
+
18. For Node.js hot paths, separate CPU, event-loop delay, and I/O wait before prescribing workers or caches. `eventLoopUtilization` is not CPU percent; pair it with CPU profiles, p95 or p99 event-loop delay, request I/O timings, worker-pool signals, and GC evidence when available.
|
|
122
|
+
19. In Node.js, treat sync APIs, large JSON parse or stringify, REDOS-prone regexes, eager log serialization, recursive `process.nextTick()`, and whole-buffer stream handling as event-loop blockers even when the surrounding code uses `async`.
|
|
123
|
+
20. Check queues and workers. Moving work to a queue only moves the bottleneck unless consumers batch DB writes, bulk external calls where safe, bound retries, apply jitter, define poison-message handling, and expose backlog. Worker threads fit CPU-heavy JavaScript; they do not fix slow DB, HTTP, Redis, or object-storage I/O.
|
|
124
|
+
21. Check retry and timeout multiplication. A request with several calls, long timeouts, and several retries can become a tail-latency monster. Count worst-case wait and verify idempotency before adding more attempts.
|
|
125
|
+
22. Review tail behavior, not just average. p50 can look fine while p95 or p99 holds locks, connections, workers, event loops, or thread-pool slots long enough to hurt everyone else.
|
|
126
|
+
23. Add observability before large optimization when evidence is missing. Prefer query count, external-call count, payload bytes, allocation count, heap growth, GC pause, event-loop delay, cache hit rate, queue backlog, queue wait, pool wait, lock wait, retry count, and span timing over guessing.
|
|
127
|
+
24. Rank the likely payoff. Usually fix repeated external round trips, N+1 access, hidden quadratic scans, overfetching, wide transactions, lock hold time, allocation churn, unbounded fan-out, missing timeouts, and event-loop blockers before micro-optimizing arithmetic.
|
|
128
|
+
25. Label evidence honestly. If there is no configured benchmark, profile, trace, or production evidence, report the finding as static complexity or hot-path risk, not measured speedup. V8 evidence from Chrome or Node should be labeled as V8-specific until Safari, Firefox, or the project's other target runtimes are measured.
|
|
118
129
|
|
|
119
130
|
<!-- mustflow-section: postconditions -->
|
|
120
131
|
## Postconditions
|
|
121
132
|
|
|
122
133
|
- Hot path, cost multipliers, data size, round-trip count, wait points, and copy or allocation points are explicit.
|
|
123
|
-
- N+1 queries, repeated external calls, hidden quadratic scans, unbounded materialization, temporary-array chains, spread or concat copy accumulation, sequential waits, unbounded fan-out, per-item client creation, broad logging, repeated parsing or serialization, allocation churn, and lock or transaction hold time are fixed or reported.
|
|
134
|
+
- N+1 queries, repeated external calls, hidden quadratic scans, unbounded materialization, temporary-array chains, spread or concat copy accumulation, sequential waits, unbounded fan-out, large JSON parse or stringify, CPU-heavy async illusions, per-item client creation, broad logging, repeated parsing or serialization, allocation churn, event-loop blocking, worker-pool starvation, stream backpressure gaps, and lock or transaction hold time are fixed or reported.
|
|
124
135
|
- Cache, queue, retry, timeout, batching, bulk-write, concurrency, pagination, projection, index-fit, and observability behavior are explicit where relevant.
|
|
125
136
|
- Correctness, authorization, tenant isolation, ordering, duplicates, partial failure, cancellation, and stale-data behavior remain intact or are called out as tradeoffs.
|
|
126
137
|
- Performance claims are backed by configured evidence or labeled as static review risk.
|
|
@@ -157,6 +168,7 @@ Use the narrowest configured test, build, docs, release, or mustflow intent that
|
|
|
157
168
|
- Cost ledger: iteration count, data size, round trips, wait time, copy or allocation count
|
|
158
169
|
- Repeated external access, N+1, hidden quadratic scans, and multi-pass collection findings
|
|
159
170
|
- DB, pagination, index-fit, transaction, lock, async, client reuse, cache, queue, retry, timeout, logging, temporary arrays, spread or concat accumulation, serialization, clone, regex, parsing, formatting, allocation, GC, and CPU-heavy work checked where relevant
|
|
171
|
+
- Runtime pressure: CPU profile, event-loop delay, event-loop utilization, worker-pool, stream backpressure, and I/O wait checked where relevant
|
|
160
172
|
- Optimization or review recommendation
|
|
161
173
|
- Evidence level: measured, configured-test evidence, static complexity risk, manual-only, missing, or not applicable
|
|
162
174
|
- Command intents run
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: skill.javascript-code-change
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 6
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: procedure
|
|
8
8
|
name: javascript-code-change
|
|
@@ -28,7 +28,7 @@ metadata:
|
|
|
28
28
|
<!-- mustflow-section: purpose -->
|
|
29
29
|
## Purpose
|
|
30
30
|
|
|
31
|
-
Preserve JavaScript module, runtime, package entry, Promise, cleanup, dependency, and test boundaries.
|
|
31
|
+
Preserve JavaScript module, runtime, package entry, Promise, cleanup, dependency, data-shape, hot-path, and test boundaries.
|
|
32
32
|
|
|
33
33
|
<!-- mustflow-section: use-when -->
|
|
34
34
|
## Use When
|
|
@@ -48,6 +48,8 @@ Preserve JavaScript module, runtime, package entry, Promise, cleanup, dependency
|
|
|
48
48
|
- `package.json`, lockfile, engines, module `type`, package `exports`, bundler config, lint config, test config, and relevant entrypoints.
|
|
49
49
|
- Target runtime: browser, Node, worker, edge, Bun, or multi-runtime boundary.
|
|
50
50
|
- Runtime adapter files, source entrypoints, package docs examples, and build output layout when package entry or runtime support changes.
|
|
51
|
+
- Data shape and hot-path surface when collection lookup, grouping, sorting, queueing, array mutation, object shape, typed arrays, allocation, or GC pressure changes.
|
|
52
|
+
- JavaScript engine evidence when performance is claimed: Chrome or Node V8 profile, browser DevTools Performance or Memory output, Node CPU profile, event-loop delay, GC evidence, or an explicit note that Safari and Firefox behavior still needs project-specific measurement.
|
|
51
53
|
- Async ownership and cleanup surface when Promises, retries, timers, event listeners, streams, abort signals, background tasks, startup, shutdown, or external I/O change.
|
|
52
54
|
- Configured verification intents.
|
|
53
55
|
|
|
@@ -66,6 +68,7 @@ Preserve JavaScript module, runtime, package entry, Promise, cleanup, dependency
|
|
|
66
68
|
- Prefer existing dependencies and platform APIs over adding a new dependency.
|
|
67
69
|
- Keep runtime-specific APIs behind platform adapters or runtime-specific entrypoints.
|
|
68
70
|
- Keep package entry changes synchronized with declarations, docs examples, build output, and consumer smoke coverage when available.
|
|
71
|
+
- Prefer semantic data-shape changes over folklore micro-optimizations: use `Set` or `Map` for repeated lookup only when the setup cost is paid back, use objects for fixed-shape records, and keep order, duplicate, and winner semantics explicit.
|
|
69
72
|
|
|
70
73
|
<!-- mustflow-section: procedure -->
|
|
71
74
|
## Procedure
|
|
@@ -95,14 +98,27 @@ Preserve JavaScript module, runtime, package entry, Promise, cleanup, dependency
|
|
|
95
98
|
12. For package entry changes, check source entrypoints, build output layout, docs import examples, TypeScript or declaration settings, bundler config, and consumer-style tests. Report missing Node ESM, Node CJS, browser bundle, edge, Bun, or TypeScript consumer verification when those targets are claimed but no configured intent exists.
|
|
96
99
|
13. Treat build targets as syntax/output compatibility, not as permission to use a runtime API. A browser or edge build target does not make Node filesystem, process, Buffer, or native APIs safe.
|
|
97
100
|
14. Treat implicit globals as failures.
|
|
98
|
-
15. Do not
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
15. Do not treat `async`, `await`, or Promise syntax as a thread or CPU offload boundary. CPU-heavy parsing, sorting, diffing, compression, crypto, markdown rendering, syntax highlighting, chart preparation, and large JSON work still block the browser main thread or Node event loop unless moved to a real worker, backend job, streaming pipeline, or bounded chunked scheduler.
|
|
102
|
+
- When optimizing JavaScript syntax or data shape, classify the evidence by engine. V8 evidence from Chrome or Node is useful, but it does not prove Safari or Firefox behavior without measurement in the target browser/runtime.
|
|
103
|
+
16. Do not claim JavaScript `Map`, `Set`, `WeakMap`, or `WeakSet` are guaranteed O(1). Treat them as average sublinear keyed collections, then choose them only when repeated lookups, dynamic keys, object keys, or membership checks justify the setup and memory cost.
|
|
104
|
+
17. Use `Map` for dynamic, user-controlled, object-identity, or frequently added and removed keys. Use plain objects for fixed-shape records with known fields. Avoid turning hot objects into ad hoc dictionaries.
|
|
105
|
+
18. Keep hot object shapes stable. Create the same fields in the same order for the same record kind, prefer sentinel values such as `null` for optional fields, and avoid `delete` on hot objects unless dynamic-key behavior is the real requirement and a `Map` is more honest. In V8-heavy Chrome or Node paths, treat late property addition and inconsistent field order as engine-shape risks unless a profile proves they are outside the hot path.
|
|
106
|
+
19. Keep arrays dense and type-stable in hot paths. Avoid `delete array[i]`, far-out index writes, partially-filled `new Array(n)`, mixed numeric and object values, and out-of-bounds reads. Prefer `push` when values arrive sequentially, and consider `TypedArray` for numeric buffers, vectors, pixels, counters, and other fixed numeric data. Do not mix small integers, doubles, objects, holes, and sentinel values casually in arrays that execute inside render, request, parser, or worker loops.
|
|
107
|
+
20. Avoid JavaScript array operations that move or rebuild large collections in hot paths. Use a head-index queue instead of repeated `shift()` or `unshift()`, swap-with-last plus `pop()` for unordered deletes instead of repeated middle `splice()`, and avoid `filter().map().flatMap()` chains when intermediate arrays dominate allocation.
|
|
108
|
+
21. Treat sorting as ordering work, not lookup work. Use `Map` for exact repeated lookup, sorted arrays plus binary search or merge for range work, decorate-sort-undecorate when the comparator computes expensive keys, and a heap or bounded top-k structure for repeated priority extraction. Keep comparators cheap: precompute `Date`, locale, normalized string, JSON, path, or score keys instead of recalculating them for every comparison call.
|
|
109
|
+
22. Use `WeakMap` or `WeakSet` for metadata tied to object lifetime, such as DOM nodes, AST nodes, request objects, sockets, or component instances. Do not keep those objects alive in a normal `Map` unless retention is intentional and bounded.
|
|
110
|
+
23. Prefer rest parameters over `arguments` in new hot-path code. Convert `arguments`, `NodeList`, `HTMLCollection`, and other array-like objects to a real array once when repeated `map`, `filter`, `forEach`, iteration, or indexing work follows. Pool only heavy buffers, arrays, or repeatedly allocated expensive objects after allocation evidence; do not pool ordinary short-lived records just to look optimized.
|
|
111
|
+
24. Do not discard Promises. Every Promise-producing call must be awaited, returned, joined, or intentionally supervised by the project's detached-task pattern.
|
|
112
|
+
25. Do not leave `.map(async ...)` unjoined. Join with the established Promise aggregation or bounded-concurrency helper when parallel work is intended.
|
|
113
|
+
26. Do not use unbounded parallelism for large external I/O fan-out. Use the local concurrency limit pattern when the workload touches HTTP, database, filesystem, queue, AI, or other external services.
|
|
114
|
+
27. Avoid accidental serial waits over independent work. A `for...of` loop with `await` is correct for ordered dependencies, rate spacing, or shared mutable state, but independent HTTP, filesystem, database, or worker tasks should use the local bounded-concurrency pattern instead of one slow item holding the whole line hostage.
|
|
115
|
+
28. Choose Promise aggregation by failure policy. `Promise.all` fails fast but does not cancel remaining work by itself; use `allSettled` when every result matters, `any` when the first success wins, and explicit `AbortController` or local cancellation when first failure should stop underlying work.
|
|
116
|
+
29. Treat `await fetch()` and `response.json()` as two different costs. The network wait is async, but large body buffering and JSON parse can block the main thread or event loop; prefer pagination, projection, NDJSON, streaming parsers, worker parsing, or server-side shaping when payloads can grow. Cache `Intl.NumberFormat`, `Intl.DateTimeFormat`, regexes, and similar formatter/parser objects outside hot loops or render paths when ownership and locale inputs are stable.
|
|
117
|
+
30. Propagate cancellation when the operation can outlive a request, job, stream, retry loop, timeout, or user action. Accept and forward `AbortSignal` or the repository's established cancellation token when available.
|
|
118
|
+
31. Do not implement timeout as a caller-only race that leaves the real work running. Timeout behavior must cancel or abort the underlying operation when the API supports it.
|
|
119
|
+
32. Put cleanup in a deterministic path. Timers, event listeners, stream readers, Node streams, temp files, locks, transactions, subscriptions, and shutdown drains need success, failure, timeout, and cancellation cleanup coverage when touched.
|
|
120
|
+
33. Do not build package exports or dependency changes without checking consumers, tests, and docs examples.
|
|
121
|
+
34. Choose configured verification intents that cover lint, build, tests, package entry, runtime behavior, async rejection handling, cancellation, cleanup, and hot-path data-shape semantics when available.
|
|
106
122
|
|
|
107
123
|
<!-- mustflow-section: postconditions -->
|
|
108
124
|
## Postconditions
|
|
@@ -110,8 +126,9 @@ Preserve JavaScript module, runtime, package entry, Promise, cleanup, dependency
|
|
|
110
126
|
- Runtime and module boundaries are explicit.
|
|
111
127
|
- Promise failures are not hidden.
|
|
112
128
|
- Runtime-specific APIs do not leak into shared, browser, edge, or package entry code.
|
|
129
|
+
- Collection and object-shape changes preserve lookup, ordering, duplicate, lifecycle, and allocation semantics.
|
|
113
130
|
- Package entry changes are synchronized with tests or reported as unverified.
|
|
114
|
-
- Async cancellation and cleanup behavior
|
|
131
|
+
- Async cancellation, failure policy, payload parsing, CPU offload, and cleanup behavior are covered or reported as remaining risk.
|
|
115
132
|
- No unnecessary dependency was added.
|
|
116
133
|
|
|
117
134
|
<!-- mustflow-section: verification -->
|
|
@@ -145,6 +162,7 @@ Report missing browser, Node, edge, Bun, TypeScript-consumer, package-entry, asy
|
|
|
145
162
|
- Boundary checked
|
|
146
163
|
- Runtime and module notes
|
|
147
164
|
- Async and dependency notes
|
|
165
|
+
- Data-shape and hot-path notes
|
|
148
166
|
- Files changed
|
|
149
167
|
- Command intents run
|
|
150
168
|
- Skipped checks and reasons
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: skill.memory-lifetime-review
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 3
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: procedure
|
|
8
8
|
name: memory-lifetime-review
|
|
@@ -80,6 +80,7 @@ The question is not only "where was it allocated?" The stronger review question
|
|
|
80
80
|
- Refactor setup and cleanup into a shared lifecycle boundary when it prevents duplicate registration or forgotten teardown.
|
|
81
81
|
- Add focused tests, fixtures, probes, or docs that prove cleanup symmetry, bounded retention, repeated lifecycle behavior, or native-resource disposal when repository evidence supports them.
|
|
82
82
|
- Do not hide leak warnings by raising listener limits, disabling strict lifecycle checks, adding finalizers as primary cleanup, or weakening tests.
|
|
83
|
+
- Do not add object pools as a default leak or GC fix. Pool only heavy buffers, large arrays, native handles, or repeatedly allocated expensive objects after allocation evidence shows churn; ordinary short-lived records are often cheaper to let the generational collector reclaim.
|
|
83
84
|
- Do not use weak references as a design cover-up when the real owner and cleanup point should be explicit.
|
|
84
85
|
|
|
85
86
|
<!-- mustflow-section: procedure -->
|
|
@@ -110,6 +111,8 @@ The question is not only "where was it allocated?" The stronger review question
|
|
|
110
111
|
- Producer-consumer queues need a capacity, drop or backpressure policy, timeout, and consumer shutdown path.
|
|
111
112
|
10. Check language and runtime traps where applicable.
|
|
112
113
|
- JavaScript and TypeScript: `addEventListener`, EventEmitter listeners, `setMaxListeners`, timers, intervals, unresolved promises, `AbortSignal`, React effects, ref arrays, module caches, maps, and logging queues.
|
|
114
|
+
- JavaScript metadata: use `WeakMap` or `WeakSet` for metadata attached to DOM nodes, AST nodes, request objects, sockets, or component instances when the metadata should die with the object; use a normal `Map` only when retention is intentional and bounded.
|
|
115
|
+
- JavaScript allocation and GC: avoid turning small short-lived records into long-lived pooled objects without evidence; check large temporary arrays, buffers, object graphs, array method chains, and old-generation retention before tuning `--max-old-space-size` or `--max-semi-space-size`.
|
|
113
116
|
- React and similar UI runtimes: effects that touch the outside world need cleanup that reverses setup; ref callbacks and registries must remove old nodes and survive strict double-invocation checks.
|
|
114
117
|
- Android: ViewModel or application-scope objects must not retain Activity, Fragment, View, lifecycle owner, or short-lived context; use lifecycle cleanup such as `onCleared` where appropriate.
|
|
115
118
|
- Java and Kotlin: thread pools plus `ThreadLocal`, static caches, listener registries, executors, cursors, streams, and closeable resources need explicit release.
|
|
@@ -131,7 +134,8 @@ The question is not only "where was it allocated?" The stronger review question
|
|
|
131
134
|
- Core dump, exact binary, symbols, build id, shared library list, process maps, allocator state, failing input, and deployment version can be the only evidence for a memory fault.
|
|
132
135
|
- If those artifacts are unavailable or manual-only, report that boundary instead of implying the crash was diagnosed from logs alone.
|
|
133
136
|
15. Reject finalizers as the main plan. Finalizers, destructors, drop hooks, or weak callbacks can be last-resort diagnostics or safety nets, but the review should still identify deterministic cleanup for resources and reference removal.
|
|
134
|
-
16.
|
|
137
|
+
16. Separate allocation churn from retained memory. High allocation rate, GC pauses, retained heap, external memory, and RSS growth point to different fixes. Prefer allocation timeline, heap snapshot, retaining-path, `--trace-gc`, sanitizer, or runtime memory evidence when configured; report unconfigured tools as manual evidence instead of guessing from RSS alone.
|
|
138
|
+
17. Add a repeated-lifecycle proof when feasible. Prefer a focused test or probe that repeats the risky lifecycle, then asserts listener count, registry size, cache size, goroutine/task completion, handle closure, queue depth, or retained object count. If heap snapshots, leak profilers, sanitizer runs, memory-checker runs, fuzzers, core dump inspection, or platform-specific diagnostics are not configured intents, report them as manual evidence gaps instead of running raw commands.
|
|
135
139
|
|
|
136
140
|
<!-- mustflow-section: postconditions -->
|
|
137
141
|
## Postconditions
|
|
@@ -139,6 +143,7 @@ The question is not only "where was it allocated?" The stronger review question
|
|
|
139
143
|
- Every setup site has a cleanup owner, cleanup trigger, and repeated-path behavior, or the missing evidence is reported.
|
|
140
144
|
- Long-lived owners no longer retain short-lived objects beyond their intended lifecycle, or the remaining retention is intentional and bounded.
|
|
141
145
|
- Caches, queues, registries, debug stores, and logging or telemetry buffers have capacity, eviction, truncation, or copied-value boundaries where they can grow.
|
|
146
|
+
- Weak metadata, object pooling, allocation churn, GC flags, and retained-heap claims are backed by ownership or diagnostic evidence rather than folklore.
|
|
142
147
|
- Async, stream, worker, goroutine, thread, and native-resource paths have deterministic cancellation, close, shutdown, or release behavior where the platform supports it.
|
|
143
148
|
- Native or low-level memory fault analysis names the first invalid access evidence or reports the missing diagnostic boundary instead of blaming the final crash line.
|
|
144
149
|
- Tests or configured verification cover the highest-risk repeated lifecycle when feasible.
|
|
@@ -177,6 +182,7 @@ Use the narrowest configured test, build, docs, release, or mustflow intent that
|
|
|
177
182
|
- Retainer paths found or ruled out
|
|
178
183
|
- Long-lived owners and short-lived objects checked
|
|
179
184
|
- Timers, listeners, subscriptions, streams, workers, goroutines, threads, native handles, caches, queues, registries, closures, and logs checked where relevant
|
|
185
|
+
- Weak metadata, object pooling, allocation churn, and GC diagnostics checked where relevant
|
|
180
186
|
- First invalid access, diagnostic build axis, dangling ownership, fuzzing or core-dump evidence where relevant
|
|
181
187
|
- Cleanup symmetry changes made or recommended
|
|
182
188
|
- Repeated-lifecycle proof: configured, manual-only, missing, or not applicable
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
mustflow_doc: skill.node-code-change
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 4
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: procedure
|
|
8
8
|
name: node-code-change
|
|
9
|
-
description: Apply this skill when Node.js runtime code, package manager ownership, module format, package entry metadata, native dependencies, Node test runner behavior, TypeScript execution mode, or deployment runtime support is created or changed.
|
|
9
|
+
description: Apply this skill when Node.js runtime code, server performance behavior, event-loop blocking, libuv worker-pool use, package manager ownership, module format, package entry metadata, native dependencies, Node test runner behavior, TypeScript execution mode, or deployment runtime support is created or changed.
|
|
10
10
|
metadata:
|
|
11
11
|
mustflow_schema: "1"
|
|
12
12
|
mustflow_kind: procedure
|
|
@@ -29,12 +29,13 @@ metadata:
|
|
|
29
29
|
<!-- mustflow-section: purpose -->
|
|
30
30
|
## Purpose
|
|
31
31
|
|
|
32
|
-
Preserve the actual Node.js runtime, module, package manager, TypeScript execution, test runner, package entry, native dependency, and
|
|
32
|
+
Preserve the actual Node.js runtime, module, package manager, TypeScript execution, test runner, package entry, native dependency, deployment, event-loop, worker-pool, and server-performance boundaries.
|
|
33
33
|
|
|
34
34
|
<!-- mustflow-section: use-when -->
|
|
35
35
|
## Use When
|
|
36
36
|
|
|
37
37
|
- Node.js runtime code, `node:*` APIs, `process`, `Buffer`, streams, workers, child processes, native addons, Node permission flags, Node test runner behavior, package entry metadata, or deployment runtime support changes.
|
|
38
|
+
- Node server code, CLI code, workers, request handlers, stream handlers, serializers, parsers, regex validation, crypto, zlib, filesystem, DNS, child process, or CPU-heavy JavaScript changes can affect event-loop delay, event-loop utilization, libuv worker-pool pressure, CPU profiles, GC, or p95/p99 latency.
|
|
38
39
|
- `package.json` Node fields change, including `engines.node`, `devEngines`, `packageManager`, `type`, `main`, `exports`, `imports`, `types`, `typesVersions`, `files`, `bin`, `sideEffects`, or `workspaces`.
|
|
39
40
|
- Node version signals, CI Node setup, Docker Node base images, serverless Node runtime settings, Corepack usage, npm, pnpm, Yarn, or lockfile ownership changes.
|
|
40
41
|
- The task proposes native Node TypeScript execution, ESM/CJS conversion, conditional exports, package manager migration, or Node built-in test runner migration.
|
|
@@ -55,6 +56,7 @@ Preserve the actual Node.js runtime, module, package manager, TypeScript executi
|
|
|
55
56
|
- Module and package metadata: nearest `package.json#type`, file extensions, `main`, `module`, `exports`, `imports`, `types`, `typings`, `typesVersions`, `files`, `bin`, `sideEffects`, and documented import paths.
|
|
56
57
|
- TypeScript and loader signals: `tsconfig*.json`, `tsx`, `ts-node`, SWC, Babel, Vite, tsup, esbuild, Node native type stripping, path aliases, declaration output, and test or build transforms.
|
|
57
58
|
- Test, native, and deployment signals: package scripts, test runner config, `node:test` usage, native dependency indicators such as `.node`, `binding.gyp`, `node-gyp`, lifecycle scripts, optional dependencies, serverless or edge config, and command contract entries.
|
|
59
|
+
- Node performance signals: `perf_hooks` usage, event-loop utilization, event-loop delay histograms, CPU profile or flame graph setup, request-level I/O timings, `--trace-sync-io`, worker-thread pools, `UV_THREADPOOL_SIZE`, stream backpressure, large JSON handling, regex validation, GC or heap flags, and timeout or cancellation paths.
|
|
58
60
|
|
|
59
61
|
<!-- mustflow-section: preconditions -->
|
|
60
62
|
## Preconditions
|
|
@@ -99,7 +101,16 @@ Preserve the actual Node.js runtime, module, package manager, TypeScript executi
|
|
|
99
101
|
17. Inspect native and install-sensitive dependencies when package metadata or runtime imports touch `.node`, `binding.gyp`, `node-gyp`, `preinstall`, `install`, `postinstall`, `prepare`, optional dependencies, peer dependencies, OS, CPU, libc, or Node ABI boundaries.
|
|
100
102
|
18. Treat optional dependencies and optional peers as absent until code handles absence. Do not require optional packages directly without fallback or error handling that matches the existing project pattern.
|
|
101
103
|
19. Treat the Node permission model as a trusted-code seatbelt, not a sandbox for untrusted code. If permission flags are introduced or changed, map required filesystem, network, child process, worker, native addon, WASI, inspector, and temporary directory access explicitly.
|
|
102
|
-
20.
|
|
104
|
+
20. Separate Node performance bottlenecks before choosing a fix. Use available `perf_hooks` or configured evidence to distinguish JavaScript CPU, event-loop delay, external I/O wait, libuv worker-pool saturation, stream backpressure, and GC or allocation churn. Event-loop utilization is not CPU percent; high ELU with low CPU can still mean sync blocking.
|
|
105
|
+
21. Prefer CPU profiles or flame graphs over timing logs for CPU-heavy Node paths. Use profile or configured evidence for parsing, validation, rendering, hashing, compression, crypto, diffing, report generation, sorting, JSON work, formatter creation, or AST work; log timers alone rarely prove the hot stack.
|
|
106
|
+
22. Treat event-loop delay as a tail metric. Check p95 and p99 delay when evidence exists, not only averages. A rare 800ms block can dominate user-visible latency while average delay looks clean.
|
|
107
|
+
23. Keep server code off synchronous Node APIs after startup. `fs`, crypto, zlib, DNS, and child-process sync calls block the event loop; large `JSON.parse` or `JSON.stringify`, catastrophic regex, expensive sort comparators, repeated `Intl` or `Date` formatter construction, and eager logging serialization can do the same even without `Sync` in the name.
|
|
108
|
+
24. Use worker threads for CPU-bound JavaScript or native-bound work, not as a cure for slow DB, HTTP, Redis, or filesystem waits. Slow external I/O needs query, pool, timeout, cancellation, backpressure, batching, or provider-boundary fixes.
|
|
109
|
+
25. Treat the libuv worker pool as shared. Async `fs`, crypto, zlib, and `dns.lookup` can starve each other; `UV_THREADPOOL_SIZE` is a startup environment decision, not a runtime patch hidden inside application code.
|
|
110
|
+
26. Preserve stream backpressure. For large files, uploads, exports, compression, proxying, and generated responses, prefer pipeline-style boundaries with error handling over whole-buffer reads or unchecked writes.
|
|
111
|
+
27. Avoid `process.nextTick()` starvation. Recursive next-tick queues can prevent I/O polling; long work should be batched with event-loop yielding that lets I/O progress.
|
|
112
|
+
28. Include GC and allocation in Node CPU diagnosis. A profile dominated by V8, GC, allocation, string/Buffer copies, or JSON work usually needs allocation reduction, streaming, chunking, pagination, bounded caches, or worker offload before heap-size tuning.
|
|
113
|
+
29. Choose configured verification intents that cover lint, build, tests, package metadata, release-sensitive package output, docs examples, and mustflow contract checks when available. Report missing consumer fixture, ESM, CJS, TypeScript consumer, native dependency, deployment, permission, profiler, event-loop-delay, worker-pool, stream, or performance verification.
|
|
103
114
|
|
|
104
115
|
<!-- mustflow-section: postconditions -->
|
|
105
116
|
## Postconditions
|
|
@@ -109,6 +120,7 @@ Preserve the actual Node.js runtime, module, package manager, TypeScript executi
|
|
|
109
120
|
- Native TypeScript execution is not mistaken for typecheck, declaration emit, or a full build pipeline.
|
|
110
121
|
- Node-only APIs do not leak into browser, edge, Bun, or shared package surfaces unintentionally.
|
|
111
122
|
- Native dependency, lifecycle, optional dependency, and permission-model risks are handled or reported.
|
|
123
|
+
- Event-loop blocking, CPU profile, libuv worker-pool, stream backpressure, large JSON, regex REDOS, worker-thread fit, `process.nextTick()` starvation, and GC or allocation risks are handled or reported when touched.
|
|
112
124
|
|
|
113
125
|
<!-- mustflow-section: verification -->
|
|
114
126
|
## Verification
|
|
@@ -123,7 +135,7 @@ Use configured oneshot command intents when available:
|
|
|
123
135
|
- `test_release`
|
|
124
136
|
- `mustflow_check`
|
|
125
137
|
|
|
126
|
-
Report missing ESM/CJS consumer, declaration output, package artifact, frozen install, native dependency, deployment runtime, permission-model,
|
|
138
|
+
Report missing ESM/CJS consumer, declaration output, package artifact, frozen install, native dependency, deployment runtime, permission-model, runner-specific, CPU-profile, event-loop-delay, worker-pool, stream-backpressure, or performance verification intents when those surfaces change.
|
|
127
139
|
|
|
128
140
|
<!-- mustflow-section: failure-handling -->
|
|
129
141
|
## Failure Handling
|
|
@@ -133,6 +145,7 @@ Report missing ESM/CJS consumer, declaration output, package artifact, frozen in
|
|
|
133
145
|
- If a package entry change blocks a documented or previously supported import path, restore compatibility or report the breaking-change requirement.
|
|
134
146
|
- If native Node TypeScript execution fails, repair the build/loader boundary instead of weakening typecheck or deleting the TypeScript pipeline.
|
|
135
147
|
- If native dependency installation or optional dependency behavior is unclear, classify the change as release-sensitive and report the missing install or runtime evidence.
|
|
148
|
+
- If a Node performance claim lacks event-loop, CPU, I/O, worker-pool, stream, or GC evidence, label it as static risk or missing measurement instead of reporting a measured speedup.
|
|
136
149
|
|
|
137
150
|
<!-- mustflow-section: output-format -->
|
|
138
151
|
## Output Format
|
|
@@ -141,6 +154,7 @@ Report missing ESM/CJS consumer, declaration output, package artifact, frozen in
|
|
|
141
154
|
- Module and package entry notes
|
|
142
155
|
- TypeScript execution and test runner notes
|
|
143
156
|
- Native, lifecycle, deployment, or permission risks
|
|
157
|
+
- Event-loop, CPU, worker-pool, stream, JSON, regex, next-tick, or GC risks
|
|
144
158
|
- Files changed
|
|
145
159
|
- Command intents run
|
|
146
160
|
- Skipped checks and reasons
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: skill.performance-budget-check
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 24
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: procedure
|
|
8
8
|
name: performance-budget-check
|
|
@@ -55,6 +55,9 @@ Prefer removing unnecessary work over making unnecessary work slightly faster. A
|
|
|
55
55
|
- Performance surface: request path, command path, render path, build step, batch job, queue, cache, database path, filesystem path, IPC/RPC boundary, or test scheduler.
|
|
56
56
|
- Hot-path shape: expected call frequency, input size, growth direction, nested loops, external round trips, payload size, rendered node count, allocation rate, data layout, branch predictability, lock or pool contention, queue depth, and whether the path runs during user input or startup.
|
|
57
57
|
- Time breakdown evidence: user-visible moment, wall-time split across browser, network, application CPU, DB, cache, external API, queue, filesystem, IPC, serialization, compression, logging, and render work, plus CPU time versus wait time when available.
|
|
58
|
+
- Runtime and browser execution evidence: initial JavaScript parse, compile, evaluate, hydration, long tasks, event-loop utilization, p95 or p99 event-loop delay, CPU profile, libuv worker-pool pressure, stream backpressure, GC pause, and request-level I/O timings when relevant.
|
|
59
|
+
- JavaScript engine evidence boundary when relevant: whether claims come from Chrome or Node V8, browser DevTools Performance or Memory output, Node CPU profiles, Safari or Firefox traces, or static complexity review only.
|
|
60
|
+
- Main-thread contention evidence for browser paths: microtask pressure, large JSON parsing, DOM mutation count, forced layout, style invalidation scope, animation frame work, high-frequency event handlers, idle work, worker offload boundary, Long Tasks API entries, and Performance panel traces when available.
|
|
58
61
|
- Measurement method or evidence: configured command intent, profiler output, query count, runtime log, trace span, resource metric, benchmark, complexity analysis, or reason the metric is unavailable.
|
|
59
62
|
- Baseline and post-change result when measurable under comparable constraints, including whether the evidence reflects average, p95, p99, cold start, warm cache, realistic data size, or local-only behavior.
|
|
60
63
|
- Saturation evidence: utilization, backlog or queue depth, pool wait, lock wait, retry or error rate, tenant or data skew, and good-period versus bad-period comparison when available.
|
|
@@ -91,13 +94,16 @@ Prefer removing unnecessary work over making unnecessary work slightly faster. A
|
|
|
91
94
|
- Decompose elapsed time before touching code. Split request, render, command, or job wall time across browser, network, server routing, authorization, application CPU, DB, cache, external APIs, queue wait, filesystem, IPC, serialization, compression, logging, response download, and render. Distinguish CPU time from wait time; high wall time with low CPU means the path is waiting.
|
|
92
95
|
- Find queueing and saturation, not just high utilization. Check utilization, backlog, queue depth, pool waits, lock waits, retry or error rate, and p95/p99 latency together. Compare good periods to bad periods, affected tenants or data sizes, specific workers or replicas, and cold versus warm cache before declaring the bottleneck.
|
|
93
96
|
2. Rank the likely return on effort before choosing a technique. In typical web or service paths, first check DB/API round-trip count, slow query plans, repeated reads that could be safely cached, work that does not need to block the response, static or media delivery, response payload shape, and then CPU or allocation micro-optimizations. Escalate algorithmic or runtime work early only when the measured hot path is CPU-heavy, data-processing-heavy, render-loop-heavy, or clearly quadratic.
|
|
94
|
-
3. Do not stop at asymptotic complexity. For `O(N)`, check sequential versus pointer-chasing access, working-set size, branch predictability, per-item allocation, string or Unicode work, runtime dispatch, logging, locks, and external round trips. For `O(log N)`, check node locality, comparator cost, key size, pointer jumps, and branch behavior. For `O(1)` maps or caches, check hash cost, key equality, load factor, resize or rehash spikes, collision behavior, key mutability, cache miss path, and hot-key contention.
|
|
97
|
+
3. Do not stop at asymptotic complexity. For `O(N)`, check sequential versus pointer-chasing access, working-set size, branch predictability, per-item allocation, string or Unicode work, runtime dispatch, logging, locks, and external round trips. For `O(log N)`, check node locality, comparator cost, key size, pointer jumps, and branch behavior. For `O(1)` maps or caches, check hash cost, key equality, load factor, resize or rehash spikes, collision behavior, key mutability, cache miss path, and hot-key contention. For JavaScript, separate engine-friendly data shape from language preference: V8-friendly object and array shapes are useful for Chrome and Node, but Safari and Firefox need their own measurement before the claim becomes cross-browser.
|
|
95
98
|
4. Classify the performance surface:
|
|
96
99
|
- CPU and algorithm: nested loops, repeated lookup, sorting, parsing, formatting, validation, scoring, diffing, search, regex, JSON work, compression, crypto, image processing, context switching, event-loop blocking, runtime dispatch, or CPU throttling.
|
|
97
100
|
- I/O and external boundaries: DB, filesystem, HTTP/RPC, Redis/cache, object storage, IPC, child processes, provider SDKs, DNS, TLS, retransmits, cross-region calls, or load-balancer hot spots.
|
|
98
101
|
- Memory and allocation: object churn, deep clone, DTO conversion, large object graphs, byte/string copies, serialization, boxing, pointer chasing, cache locality, and GC pressure.
|
|
99
102
|
- UI and delivery: unstable references, broad store invalidation, large lists, layout thrashing, image or icon load, font loading, hydration cost, bundle parse or execute time, payload size, input delay, and main-thread work.
|
|
100
103
|
- Concurrency and resilience: pool exhaustion, long transactions, locks, retry storms, queue growth, backpressure, cancellation, partial failure, and shared-resource bottlenecks that autoscaling cannot remove.
|
|
104
|
+
- Frontend bundle execution: compressed bytes, decompressed bytes, initial JS parse, compile, evaluate, hydration, long tasks, route Coverage, shared vendor chunks, modulepreload, preload or prefetch priority, and chunk cache stability. Do not accept gzip-only savings as proof of faster first interaction.
|
|
105
|
+
- Browser main-thread contention: async callbacks, microtasks, JSON parsing, DOM insertion, style recalculation, forced reflow, paint, compositing, and framework rerenders compete for the same interaction budget. Do not evaluate "async optimization" and "render optimization" as separate wins unless the shared main-thread budget improved.
|
|
106
|
+
- Node.js runtime pressure: CPU profile, event-loop utilization, p95 or p99 event-loop delay, sync API use, large JSON, REDOS, libuv worker-pool saturation, stream backpressure, worker-thread fit, `process.nextTick()` starvation, and GC or allocation churn.
|
|
101
107
|
5. Look for repeated external access first. Loops around repository calls, ORM lazy fields, DB queries, network calls, Redis gets, object storage calls, filesystem stats, IPC commands, or child processes are usually higher risk than local arithmetic.
|
|
102
108
|
6. Remove N+1 and fan-out before micro-optimizing. Prefer batch loading, bulk APIs, bounded concurrency, preloading, projection, and one request that returns the data shape the caller actually needs.
|
|
103
109
|
7. Check DB and ORM reality before adding caches. Confirm query count, selected columns, lazy loading, index fit, sort or pagination shape, row estimates, rows examined versus returned, temp sorts or tables, lock waits, transaction duration, replication lag, WAL or checkpoint pressure, and connection-pool waits. Do not use a cache to hide a query shape that should be fixed first. Treat pool size as a safety valve, not a cure for slow queries, long transactions, hot rows, or N+1 access.
|
|
@@ -107,7 +113,7 @@ Prefer removing unnecessary work over making unnecessary work slightly faster. A
|
|
|
107
113
|
11. Bound reads and materialization. Avoid unbounded `SELECT *`, `findAll`, full filesystem scans, full JSON loads, full array materialization, whole response bodies, and API responses without pagination, projection, chunking, or streaming when data can grow.
|
|
108
114
|
12. Reduce payload and media work before tuning rendering internals. Send only needed fields, avoid overfetching, split late or optional data, use HTTP caching or CDN only for cacheable assets or responses, and check image dimensions, formats, lazy loading, and fixed layout dimensions before adding component memoization.
|
|
109
115
|
- Treat compression and streaming as latency tradeoffs, not free wins. Check compression CPU, content-coding negotiation, dictionary fallback, proxy buffering, buffered stream latency, flush latency, reconnect pressure, and whether p95/p99 improves for the actual client path. Do not report a false compression win when smaller bytes increase CPU, buffering, or tail latency.
|
|
110
|
-
13. Check sorting and top-k work. Do not sort entire collections when only a top subset is needed. Precompute sort keys when comparison logic parses dates, normalizes strings, computes scores, or reads paths.
|
|
116
|
+
13. Check sorting and top-k work. Do not sort entire collections when only a top subset is needed. Precompute sort keys when comparison logic parses dates, calls locale comparison, normalizes strings, computes scores, serializes data, builds lookup keys, or reads paths.
|
|
111
117
|
14. Check pagination semantics. Offset pagination can become linearly slower and can duplicate or skip items on changing data. Prefer stable keyset or cursor semantics when the product does not require arbitrary page jumps.
|
|
112
118
|
15. Move repeated pure computation out of loops and renders. Normalize queries once, precompute search blobs or numeric timestamps, reuse regexes and formatters, and avoid repeated schema validation after data crosses a trusted boundary.
|
|
113
119
|
16. Reuse expensive clients and sessions. Do not create HTTP clients, DB clients, ORM clients, SDK clients, regexes, date formatters, connection pools, or thread pools per request, per item, or per render unless the local API explicitly requires that lifecycle.
|
|
@@ -129,11 +135,13 @@ Prefer removing unnecessary work over making unnecessary work slightly faster. A
|
|
|
129
135
|
30. Check retry, timeout, and external dependency behavior. Retries need maximum attempts, exponential backoff, jitter, idempotency, and circuit-breaking or graceful degradation when an external service is slow or unavailable.
|
|
130
136
|
31. Check logging and telemetry overhead. Avoid serializing large payloads or building expensive log strings on successful hot paths. Metrics and logs also need bounded cardinality and sampling on high-frequency paths. Do not remove useful observability to make numbers look better; good traces, query counts, cache hit rates, queue backlog, pool waits, tenant or shard labels, and retry/error signals are part of the performance surface.
|
|
131
137
|
32. Run a language and runtime smell pass when applicable:
|
|
132
|
-
- TypeScript and JavaScript: repeated `includes` or `find`, unbounded `Promise.all`, `forEach(async ...)`, ORM N+1, object spread clones, JSON deep clone, repeated `new Date`, `console.log(JSON.stringify(...))`, per-request clients, large sync JSON or file work,
|
|
138
|
+
- TypeScript and JavaScript: repeated `includes` or `find`, unbounded `Promise.all`, `forEach(async ...)`, ORM N+1, object spread clones, JSON deep clone, repeated `new Date`, repeated `Intl` formatter construction, repeated Array built-in borrowing on `arguments` or `NodeList`, `console.log(JSON.stringify(...))`, per-request clients, large sync JSON or file work, CPU work on the event loop, `Map` or `Set` O(1) folklore, `shift()` queues, middle-`splice` deletes, expensive sort comparators, holey or mixed-kind arrays, hot-object `delete`, and object pooling without allocation evidence.
|
|
139
|
+
- Node.js servers and CLIs: sync `fs`, crypto, zlib, DNS, or child-process calls after startup; large `JSON.parse` or `JSON.stringify`; REDOS-prone regexes; CPU-heavy work without a profile; treating ELU as CPU percent; averages hiding p95 or p99 event-loop delay; worker threads used for slow external I/O; runtime changes to `UV_THREADPOOL_SIZE`; streams without backpressure; recursive `process.nextTick()`; and heap-size tuning before allocation evidence.
|
|
140
|
+
- Frontend JavaScript bundles: gzip-only budgets, analyzer-only claims without route Coverage, `dynamic import()` modules also statically imported by the first route, arbitrary component-level chunking, one giant vendor chunk, unsafe `sideEffects: false`, barrel files on first-route paths, old browser targets that add transforms or polyfills, asset inline thresholds that bloat JavaScript or CSS, and preload or prefetch priority inflation without Resource Timing evidence.
|
|
133
141
|
- Go: goroutine per item, missing `context` or timeout, per-call `http.Client`, `io.ReadAll` on growing input, slice growth without capacity, one mutex around a large map, and synchronous logging or formatting in hot loops.
|
|
134
142
|
- Rust: `.clone()` to silence ownership design, unnecessary `collect`, repeated `Regex::new`, `Arc<Mutex<_>>` as a default, `join_all` over unbounded futures, CPU-bound work on async executors, and missing `with_capacity` for large collections.
|
|
135
143
|
- Python: list membership in loops, sequential `requests` calls without session reuse, unbounded `asyncio.gather`, full `read()` or `json.load()` on growing files, `deepcopy`, repeated `datetime.strptime`, f-string logging at disabled levels, row-wise pandas loops, and CPU work on the event loop.
|
|
136
|
-
33. Measure when possible. Use the narrowest configured command intent that exercises the path. If measurement is unavailable, report the result as complexity evidence rather than a speed claim. Do not compare local microbenchmarks to production user experience unless data size, cache state, network, concurrency, and tail-latency conditions are comparable.
|
|
144
|
+
33. Measure when possible. Use the narrowest configured command intent that exercises the path. If measurement is unavailable, report the result as complexity evidence rather than a speed claim. Do not compare local microbenchmarks to production user experience unless data size, cache state, network, concurrency, and tail-latency conditions are comparable. Do not treat a Chrome or Node V8 profile as proof for Safari or Firefox; label it as V8-specific unless those targets were measured.
|
|
137
145
|
34. Treat deploys, restarts, migrations, rebalances, and cache warmups as performance events. A path that is fast only after warm caches, settled JIT, stable replicas, or completed compaction should report cold-start and recovery risk separately from steady-state speed.
|
|
138
146
|
35. Keep large performance architecture changes separate. Watcher refresh, bulk IPC commands, projection caches, virtualized lists, worker offload, queue introduction, cache layers, CDN behavior, sharding, and storage redesigns should be independent changes unless the repository evidence proves they must land together.
|
|
139
147
|
|
|
@@ -143,7 +151,7 @@ Prefer removing unnecessary work over making unnecessary work slightly faster. A
|
|
|
143
151
|
- The hot path, cost multiplier, and affected input scale are explicit.
|
|
144
152
|
- The optimization goal is explicit: user-perceived speed, server cost, p95 or p99 stability, failure isolation, memory headroom, or developer-loop speed.
|
|
145
153
|
- The wall-time breakdown, CPU-versus-wait classification, saturation signal, and resource bottleneck class are explicit when evidence exists.
|
|
146
|
-
- Speed, memory, bundle, payload, query-count, render, CPU locality, allocation, lock, pool, queue, or I/O claims are backed by measurement or labeled as complexity-only.
|
|
154
|
+
- Speed, memory, bundle, payload, query-count, render, CPU locality, allocation, event-loop, worker-pool, long-task, lock, pool, queue, or I/O claims are backed by measurement or labeled as complexity-only.
|
|
147
155
|
- N+1 work, hidden quadratic scans, unbounded materialization, repeated serialization, repeated allocation, client/session churn, broad rendering, and unbounded or accidentally sequential async work are removed or reported.
|
|
148
156
|
- Caches, queues, batching, concurrency, workers, streams, compression, CDN or HTTP caching, media optimization, and projections have invalidation, ordering, duplicate, partial-failure, cancellation, backpressure, capacity, stale-data, CPU, and memory behavior defined where relevant.
|
|
149
157
|
- Correctness, security, durability, privacy, and user-visible semantics remain intact or are explicitly reported as tradeoffs.
|
|
@@ -182,7 +190,7 @@ Use the narrowest configured test, build, docs, release, or mustflow intent that
|
|
|
182
190
|
- Performance evidence: measured, complexity-only, or unverified
|
|
183
191
|
- Semantics preserved: order, duplicates, IDs, consistency, partial failure, cancellation, and stale result handling
|
|
184
192
|
- Optimization applied or recommended
|
|
185
|
-
- Cache, queue, batching, concurrency, projection, UI, payload, compression, HTTP delivery, media, memory, runtime, lock, pool, stream, retry, timeout, deployment, sharding, and I/O notes where relevant
|
|
193
|
+
- Cache, queue, batching, concurrency, projection, UI, payload, compression, HTTP delivery, media, memory, runtime, Node event-loop, worker-pool, frontend initial-JS, long-task, lock, pool, stream, retry, timeout, deployment, sharding, and I/O notes where relevant
|
|
186
194
|
- Command intents run
|
|
187
195
|
- Skipped measurements and reasons
|
|
188
196
|
- Remaining performance risk
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: skill.quadratic-scan-review
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 4
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: procedure
|
|
8
8
|
name: quadratic-scan-review
|
|
@@ -53,7 +53,7 @@ The review question is not "is there a loop inside a loop?" That catches only th
|
|
|
53
53
|
## Required Inputs
|
|
54
54
|
|
|
55
55
|
- Outer work: the loop, mapper, reducer, render, resolver, batch, import, export, queue consumer, tree builder, graph traversal, or helper call site that repeats.
|
|
56
|
-
- Inner work: the scan, membership check, lookup, sort, clone, string copy, JSON serialization, DB query, resolver call, or helper body run for each item.
|
|
56
|
+
- Inner work: the scan, membership check, lookup, sort comparator, clone, string copy, JSON serialization, DB query, resolver call, or helper body run for each item.
|
|
57
57
|
- Data shape: which collections grow, whether they are user-generated or fixed configuration, maximum known size, duplicate behavior, order requirements, and key fields.
|
|
58
58
|
- Join or membership key: ID, composite key, normalized key, parent ID, foreign key, timestamp bucket, interval boundary, permission key, tag key, or object identity.
|
|
59
59
|
- Current semantic contract: order, duplicates, first or last winner, stable tie-breakers, missing records, authorization filtering, stale data, and partial failure.
|
|
@@ -78,6 +78,7 @@ The review question is not "is there a loop inside a loop?" That catches only th
|
|
|
78
78
|
- Add small tests or fixtures that preserve order, duplicate handling, first or last winner behavior, missing IDs, and composite-key behavior when changing lookup structure.
|
|
79
79
|
- Add bounded static-review notes or complexity comments only when the code would otherwise look misleading.
|
|
80
80
|
- Do not add caches when an index built from already-loaded data is enough.
|
|
81
|
+
- Do not claim `Set` or `Map` is guaranteed O(1) or always faster than an array. Use them when repeated lookup count, key dynamics, and data size justify the index setup and memory cost.
|
|
81
82
|
- Do not replace arrays with maps or sets when duplicates, order, stable tie-breakers, or small hard-capped lists make the array behavior intentional.
|
|
82
83
|
|
|
83
84
|
<!-- mustflow-section: procedure -->
|
|
@@ -85,34 +86,36 @@ The review question is not "is there a loop inside a loop?" That catches only th
|
|
|
85
86
|
|
|
86
87
|
1. Name the repeated path and multiply call count by inner scan length. Review the product `outer_count * inner_count`, not the apparent number of loops.
|
|
87
88
|
2. Search for the obvious collection-combinator shapes: `map` plus `filter`, `map` plus `find`, `forEach` plus `includes`, `filter` plus `indexOf`, `filter` plus `findIndex`, `reduce` plus spread, and chained `filter().map().sort()` inside a repeated path.
|
|
88
|
-
|
|
89
|
+
- Treat helper-hidden `find`, `includes`, `some`, `filter`, `indexOf`, or membership checks as the same problem even when the outer call site only says `getStatus`, `hasPermission`, `resolveOwner`, or `renderRow`.
|
|
90
|
+
3. Search for membership checks over arrays. `includes`, `indexOf`, `contains`, `find`, `some`, and list membership inside a loop usually want `Set.has` or `Map.has` unless the searched list is tiny and hard-capped. In JavaScript, frame this as "avoid repeated linear scans" rather than "Set is guaranteed O(1)"; keyed collections are average sublinear and still have setup, hashing, equality, memory, and resize costs.
|
|
89
91
|
4. Search for code joins by ID. `posts.map(post => users.find(...))`, `users.map(user => orders.filter(...))`, permission lookups, likes, bookmarks, read state, tags, and relation lists usually need a `Map` or grouped `Map` keyed by ID or composite key.
|
|
90
92
|
5. Check duplicate removal. `filter((x, i) => arr.indexOf(x) === i)` is O(N^2). Prefer `Set` for scalar values and `Map` keyed by stable identity for objects.
|
|
91
93
|
6. Check sorted arrays. Sorting does not make `find` fast. If code repeatedly searches a sorted array, use a prebuilt map, binary search with a proven comparator, or a single sorted merge.
|
|
92
|
-
7. Check repeated sorting. Sorting inside a per-item loop is usually worse than scanning once, keeping a top candidate, using a heap, or sorting once before the loop.
|
|
93
|
-
8. Check
|
|
94
|
-
9. Check
|
|
95
|
-
10. Check
|
|
96
|
-
11.
|
|
97
|
-
12.
|
|
98
|
-
13. Check
|
|
99
|
-
14. Check
|
|
100
|
-
15. Check
|
|
101
|
-
16. Check
|
|
102
|
-
17. Check
|
|
103
|
-
18. Check
|
|
104
|
-
19. Check
|
|
105
|
-
20. Check
|
|
106
|
-
21.
|
|
107
|
-
22.
|
|
108
|
-
23.
|
|
109
|
-
24.
|
|
94
|
+
7. Check repeated sorting. Sorting inside a per-item loop is usually worse than scanning once, keeping a top candidate, using a heap, or sorting once before the loop. Sorting a collection does not make exact lookup cheap; use `Map` for exact key lookup and sorted merge or binary search for range or ordered-window work.
|
|
95
|
+
8. Check expensive sort comparators. A comparator that parses dates, calls `localeCompare` with options, normalizes strings, computes scores, reads files, serializes JSON, or builds lookup keys may run many times per item. Precompute keys with decorate-sort-undecorate or store the normalized key before sorting.
|
|
96
|
+
9. Check queue and deletion patterns. JavaScript `shift()` or `unshift()` in a large BFS or queue loop moves the remaining array repeatedly; use a head index or real queue. `findIndex` plus `splice` while matching requests to available items can scan and move the same growing array repeatedly; bucket by key and advance a consumption pointer instead. If order is irrelevant, swap the item with the last slot and `pop()` instead of repeated middle `splice()`.
|
|
97
|
+
10. Check copy-accumulation patterns. `reduce` with `[...acc, item]`, repeated object spread over a growing object, repeated string `+=`, repeated `concat`, and repeated array spread over a growing result can become quadratic copy work. Prefer push, builders, buffers, or one final copy at the boundary.
|
|
98
|
+
11. Check JSON and serialization comparisons. Repeated `JSON.stringify` inside search, equality, sort, dedupe, or render logic multiplies object size by item count. Use explicit keys and precomputed normalized keys.
|
|
99
|
+
12. Open helper bodies called from loops or render paths. Harmless helper names can hide full-list scans, database calls, resolver calls, serialization, sorting, or permission checks.
|
|
100
|
+
13. Check ORM and lazy relations. A single visible loop can become one query per entity. Replace per-entity relation access with eager loading, joins, `WHERE id IN (...)`, batch loading, or DataLoader-style batching.
|
|
101
|
+
14. Check GraphQL and nested resolvers. Parent-list resolvers plus per-field DB or API calls create hidden pairwise fan-out. Batch by parent IDs and preserve field-level authorization semantics.
|
|
102
|
+
15. Check render-time lookup. `rows.map(row => columns.find(...))`, `items.map(item => selectedIds.includes(item.id))`, derived data recomputed on every render, and per-row helper scans should move to memoized sets or maps when inputs are large or stable.
|
|
103
|
+
16. Check all-data-in-app joins. Fetching `allUsers`, `allOrders`, or `allLogs` and joining in application arrays is often a database join without an index. Push join, filter, sort, and pagination to the data store when the data store owns the index and semantics allow it.
|
|
104
|
+
17. Check tree and graph construction. `nodes.map(node => nodes.filter(child => child.parentId === node.id))` should usually become `childrenByParentId` plus one assembly pass. `visited.includes(id)` in traversal should be a `Set`. Very deep trees may also need an explicit stack to avoid call-stack failure.
|
|
105
|
+
18. Check event-log and time-window scans. Repeatedly scanning all previous events per event should usually become grouping, sorting once, and one pointer or rolling aggregate per key.
|
|
106
|
+
19. Check interval overlap. All-pairs range checks are sometimes necessary, but overlap detection often only needs sorting by start and comparing adjacent or active intervals.
|
|
107
|
+
20. Check true all-pairs similarity separately. If every item must be compared with every other item, do not promise a linear rewrite. First narrow candidates with stable keys, categories, buckets, hashes, n-grams, ranges, or database indexes, then compare only within the candidate set.
|
|
108
|
+
21. Check incremental updates. Adding one item should not recompute a full ranking, group map, unread count, cart total, or dashboard aggregate unless the collection is fixed and tiny.
|
|
109
|
+
22. Separate index from cache. A `Map` built from current input is an index. A cache stores results across calls or time. Use an index for repeated lookup over already-owned data before introducing cache invalidation.
|
|
110
|
+
23. Require a hard cap for "small list" exceptions. Countries, enum options, or fixed config lists may stay arrays if the cap is real. User data, logs, orders, comments, permissions, tags, events, and uploaded rows need scalable lookup.
|
|
111
|
+
24. Preserve behavior while changing shape. Before replacing scans with indexes, state how order, duplicates, first or last match, missing references, authorization filtering, and stable keys are preserved.
|
|
112
|
+
25. Add growth evidence when feasible. If configured tests or fixtures can scale input size, prefer a small growth test that compares behavior at larger counts. If benchmarking is not configured, report complexity-only evidence instead of a speedup claim.
|
|
110
113
|
|
|
111
114
|
<!-- mustflow-section: postconditions -->
|
|
112
115
|
## Postconditions
|
|
113
116
|
|
|
114
117
|
- Each suspected O(N^2) path has an outer count, inner count, and data-growth classification.
|
|
115
|
-
- Repeated membership checks, code joins, duplicate removal, tree building, resolver fan-out, render-time lookup, helper-hidden scans, repeated sort, queue `shift()`, `findIndex` plus `splice`, copy accumulation, interval scans, all-pairs candidate narrowing, and JSON comparison are fixed or reported.
|
|
118
|
+
- Repeated membership checks, code joins, duplicate removal, tree building, resolver fan-out, render-time lookup, helper-hidden scans, repeated sort, expensive comparators, queue `shift()` or `unshift()`, `findIndex` plus `splice`, copy accumulation, interval scans, all-pairs candidate narrowing, and JSON comparison are fixed or reported.
|
|
116
119
|
- Array-to-set or array-to-map changes preserve order, duplicates, missing records, first or last winner, authorization, and stable key behavior.
|
|
117
120
|
- Small-list exceptions have an explicit hard cap or are reported as residual risk.
|
|
118
121
|
- Performance claims are backed by configured evidence or labeled as static complexity risk.
|
package/templates/default/locales/en/.mustflow/skills/web-render-performance-review/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: skill.web-render-performance-review
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 2
|
|
6
6
|
lifecycle: mustflow-owned
|
|
7
7
|
authority: procedure
|
|
8
8
|
name: web-render-performance-review
|
|
@@ -29,7 +29,7 @@ metadata:
|
|
|
29
29
|
<!-- mustflow-section: purpose -->
|
|
30
30
|
## Purpose
|
|
31
31
|
|
|
32
|
-
Review web first-render performance as a critical rendering path problem: the browser must discover the first viewport HTML, CSS, data, fonts, scripts, and LCP media early, while noncritical work stays out of the way.
|
|
32
|
+
Review web first-render performance as a critical rendering path problem: the browser must discover the first viewport HTML, CSS, data, fonts, scripts, and LCP media early, while noncritical work stays out of the way. Treat initial JavaScript as main-thread work, not just transfer bytes.
|
|
33
33
|
|
|
34
34
|
The review question is not "did we compress assets?" It is "what blocks the first useful pixels, what competes with the LCP resource, what shifts layout later, and what work runs on the main thread before the user can see or use the page?"
|
|
35
35
|
|
|
@@ -59,7 +59,7 @@ The review question is not "did we compress assets?" It is "what blocks the firs
|
|
|
59
59
|
- Font loading ledger: font files, weights, subsets, `unicode-range`, format, preload list, `font-display`, fallback metrics, Korean or CJK coverage, FOIT risk, and CLS risk.
|
|
60
60
|
- Image, video, and iframe ledger: `srcset`, `sizes`, intrinsic dimensions, `aspect-ratio`, lazy/eager loading, `fetchpriority`, CDN transformation, thumbnails, embeds, ads, maps, and offscreen media.
|
|
61
61
|
- Third-party script ledger: analytics, tag managers, ads, A/B testing, heatmaps, chat widgets, payment widgets, maps, embeds, consent gates, page scope, and user-intent loading.
|
|
62
|
-
- JavaScript bundle and hydration ledger: initial route bundle, client/server boundaries, `use client` placement, dynamic imports, chunk graph, modulepreload, route prefetching, parse/compile/
|
|
62
|
+
- JavaScript bundle and hydration ledger: initial route bundle, client/server boundaries, `use client` placement, dynamic imports, chunk graph, modulepreload, route prefetching, gzip or brotli transfer size, decompressed size, parse/compile/evaluate cost, and main-thread tasks.
|
|
63
63
|
- Data and HTML delivery ledger: first-view data owner, SSR/RSC/loader/static generation, client effects, serialized initial data, streaming shell, Suspense or loading boundaries, personalization holes, and TTFB evidence.
|
|
64
64
|
- Cache, compression, and resource-hint ledger: CDN HTML cacheability, cache-control headers, fingerprinted assets, private data boundaries, text compression, Early Hints, preconnect origins, and preload accuracy.
|
|
65
65
|
- Main-thread and long-task ledger: expensive parsing, syntax highlighting, charting, search indexing, markdown rendering, JSON work, layout-heavy below-fold DOM, idle work, worker offload, and chunking strategy.
|
|
@@ -103,25 +103,26 @@ The review question is not "did we compress assets?" It is "what blocks the firs
|
|
|
103
103
|
16. Keep `use client` boundaries narrow in React and Next.js style apps. A top-level layout or page marked client-side can drag static markup, data, and child components into the hydration and bundle cost.
|
|
104
104
|
17. Lazy-load heavy interactive widgets. Modals, charts, editors, maps, markdown renderers, syntax highlighters, date pickers, and rarely opened panels should usually enter through dynamic import or route-level loading.
|
|
105
105
|
18. Split code by "not needed for this route now," not by chunk theater. Too many tiny chunks can add request and module scheduling overhead, while one giant common chunk ships unused code everywhere.
|
|
106
|
-
19.
|
|
107
|
-
20.
|
|
108
|
-
21.
|
|
109
|
-
22.
|
|
110
|
-
23.
|
|
111
|
-
24.
|
|
112
|
-
25. Cache
|
|
113
|
-
26.
|
|
114
|
-
27.
|
|
115
|
-
28. Use
|
|
116
|
-
29.
|
|
117
|
-
30.
|
|
118
|
-
31.
|
|
106
|
+
19. Do not report gzip-only JavaScript wins as first-render wins. Check whether initial parse, compile, evaluate, hydration, and long tasks improved for the route; use `client-bundle-pruning-review` when unused initial code, chunk boundaries, barrels, side effects, or vendor chunks are the root cause.
|
|
107
|
+
20. Use `modulepreload` only for critical initial modules. Preloading every possible route, widget, or secondary chunk creates a new waterfall in nicer clothes. Validate preload, prefetch, and route-prefetch priority with Resource Timing or configured evidence when a claim depends on request order.
|
|
108
|
+
21. Do not fetch first-view data in a client effect when server, route loader, RSC, static generation, or serialized initial data can safely provide it. Client effects are for enhancement, subscriptions, and browser-only data, not required first pixels.
|
|
109
|
+
22. Stream HTML and shell early. Send stable layout, navigation, critical content, and placeholders as soon as possible; put slow regions behind Suspense, loading boundaries, or progressive sections when the framework supports it.
|
|
110
|
+
23. Split static shells from dynamic holes. Cache and reuse stable HTML around narrow personalized or fast-changing regions instead of making the whole page uncached and origin-bound for one username, cart count, or recommendation slot.
|
|
111
|
+
24. Investigate slow TTFB before polishing the browser side. If TTFB is around or above one second, use Server-Timing, origin logs, cache status, query count, API count, SSR timing, or configured evidence to find the upstream wait.
|
|
112
|
+
25. Cache HTML at the edge when it is safe. Low-personalization pages can often be CDN cached with revalidation or hole punching; private or user-specific pages need explicit cache boundaries to avoid data leaks.
|
|
113
|
+
26. Cache fingerprinted assets with long immutable headers. Do not confuse `no-cache`, `no-store`, `private`, and long-lived immutable caching; the wrong header can either slow every visit or leak user-specific content.
|
|
114
|
+
27. Enable text compression for HTML, CSS, JS, JSON, SVG, and other text resources. Do not waste time recompressing already compressed media such as JPEG, PNG, WebP, AVIF, video, or font formats that are already compressed.
|
|
115
|
+
28. Use Early Hints and preconnect sparingly. They help only when the critical resource or origin is definitely needed soon; speculative hints for many origins can steal sockets and bandwidth from the real first-render path.
|
|
116
|
+
29. Use `content-visibility: auto` with `contain-intrinsic-size` for huge below-fold DOM when supported. It can reduce early layout and paint work, but missing intrinsic size can cause scroll jumps.
|
|
117
|
+
30. Break long main-thread tasks. Heavy JSON parsing, syntax highlighting, chart rendering, markdown rendering, search indexing, diffing, and data formatting may need chunking, idle callbacks, workers, virtualization, or server-side precomputation.
|
|
118
|
+
31. Audit route prefetch behavior. Framework prefetching can help a few likely next clicks, but a page with hundreds of links can turn prefetch into a silent network and CPU tax; disable or move it to hover or viewport intent when needed.
|
|
119
|
+
32. Label evidence honestly. If there is no configured browser trace, network waterfall, bundle report, RUM, or lab measurement, report findings as static critical-path risk or configured-test evidence, not measured Web Vitals improvement.
|
|
119
120
|
|
|
120
121
|
<!-- mustflow-section: postconditions -->
|
|
121
122
|
## Postconditions
|
|
122
123
|
|
|
123
124
|
- The first viewport, LCP candidate, discovery path, critical CSS, fonts, media, scripts, data, HTML delivery, cache behavior, resource hints, and main-thread work are explicit.
|
|
124
|
-
- Lazy LCP media, hidden background hero discovery, priority inflation, render-blocking global CSS, over-preloaded fonts, unsubset Korean or CJK fonts, oversized images, missing dimensions, eager offscreen embeds, global third-party scripts, broad client boundaries, eager heavy widgets, client-effect first data, all-or-nothing HTML waits, unsafe cache headers, hint spam, below-fold layout work, long tasks, and overbroad prefetch are fixed or reported.
|
|
125
|
+
- Lazy LCP media, hidden background hero discovery, priority inflation, render-blocking global CSS, over-preloaded fonts, unsubset Korean or CJK fonts, oversized images, missing dimensions, eager offscreen embeds, global third-party scripts, broad client boundaries, eager heavy widgets, gzip-only JavaScript claims, client-effect first data, all-or-nothing HTML waits, unsafe cache headers, hint spam, below-fold layout work, long tasks, and overbroad prefetch are fixed or reported.
|
|
125
126
|
- Performance claims are backed by current configured evidence or labeled as static review risk, manual-only measurement, or missing evidence.
|
|
126
127
|
- Accessibility, layout stability, privacy, security, cache correctness, and framework boundaries remain intact or are reported as tradeoffs.
|
|
127
128
|
|