@brunosps00/dev-workflow 0.9.0 → 0.10.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/README.md +18 -19
- package/lib/constants.js +2 -10
- package/lib/migrate-gsd.js +1 -1
- package/package.json +1 -1
- package/scaffold/en/commands/dw-autopilot.md +6 -6
- package/scaffold/en/commands/dw-brainstorm.md +1 -1
- package/scaffold/en/commands/dw-bugfix.md +1 -0
- package/scaffold/en/commands/dw-code-review.md +1 -0
- package/scaffold/en/commands/dw-commit.md +6 -0
- package/scaffold/en/commands/dw-create-techspec.md +2 -0
- package/scaffold/en/commands/dw-deep-research.md +6 -0
- package/scaffold/en/commands/dw-deps-audit.md +1 -0
- package/scaffold/en/commands/dw-find-skills.md +4 -4
- package/scaffold/en/commands/dw-fix-qa.md +1 -0
- package/scaffold/en/commands/dw-generate-pr.md +1 -0
- package/scaffold/en/commands/dw-help.md +9 -29
- package/scaffold/en/commands/dw-intel.md +1 -1
- package/scaffold/en/commands/dw-refactoring-analysis.md +2 -1
- package/scaffold/en/commands/dw-review-implementation.md +28 -2
- package/scaffold/en/commands/dw-run-plan.md +2 -2
- package/scaffold/en/templates/idea-onepager.md +1 -1
- package/scaffold/pt-br/commands/dw-autopilot.md +6 -6
- package/scaffold/pt-br/commands/dw-brainstorm.md +1 -1
- package/scaffold/pt-br/commands/dw-bugfix.md +1 -0
- package/scaffold/pt-br/commands/dw-code-review.md +1 -0
- package/scaffold/pt-br/commands/dw-commit.md +6 -0
- package/scaffold/pt-br/commands/dw-create-techspec.md +2 -0
- package/scaffold/pt-br/commands/dw-deep-research.md +6 -0
- package/scaffold/pt-br/commands/dw-deps-audit.md +1 -0
- package/scaffold/pt-br/commands/dw-find-skills.md +4 -4
- package/scaffold/pt-br/commands/dw-fix-qa.md +1 -0
- package/scaffold/pt-br/commands/dw-generate-pr.md +1 -0
- package/scaffold/pt-br/commands/dw-help.md +9 -29
- package/scaffold/pt-br/commands/dw-intel.md +1 -1
- package/scaffold/pt-br/commands/dw-refactoring-analysis.md +2 -1
- package/scaffold/pt-br/commands/dw-review-implementation.md +21 -2
- package/scaffold/pt-br/commands/dw-run-plan.md +2 -2
- package/scaffold/pt-br/templates/idea-onepager.md +1 -1
- package/scaffold/skills/dw-codebase-intel/SKILL.md +1 -0
- package/scaffold/skills/dw-codebase-intel/references/api-design-discipline.md +138 -0
- package/scaffold/skills/dw-debug-protocol/SKILL.md +106 -0
- package/scaffold/skills/dw-debug-protocol/references/error-categorization.md +127 -0
- package/scaffold/skills/dw-debug-protocol/references/non-reproducible-strategy.md +108 -0
- package/scaffold/skills/dw-debug-protocol/references/six-step-triage.md +139 -0
- package/scaffold/skills/dw-debug-protocol/references/stop-the-line.md +52 -0
- package/scaffold/skills/dw-git-discipline/SKILL.md +120 -0
- package/scaffold/skills/dw-git-discipline/references/atomic-commits-discipline.md +158 -0
- package/scaffold/skills/dw-git-discipline/references/branch-hygiene.md +150 -0
- package/scaffold/skills/dw-git-discipline/references/trunk-based-pattern.md +82 -0
- package/scaffold/skills/dw-memory/SKILL.md +1 -2
- package/scaffold/skills/dw-simplification/SKILL.md +142 -0
- package/scaffold/skills/dw-simplification/references/behavior-preserving.md +148 -0
- package/scaffold/skills/dw-simplification/references/chestertons-fence.md +152 -0
- package/scaffold/skills/dw-simplification/references/complexity-metrics.md +147 -0
- package/scaffold/skills/dw-source-grounding/SKILL.md +128 -0
- package/scaffold/skills/dw-source-grounding/references/citation-protocol.md +108 -0
- package/scaffold/skills/dw-source-grounding/references/freshness-check.md +108 -0
- package/scaffold/skills/dw-source-grounding/references/source-priority.md +146 -0
- package/scaffold/skills/dw-verify/SKILL.md +0 -1
- package/scaffold/skills/vercel-react-best-practices/SKILL.md +4 -0
- package/scaffold/skills/vercel-react-best-practices/references/perf-discipline.md +122 -0
- package/scaffold/skills/webapp-testing/SKILL.md +5 -0
- package/scaffold/skills/webapp-testing/references/security-boundary.md +115 -0
- package/scaffold/skills/webapp-testing/references/three-workflow-patterns.md +144 -0
- package/scaffold/en/commands/dw-execute-phase.md +0 -149
- package/scaffold/en/commands/dw-plan-checker.md +0 -144
- package/scaffold/en/commands/dw-quick.md +0 -103
- package/scaffold/en/commands/dw-resume.md +0 -84
- package/scaffold/pt-br/commands/dw-execute-phase.md +0 -149
- package/scaffold/pt-br/commands/dw-plan-checker.md +0 -144
- package/scaffold/pt-br/commands/dw-quick.md +0 -103
- package/scaffold/pt-br/commands/dw-resume.md +0 -84
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Freshness check — keeping citations valid over time
|
|
2
|
+
|
|
3
|
+
A citation goes stale in two ways: the URL stops resolving (404, redirect, paywall added) OR the project's installed version moves past the version the citation pinned. Both invalidate the citation's authority. This file describes how to detect both and what to do.
|
|
4
|
+
|
|
5
|
+
## Two staleness modes
|
|
6
|
+
|
|
7
|
+
### Mode 1 — URL drift
|
|
8
|
+
|
|
9
|
+
The URL still loads, but the content has changed (doc was rewritten, section deleted, deprecated). Or the URL 404s outright.
|
|
10
|
+
|
|
11
|
+
Detection: re-fetch the URL on demand. Compare the section/heading the original citation pointed to.
|
|
12
|
+
|
|
13
|
+
Action when detected:
|
|
14
|
+
- If the new content still supports the original claim → update the citation's `retrieved` date.
|
|
15
|
+
- If the new content contradicts or removes the claim → the citation is invalid. Find a replacement source OR revisit the decision.
|
|
16
|
+
|
|
17
|
+
### Mode 2 — Version drift
|
|
18
|
+
|
|
19
|
+
The URL is fine, but the project bumped from React 18.3 to React 19. The citation `[..., version: 18.3, ...]` no longer pins to the version installed.
|
|
20
|
+
|
|
21
|
+
Detection: compare the cited version with the manifest's current version (`package.json` etc.). Mismatch → drift.
|
|
22
|
+
|
|
23
|
+
Action:
|
|
24
|
+
- If the doc has version-aware content (most modern docs do), find the equivalent for the new version.
|
|
25
|
+
- If the API was renamed/removed in the new version, the underlying decision needs re-evaluation, not just a citation patch.
|
|
26
|
+
|
|
27
|
+
## When to check freshness
|
|
28
|
+
|
|
29
|
+
| Trigger | Check what |
|
|
30
|
+
|---------|-----------|
|
|
31
|
+
| Acting on an artifact older than 90 days | Both URL drift and version drift |
|
|
32
|
+
| About to ship code based on a citation | URL drift (single fetch) |
|
|
33
|
+
| User explicitly asks "is this still current?" | Both |
|
|
34
|
+
| Routine `dw-deps-audit` | Version drift for every cited dep |
|
|
35
|
+
|
|
36
|
+
Don't check on every read — that turns documentation into a trip hazard. Check at decision points: before committing, before merging, before promoting to production.
|
|
37
|
+
|
|
38
|
+
## How to check programmatically
|
|
39
|
+
|
|
40
|
+
For URL drift:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Quick HEAD check — does the URL still resolve?
|
|
44
|
+
curl -sI "<url>" | head -1
|
|
45
|
+
# 200 OK → fine; 301/302 → follow; 404 → broken; 403 → paywall added
|
|
46
|
+
|
|
47
|
+
# Content drift check — fetch and grep for the original heading
|
|
48
|
+
curl -s "<url>" | grep -i "<expected-heading-or-section>"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
In an agent context: use `WebFetch` on the URL and confirm the cited section still exists. If a heading the citation referenced is gone, mark the citation as drift.
|
|
52
|
+
|
|
53
|
+
For version drift:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# What does the manifest say now?
|
|
57
|
+
node -p "require('./package.json').dependencies.react"
|
|
58
|
+
# Compare to the cited version in the artifact
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
In an agent context: read the manifest, parse the dep version, compare to the citation's `version` field.
|
|
62
|
+
|
|
63
|
+
## Updating stale citations
|
|
64
|
+
|
|
65
|
+
When a citation drifts but the underlying decision still holds, update in place:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Before:
|
|
69
|
+
[source: https://react.dev/reference/react/useEffect, version: 18.3, retrieved: 2025-09-01]
|
|
70
|
+
|
|
71
|
+
After URL drift detected (page restructured):
|
|
72
|
+
[source: https://react.dev/reference/react/useEffect, version: 18.3, retrieved: 2026-05-07,
|
|
73
|
+
superseded-by: https://react.dev/learn/synchronizing-with-effects, retrieved: 2026-05-07]
|
|
74
|
+
|
|
75
|
+
After version drift (project moved to React 19):
|
|
76
|
+
[source: https://react.dev/reference/react/useEffect, version: 19.0, retrieved: 2026-05-07,
|
|
77
|
+
previous: 18.3]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The artifact records the history. Reviewers can see: "this decision was first sourced for v18.3 in Sep 2025; re-verified for v19.0 in May 2026."
|
|
81
|
+
|
|
82
|
+
## When the underlying decision dies
|
|
83
|
+
|
|
84
|
+
Sometimes drift means the API the decision used no longer exists. Example: a decision in 2023 to use `React.useTransition` with the `pending` second tuple element. In React 18.3 that's the API; in React 19 the API shape changed.
|
|
85
|
+
|
|
86
|
+
In this case:
|
|
87
|
+
|
|
88
|
+
1. Don't silently update the citation. The decision IS now invalid.
|
|
89
|
+
2. Open an ADR or comment in the techspec: "decision X relied on API Y; API Y was changed in v<new>; need to revisit."
|
|
90
|
+
3. Loop the user (or the next iteration of `dw-create-techspec`/`dw-deps-audit`) into the decision, with the new constraint.
|
|
91
|
+
|
|
92
|
+
Quietly patching a stale citation when the underlying API is gone is a subtle category of bug. Surface it.
|
|
93
|
+
|
|
94
|
+
## Bibliography rotation in long-lived artifacts
|
|
95
|
+
|
|
96
|
+
For artifacts that live more than 6 months (long-running PRDs, ADRs, design docs), consider a "Sources last verified: YYYY-MM-DD" header at the top:
|
|
97
|
+
|
|
98
|
+
```markdown
|
|
99
|
+
---
|
|
100
|
+
type: techspec
|
|
101
|
+
schema_version: "1.0"
|
|
102
|
+
sources_last_verified: 2026-05-07
|
|
103
|
+
---
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
When an agent re-reads the artifact and the verification date is >90 days old, prompt: "Sources last verified <date>; re-run freshness check?"
|
|
107
|
+
|
|
108
|
+
Cheap operational discipline; prevents silent decay.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Source priority — what counts as authoritative
|
|
2
|
+
|
|
3
|
+
Not all sources are equal. The whole point of grounded development is using authoritative sources, not the loudest ones. This file is the hierarchy.
|
|
4
|
+
|
|
5
|
+
## Tier 1 — Authoritative
|
|
6
|
+
|
|
7
|
+
These are the only valid PRIMARY sources. Cite these for any claim about how a library, framework, or standard works.
|
|
8
|
+
|
|
9
|
+
### 1.1 Official versioned documentation
|
|
10
|
+
|
|
11
|
+
The exact version's published docs:
|
|
12
|
+
|
|
13
|
+
- React: `react.dev/reference/react?version=<X>`
|
|
14
|
+
- Next.js: `nextjs.org/docs` (versioned via release page)
|
|
15
|
+
- Python: `docs.python.org/<X.Y>/`
|
|
16
|
+
- Node: `nodejs.org/api/` (version-pinned via dropdown / URL `/dist/v<X.Y.Z>/`)
|
|
17
|
+
- ASP.NET Core: `learn.microsoft.com/aspnet/core/` (filter by version)
|
|
18
|
+
- Rust: `doc.rust-lang.org/<X.Y>/` and `docs.rs/<crate>/<version>/`
|
|
19
|
+
- Postgres: `postgresql.org/docs/<major>/`
|
|
20
|
+
- AWS: `docs.aws.amazon.com/<service>/` (versioned per SDK / API)
|
|
21
|
+
|
|
22
|
+
When the URL doesn't pin version, add a query (`?v=`, `?version=`) or use the docs section that explicitly states the version. If neither exists, note in the citation: `version: latest-as-of-retrieved`.
|
|
23
|
+
|
|
24
|
+
### 1.2 Official changelogs and migration guides
|
|
25
|
+
|
|
26
|
+
For decisions involving version transitions (upgrade from v17 to v18, etc.):
|
|
27
|
+
|
|
28
|
+
- React's `react.dev/blog` for major releases
|
|
29
|
+
- Next.js's `nextjs.org/docs/app/building-your-application/upgrading`
|
|
30
|
+
- Maintainer-published `CHANGELOG.md` in the repo root
|
|
31
|
+
|
|
32
|
+
### 1.3 Web standards & RFCs
|
|
33
|
+
|
|
34
|
+
For cross-implementation behavior:
|
|
35
|
+
|
|
36
|
+
- W3C specs (e.g., HTML, CSS specs)
|
|
37
|
+
- WHATWG specs (e.g., Fetch, URL)
|
|
38
|
+
- IETF RFCs (e.g., RFC 7807 Problem Details, RFC 9110 HTTP Semantics)
|
|
39
|
+
- ECMA-262 (JavaScript spec)
|
|
40
|
+
- ISO standards when relevant (e.g., ISO 8601 for dates)
|
|
41
|
+
|
|
42
|
+
Cite when the question is "is this behavior portable?" or "what's the standard?"
|
|
43
|
+
|
|
44
|
+
### 1.4 Compatibility tables
|
|
45
|
+
|
|
46
|
+
For "does X work in browser/runtime Y?":
|
|
47
|
+
|
|
48
|
+
- caniuse.com for web platform features
|
|
49
|
+
- MDN's Browser Compat Data (BCD) for Web APIs
|
|
50
|
+
- Compatibility tables published in maintainer docs (Postgres has them, Node has them)
|
|
51
|
+
|
|
52
|
+
## Tier 2 — Acceptable as supplement, NOT primary
|
|
53
|
+
|
|
54
|
+
Cite Tier 2 ONLY in addition to a Tier 1 source — never as the sole basis for a decision.
|
|
55
|
+
|
|
56
|
+
### 2.1 Maintainer blog posts
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
|
|
60
|
+
- `vercel.com/blog/...` — for Vercel-published deep-dives on Next.js patterns
|
|
61
|
+
- `microsoft.com/devblogs/...` — for ASP.NET / .NET deep-dives
|
|
62
|
+
- `engineering.<company>.com` — when the company maintains the project
|
|
63
|
+
|
|
64
|
+
These are first-person from people who built the thing. Often clearer than docs. But docs are the contract; blogs are commentary.
|
|
65
|
+
|
|
66
|
+
### 2.2 Conference talks (recorded)
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
|
|
70
|
+
- React Conf, Next.js Conf, Pycon, Rustconf
|
|
71
|
+
- The talk's slides + speaker handle
|
|
72
|
+
|
|
73
|
+
When citing, name the talk + year + speaker; link the video.
|
|
74
|
+
|
|
75
|
+
### 2.3 GitHub issues / PRs from the maintainer
|
|
76
|
+
|
|
77
|
+
Useful for understanding the WHY behind a doc statement. Cite the issue/PR number explicitly:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
[source: https://github.com/vercel/next.js/issues/12345, retrieved: 2026-05-07]
|
|
81
|
+
(maintainer thread on the rationale for App Router's caching behavior)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Tier 3 — Discovery only, NEVER cite as primary
|
|
85
|
+
|
|
86
|
+
These help you find the right Tier 1 doc. They do NOT support a decision on their own.
|
|
87
|
+
|
|
88
|
+
### 3.1 Stack Overflow
|
|
89
|
+
|
|
90
|
+
Frequently outdated, sometimes wrong, often not version-aware. Use to discover an answer's existence — then verify against Tier 1.
|
|
91
|
+
|
|
92
|
+
If a Stack Overflow answer points to docs, fetch the docs and cite those instead.
|
|
93
|
+
|
|
94
|
+
### 3.2 Tutorial blogs (non-maintainer)
|
|
95
|
+
|
|
96
|
+
Most blog posts are static; the framework moved on. The author may not even remember writing it. Don't cite.
|
|
97
|
+
|
|
98
|
+
### 3.3 LLM training data
|
|
99
|
+
|
|
100
|
+
Yours included. Treated as Tier 3 for two reasons: it's stale (months/years), and you can't link to it.
|
|
101
|
+
|
|
102
|
+
### 3.4 README screenshots from random repos
|
|
103
|
+
|
|
104
|
+
Someone's `examples/foo` directory isn't authoritative. The framework's official docs are.
|
|
105
|
+
|
|
106
|
+
## When sources conflict
|
|
107
|
+
|
|
108
|
+
Common scenario: the official docs say one thing, a maintainer blog says another, an issue thread says yet a third.
|
|
109
|
+
|
|
110
|
+
Resolution:
|
|
111
|
+
|
|
112
|
+
1. **Newer doc wins** if the version is the same. Docs get corrected; old blog posts don't.
|
|
113
|
+
2. **Maintainer commitment wins** if it's tracked. An issue closed with `wontfix` or a PR merged with `feat:` is binding signal.
|
|
114
|
+
3. **For grey areas, surface the conflict**. Cite all three and tell the user the authoritative resolution is unclear; ask whether to consult the maintainer directly.
|
|
115
|
+
|
|
116
|
+
## Examples in practice
|
|
117
|
+
|
|
118
|
+
### Good — multi-source decision
|
|
119
|
+
|
|
120
|
+
> Decision: use React 19 `useActionState` for the form submission flow.
|
|
121
|
+
>
|
|
122
|
+
> Rationale: idiomatic since React 19; replaces ad-hoc `useFormState`.
|
|
123
|
+
>
|
|
124
|
+
> Sources:
|
|
125
|
+
> - `[source: https://react.dev/reference/react/useActionState, version: 19.0, retrieved: 2026-05-07]` — Tier 1, official API doc
|
|
126
|
+
> - `[source: https://react.dev/blog/2024/12/05/react-19, retrieved: 2026-05-07]` — Tier 2, maintainer blog explaining the migration
|
|
127
|
+
|
|
128
|
+
### Bad — Stack Overflow as primary
|
|
129
|
+
|
|
130
|
+
> Decision: use `useEffect` cleanup with `AbortController` to cancel fetches.
|
|
131
|
+
>
|
|
132
|
+
> Source: a Stack Overflow answer with 1.2k upvotes.
|
|
133
|
+
|
|
134
|
+
The decision is correct, but the citation isn't authoritative. The fix:
|
|
135
|
+
|
|
136
|
+
> Source: `[source: https://react.dev/reference/react/useEffect#fetching-data-with-effects, version: 18.3, retrieved: 2026-05-07]` — same conclusion, authoritative origin.
|
|
137
|
+
|
|
138
|
+
### Bad — version-less citation
|
|
139
|
+
|
|
140
|
+
> Decision: use `Promise.withResolvers()`.
|
|
141
|
+
>
|
|
142
|
+
> Source: `[source: developer.mozilla.org]`
|
|
143
|
+
|
|
144
|
+
`Promise.withResolvers()` is Node 22+ / browsers TC39 stage 4. The version matters — the cite is incomplete:
|
|
145
|
+
|
|
146
|
+
> Source: `[source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers, retrieved: 2026-05-07, runtime-support: Node 22+, Chrome 119+]`
|
|
@@ -177,7 +177,6 @@ This skill is invoked transparently from:
|
|
|
177
177
|
- `/dw-bugfix` — before claiming the bug is fixed (original symptom no longer reproduces)
|
|
178
178
|
- `/dw-code-review` — before emitting an APPROVED verdict
|
|
179
179
|
- `/dw-generate-pr` — blocks PR creation if the session has no passing VERIFICATION REPORT post-last-edit
|
|
180
|
-
- `/dw-quick` — before committing the one-off change
|
|
181
180
|
|
|
182
181
|
Callers should mention this skill in their "Skills Complementares" section so the user sees the dependency.
|
|
183
182
|
|
|
@@ -144,3 +144,7 @@ Each rule file contains:
|
|
|
144
144
|
## Full Compiled Document
|
|
145
145
|
|
|
146
146
|
For the complete guide with all rules expanded: `AGENTS.md`
|
|
147
|
+
|
|
148
|
+
## References
|
|
149
|
+
|
|
150
|
+
- `references/perf-discipline.md` — workflow discipline (measure → identify → fix → verify → guard) that wraps the per-rule recipes above. Use when tackling performance work; cite the metric and tool before applying any rule. Adapted from [`addyosmani/agent-skills/performance-optimization`](https://github.com/addyosmani/agent-skills/tree/main/performance-optimization) (MIT).
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Performance discipline — measure, identify, fix, verify, guard
|
|
2
|
+
|
|
3
|
+
> Adapted from [`addyosmani/agent-skills/performance-optimization`](https://github.com/addyosmani/agent-skills/tree/main/performance-optimization) (MIT). The rules below complement the per-rule recipes in `rules/` with a workflow discipline.
|
|
4
|
+
|
|
5
|
+
The biggest performance mistake is fixing the wrong thing. The second biggest is "fixing" without measuring. This file establishes the workflow that prevents both.
|
|
6
|
+
|
|
7
|
+
## The five-step loop
|
|
8
|
+
|
|
9
|
+
### 1. Measure
|
|
10
|
+
|
|
11
|
+
Don't optimize what you haven't measured.
|
|
12
|
+
|
|
13
|
+
**Frontend:**
|
|
14
|
+
- Lighthouse / PageSpeed Insights → composite score + breakdown.
|
|
15
|
+
- DevTools Performance tab → flame graph, layout/paint timing.
|
|
16
|
+
- `web-vitals` library → LCP, FID/INP, CLS, TTFB on real users.
|
|
17
|
+
- Bundle analyzer (`next-bundle-analyzer`, `webpack-bundle-analyzer`) → see what's actually shipping.
|
|
18
|
+
|
|
19
|
+
**Backend:**
|
|
20
|
+
- Application logs with timing (`time-X-took: Yms`).
|
|
21
|
+
- DB query analyzer (`EXPLAIN ANALYZE`, slow query log).
|
|
22
|
+
- APM (Datadog, New Relic, Sentry Performance) for distributed traces.
|
|
23
|
+
- `top` / `htop` / process memory + CPU during load.
|
|
24
|
+
|
|
25
|
+
**Output:** a baseline number with a unit. "It's slow" is not a baseline. "P95 LCP is 4.8s" is a baseline.
|
|
26
|
+
|
|
27
|
+
### 2. Identify
|
|
28
|
+
|
|
29
|
+
Find where the time goes. The flame graph or trace shows it; don't guess.
|
|
30
|
+
|
|
31
|
+
Common culprits:
|
|
32
|
+
|
|
33
|
+
| Symptom | Likely cause |
|
|
34
|
+
|---------|--------------|
|
|
35
|
+
| Long initial paint | Large bundle, render-blocking resources |
|
|
36
|
+
| Slow time-to-interactive | Heavy JS execution, hydration cost |
|
|
37
|
+
| Layout shift | Missing dimensions, late-loaded fonts |
|
|
38
|
+
| Slow API response | N+1 query, missing index, expensive computation, external call latency |
|
|
39
|
+
| Memory creep | Listener leak, retained closure, unbounded cache |
|
|
40
|
+
|
|
41
|
+
The cause must come from data, not pattern-matching. The same symptom can have different causes in different apps.
|
|
42
|
+
|
|
43
|
+
### 3. Fix
|
|
44
|
+
|
|
45
|
+
Apply the smallest fix that addresses the identified cause:
|
|
46
|
+
|
|
47
|
+
- N+1 query → batch with `IN (...)`, single JOIN, or DataLoader.
|
|
48
|
+
- Heavy bundle → code splitting, lazy load, dynamic imports.
|
|
49
|
+
- Re-render storm → `useMemo`, `useCallback`, `memo`, signal-based state.
|
|
50
|
+
- Slow API → cache, precompute, parallelize, move work to background.
|
|
51
|
+
- Layout shift → reserve space (width+height attrs, CSS aspect-ratio).
|
|
52
|
+
|
|
53
|
+
The `rules/` directory in this skill has tactical recipes for each. Use them when the diagnosis points there.
|
|
54
|
+
|
|
55
|
+
**Don't apply optimizations preemptively.** `useMemo` everywhere = noise + cost. `memo` everywhere = stale prop bugs.
|
|
56
|
+
|
|
57
|
+
### 4. Verify
|
|
58
|
+
|
|
59
|
+
Re-measure with the same instrument from step 1.
|
|
60
|
+
|
|
61
|
+
- Same scenario, same env (or as close as possible).
|
|
62
|
+
- Multiple runs (perf is noisy; one run is not evidence).
|
|
63
|
+
- Compare against baseline.
|
|
64
|
+
|
|
65
|
+
If the number didn't change meaningfully (e.g., <10% improvement is below noise floor for most metrics): you fixed the wrong thing. Revert and go back to step 2.
|
|
66
|
+
|
|
67
|
+
If the number improved but the user-perceived experience didn't: you optimized a metric, not a bottleneck. Rethink what to measure.
|
|
68
|
+
|
|
69
|
+
### 5. Guard
|
|
70
|
+
|
|
71
|
+
Prevent regression:
|
|
72
|
+
|
|
73
|
+
- **Performance budgets in CI:** Lighthouse CI, bundle-size limits per route, P95 latency checks.
|
|
74
|
+
- **Regression test for the specific scenario** that was slow.
|
|
75
|
+
- **Monitoring in production** so future regressions surface from real users (not just CI runs that may not match prod load).
|
|
76
|
+
- **Document the constraint** in code comments at the boundary that must stay fast (e.g., "this loop processes the entire user list; keep it O(n)").
|
|
77
|
+
|
|
78
|
+
Without guards, every refactor risks reintroducing the bottleneck. The fix decays.
|
|
79
|
+
|
|
80
|
+
## Frontend-specific patterns
|
|
81
|
+
|
|
82
|
+
The `rules/` directory provides recipes for: bundle size (barrel imports, dynamic imports, defer third-party), client-side perf (passive listeners, swr dedup, localStorage schema), async patterns (parallel fetches, suspense boundaries, defer awaits), and JS micro-perf. Apply when measurement points there.
|
|
83
|
+
|
|
84
|
+
**Hierarchy of impact (typical):**
|
|
85
|
+
1. Bundle size — biggest impact for cold loads.
|
|
86
|
+
2. Hydration cost — biggest impact for time-to-interactive.
|
|
87
|
+
3. Network waterfalls — biggest impact for data-heavy pages.
|
|
88
|
+
4. Re-render volume — biggest impact for interactive heavy pages.
|
|
89
|
+
5. JS micro-perf — usually irrelevant unless in a hot loop.
|
|
90
|
+
|
|
91
|
+
Optimize in this order; don't jump to (5) before (1).
|
|
92
|
+
|
|
93
|
+
## Backend-specific patterns
|
|
94
|
+
|
|
95
|
+
| Pattern | When |
|
|
96
|
+
|---------|------|
|
|
97
|
+
| Add database index | Query plan shows full table scan |
|
|
98
|
+
| Batch N queries into 1 | N+1 detected in trace |
|
|
99
|
+
| Cache (Redis, in-memory, edge) | Same expensive computation repeats |
|
|
100
|
+
| Precompute / materialize | Aggregation that runs per-request but updates rarely |
|
|
101
|
+
| Background job | Work doesn't need to block the response |
|
|
102
|
+
| Parallelize independent calls | Trace shows sequential awaits with no dependency |
|
|
103
|
+
| Move to faster runtime / region | Network or CPU is the bottleneck after other fixes |
|
|
104
|
+
|
|
105
|
+
## When NOT to optimize
|
|
106
|
+
|
|
107
|
+
- The number isn't actually a problem. "P95 200ms" doesn't need optimization unless your SLA is tighter.
|
|
108
|
+
- The optimization makes the code substantially harder to maintain. A 5% gain isn't worth a 50% complexity increase.
|
|
109
|
+
- The optimized code can't be tested. If perf code can't be regression-tested, the next change will undo it silently.
|
|
110
|
+
- You're optimizing dev-mode performance, not prod. Many tools (React, Next, Vite) have very different hot paths in dev vs prod.
|
|
111
|
+
|
|
112
|
+
## Anti-patterns
|
|
113
|
+
|
|
114
|
+
- "Looks slow, let me memo this" — without measurement, this just adds complexity.
|
|
115
|
+
- "Add caching to fix the slow query" — caching hides the bug; the slow query reappears for the next user.
|
|
116
|
+
- Profiling once, optimizing five things, never re-measuring.
|
|
117
|
+
- Setting `useMemo` deps wrong — silently breaks correctness for marginal perf gain.
|
|
118
|
+
- Treating Lighthouse score as the only metric — score can improve without UX improving.
|
|
119
|
+
|
|
120
|
+
## Integration with dev-workflow
|
|
121
|
+
|
|
122
|
+
Use with `dw-refactoring-analysis` when flagging perf-related smells: cite the metric, the measurement tool, and the suggested rule from the `rules/` directory. Without those three, a perf "smell" is a guess.
|
|
@@ -131,3 +131,8 @@ try {
|
|
|
131
131
|
## Helper Functions
|
|
132
132
|
|
|
133
133
|
Some helper functions are available in [`test-helper.js`](./assets/test-helper.js) to simplify common tasks like waiting for elements, capturing screenshots, and handling errors. You can import and use these functions in your tests to improve readability and maintainability.
|
|
134
|
+
|
|
135
|
+
## References
|
|
136
|
+
|
|
137
|
+
- `references/security-boundary.md` — every byte from a browser is potentially attacker-controlled. Test that server-side authorization, validation, and CSRF protection hold even when the UI is bypassed via direct API calls or DevTools manipulation. Adapted from [`addyosmani/agent-skills/browser-devtools`](https://github.com/addyosmani/agent-skills/tree/main/browser-devtools) (MIT).
|
|
138
|
+
- `references/three-workflow-patterns.md` — UI bugs vs network issues vs performance investigations are three distinct testing workflows with different signals and failure modes. Pick the right workflow for the verification you actually need; don't conflate them in a single mega-test. Adapted from the same upstream skill.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Security boundary — every browser is hostile
|
|
2
|
+
|
|
3
|
+
> Adapted from [`addyosmani/agent-skills/browser-devtools`](https://github.com/addyosmani/agent-skills/tree/main/browser-devtools) (MIT). Adopts the security-boundary principle to inform how webapp-testing scenarios should validate trust boundaries.
|
|
4
|
+
|
|
5
|
+
The browser is not a secure environment. Anything that runs there — JS, CSS, HTML, devtools — is under the user's control. When you write a webapp test, you're not just verifying functionality; you're often verifying that this assumption holds.
|
|
6
|
+
|
|
7
|
+
## The core principle
|
|
8
|
+
|
|
9
|
+
> Every byte sent from a browser is potentially attacker-controlled, regardless of what the UI presents.
|
|
10
|
+
|
|
11
|
+
The UI is a convenience for the user. The server cannot trust:
|
|
12
|
+
|
|
13
|
+
- Hidden form fields (the user can edit them in DevTools).
|
|
14
|
+
- Disabled buttons (the user can re-enable them).
|
|
15
|
+
- Client-side validation (the user can bypass it).
|
|
16
|
+
- Cookie values (the user can modify them).
|
|
17
|
+
- HTTP request bodies (the user can craft any payload).
|
|
18
|
+
- Headers (mostly user-controlled; a few are browser-set).
|
|
19
|
+
|
|
20
|
+
Only server-side checks count for security. Client-side checks are UX, not security.
|
|
21
|
+
|
|
22
|
+
## Implications for webapp testing
|
|
23
|
+
|
|
24
|
+
When designing test scenarios for a webapp, validate:
|
|
25
|
+
|
|
26
|
+
### 1. Server-side authorization on every action
|
|
27
|
+
|
|
28
|
+
Test that a user CANNOT perform an action they shouldn't, even if they manipulate the UI to send the request:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
- Log in as user A.
|
|
32
|
+
- Attempt to access another user's resource by directly hitting the endpoint
|
|
33
|
+
(skip the UI navigation; craft the request).
|
|
34
|
+
- Expected: 403 Forbidden, no data leakage in error response.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
If the test passes only when going through the UI, the test is incomplete. Real attackers don't go through the UI.
|
|
38
|
+
|
|
39
|
+
### 2. Server-side validation independent of client
|
|
40
|
+
|
|
41
|
+
Test that the server rejects malformed input even when the client would normally prevent it:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
- Open the form.
|
|
45
|
+
- Use DevTools to remove the `maxlength` attribute from an input.
|
|
46
|
+
- Submit an oversized value.
|
|
47
|
+
- Expected: server rejects with 400/422, not 500 (server crashed because client validation was assumed).
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 3. Auth state cannot be forged
|
|
51
|
+
|
|
52
|
+
Test that:
|
|
53
|
+
|
|
54
|
+
- Modifying client-stored tokens (localStorage, sessionStorage) does not grant access.
|
|
55
|
+
- Removing or modifying cookies does not grant access (or it gracefully de-authenticates).
|
|
56
|
+
- Replaying captured requests after logout fails.
|
|
57
|
+
|
|
58
|
+
### 4. CSRF / cross-origin protection
|
|
59
|
+
|
|
60
|
+
Test that:
|
|
61
|
+
|
|
62
|
+
- A request originating from a different origin (set `Origin: https://attacker.com` in test) is rejected for state-changing operations.
|
|
63
|
+
- CSRF tokens (or SameSite cookie equivalents) are validated, not just included.
|
|
64
|
+
|
|
65
|
+
### 5. No client-side secrets
|
|
66
|
+
|
|
67
|
+
Audit the bundle for accidentally-shipped secrets:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
- Build the production bundle.
|
|
71
|
+
- grep for: API keys (hex strings, JWT structure), private endpoints, internal URLs,
|
|
72
|
+
source maps containing internal paths, debug flags left enabled.
|
|
73
|
+
- Expected: nothing sensitive present.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Common UI-as-security misconceptions
|
|
77
|
+
|
|
78
|
+
| Misconception | Why it fails |
|
|
79
|
+
|---------------|--------------|
|
|
80
|
+
| "Hidden field hides the value" | Visible in HTML source / DevTools |
|
|
81
|
+
| "Disabled button prevents action" | User can re-enable in DevTools |
|
|
82
|
+
| "Client-side regex prevents bad input" | Bypassable with crafted request |
|
|
83
|
+
| "Auth check on the page renders the wrong page" | Page didn't render but the API is still callable |
|
|
84
|
+
| "We minified the code" | Reverse-engineering minified code is trivial |
|
|
85
|
+
| "We obfuscated the API" | Network tab reveals the calls |
|
|
86
|
+
| "Only our app calls this endpoint" | Anyone can call any URL |
|
|
87
|
+
|
|
88
|
+
## Testing browser-side trust boundaries
|
|
89
|
+
|
|
90
|
+
When using Playwright/Puppeteer/MCP for testing:
|
|
91
|
+
|
|
92
|
+
- **Capture and replay attacks:** record a request, replay with modified payload, assert the server rejects.
|
|
93
|
+
- **Session manipulation:** modify cookies/localStorage between actions, assert the server detects.
|
|
94
|
+
- **Direct API calls:** skip the UI; call endpoints directly; assert correct authorization.
|
|
95
|
+
- **Cross-origin simulation:** override `Origin` header; assert correct rejection.
|
|
96
|
+
|
|
97
|
+
These tests catch bugs unit tests miss, because unit tests assume well-formed input. The browser-as-attacker tests assume malicious input.
|
|
98
|
+
|
|
99
|
+
## Anti-patterns
|
|
100
|
+
|
|
101
|
+
- Testing only the happy path through the UI.
|
|
102
|
+
- Asserting "the button is disabled" without asserting "the API rejects the call."
|
|
103
|
+
- Treating client-side validation messages as if they were security checks.
|
|
104
|
+
- Relying on minification/obfuscation as defense.
|
|
105
|
+
- Testing once, never re-testing after dependency updates that change the trust surface.
|
|
106
|
+
|
|
107
|
+
## When this matters most
|
|
108
|
+
|
|
109
|
+
- Auth flows, account changes, password resets.
|
|
110
|
+
- Payment / billing operations.
|
|
111
|
+
- Data export, account deletion, irreversible actions.
|
|
112
|
+
- Multi-tenant boundaries (one user's data must not leak to another).
|
|
113
|
+
- Admin endpoints (must reject non-admin users at the server, not just hide UI).
|
|
114
|
+
|
|
115
|
+
These are the tests that catch real production incidents.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Three workflow patterns for browser-based testing
|
|
2
|
+
|
|
3
|
+
> Adapted from [`addyosmani/agent-skills/browser-devtools`](https://github.com/addyosmani/agent-skills/tree/main/browser-devtools) (MIT). The three workflows below organize webapp testing tasks by what's actually being verified.
|
|
4
|
+
|
|
5
|
+
Most webapp testing tasks fall into one of three workflows. Each has different goals, different signals, and different failure modes. Don't conflate them.
|
|
6
|
+
|
|
7
|
+
## Workflow 1 — UI bugs
|
|
8
|
+
|
|
9
|
+
**Goal:** verify what the user sees matches what's expected.
|
|
10
|
+
|
|
11
|
+
**Signals:**
|
|
12
|
+
- Screenshot diff vs reference.
|
|
13
|
+
- Element exists / does not exist in DOM.
|
|
14
|
+
- Element has expected text / attributes.
|
|
15
|
+
- Element is visible / styled correctly.
|
|
16
|
+
- Click triggers expected navigation or state change.
|
|
17
|
+
|
|
18
|
+
**Tools:**
|
|
19
|
+
- Playwright / Puppeteer for navigation and interaction.
|
|
20
|
+
- Visual regression (Percy, Chromatic, Playwright's `toHaveScreenshot`).
|
|
21
|
+
- Accessibility checks (`axe-core`, Playwright's accessibility snapshot).
|
|
22
|
+
|
|
23
|
+
**Common bugs caught:**
|
|
24
|
+
- Layout shift after image loads.
|
|
25
|
+
- Text wrapping that overflows containers.
|
|
26
|
+
- Missing focus styles on interactive elements.
|
|
27
|
+
- Hover/active states broken on touch devices.
|
|
28
|
+
- Hydration mismatch (server-rendered ≠ client-rendered DOM).
|
|
29
|
+
|
|
30
|
+
**Common bugs missed:**
|
|
31
|
+
- Behavior bugs (click works but state is wrong).
|
|
32
|
+
- Race conditions (UI state stable; network race underneath).
|
|
33
|
+
- Security bugs (UI hides the action; server still accepts it).
|
|
34
|
+
|
|
35
|
+
**When to use this workflow:**
|
|
36
|
+
- After a CSS / component refactor.
|
|
37
|
+
- Before / after design system migrations.
|
|
38
|
+
- Smoke testing critical pages on every release.
|
|
39
|
+
|
|
40
|
+
## Workflow 2 — Network issues
|
|
41
|
+
|
|
42
|
+
**Goal:** verify the client-server contract is honored under various network conditions.
|
|
43
|
+
|
|
44
|
+
**Signals:**
|
|
45
|
+
- Request was sent with expected payload, headers, method, URL.
|
|
46
|
+
- Response was received with expected status, body, headers.
|
|
47
|
+
- Retries occurred when expected (and didn't when not).
|
|
48
|
+
- Errors are surfaced to UI vs swallowed silently.
|
|
49
|
+
- Requests don't fire when they shouldn't (e.g., debounced search).
|
|
50
|
+
|
|
51
|
+
**Tools:**
|
|
52
|
+
- Playwright `page.route()` to intercept and inspect / modify requests.
|
|
53
|
+
- DevTools Network panel via MCP / inspection.
|
|
54
|
+
- Mock server / MSW for controlled scenarios.
|
|
55
|
+
- Network throttling (slow 3G, offline) for resilience tests.
|
|
56
|
+
|
|
57
|
+
**Common bugs caught:**
|
|
58
|
+
- N+1 requests on page load.
|
|
59
|
+
- Missing error handling (200 success path tested; 500 path crashes UI).
|
|
60
|
+
- Auth headers missing on retried requests.
|
|
61
|
+
- Stale data shown after offline reconnect.
|
|
62
|
+
- Race conditions when multiple requests resolve out of order.
|
|
63
|
+
|
|
64
|
+
**Common bugs missed:**
|
|
65
|
+
- Visual bugs that don't affect network (CSS issues).
|
|
66
|
+
- Server-side bugs (test only checks request/response shape, not server logic).
|
|
67
|
+
- Performance bugs at scale (single request looks fine; thousands per second don't).
|
|
68
|
+
|
|
69
|
+
**When to use this workflow:**
|
|
70
|
+
- After auth / API client refactor.
|
|
71
|
+
- Verifying offline / connectivity-loss behavior.
|
|
72
|
+
- Validating against contract tests / API mocks.
|
|
73
|
+
- Reproducing user-reported "loading forever" bugs.
|
|
74
|
+
|
|
75
|
+
## Workflow 3 — Performance investigation
|
|
76
|
+
|
|
77
|
+
**Goal:** find why a page is slow and verify a fix.
|
|
78
|
+
|
|
79
|
+
**Signals:**
|
|
80
|
+
- Lighthouse scores (LCP, FID/INP, CLS, TTFB).
|
|
81
|
+
- DevTools Performance flame graph timing.
|
|
82
|
+
- Bundle analyzer output.
|
|
83
|
+
- `web-vitals` library captures from real browser sessions.
|
|
84
|
+
- Frame rate during interactions (`requestAnimationFrame` timing).
|
|
85
|
+
|
|
86
|
+
**Tools:**
|
|
87
|
+
- Playwright `tracing.start({ snapshots: true, screenshots: true })`.
|
|
88
|
+
- Lighthouse CI for automated runs.
|
|
89
|
+
- DevTools Performance tab via MCP.
|
|
90
|
+
- WebPageTest for repeatable third-party measurement.
|
|
91
|
+
- Bundle analyzer (`next-bundle-analyzer`, `webpack-bundle-analyzer`).
|
|
92
|
+
|
|
93
|
+
**Common bugs caught:**
|
|
94
|
+
- Render-blocking third-party scripts.
|
|
95
|
+
- Unintended re-renders amplifying click handlers.
|
|
96
|
+
- Large bundle from accidental lib import (e.g., `import _ from 'lodash'` instead of specific function).
|
|
97
|
+
- Images larger than displayed size.
|
|
98
|
+
- N+1 client-side renders (list of 1000 items each fetching).
|
|
99
|
+
|
|
100
|
+
**Common bugs missed:**
|
|
101
|
+
- Network correctness (perf can pass even when results are wrong).
|
|
102
|
+
- Visual issues unrelated to render time.
|
|
103
|
+
- Backend perf (this workflow looks at client-side; backend traces are needed too).
|
|
104
|
+
|
|
105
|
+
**When to use this workflow:**
|
|
106
|
+
- Performance regression alerts firing.
|
|
107
|
+
- User-reported slowness.
|
|
108
|
+
- Before / after a perf-targeted refactor.
|
|
109
|
+
- Pre-launch validation against budget targets.
|
|
110
|
+
|
|
111
|
+
## Choosing a workflow
|
|
112
|
+
|
|
113
|
+
The first question for any test: what am I trying to verify?
|
|
114
|
+
|
|
115
|
+
| Concern | Workflow |
|
|
116
|
+
|---------|----------|
|
|
117
|
+
| "Does the page look right?" | UI bugs |
|
|
118
|
+
| "Does clicking this button do the right thing visually?" | UI bugs |
|
|
119
|
+
| "Does the API get called correctly?" | Network issues |
|
|
120
|
+
| "Does the UI handle errors gracefully?" | Network issues |
|
|
121
|
+
| "Why is this page slow?" | Performance |
|
|
122
|
+
| "Does this hit our perf budget?" | Performance |
|
|
123
|
+
| "Does an attacker get blocked here?" | Network issues + security boundary (`security-boundary.md`) |
|
|
124
|
+
|
|
125
|
+
Mixing workflows in a single test produces flaky, slow, or incomplete coverage. A test that asserts BOTH "the button is styled correctly" AND "Lighthouse score is >90" runs slowly and fails for unrelated reasons.
|
|
126
|
+
|
|
127
|
+
## Anti-patterns
|
|
128
|
+
|
|
129
|
+
- One mega-test that "checks everything" — fails fragilely, hard to debug.
|
|
130
|
+
- UI tests that assert pixel-perfect layout in CI (CI rendering differs from local).
|
|
131
|
+
- Network tests that mock the entire API (you stop testing the contract; you test the mock).
|
|
132
|
+
- Performance tests run once during dev, never in CI (regressions land silently).
|
|
133
|
+
- Skipping security workflow because "we have unit tests for auth" — unit tests don't catch UI/server-disagreement bugs.
|
|
134
|
+
|
|
135
|
+
## How these compose
|
|
136
|
+
|
|
137
|
+
A real webapp test suite has all three workflows running:
|
|
138
|
+
|
|
139
|
+
- **Per commit (CI):** UI smoke tests + critical-path network tests.
|
|
140
|
+
- **Per PR:** above + visual regression on changed components.
|
|
141
|
+
- **Per release:** above + Lighthouse CI + extended network resilience tests.
|
|
142
|
+
- **Periodically (nightly / weekly):** full perf baseline + security boundary checks.
|
|
143
|
+
|
|
144
|
+
Different cadences match different cost profiles. UI smoke is cheap; full perf + security is expensive. Balance accordingly.
|