@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,158 @@
|
|
|
1
|
+
# Atomic commits — one intent per commit
|
|
2
|
+
|
|
3
|
+
A commit is atomic if it represents exactly one logical change. Atomic commits are the foundation of `git bisect`, `git revert`, code review quality, and reading history six months later.
|
|
4
|
+
|
|
5
|
+
## The single-intent rule
|
|
6
|
+
|
|
7
|
+
If your commit message naturally contains "and" connecting two things — that's two commits.
|
|
8
|
+
|
|
9
|
+
| Bad subject | Better |
|
|
10
|
+
|-------------|--------|
|
|
11
|
+
| `feat: add login form and fix navbar bug` | Two commits: `feat(login): add form`, `fix(nav): correct mobile menu` |
|
|
12
|
+
| `refactor: extract user service and add caching` | Two commits: `refactor(user): extract service`, `feat(user): add result cache` |
|
|
13
|
+
| `chore: update deps and reformat` | Two commits: `chore(deps): bump foo to 2.0`, `style: apply prettier sweep` |
|
|
14
|
+
| `fix: handle null and add tests` | Two commits: `test(payment): cover null amount case`, `fix(payment): handle null amount` (or merge tests + fix when they're the same logical change — see below) |
|
|
15
|
+
|
|
16
|
+
**Exception:** if you fix a bug AND add the regression test for it, those belong in ONE commit. The test proves the bug and proves the fix; separating them loses the link.
|
|
17
|
+
|
|
18
|
+
## Refactor vs feature: always separate
|
|
19
|
+
|
|
20
|
+
The most common atomicity violation: refactoring "while I'm in here" alongside a feature.
|
|
21
|
+
|
|
22
|
+
Bad:
|
|
23
|
+
```
|
|
24
|
+
feat(orders): add bulk-order export AND extract OrderRepository
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Good:
|
|
28
|
+
```
|
|
29
|
+
refactor(orders): extract OrderRepository (no behavior change)
|
|
30
|
+
feat(orders): add bulk-order export endpoint
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Why: when bulk-order export turns out to have a bug 2 months later, `git bisect` lands on the second commit. The first commit is a clean prior baseline you can compare against. If they were combined, the refactor's surface area dilutes the diagnosis.
|
|
34
|
+
|
|
35
|
+
## Practical: how to make commits atomic
|
|
36
|
+
|
|
37
|
+
When you find yourself with mixed changes in the working directory:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# 1. See what's changed
|
|
41
|
+
git status
|
|
42
|
+
git diff
|
|
43
|
+
|
|
44
|
+
# 2. Stage just the refactor (no behavior change)
|
|
45
|
+
git add -p # interactive — pick hunks one by one
|
|
46
|
+
# Or stage specific files:
|
|
47
|
+
git add src/orders/repository.ts
|
|
48
|
+
|
|
49
|
+
# 3. Verify what's staged matches one logical intent
|
|
50
|
+
git diff --cached
|
|
51
|
+
|
|
52
|
+
# 4. Commit
|
|
53
|
+
git commit -m "refactor(orders): extract OrderRepository (no behavior change)"
|
|
54
|
+
|
|
55
|
+
# 5. Stage the feature
|
|
56
|
+
git add src/orders/bulk-export.ts src/orders/__tests__/bulk-export.test.ts
|
|
57
|
+
|
|
58
|
+
# 6. Commit
|
|
59
|
+
git commit -m "feat(orders): add bulk-order export endpoint"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`git add -p` is the workhorse for unmixing changes. Practice it.
|
|
63
|
+
|
|
64
|
+
## Commit message structure
|
|
65
|
+
|
|
66
|
+
Conventional Commits format:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
type(scope): subject
|
|
70
|
+
|
|
71
|
+
body — explains WHY, not what (the diff already shows what)
|
|
72
|
+
|
|
73
|
+
Footer: BREAKING CHANGE, Refs, Co-Authored-By
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Type vocabulary:**
|
|
77
|
+
|
|
78
|
+
| Type | Use for |
|
|
79
|
+
|------|---------|
|
|
80
|
+
| `feat` | New user-facing capability |
|
|
81
|
+
| `fix` | Bug fix |
|
|
82
|
+
| `refactor` | Code change with NO behavior change |
|
|
83
|
+
| `perf` | Behavior unchanged but faster |
|
|
84
|
+
| `docs` | Docs-only |
|
|
85
|
+
| `test` | Test additions/changes only |
|
|
86
|
+
| `style` | Formatting, no semantic change |
|
|
87
|
+
| `chore` | Build, deps, config, no source change |
|
|
88
|
+
| `ci` | CI pipeline changes only |
|
|
89
|
+
| `build` | Build system changes |
|
|
90
|
+
|
|
91
|
+
**Subject line rules:**
|
|
92
|
+
- ≤72 chars
|
|
93
|
+
- Imperative ("add" not "added", "fix" not "fixes")
|
|
94
|
+
- No trailing period
|
|
95
|
+
- Lowercase after the colon
|
|
96
|
+
|
|
97
|
+
**Body rules:**
|
|
98
|
+
- Wrap at 72-100 chars per line
|
|
99
|
+
- Blank line between subject and body
|
|
100
|
+
- WHY > WHAT
|
|
101
|
+
- Reference issues, PRDs, ADRs when relevant
|
|
102
|
+
|
|
103
|
+
## When to write a body
|
|
104
|
+
|
|
105
|
+
You don't need a body for trivial changes. You need one when:
|
|
106
|
+
|
|
107
|
+
- The reason for the change isn't obvious from the diff (e.g., a workaround for a bug in a dependency).
|
|
108
|
+
- The change addresses an issue with non-obvious consequences (e.g., performance, security).
|
|
109
|
+
- The change is a deliberate design choice over alternatives (briefly note the rejected option).
|
|
110
|
+
- The change has a non-obvious blast radius.
|
|
111
|
+
|
|
112
|
+
A good rule: if a future maintainer would say "huh, why?" reading the diff, write a body.
|
|
113
|
+
|
|
114
|
+
## What goes in the footer
|
|
115
|
+
|
|
116
|
+
- `BREAKING CHANGE: <explanation>` — for breaking-change commits.
|
|
117
|
+
- `Refs #123` — issue reference.
|
|
118
|
+
- `Co-Authored-By: Name <email>` — for pair work or AI assistance.
|
|
119
|
+
|
|
120
|
+
## Bisect-friendly commits
|
|
121
|
+
|
|
122
|
+
For `git bisect` to work, every commit must:
|
|
123
|
+
- Build
|
|
124
|
+
- Pass tests
|
|
125
|
+
- Be a coherent state (not "WIP, half-implemented")
|
|
126
|
+
|
|
127
|
+
If you can't bisect through your branch, the commits aren't atomic enough. Squash before merging is acceptable; intra-branch WIP commits get rebased away before push.
|
|
128
|
+
|
|
129
|
+
## What to do with WIP / "save point" commits
|
|
130
|
+
|
|
131
|
+
Local WIP is fine. Pushed WIP is not.
|
|
132
|
+
|
|
133
|
+
Workflow:
|
|
134
|
+
1. Make many small commits as you work (saves your progress).
|
|
135
|
+
2. Before pushing OR before opening PR, `git rebase -i origin/main` to reorganize:
|
|
136
|
+
- Squash WIP commits into their logical parent.
|
|
137
|
+
- Drop accidental commits.
|
|
138
|
+
- Reorder so refactor comes before feature.
|
|
139
|
+
- Edit messages.
|
|
140
|
+
3. Push the cleaned history.
|
|
141
|
+
|
|
142
|
+
After pushing, no rewrites unless explicitly authorized — others may have pulled.
|
|
143
|
+
|
|
144
|
+
## Common atomic-commit mistakes
|
|
145
|
+
|
|
146
|
+
- **"Tiny extra fix" piggy-backed.** "While I was in there" → separate commit.
|
|
147
|
+
- **Reformat sweep mixed with logic change.** Apply formatter as its own commit BEFORE making logic changes.
|
|
148
|
+
- **Test fixture changes mixed with code changes.** If the fixture change is just to support the new code, fine — keep together. If the fixture was wrong before and you're fixing it, separate commit.
|
|
149
|
+
- **Lockfile churn separate from intent.** Sometimes lockfile updates accompany intentional dep bumps; that's fine. But noisy lockfile changes from running `npm install` for unrelated reasons → revert.
|
|
150
|
+
- **Generated file diffs mixed in.** Generated files (build artifacts, generated types) should regenerate from source automatically; don't commit them by hand alongside source changes if you can avoid it.
|
|
151
|
+
|
|
152
|
+
## What atomic commits unlock
|
|
153
|
+
|
|
154
|
+
- `git bisect` finds the exact commit that broke X — and that commit is small enough to inspect quickly.
|
|
155
|
+
- `git revert <sha>` removes ONE feature without unwinding others.
|
|
156
|
+
- Code review focuses: each commit reviewed in isolation makes a tight discussion possible.
|
|
157
|
+
- Cherry-picking to other branches works cleanly when the change is one thing.
|
|
158
|
+
- Commit messages become reliable changelog material.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Branch hygiene — naming, lifetime, rebase vs merge
|
|
2
|
+
|
|
3
|
+
Branches are conversations between developers. Names, lifetimes, and integration choices shape that conversation.
|
|
4
|
+
|
|
5
|
+
## Branch naming conventions
|
|
6
|
+
|
|
7
|
+
Format: `<type>/<scope>` or `<type>/<scope>-<short-description>`
|
|
8
|
+
|
|
9
|
+
| Prefix | When |
|
|
10
|
+
|--------|------|
|
|
11
|
+
| `feat/` | New user-facing capability |
|
|
12
|
+
| `fix/` | Bug fix |
|
|
13
|
+
| `refactor/` | No behavior change, internal restructure |
|
|
14
|
+
| `perf/` | Performance improvement |
|
|
15
|
+
| `chore/` | Build, deps, config |
|
|
16
|
+
| `docs/` | Documentation only |
|
|
17
|
+
| `test/` | Test additions or fixes |
|
|
18
|
+
| `experiment/` | Spike / exploration; usually NOT merged |
|
|
19
|
+
| `hotfix/` | Urgent production fix |
|
|
20
|
+
| `release/` | Release preparation (if your team uses release branches) |
|
|
21
|
+
|
|
22
|
+
Rules:
|
|
23
|
+
- Lowercase, kebab-case.
|
|
24
|
+
- ≤40 characters total.
|
|
25
|
+
- Match the prefix to the dominant change type if mixed.
|
|
26
|
+
- Include a PRD/issue reference when one exists: `feat/prd-user-onboarding`, `fix/issue-1234-login-loop`.
|
|
27
|
+
|
|
28
|
+
Examples:
|
|
29
|
+
|
|
30
|
+
| Good | Bad |
|
|
31
|
+
|------|-----|
|
|
32
|
+
| `feat/user-onboarding` | `feature/UserOnboarding` (capitalized) |
|
|
33
|
+
| `fix/login-redirect-loop` | `bug-fix-stuff` (no prefix, vague) |
|
|
34
|
+
| `refactor/extract-user-service` | `mybranch` (meaningless) |
|
|
35
|
+
| `chore/bump-react-19` | `update-deps-and-tests` (multi-intent in name) |
|
|
36
|
+
|
|
37
|
+
## Branch lifetime
|
|
38
|
+
|
|
39
|
+
| Branch type | Target lifetime |
|
|
40
|
+
|-------------|-----------------|
|
|
41
|
+
| `feat/` for normal feature | 1-3 days |
|
|
42
|
+
| `fix/` for normal bug | hours to 1 day |
|
|
43
|
+
| `hotfix/` | hours, ship same day |
|
|
44
|
+
| `refactor/` for small refactor | hours to 1 day |
|
|
45
|
+
| `refactor/` for major refactor | break into multiple `refactor/`+ branches, each 1-3 days |
|
|
46
|
+
| `experiment/` | as long as needed, but NOT merged to main without conversion |
|
|
47
|
+
| `release/` | until release ships |
|
|
48
|
+
|
|
49
|
+
A branch older than a week is a smell. Either:
|
|
50
|
+
- It's blocked on review (fix the review process).
|
|
51
|
+
- It's too big (split it).
|
|
52
|
+
- It should have been a feature flag on `main` (kill the branch, do it on main).
|
|
53
|
+
|
|
54
|
+
## Daily integration with `main`
|
|
55
|
+
|
|
56
|
+
While on a branch, integrate from `main` daily:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git fetch origin
|
|
60
|
+
git rebase origin/main # preferred for personal branches
|
|
61
|
+
# OR
|
|
62
|
+
git merge origin/main # acceptable for shared branches
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Why daily:
|
|
66
|
+
- 1 day of drift = trivial conflicts.
|
|
67
|
+
- 7 days of drift = cascading conflicts; same files changed on both sides multiple times.
|
|
68
|
+
- Conflicts caught daily are individually small; conflicts caught at PR time are an avalanche.
|
|
69
|
+
|
|
70
|
+
## Rebase vs merge
|
|
71
|
+
|
|
72
|
+
| Situation | Choice |
|
|
73
|
+
|-----------|--------|
|
|
74
|
+
| Personal branch, never shared | Rebase. Linear history. |
|
|
75
|
+
| Shared branch (others have pulled) | Merge. Rebase rewrites history; collaborators' branches diverge. |
|
|
76
|
+
| Pulling latest `main` into your active feature branch | Rebase, IF nobody else has pulled your branch yet. |
|
|
77
|
+
| Merging your feature into `main` via PR | Whatever the team standard is. Squash-merge is fine if commits weren't atomic; preserve commits if they were. |
|
|
78
|
+
|
|
79
|
+
Rule of thumb: **rebase what's yours; merge what's shared.**
|
|
80
|
+
|
|
81
|
+
## When NOT to force-push
|
|
82
|
+
|
|
83
|
+
After a `git rebase`, the branch's history is rewritten — you must force-push to update the remote. This is FINE on a branch only YOU touch. It is BAD on shared branches because:
|
|
84
|
+
|
|
85
|
+
- Collaborators have pulled the old history; their next pull will conflict in confusing ways.
|
|
86
|
+
- Open PRs against the old SHAs may show garbled diffs.
|
|
87
|
+
- Reviewers lose context if they linked to a specific SHA.
|
|
88
|
+
|
|
89
|
+
Discipline:
|
|
90
|
+
- `git push --force-with-lease` on personal branches: OK.
|
|
91
|
+
- `git push --force` (without `with-lease`): never — too dangerous.
|
|
92
|
+
- Force-push to `main` / `master` / `production` / shared release branches: only with explicit authorization, ideally never.
|
|
93
|
+
|
|
94
|
+
## Cleanup: deleting merged branches
|
|
95
|
+
|
|
96
|
+
After a branch merges:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Delete locally
|
|
100
|
+
git branch -d feat/user-onboarding
|
|
101
|
+
|
|
102
|
+
# Delete remotely (most platforms auto-delete on PR merge)
|
|
103
|
+
git push origin --delete feat/user-onboarding
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
A repo with hundreds of stale branches is noise. Most platforms (GitHub, GitLab) auto-delete on merge — enable that setting if you can.
|
|
107
|
+
|
|
108
|
+
## Stale branch audit
|
|
109
|
+
|
|
110
|
+
Once a quarter (or whenever the branch list gets noisy):
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# List branches not merged to main, sorted by date
|
|
114
|
+
git for-each-ref --sort=-committerdate refs/remotes/origin --format='%(committerdate:short) %(refname:short)' | head -50
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Anything older than 60 days that hasn't merged: ask the owner — close, finish, or delete.
|
|
118
|
+
|
|
119
|
+
## Hotfix branches
|
|
120
|
+
|
|
121
|
+
When prod breaks and you need to ship fast:
|
|
122
|
+
|
|
123
|
+
1. Branch from `main` (or the production tag, if you have one).
|
|
124
|
+
2. Name: `hotfix/<short-description>` or `hotfix/<incident-id>`.
|
|
125
|
+
3. Make ONE change. Atomic commit. No "while I'm here" piggybacks.
|
|
126
|
+
4. PR to `main` (and to release branch if you have one) — fast review, fast merge, fast deploy.
|
|
127
|
+
5. Verify in production.
|
|
128
|
+
6. Add a regression test on `main` if hotfix didn't include one.
|
|
129
|
+
|
|
130
|
+
Hotfix discipline matters because the temptation is to bundle other fixes — and hotfix bundles cause the next outage.
|
|
131
|
+
|
|
132
|
+
## Stacked branches (advanced)
|
|
133
|
+
|
|
134
|
+
Sometimes you must stack branches: feature B depends on feature A, A is in review.
|
|
135
|
+
|
|
136
|
+
Options:
|
|
137
|
+
|
|
138
|
+
1. **Wait for A to merge.** Best, when possible. Start B from updated `main`.
|
|
139
|
+
2. **Stack:** branch B from A. PR B against A. When A merges, rebase B onto `main`, update PR target.
|
|
140
|
+
3. **Feature flag both A and B on `main`.** A merges first behind flag, B merges next behind flag, both flip on together.
|
|
141
|
+
|
|
142
|
+
Option 3 is the cleanest at scale. Stacking causes review and rebase pain.
|
|
143
|
+
|
|
144
|
+
## Anti-patterns
|
|
145
|
+
|
|
146
|
+
- Branch named `bruno-changes` — meaningless.
|
|
147
|
+
- Branch lives 3 weeks "because we're discussing the design" — branch isn't where design happens. Keep designing in docs/PRDs; branch when you're ready to code.
|
|
148
|
+
- `git pull` instead of `git pull --rebase` on a personal feature branch — creates merge commits in your history that you'll then need to clean up.
|
|
149
|
+
- Force-pushing to fix "a typo in the commit message" on a shared branch — use `git revert` + new commit instead.
|
|
150
|
+
- Multiple developers on the same branch without coordinating push order — non-fast-forward errors and conflicts. Pick one driver per branch or coordinate.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Trunk-based development — short branches, fast integration
|
|
2
|
+
|
|
3
|
+
Trunk-based means: `main` is always shippable, and most work lands on `main` within hours-to-days, not weeks. The opposite (long-lived feature branches) creates merge debt that compounds non-linearly.
|
|
4
|
+
|
|
5
|
+
## The rules
|
|
6
|
+
|
|
7
|
+
1. **Branches live 1-3 days, max a week.** Past a week, you're carrying risk.
|
|
8
|
+
2. **Rebase from `main` daily.** A 1-day rebase is trivial; a 7-day one is a project.
|
|
9
|
+
3. **Incomplete work hides behind a feature flag.** It can sit in `main` half-built without users seeing it.
|
|
10
|
+
4. **Small PRs (≤400 lines diff).** Larger PRs get worse review quality and longer review cycles.
|
|
11
|
+
5. **CI green before merge, always.** Yellow/red CI on `main` blocks everyone.
|
|
12
|
+
|
|
13
|
+
## Why short branches
|
|
14
|
+
|
|
15
|
+
A 7-day branch is not 7× the work of a 1-day branch. It's much worse:
|
|
16
|
+
|
|
17
|
+
- **Compound merge cost.** Every day, the gap between your branch and `main` grows. Conflicts multiply non-linearly because the same files keep moving on both sides.
|
|
18
|
+
- **Stale assumptions.** You wrote code against APIs/types from a week ago. The current version differs in ways you don't know.
|
|
19
|
+
- **Lost context.** By day 7, you've forgotten why you wrote line 200 of file X. Reviews suffer.
|
|
20
|
+
- **Coordination drag.** Other developers can't ship work that depends on your branch finishing.
|
|
21
|
+
|
|
22
|
+
## Feature flags vs feature branches
|
|
23
|
+
|
|
24
|
+
The classic question: "I'm building feature X but it's not ready to ship — won't merging it break things?"
|
|
25
|
+
|
|
26
|
+
Two options:
|
|
27
|
+
|
|
28
|
+
| Long branch | Feature flag |
|
|
29
|
+
|-------------|--------------|
|
|
30
|
+
| Code lives on a branch until ready | Code lives on `main` behind a `if (flag)` check |
|
|
31
|
+
| Merge debt accumulates daily | No merge debt; integrates as you go |
|
|
32
|
+
| Other devs can't see your changes | Other devs can read/review/depend on contracts |
|
|
33
|
+
| Single big risky merge at the end | Many small low-risk merges |
|
|
34
|
+
| Hard to demo / preview | Can demo to stakeholders by toggling flag |
|
|
35
|
+
|
|
36
|
+
Feature flags win for almost every non-trivial feature. Costs:
|
|
37
|
+
|
|
38
|
+
- Flag system needs to exist (LaunchDarkly, GrowthBook, env-based, or just a constant).
|
|
39
|
+
- Flags have a lifecycle: introduce → ship code behind flag → enable → remove flag. The remove step is critical and often skipped.
|
|
40
|
+
|
|
41
|
+
## When trunk-based bends
|
|
42
|
+
|
|
43
|
+
- **Open-source / external contributors:** they can't push directly to `main`; long branches are inherent to fork-and-PR. Mitigation: small PRs, fast review, frequent merges.
|
|
44
|
+
- **Compliance / audited environments:** PR + multi-stage review may take days regardless of branch life. Compress what you can.
|
|
45
|
+
- **Big migrations / refactors crossing many modules:** can't always be flag-gated. Mitigation: break into many small PRs, each independently shippable, merged sequentially.
|
|
46
|
+
|
|
47
|
+
In all bend cases, the SPIRIT of trunk-based still applies: minimize the gap between branch and `main`; integrate often; don't let drift compound.
|
|
48
|
+
|
|
49
|
+
## The "let it sit on a branch" anti-pattern
|
|
50
|
+
|
|
51
|
+
Common scenario: developer finishes feature X, opens PR, gets review delays, starts feature Y on a new branch from X (because Y depends on X), then X gets review feedback, X is rebased, Y now diverges from rebased X, X merges, Y has to rebase against the merged-X (different from branched-X), conflicts everywhere, Y stalls, X starts to bit-rot in production usage…
|
|
52
|
+
|
|
53
|
+
Three fixes:
|
|
54
|
+
|
|
55
|
+
1. **Don't stack branches.** If Y depends on X, wait for X to land. (Or merge X behind a flag and start Y from `main`.)
|
|
56
|
+
2. **Cut review delays.** A PR sitting in review for 3 days is the bug; fix the review process, don't work around it.
|
|
57
|
+
3. **Tighter scope.** If X is so big it takes 3 days to review, X should have been three PRs.
|
|
58
|
+
|
|
59
|
+
## CI and trunk-based
|
|
60
|
+
|
|
61
|
+
Trunk-based assumes CI is fast and reliable. If CI takes 45 minutes and is flaky:
|
|
62
|
+
|
|
63
|
+
- Developers won't rebase frequently (too painful).
|
|
64
|
+
- Branches drift, then conflicts on merge are big.
|
|
65
|
+
- Pressure mounts to bypass CI ("just merge it, CI's broken anyway").
|
|
66
|
+
|
|
67
|
+
Fixes happen in two directions:
|
|
68
|
+
|
|
69
|
+
- Make CI fast (under 10 minutes ideally; under 20 acceptable).
|
|
70
|
+
- Make CI reliable (flaky tests are bugs; fix or remove them).
|
|
71
|
+
|
|
72
|
+
A team that can't trust CI cannot run trunk-based effectively.
|
|
73
|
+
|
|
74
|
+
## Trunk-based + feature flags + atomic commits
|
|
75
|
+
|
|
76
|
+
These three disciplines compound:
|
|
77
|
+
|
|
78
|
+
- **Atomic commits** make rebases and reverts surgical.
|
|
79
|
+
- **Trunk-based** keeps branches short, so rebases are tiny.
|
|
80
|
+
- **Feature flags** decouple "code in main" from "feature live for users."
|
|
81
|
+
|
|
82
|
+
Together: you can ship work daily, revert any single change without unwinding others, and toggle features without redeploys. This is the working norm for high-velocity teams; it's not optional discipline, it's load-bearing.
|
|
@@ -155,8 +155,7 @@ When flagged for compaction, apply inline:
|
|
|
155
155
|
|
|
156
156
|
- `/dw-run-task` — reads memory before coding; updates `<N>_memory.md` during; runs promotion test + updates `MEMORY.md` at the end.
|
|
157
157
|
- `/dw-run-plan` — runs promotion + compaction between tasks, so each task starts with clean shared state.
|
|
158
|
-
- `/dw-autopilot` — threads memory through every phase (brainstorm → PRD → techspec → tasks → execution).
|
|
159
|
-
- `/dw-resume` — reads `MEMORY.md` first to reconstitute cross-session context, then the active task's memory.
|
|
158
|
+
- `/dw-autopilot` — threads memory through every phase (brainstorm → PRD → techspec → tasks → execution); on re-invocation reads `MEMORY.md` first to reconstitute cross-session context.
|
|
160
159
|
|
|
161
160
|
Callers should mention this skill in their "Skills Complementares" section.
|
|
162
161
|
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dw-simplification
|
|
3
|
+
description: Disciplined code simplification — understand WHY code exists before changing it (Chesterton's Fence), preserve behavior exactly, prefer clarity over cleverness, scope to recent changes. Used by /dw-code-review and /dw-refactoring-analysis. Adapted from addyosmani/agent-skills (MIT).
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Edit
|
|
7
|
+
- Bash
|
|
8
|
+
- Grep
|
|
9
|
+
- Glob
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# dw-simplification
|
|
13
|
+
|
|
14
|
+
Behavioral discipline for simplifying code without breaking it. The trap of refactoring is removing something that "looked unused" but was load-bearing for an edge case nobody documented. This skill enforces a protocol that prevents that class of regression.
|
|
15
|
+
|
|
16
|
+
## When to Use
|
|
17
|
+
|
|
18
|
+
Read this skill when:
|
|
19
|
+
|
|
20
|
+
- `/dw-code-review` flagged a complexity issue (deep nesting, long function, duplication).
|
|
21
|
+
- `/dw-refactoring-analysis` proposed a simplification target.
|
|
22
|
+
- The user explicitly asks to "clean this up" / "simplify X".
|
|
23
|
+
- During `/dw-run-task` if the implementation accidentally produced complex code that wants pre-commit cleanup.
|
|
24
|
+
|
|
25
|
+
Do NOT use when:
|
|
26
|
+
|
|
27
|
+
- The complexity is intentional (e.g., performance hot path with optimization comments — leave alone).
|
|
28
|
+
- You're simplifying code you didn't just write or read recently — scope creep.
|
|
29
|
+
- Tests are missing for the area — without tests, "preserve behavior exactly" is unverifiable. Add tests first, then simplify.
|
|
30
|
+
|
|
31
|
+
## The Five Rules
|
|
32
|
+
|
|
33
|
+
### 1. Chesterton's Fence — understand BEFORE changing
|
|
34
|
+
|
|
35
|
+
Before removing or rewriting any code, answer three questions:
|
|
36
|
+
|
|
37
|
+
1. **What does it actually do?** Run/trace it; don't guess from the name.
|
|
38
|
+
2. **Why was it added?** Check `git log --follow <file> --oneline` and look at the introducing commit's message + PR. Often there's a reason.
|
|
39
|
+
3. **What breaks if it's gone?** Search for callers. Run the test suite to find what changes.
|
|
40
|
+
|
|
41
|
+
If you can't answer all three, you're not ready to simplify. Get answers first.
|
|
42
|
+
|
|
43
|
+
Concrete cases where Chesterton's Fence saves you:
|
|
44
|
+
- A "redundant" early return that handles a race condition.
|
|
45
|
+
- A "useless" type cast that fixes a compiler bug on a specific platform.
|
|
46
|
+
- A "duplicated" check that exists for clarity at the API boundary.
|
|
47
|
+
- A "dead" branch that runs only with a feature flag enabled in production.
|
|
48
|
+
|
|
49
|
+
### 2. Preserve behavior exactly
|
|
50
|
+
|
|
51
|
+
The test for "did I simplify or did I change?" is: do the existing tests still pass without modification? If yes, behavior is preserved. If you needed to update tests, you changed behavior — that's a refactor, not a simplification.
|
|
52
|
+
|
|
53
|
+
When tests are inadequate to confirm behavior preservation, write tests FIRST that document current behavior, then simplify against them. This is the test characterization technique.
|
|
54
|
+
|
|
55
|
+
### 3. Follow project conventions
|
|
56
|
+
|
|
57
|
+
Match what the project already does. If files use 2-space indent and arrow functions, your simplified version uses 2-space indent and arrow functions — even if you'd prefer 4-space and `function`. Conventions matter more than personal preference; consistency is itself a form of clarity.
|
|
58
|
+
|
|
59
|
+
Project conventions live in `.dw/rules/<module>.md` (from `/dw-analyze-project`). Read first.
|
|
60
|
+
|
|
61
|
+
### 4. Prefer clarity over cleverness
|
|
62
|
+
|
|
63
|
+
Rules of thumb:
|
|
64
|
+
|
|
65
|
+
- A line of code that takes 30 seconds to understand is worse than three lines that take 5 seconds each.
|
|
66
|
+
- A "neat trick" with comments is uglier than the boring obvious code without comments.
|
|
67
|
+
- Optimization that costs readability needs measurement (`dw-performance` skill territory) — without numbers, prefer the readable version.
|
|
68
|
+
- "Magic" that requires knowing a language feature most teammates haven't used is anti-clarity. Use it only when the alternative is genuinely worse.
|
|
69
|
+
|
|
70
|
+
### 5. Scope to recent changes
|
|
71
|
+
|
|
72
|
+
Don't go simplifying old code while you're "in there". The risk-to-benefit ratio of changing 5-year-old battle-tested code is bad. Limit simplification to:
|
|
73
|
+
|
|
74
|
+
- Code you just wrote in this session.
|
|
75
|
+
- Code your current task touches.
|
|
76
|
+
- Code with explicit recent breakage (e.g., a bug just fixed that revealed bad structure).
|
|
77
|
+
|
|
78
|
+
Out of scope: any other code, no matter how ugly. Open a task / ADR for those instead of fixing in-flight.
|
|
79
|
+
|
|
80
|
+
## Pattern recognition
|
|
81
|
+
|
|
82
|
+
Frequent simplification targets — but apply Rules 1-5 before acting:
|
|
83
|
+
|
|
84
|
+
| Smell | Healthy refactor | When NOT to refactor |
|
|
85
|
+
|-------|------------------|----------------------|
|
|
86
|
+
| Deep nesting (4+ levels) | Early returns / guard clauses | When the nesting maps to a real domain hierarchy (e.g., visitor pattern) |
|
|
87
|
+
| Long function (>50 lines) | Extract method | When the "natural" extraction would produce 3-4 single-call helpers — you're trading complexity for indirection |
|
|
88
|
+
| Generic name (`data`, `info`, `helper`) | Rename to specific | When the function genuinely processes generic input (e.g., a serializer middleware) |
|
|
89
|
+
| Duplication (same 5 lines twice) | Extract to function/constant | When the duplication is by design (e.g., independent business rules that may diverge) |
|
|
90
|
+
| `if/elif/else` chain (5+ branches) | Strategy pattern / lookup table | When the branches are naturally exclusive states with branch-specific logic |
|
|
91
|
+
|
|
92
|
+
## Rule of 500 — automate large refactors
|
|
93
|
+
|
|
94
|
+
If a simplification touches >500 lines, **don't do it manually**. Use:
|
|
95
|
+
|
|
96
|
+
- AST-based codemods (`jscodeshift` for JS/TS, `libcst` for Python, Roslyn for C#, `rust-analyzer` for Rust).
|
|
97
|
+
- IDE-driven refactoring tools (Rename Symbol, Extract Method, Inline Variable).
|
|
98
|
+
- Search-and-replace ONLY when the pattern is unambiguous and verifiable.
|
|
99
|
+
|
|
100
|
+
Manual edits across hundreds of lines are how subtle bugs creep in.
|
|
101
|
+
|
|
102
|
+
## Verification protocol
|
|
103
|
+
|
|
104
|
+
Before committing the simplification:
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
1. Lint passes: pnpm lint / ruff check / dotnet format --verify-no-changes / cargo clippy
|
|
108
|
+
2. Tests pass: pnpm test / pytest / dotnet test / cargo test
|
|
109
|
+
3. Build passes: pnpm tsc --noEmit / mypy / dotnet build / cargo check
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
All three GREEN. If any is RED, the simplification broke something — revert or fix.
|
|
113
|
+
|
|
114
|
+
For changes that altered cyclomatic complexity, optionally run a complexity analyzer to confirm the metric actually improved (some "simplifications" make code more complex by spreading it).
|
|
115
|
+
|
|
116
|
+
## How `dw-code-review` uses this
|
|
117
|
+
|
|
118
|
+
In the formal Level 3 review (post-Level 2 chain from `dw-review-implementation`), code-review flags complexity issues using the patterns above. Each flagged issue references this skill: "consider simplifying via guard clauses; apply Chesterton's Fence — verify why the nested check exists before flattening."
|
|
119
|
+
|
|
120
|
+
## How `dw-refactoring-analysis` uses this
|
|
121
|
+
|
|
122
|
+
The analysis catalogs code smells (Fowler vocabulary). For each smell, the proposed refactor cites:
|
|
123
|
+
1. Which simplification rule applies (early return / extract method / lookup table / etc.).
|
|
124
|
+
2. Whether Chesterton's Fence concerns block the refactor (existing tests inadequate? no recent commits explaining the structure? → flag as YELLOW, don't act).
|
|
125
|
+
|
|
126
|
+
## Anti-patterns
|
|
127
|
+
|
|
128
|
+
1. Simplifying code you didn't read carefully. The "obvious dead code" is often someone's hard-won bug fix.
|
|
129
|
+
2. Skipping the test gate "because the change is small". Small changes break things too.
|
|
130
|
+
3. Changing whitespace + naming + structure in one commit. Atomic: each commit one kind of change.
|
|
131
|
+
4. Refactoring while touching unrelated code (mix-in scope creep). Open a separate task.
|
|
132
|
+
5. Personal-style refactors disguised as simplification. Project conventions > your preferences.
|
|
133
|
+
|
|
134
|
+
## References
|
|
135
|
+
|
|
136
|
+
- `references/chestertons-fence.md` — the protocol in detail; case studies of "obvious-but-wrong" removals.
|
|
137
|
+
- `references/complexity-metrics.md` — when each metric (cyclomatic, cognitive, depth, fanout) actually matters; how to measure cheaply.
|
|
138
|
+
- `references/behavior-preserving.md` — characterization tests, refactor with test gate, rollback patterns, codemod tooling per language.
|
|
139
|
+
|
|
140
|
+
## Inspired by
|
|
141
|
+
|
|
142
|
+
Adapted from [`addyosmani/agent-skills/code-simplification`](https://github.com/addyosmani/agent-skills) by Addy Osmani (MIT license). Core principles (Chesterton's Fence, behavior preservation, scope discipline, Rule of 500) preserved. dev-workflow integration: invoked by `dw-code-review` and `dw-refactoring-analysis` via Complementary Skills.
|