Skip to content

Commit f2b2b0f

Browse files
authored
feat(build): surgical-diff + YAGNI gate before ship (#213)
1 parent 559f5ee commit f2b2b0f

3 files changed

Lines changed: 58 additions & 1 deletion

File tree

config/cspell.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"glab",
66
"codegen",
77
"conventionalcommits",
8+
"lockfiles",
89
"frontmatter",
910
"geolocation",
1011
"goldens",
@@ -20,6 +21,7 @@
2021
"pubspec",
2122
"worktrees",
2223
"undiscussed",
24+
"unrequested",
2325
"pipefail"
2426
],
2527
"flagWords": []

skills/build/SKILL.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Copy this checklist and track your progress:
2121
Build Progress:
2222
- [ ] Phase 0: Load plan and confirm scope
2323
- [ ] Phase 1: Read context files
24-
- [ ] Phase 2: Implement and test each task
24+
- [ ] Phase 2: Implement, test, and run the surgical-diff gate
2525
- [ ] Phase 3: Run review agents (5 in parallel)
2626
- [ ] Phase 4: Final validation, cleanup, and ship
2727
```
@@ -100,6 +100,10 @@ After each logical unit of work:
100100
- Ask the user only when genuinely stuck: ambiguous architecture decision, 3 failed fix attempts, or a missing dependency not mentioned in the plan.
101101
- If a task in the plan is unclear, re-read the plan and the relevant codebase context before asking the user.
102102

103+
### Surgical-Diff Gate
104+
105+
Once every task is implemented, tested, and validated, follow the [surgical-diff gate](references/surgical-diff-gate.md) before moving to review: diff the whole branch against its merge-base, remove untraceable churn, delete only self-created orphans, and collect a "Noticed (not changed):" note for pre-existing dead code. Running it here keeps the review phase focused on the diff that belongs, not churn that would be reverted anyway.
106+
103107
## Phase 3 — Quality Review
104108

105109
After all implementation tasks are complete, run 5 review agents **in parallel**.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Surgical-Diff Gate
2+
3+
Before the implementation goes to review, every change on the branch must trace to a plan task or the original request. This gate removes untraceable churn (drive-by reformatting, unrequested type hints, speculative validation), deletes only the symbols this branch orphaned, and reports pre-existing dead code without touching it. The build skill runs it at the end of Phase 2, before the review phase, so reviewers only see the diff that belongs.
4+
5+
## Step 1: Establish the diff base
6+
7+
Determine the base branch, then diff the whole branch against it.
8+
9+
1. Base branch: use the plan's stated target if it names one. Otherwise read `git symbolic-ref refs/remotes/origin/HEAD` and strip it to the branch name. Fall back to `main`.
10+
2. Anchor: `BASE=$(git merge-base HEAD <base-branch>)`.
11+
3. Inspect the full branch diff: `git diff "$BASE"` for tracked changes, and `git status --porcelain` for new untracked files.
12+
13+
Diff against the merge-base, not a bare `git diff`. That captures the whole branch — committed history and working-tree changes alike — so the gate sees every hunk no matter what has been committed yet. At the end of Phase 2 the implementation is usually still uncommitted, so remember to include untracked files.
14+
15+
## Step 2: Classify every hunk
16+
17+
A hunk is **traceable** when it maps to one of two origins:
18+
19+
1. A **plan task** — the hunk's file appears in the plan's files-to-create/modify list and the change matches the task's intent.
20+
2. The **original request**.
21+
22+
## Step 3: Honor the auto-traceable whitelist
23+
24+
Never flag or remove these, even when they lack an obvious plan task:
25+
26+
- Generated files: mocks, codegen output, `*.g.dart`, `*.mocks.dart`, `*.freezed.dart`, and equivalents.
27+
- New test files. The non-negotiable testing rule mandates them, so they trace to the task whose code they cover.
28+
- Formatter or whitespace-only hunks on lines this branch already touched.
29+
- Auto-added or reordered imports that are side effects of a traceable change.
30+
- Dependency lockfiles and manifests changed by a dependency the plan called for (`pubspec.lock` and equivalents).
31+
32+
## Step 4: Remove untraceable churn
33+
34+
Edit the working tree to strip untraceable lines. Work at line-level granularity, not whole-hunk, because a single hunk often mixes a real change with a drive-by edit. If any work is already committed, do not rewrite history — correcting the working tree reaches the same end state, and the removal gets committed with the rest of the implementation.
35+
36+
## Step 5: Revert safety
37+
38+
After removals, re-run the linter and tests per [validate-and-fix](validate-and-fix.md). If a removal breaks the build, that hunk was load-bearing, not pure churn. Restore it and surface it to the user with **AskUserQuestion** rather than shipping a red build.
39+
40+
## Step 6: Handle dead code — bias toward keeping
41+
42+
Delete a symbol only when **both** conditions hold:
43+
44+
1. Its sole references were on lines this branch removed, and
45+
2. It is defined in a file this branch touched.
46+
47+
That is a self-created orphan. Every other unused symbol is pre-existing dead code: leave it in place and add it to a **"Noticed (not changed):"** list. When in doubt, do not delete.
48+
49+
## Step 7: Surface results
50+
51+
Report the removed churn and the "Noticed (not changed):" list to the user. This is an observation about pre-existing code the branch did not touch, so keep it in the build session for the user to act on. Do not add it to the PR body, which describes only what this change implements.

0 commit comments

Comments
 (0)