devrites 2.0.0 → 2.1.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to DevRites are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and DevRites adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Releases are generated automatically by [semantic-release](https://semantic-release.gitbook.io/) from Conventional Commits on `main`.
4
4
 
5
+ ## [2.1.0](https://github.com/ViktorsBaikers/DevRites/compare/v2.0.0...v2.1.0) (2026-06-23)
6
+
7
+ ### Added
8
+
9
+ * **agents:** perf reviewer gets Source/Measured CWV modes ([be82b20](https://github.com/ViktorsBaikers/DevRites/commit/be82b20b37252a9f55d77e0f71659ec58a213ca6))
10
+
5
11
  ## [2.0.0](https://github.com/ViktorsBaikers/DevRites/compare/v1.18.0...v2.0.0) (2026-06-23)
6
12
 
7
13
  ### ⚠ BREAKING CHANGES
package/README.md CHANGED
@@ -94,7 +94,7 @@ Full diagram set (lifecycle, polish orchestrator, review fan-out, debug loop,
94
94
  rules carrier, workspace state, namespace map) →
95
95
  [`docs/flow.md`](docs/flow.md).
96
96
 
97
- **Status:** [`v2.0.0`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v2.0.0) — see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
97
+ **Status:** [`v2.1.0`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v2.1.0) — see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
98
98
 
99
99
  ## Contents
100
100
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: devrites-performance-reviewer
3
- description: Fresh-context, measure-first performance reviewer for /rite-seal. Use to independently review a DevRites feature diff for N+1s, hot-path work, payload/bundle size, and Core Web Vitals risks. Won't claim a slowdown without a number or a measurement to take.
3
+ description: Fresh-context, measure-first performance reviewer for /rite-seal. Use to independently review a DevRites feature diff for N+1s, hot-path work, payload/bundle size, and Core Web Vitals risks. Runs in Source mode (static scan, findings tagged potential) or Measured mode (judges real Lighthouse/PSI/CrUX/trace numbers and leads with a source-labeled CWV scorecard). Won't claim a slowdown without a number or a measurement to take, and never presents lab data as field data.
4
4
  tools: Read, Grep, Glob, Bash
5
5
  hooks:
6
6
  PreToolUse:
@@ -17,19 +17,50 @@ You are measure-first: no performance claim without a number or a specified meas
17
17
 
18
18
  ## Inputs
19
19
  Workspace `.devrites/work/<slug>/`: read `spec.md` (any perf budget), `evidence.md`,
20
- `touched-files.md`. Run `git diff` and read the touched files.
20
+ `touched-files.md`. Run `git diff` and read the touched files. Also look for Core Web
21
+ Vitals artifacts — numbers already in `evidence.md`, a Lighthouse / PageSpeed Insights /
22
+ CrUX JSON path the builder left, or a browser-proof capture in `browser-evidence.md`.
23
+
24
+ Read the baseline checklist on demand (resolve the path like the readonly hook):
25
+ ```
26
+ C=.claude/skills/rite-review/reference/performance-checklist.md
27
+ [ -f "$C" ] || C="$CLAUDE_PLUGIN_ROOT/pack/.claude/skills/rite-review/reference/performance-checklist.md"
28
+ [ -f "$C" ] || C=pack/.claude/skills/rite-review/reference/performance-checklist.md
29
+ ```
30
+
31
+ ## Two modes (the inputs set the mode, not a flag)
32
+ - **Source mode** — default, no perf artifacts present. Scan the diff statically for
33
+ structural anti-patterns. Every frontend finding is **potential impact**, never a
34
+ measurement; name the command that would confirm it. Emit **no scorecard**.
35
+ - **Measured mode** — a CWV artifact or a real number exists. Judge it against the
36
+ `spec.md` budget or the pre-change baseline, and lead with the scorecard.
37
+
38
+ Source mode is the same discipline as the old "specify the measurement" — it just names
39
+ the contract for when the scorecard appears.
21
40
 
22
41
  ## Review (feature scope)
23
- - **Backend** — N+1 queries, missing indexes on new queries, unbounded result sets,
24
- per-request work that should be cached/batched, blocking sync work.
25
- - **Frontend (Core Web Vitals)** — LCP (oversized images, render-blocking work), CLS
26
- (layout shift), INP (interaction latency), bundle growth, unnecessary re-renders.
42
+ - **Backend** (always, every feature) — N+1 queries, missing indexes on new queries,
43
+ unbounded result sets, per-request work that should be cached/batched, blocking sync
44
+ work. *AI-codegen smell:* over-fetching "just in case", sequential `await`s where
45
+ `Promise.all` fits, redundant calls a dedup would collapse.
46
+ - **Frontend (Core Web Vitals)** — only when the feature is UI-facing. Identify the
47
+ framework and rendering model first (React / Vue / Svelte / Angular / Next / Astro /
48
+ vanilla) and apply only that stack's idioms — don't recommend `next/image` to a Vue app
49
+ or `React.memo` to Svelte. Check LCP (oversized images, render-blocking work, missing
50
+ `fetchpriority`), CLS (layout shift, missing image dimensions), INP (long tasks, heavy
51
+ event handlers), bundle growth, unnecessary re-renders. *AI-codegen smell:* `memo` /
52
+ `useMemo` / `useCallback` wrapping everything, over-eager effect deps, broad watchers.
27
53
  - **General** — accidental quadratic loops, repeated hot-path work, large allocations.
28
54
 
29
55
  ## Measure-first discipline
30
- - If a real number exists in `evidence.md`, judge it against the budget/baseline.
56
+ - If a real number exists, judge it against the budget/baseline; state the before/after.
31
57
  - If not, **specify the measurement** (command, scenario, metric) instead of asserting a
32
58
  regression. Distinguish "measured regression" from "likely hot spot, verify with X".
59
+ - **Source-honesty.** Label every measured CWV value with where it came from —
60
+ `Field (CrUX)` (real users, p75), `Lab (Lighthouse)` (one synthetic run), or
61
+ `Trace (DevTools)`. Field and lab are not interchangeable; presenting one as the other
62
+ is fabrication. Reading static source cannot measure LCP / INP / CLS — never invent a
63
+ number for a value you did not capture.
33
64
 
34
65
  ## Rules
35
66
  - Don't edit. Findings only, labeled Critical / Important / Suggestion / Nit / FYI with
@@ -37,9 +68,26 @@ Workspace `.devrites/work/<slug>/`: read `spec.md` (any perf budget), `evidence.
37
68
  micro-opt with no measured impact is a Suggestion at most. Feature scope only.
38
69
 
39
70
  ## Output
71
+
72
+ **Measured mode** — lead with a compact scorecard, then the line findings:
73
+ ```
74
+ Performance review (<slug>) — independent
75
+ Scorecard (source-labeled):
76
+ LCP <value> <Field(CrUX) | Lab(LH) | Trace> <Good/Needs Work/Poor> (target ≤2.5s)
77
+ INP <value> <source> <status> (target ≤200ms)
78
+ CLS <value> <source> <status> (target ≤0.1)
79
+ [Lighthouse perf <score> Lab(LH)] Artifacts: <which> Stack: <detected>
80
+ [Critical]/[Important] file:line — issue. measured: <number>. direction.
81
+ [Suggestion]/[Nit]/[FYI] ...
82
+ Budget: <breached? | none stated>
83
+ Verdict: <blockers? none/list>
84
+ ```
85
+
86
+ **Source mode** — no artifacts; one scorecard line, findings tagged `potential`:
40
87
  ```
41
88
  Performance review (<slug>) — independent
42
- [Important] file:line issue. measured: <number | "measure: <cmd/metric>">. direction.
89
+ Scorecard: not measured (Source mode)
90
+ [Important] file:line — issue. potential; verify: <cmd/metric>. direction.
43
91
  [Suggestion]/[Nit]/[FYI] ...
44
92
  Budget: <breached? | none stated>
45
93
  To prove any win: <measure X before/after>
@@ -21,6 +21,15 @@ Measure first. An optimization without a measurement is a guess that adds comple
21
21
  - Don't trade correctness or readability for a micro-win that doesn't matter.
22
22
  - Prefer a better algorithm or query over micro-tuning; the big wins are structural.
23
23
 
24
+ ## Frontend — Core Web Vitals
25
+ For UI work, measure-first means LCP / INP / CLS judged against real numbers, each labeled
26
+ by source (`Field (CrUX)`, `Lab (Lighthouse)`, `Trace (DevTools)`) — field and lab are not
27
+ interchangeable, and static source cannot measure a CWV. The reviewer captures these via the
28
+ browser-proof ladder when a budget exists, then judges them in Measured mode (a
29
+ source-labeled scorecard); with no artifact it runs in Source mode and names the command.
30
+ Baseline checks + measurement commands:
31
+ [`rite-review/reference/performance-checklist.md`](../skills/rite-review/reference/performance-checklist.md).
32
+
24
33
  ## Scope
25
34
  Optimize what the change touches or what a measurement flags. Project-wide performance
26
35
  work is its own effort — record it as a follow-up, don't smuggle it into an unrelated
@@ -22,12 +22,32 @@ of the ladder that's available; record which one.
22
22
  the project's existing commands. Don't add a new framework.
23
23
  5. **Manual fallback** — none available: record the limitation + exact manual steps.
24
24
 
25
+ ## Core Web Vitals capture (when the spec states a perf budget)
26
+ If `spec.md` carries a perf budget — or a frontend regression risk is visible — capture the
27
+ CWV numbers here so the perf reviewer judges real data instead of guessing. Use the highest
28
+ rung available; **detect, don't install**.
29
+
30
+ 1. **Chrome DevTools MCP** (if configured) — `lighthouse_audit` for LCP/INP/CLS + the
31
+ Lighthouse performance score. Source label: **Lab (Lighthouse)**. A `performance_*` trace
32
+ gives **Trace (DevTools)** attribution.
33
+ 2. **browser-harness** — drive the route, capture a performance trace over CDP. Source
34
+ label: **Trace (DevTools)**.
35
+ 3. **CrUX / PageSpeed Insights** — only if the user supplied an API key. Field data, p75.
36
+ Source label: **Field (CrUX)**.
37
+ 4. **None available** → mark CWV **pending (manual)** and name the exact command
38
+ (`npx lighthouse <url> --output json …`). Don't install anything; don't fake a number.
39
+
40
+ Write each captured value **with its source label** to `evidence.md` (so the perf reviewer
41
+ reads it in Measured mode) and note the tool + route in `browser-evidence.md`. Never present
42
+ a lab value as a field value or vice versa.
43
+
25
44
  ## Evidence schema → `browser-evidence.md`
26
45
  Tooling used · route(s) · viewports (375/768/1280) · screenshot paths **opened and
27
46
  described** · console errors/warnings · network failures · interaction path tested ·
28
- accessibility basics · responsive checks · **design-reference match** (if the spec saved
29
- references in `references/`, compare the built UI to them and note match/diffs) ·
30
- limitations.
47
+ accessibility basics · responsive checks · **CWV capture** (tool + route + each
48
+ source-labeled value, or `pending (manual)` + the command) · **design-reference match** (if
49
+ the spec saved references in `references/`, compare the built UI to them and note
50
+ match/diffs) · limitations.
31
51
 
32
52
  ## Hard rules
33
53
  - A screenshot **path is not proof** — open it and describe what's visible.
@@ -0,0 +1,80 @@
1
+ # Performance checklist (baseline for the perf reviewer)
2
+
3
+ The minimum baseline `devrites-performance-reviewer` checks against, in feature scope. It
4
+ is a checklist, not a mandate: flag what the diff actually touches or what a measurement
5
+ flags, never a project-wide sweep. The philosophy lives in
6
+ [`rules/performance.md`](../../../rules/performance.md) (measure first) — this file is the
7
+ concrete what-to-look-for.
8
+
9
+ ## Core Web Vitals targets
10
+
11
+ | Metric | Good | Needs work | Poor |
12
+ |---|---|---|---|
13
+ | LCP — Largest Contentful Paint | ≤ 2.5s | ≤ 4.0s | > 4.0s |
14
+ | INP — Interaction to Next Paint | ≤ 200ms | ≤ 500ms | > 500ms |
15
+ | CLS — Cumulative Layout Shift | ≤ 0.1 | ≤ 0.25 | > 0.25 |
16
+
17
+ A CWV value only counts when it carries a source — `Field (CrUX)`, `Lab (Lighthouse)`, or
18
+ `Trace (DevTools)`. No source → it's a Source-mode hypothesis, not a measurement.
19
+
20
+ ## Frontend (only when the feature is UI-facing)
21
+
22
+ Identify the framework first; apply only its idioms.
23
+
24
+ - **Images** — modern format (WebP/AVIF); responsive `srcset`/`sizes`; explicit
25
+ `width`/`height` to reserve space (CLS); below-the-fold `loading="lazy"`; the LCP image
26
+ gets `fetchpriority="high"` and is **not** lazy-loaded.
27
+ - **JavaScript** — initial bundle stays small (≈200KB gzipped is the usual line); code-split
28
+ routes and heavy features; no blocking script in `<head>` without `defer`/`async`; break
29
+ long tasks (>50ms) so the main thread stays free (the main INP lever); `memo`/`useMemo`/
30
+ `useCallback` only where profiling shows a win, not wrapped over everything.
31
+ - **CSS** — critical CSS not render-blocking; no per-render CSS-in-JS runtime cost in prod.
32
+ - **Fonts** — 2–3 families max; WOFF2; self-hosted where possible; preload the LCP font;
33
+ `font-display: swap`; subset with `unicode-range`.
34
+ - **Rendering** — no layout thrashing (batch reads, then writes); animate `transform`/
35
+ `opacity` only; virtualize long lists; `content-visibility: auto` for off-screen sections;
36
+ don't break bfcache (no `unload` handler, no `Cache-Control: no-store` on HTML).
37
+
38
+ ## Backend (every feature, UI or not)
39
+
40
+ - No N+1 queries; eager-load / join / batch instead.
41
+ - New queries have the indexes they need for their filter/sort columns.
42
+ - List endpoints paginate — never an unbounded `SELECT *`.
43
+ - Per-request work that doesn't change per call is cached or hoisted.
44
+ - Responses compressed (gzip/brotli); bulk operations instead of a loop of single calls.
45
+
46
+ ## Network
47
+
48
+ - Static assets cached with a long `max-age` + content hashing.
49
+ - Known origins `preconnect`-ed; no unnecessary redirects; HTTP/2 or HTTP/3 where available.
50
+
51
+ ## AI-codegen perf smells (fold into the area above, not a separate finding category)
52
+
53
+ - State duplicated instead of lifted; effects with over-broad deps that re-run needlessly.
54
+ - Sequential `await`s where `Promise.all` / parallel fetch fits.
55
+ - Over-fetching "just in case"; redundant calls a dedup would collapse.
56
+ - Defensive memoization wrapping cheap components — cost with no benefit.
57
+
58
+ ## Modern APIs to consider (one-liners — reach for these, don't gate on them)
59
+
60
+ `scheduler.yield()` to keep input responsive in long loops · Speculation Rules for
61
+ prefetch/prerender · View Transitions on SPA navigation · Long Animation Frames (LoAF) for
62
+ production INP attribution · `fetchpriority` on critical non-image resources.
63
+
64
+ ## Measurement commands (name these in Source mode; don't run installs in review)
65
+
66
+ ```bash
67
+ # Lighthouse (lab)
68
+ npx lighthouse <url> --output json --output-path ./report.json
69
+ # or via the Chrome DevTools MCP CLI, no install:
70
+ npx -p chrome-devtools-mcp chrome-devtools lighthouse_audit --output-format=json > report.json
71
+
72
+ # Bundle size
73
+ npx vite-bundle-visualizer # Vite
74
+ npx webpack-bundle-analyzer stats.json # webpack
75
+
76
+ # Field data: CrUX / PageSpeed Insights (real users, p75) — needs an API key
77
+ ```
78
+
79
+ Field is what real users experienced; lab is one synthetic run. Don't present one as the
80
+ other.
@@ -17,6 +17,10 @@ a hunch.
17
17
  unnecessary re-renders.
18
18
  - **General**: accidental quadratic loops, repeated work in hot paths, large allocations.
19
19
 
20
+ The agent runs **Source mode** (static scan, findings tagged `potential` + the verify
21
+ command) or **Measured mode** (real CWV numbers → a source-labeled scorecard). Baseline
22
+ checks + measurement commands: [`performance-checklist.md`](performance-checklist.md).
23
+
20
24
  ## Optimize responsibly
21
25
  - Fix the measured bottleneck, then **re-measure** to prove the win (before/after in
22
26
  `evidence.md`). An optimization with no measured improvement is just added complexity.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devrites",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "DevRites — disciplined senior-engineer workflow skills pack for Claude Code",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://github.com/ViktorsBaikers/DevRites#readme",