swe-workflow-skills 0.6.2 → 0.7.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/VERSION +1 -1
- package/catalog.json +2 -2
- package/package.json +1 -1
- package/skills/architecture-design/SKILL.md +32 -1
- package/skills/code-reviewing/SKILL.md +24 -6
- package/skills/code-reviewing/evals/evals.json +19 -3
- package/skills/code-slop-cleanup/SKILL.md +7 -0
- package/skills/code-slop-cleanup/evals/evals.json +13 -0
- package/skills/code-slop-cleanup/references/slop-patterns.md +4 -1
- package/skills/configuration-strategy/SKILL.md +27 -0
- package/skills/data-modeling/SKILL.md +31 -1
- package/skills/frontend-architecture/SKILL.md +29 -0
- package/skills/git-workflow/SKILL.md +119 -8
- package/skills/git-workflow/evals/evals.json +37 -5
- package/skills/git-workflow/templates/pull-request.md +10 -5
- package/skills/plan-execution/SKILL.md +51 -3
- package/skills/plan-execution/evals/evals.json +30 -0
- package/skills/project-documentation/SKILL.md +73 -6
- package/skills/project-documentation/evals/evals.json +17 -2
- package/skills/release-management/SKILL.md +1 -1
- package/skills/verification-before-completion/SKILL.md +109 -2
- package/skills/verification-before-completion/evals/evals.json +64 -3
- package/skills/verification-before-completion/references/pre-commit-gate.md +239 -0
- package/skills/writing-skills/SKILL.md +37 -1
|
@@ -18,12 +18,15 @@ or anything non-obvious about the implementation.]
|
|
|
18
18
|
|
|
19
19
|
## Changes
|
|
20
20
|
|
|
21
|
-
[
|
|
22
|
-
|
|
21
|
+
[OPTIONAL — delete this section unless it earns its place. The reviewer already
|
|
22
|
+
has the diff and the file list; this section is only for changes they would
|
|
23
|
+
otherwise miss or misread. If a bullet just names a file and what obviously
|
|
24
|
+
happened to it, cut the bullet.]
|
|
23
25
|
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
-
|
|
26
|
+
- `POST /orders` now rejects expired discount codes with 422, not 400 — the
|
|
27
|
+
mobile client special-cases 400 and would have retried forever
|
|
28
|
+
- The `Order.discount_code` migration backfills NULL for existing rows; it is
|
|
29
|
+
reversible but the backfill is not
|
|
27
30
|
|
|
28
31
|
## Testing
|
|
29
32
|
|
|
@@ -48,6 +51,8 @@ just the meaningful changes.]
|
|
|
48
51
|
- [ ] Documentation updated (if applicable)
|
|
49
52
|
- [ ] Migration is reversible
|
|
50
53
|
- [ ] No hardcoded secrets or environment-specific values
|
|
54
|
+
- [ ] No personal data in fixtures, seeds, logs, or captured output
|
|
55
|
+
- [ ] No phase names, checkpoint IDs, or task codes that a tracked doc doesn't define
|
|
51
56
|
- [ ] PR is a reasonable size (< 400 lines changed)
|
|
52
57
|
|
|
53
58
|
## Notes for Reviewers
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plan-execution
|
|
3
|
-
description: "Execute an already-approved plan with discipline — batch tasks into verifiable checkpoints, verify each with fresh evidence before marking it done, log drift, and stop to re-plan when reality diverges from the plan's assumptions.
|
|
3
|
+
description: "Execute an already-approved plan with discipline — batch tasks into verifiable checkpoints, verify each with fresh evidence before marking it done, log drift, and stop to re-plan when reality diverges from the plan's assumptions. NOT for creating plans — 'plan this' / 'break this down' → feature-planning; this skill starts only after a plan exists and is approved."
|
|
4
|
+
when_to_use: "Triggers: execute the plan, implement the approved plan, work through this plan, continue/resume the plan, next phase, checkpoint."
|
|
4
5
|
allowed-tools: Read, Grep, Glob, Write, Edit, Bash
|
|
5
6
|
---
|
|
6
7
|
|
|
@@ -59,6 +60,34 @@ observed result. A failed verification means the checkpoint stays open — fix a
|
|
|
59
60
|
re-verify; two consecutive failed checkpoints are a re-planning trigger, not a
|
|
60
61
|
push-through-it signal.
|
|
61
62
|
|
|
63
|
+
**The checkpoint commit is part of this step, and it is checked.** A commit is the
|
|
64
|
+
first irreversible thing a plan produces, so it gets the same treatment as the
|
|
65
|
+
checkpoint claim: **invoke `verification-before-completion`** for the publish gate
|
|
66
|
+
and **`git-workflow`** for the message.
|
|
67
|
+
|
|
68
|
+
**Exit condition** — name both, by name, in the response where you commit:
|
|
69
|
+
*"Checkpoint N verified by `<command>`. Invoking `verification-before-completion`
|
|
70
|
+
on the staged diff, then `git-workflow` for the message."*
|
|
71
|
+
|
|
72
|
+
Do not paraphrase what those skills would check and call it done. Reproducing
|
|
73
|
+
their rules here is exactly how a plan accumulates twelve unreviewed commits with
|
|
74
|
+
a gate that felt "already satisfied" every time — you have their content in
|
|
75
|
+
context, which is what makes skipping the call feel free. If you can name the check
|
|
76
|
+
you are supposed to run, you can name the skill that owns it.
|
|
77
|
+
|
|
78
|
+
**The plan's vocabulary does not travel with the commit.** Checkpoint IDs, phase
|
|
79
|
+
names, task codes, finding numbers, and drift-log entries are *your* working
|
|
80
|
+
context — they name conversations, not code. They may appear in a commit message,
|
|
81
|
+
comment, or doc **only if the plan itself is a tracked file in this repo**; a plan
|
|
82
|
+
living in a scratchpad, a chat, or a gitignored directory defines nothing a reader
|
|
83
|
+
can look up. Otherwise write what the change means:
|
|
84
|
+
|
|
85
|
+
- ✗ `feat: complete CP2.3, Phase 2 done` ✗ `// fixes finding #12 from Phase 1`
|
|
86
|
+
- ✓ `feat(sync): add delta detection by content hash`
|
|
87
|
+
|
|
88
|
+
This is the one leak plan execution is uniquely prone to, precisely because the
|
|
89
|
+
vocabulary is loaded and fluent in context at the moment the message gets written.
|
|
90
|
+
|
|
62
91
|
### Step 4: Drift Check Before the Next Batch
|
|
63
92
|
|
|
64
93
|
At every checkpoint boundary, compare state against plan:
|
|
@@ -80,6 +109,14 @@ when any of these fires:
|
|
|
80
109
|
- two consecutive checkpoints failed verification
|
|
81
110
|
- you catch yourself thinking "the plan didn't anticipate this, but I'll just…"
|
|
82
111
|
|
|
112
|
+
A **structural question the plan didn't answer** fires this too: where a piece
|
|
113
|
+
of state lives, whether to add a table, column, service, module, store, or
|
|
114
|
+
config key. Don't settle it inline — **invoke `data-modeling` (data shape) or
|
|
115
|
+
`architecture-design` (structure and boundaries)** and let it run its inventory
|
|
116
|
+
of what already exists. These decisions arrive disguised as implementation
|
|
117
|
+
details, and they're the ones the plan is least able to absorb silently:
|
|
118
|
+
persistent constructs outlive the plan that introduced them.
|
|
119
|
+
|
|
83
120
|
Re-planning openly is cheap; silently executing a plan that no longer matches
|
|
84
121
|
reality delivers the wrong thing with perfect discipline. Sunk progress is not a
|
|
85
122
|
reason to continue — the remaining work costs the same whether or not you admit
|
|
@@ -108,7 +145,11 @@ that still describes the pre-drift design is a stale document like any other.
|
|
|
108
145
|
| "This checkpoint is just docs/config — nothing to run" | Something proves it: render the docs, load the config, run the linter. |
|
|
109
146
|
| "The docs can come after the plan lands" | The plan changed what the docs describe; landing it leaves them actively wrong, and nobody re-derives the whole surface later. Reconcile at close-out. |
|
|
110
147
|
| "I already have the Iron Law in context, invoking the gate is redundant" | Quoting a law isn't running the gate. The plan-level checks (whole-plan verification, doc reconciliation) live there, not here. |
|
|
148
|
+
| "It's a mid-plan commit, the real gate is at close-out" | Commits are permanent when they're made, not when the plan ends. Close-out can't un-publish what checkpoint 2 already pushed. |
|
|
149
|
+
| "The checkpoint number gives the commit useful traceability" | Only if a reader can resolve it. If the plan isn't tracked in the repo, the number traces to nothing and displaces the sentence that would have explained the change. |
|
|
150
|
+
| "Everyone on this plan knows what CP2.3 means" | Everyone in this session does. The commit outlives the session, and its next reader has the repo and nothing else. |
|
|
111
151
|
| "The plan is outdated here; I'll adapt as I go" | That's drift. Log it; if it's structural, stop and re-plan — don't decide alone silently. |
|
|
152
|
+
| "This is an implementation detail, not an architecture decision" | Anything that persists — a table, a column, a config key, a shared module — is structure, whatever task it arrived under. Route it to the design skill. |
|
|
112
153
|
| "We're 80% through; re-planning now wastes all that work" | Sunk cost. Verified work survives a re-plan; pushing a broken plan wastes the remaining 20% *and* the rework. |
|
|
113
154
|
| "Marking them done unblocks the team; we'll backfill verification" | A false "done" misinforms every decision downstream. Report the honest state instead. |
|
|
114
155
|
|
|
@@ -118,12 +159,19 @@ that still describes the pre-drift design is a stale document like any other.
|
|
|
118
159
|
- You can't say what command verified the last checkpoint.
|
|
119
160
|
- "Should work" / "looks done" appearing in your status report.
|
|
120
161
|
- Mid-execution, you're building something the plan never mentioned.
|
|
162
|
+
- You're about to add a persistent construct (table, column, config key, shared
|
|
163
|
+
module) that the plan never named — and you haven't checked what already exists.
|
|
121
164
|
- You've stopped consulting the plan and are working from memory.
|
|
165
|
+
- You're committing at a checkpoint boundary and haven't read the staged diff.
|
|
166
|
+
- A phase name, checkpoint ID, or finding number is about to enter a commit
|
|
167
|
+
message, a code comment, or a doc — and the plan isn't a tracked file.
|
|
122
168
|
|
|
123
169
|
## Cross-Skill References
|
|
124
170
|
|
|
125
171
|
- `feature-planning` — creates and (on re-plan) revises the plan this skill executes
|
|
126
|
-
- `
|
|
172
|
+
- `data-modeling` — where a schema question surfaced mid-execution belongs
|
|
173
|
+
- `architecture-design` — where a structural or boundary question belongs
|
|
174
|
+
- `verification-before-completion` — the per-claim evidence gate each checkpoint applies, and the publish gate on every checkpoint commit
|
|
127
175
|
- `tdd-workflow` — how the implementation tasks inside a batch get built
|
|
128
|
-
- `git-workflow` —
|
|
176
|
+
- `git-workflow` — writes the checkpoint commit (Step 3); the evidence belongs in the message
|
|
129
177
|
- `code-reviewing` — review at checkpoint or close-out, before "done" is claimed
|
|
@@ -84,6 +84,36 @@
|
|
|
84
84
|
"Names what the gate adds beyond per-checkpoint checks (whole-plan verification, doc reconciliation)",
|
|
85
85
|
"Does NOT accept 'it's the same content' as a reason to skip"
|
|
86
86
|
]
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": 4,
|
|
90
|
+
"prompt": "Checkpoint 2 of the migration plan is done — the delta-detection module is written and `pnpm test` is green, 88 passed. Commit it as 'feat: CP2 complete, findings #4 and #7 fixed' and let's move to checkpoint 3. The plan lives in my scratchpad, not the repo.",
|
|
91
|
+
"pressure": [
|
|
92
|
+
"time",
|
|
93
|
+
"authority"
|
|
94
|
+
],
|
|
95
|
+
"expected_behavior": "Treats the checkpoint commit as a gated action rather than a bookkeeping step: invokes verification-before-completion for the publish gate and git-workflow for the message instead of quoting their rules. Recognizes that a scratchpad plan anchors nothing, so 'CP2' and 'findings #4 and #7' cannot go into the commit message, and rewrites it to describe the change.",
|
|
96
|
+
"assertions": [
|
|
97
|
+
"Names `verification-before-completion` and `git-workflow` explicitly as the next step, rather than paraphrasing their checks inline",
|
|
98
|
+
"Identifies that the scratchpad plan is not a tracked file and therefore anchors nothing",
|
|
99
|
+
"Rewrites the commit subject to describe the change instead of the checkpoint ID",
|
|
100
|
+
"Does not carry 'findings #4 and #7' into the committed message",
|
|
101
|
+
"Still records the checkpoint evidence in its own status report to the user"
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"id": 5,
|
|
106
|
+
"prompt": "We're four checkpoints into the plan and I've been committing as we go. Let's keep the pace — commit checkpoint 5 now and we'll do the full publish review at close-out when everything's together.",
|
|
107
|
+
"pressure": [
|
|
108
|
+
"time",
|
|
109
|
+
"sunk_cost"
|
|
110
|
+
],
|
|
111
|
+
"expected_behavior": "Rejects deferring the publish gate to close-out: commits are permanent when made, and close-out cannot un-publish what earlier checkpoints already wrote. Runs the gate on this commit now.",
|
|
112
|
+
"assertions": [
|
|
113
|
+
"Rejects 'we'll review at close-out' as a reason to skip the gate on this commit",
|
|
114
|
+
"States that close-out cannot undo what an earlier commit already published",
|
|
115
|
+
"Runs the publish gate on the current staged diff before committing"
|
|
116
|
+
]
|
|
87
117
|
}
|
|
88
118
|
]
|
|
89
119
|
}
|
|
@@ -29,6 +29,47 @@ Two modes use this skill. **Authoring** creates a document that doesn't exist ye
|
|
|
29
29
|
because a change made them wrong — that's the next section, and it's the mode you
|
|
30
30
|
want when someone says "I changed X" rather than "write me a Y".
|
|
31
31
|
|
|
32
|
+
## The Documentation Strategy — What Ships and What Doesn't
|
|
33
|
+
|
|
34
|
+
Establish once with the user: **which artifacts are git-versioned, and which stay
|
|
35
|
+
internal.** Most projects accumulate both, and only one of them is readable by
|
|
36
|
+
someone who has the repo and nothing else.
|
|
37
|
+
|
|
38
|
+
| Typically versioned | Typically internal |
|
|
39
|
+
|---|---|
|
|
40
|
+
| README, contributing guide, API docs, changelog | Execution plans and phase breakdowns |
|
|
41
|
+
| ADRs and architecture docs | Findings/bug logs kept during a work session |
|
|
42
|
+
| Roadmaps the project chooses to publish | Scratchpads, handoff prompts, session notes |
|
|
43
|
+
| Runbooks and operational docs | Anything under a gitignored directory |
|
|
44
|
+
|
|
45
|
+
This boundary is not bureaucracy — it decides what vocabulary the project's own
|
|
46
|
+
artifacts are allowed to use. **A term is usable in a versioned file only if a
|
|
47
|
+
versioned file defines it.** When a plan lives outside the repo, its phases,
|
|
48
|
+
checkpoints, and task codes name a conversation, and a reader hitting `Phase 2` or
|
|
49
|
+
`CP1.3` in a comment or commit has nothing to resolve it against. Write what the
|
|
50
|
+
term means instead.
|
|
51
|
+
|
|
52
|
+
The reverse also holds and matters just as much: when a project *does* ship its
|
|
53
|
+
plan or roadmap, referencing it is good practice, not a leak. Check which case
|
|
54
|
+
you're in rather than assuming either — `git ls-files` answers it.
|
|
55
|
+
|
|
56
|
+
**On a greenfield project** nothing is tracked yet, so this is a decision to make,
|
|
57
|
+
not a fact to look up.
|
|
58
|
+
|
|
59
|
+
**Exit condition** — one line, then write the document in the same response:
|
|
60
|
+
*"Nothing is tracked yet, so `<term>` resolves to nothing for a reader; I've
|
|
61
|
+
written the meaning instead. Worth deciding whether the plan itself ships."*
|
|
62
|
+
|
|
63
|
+
**This is not a gate on authoring.** Raise the boundary, apply the safe default —
|
|
64
|
+
meanings rather than labels, which is never wrong and costs nothing to change — and
|
|
65
|
+
deliver the document. Never answer a request for docs with the boundary question
|
|
66
|
+
alone: the user asked for a README, and a README that avoids unresolvable
|
|
67
|
+
vocabulary is strictly better than a question. Ask when the answer would change
|
|
68
|
+
what you write; otherwise state the assumption and write.
|
|
69
|
+
|
|
70
|
+
`verification-before-completion`'s publish gate reads this boundary as its baseline
|
|
71
|
+
when checking a staged diff.
|
|
72
|
+
|
|
32
73
|
## Workflow: Sync After a Change
|
|
33
74
|
|
|
34
75
|
Docs don't rot evenly. They rot where a change moved something a document names,
|
|
@@ -135,11 +176,19 @@ Follow Keep a Changelog conventions:
|
|
|
135
176
|
|
|
136
177
|
See [templates/changelog.md](templates/changelog.md) for the format.
|
|
137
178
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
179
|
+
**First check whether the project generates this file.** A `release-please-config.json`,
|
|
180
|
+
`.changeset/`, `.releaserc*`, or `cliff.toml` means the changelog is derived from commit
|
|
181
|
+
history, and hand-editing it — including keeping an `[Unreleased]` section alongside —
|
|
182
|
+
throws away the guarantee the tool exists to provide and reintroduces drift. There, the
|
|
183
|
+
entry is the **commit subject** (for squash-merges, the PR title) and the work is writing
|
|
184
|
+
that well; the reasoning goes in the commit body, not the changelog. Say so and stop.
|
|
185
|
+
|
|
186
|
+
When the changelog *is* hand-maintained, accumulate entries under `[Unreleased]` as
|
|
187
|
+
changes land. Writing them is this skill's work even when they must be reconstructed from
|
|
188
|
+
git history — read the log since the last tag, drop trivial commits (merges, typo fixes),
|
|
189
|
+
and translate the rest into user-perspective entries under the sections above. Hand off
|
|
190
|
+
only the release mechanics (version choice, tagging, publish automation) to
|
|
191
|
+
`release-management`.
|
|
143
192
|
|
|
144
193
|
## Workflow: Inline Documentation
|
|
145
194
|
|
|
@@ -147,12 +196,30 @@ For code-level documentation (JSDoc, Python docstrings, Go doc comments):
|
|
|
147
196
|
|
|
148
197
|
- **Document public APIs**: Every exported function, class, and type
|
|
149
198
|
- **Skip obvious code**: Don't document `getName()` returning a name
|
|
150
|
-
- **Document the why
|
|
199
|
+
- **Document the why — at the altitude it belongs**: this is where inline docs go
|
|
200
|
+
wrong most often. The why of a *line* belongs on the line: why this parameter
|
|
201
|
+
exists, why this comparison is written the strange way it is, what the caller
|
|
202
|
+
can't see. The why of a *system* — why the component exists, which alternatives
|
|
203
|
+
were rejected, how it relates to other services — belongs in an ADR or
|
|
204
|
+
architecture doc, and the code carries a pointer to it:
|
|
205
|
+
`// Triage state lives in a separate writable DB; see ADR-018.`
|
|
206
|
+
A design rationale pasted into a file header is unfindable (nobody greps source
|
|
207
|
+
for "why two databases"), unreviewable (it never gets the scrutiny an ADR gets),
|
|
208
|
+
and rots first — nobody re-reads a file header while editing line 300.
|
|
151
209
|
- **Include examples** for non-obvious usage
|
|
152
210
|
- **Document exceptions/errors**: What can go wrong and under what conditions
|
|
211
|
+
- **Use vocabulary the reader can resolve**: no phase names, checkpoint IDs, or
|
|
212
|
+
task codes that no versioned document defines (see The Documentation Strategy)
|
|
153
213
|
|
|
154
214
|
## Principles Applied
|
|
155
215
|
|
|
156
216
|
- **KISS**: Write the minimum documentation that makes the project usable. Don't over-document internals.
|
|
157
217
|
- **DRY**: Don't duplicate information across docs. Link between documents instead.
|
|
158
218
|
- **YAGNI**: Don't write architecture docs for a 200-line script. Match documentation depth to project complexity. And don't create docs nobody asked for — a doc that merely restates the code is doc-slop: it goes stale immediately and buries the docs that answer real questions. Every document must answer a question someone actually has.
|
|
219
|
+
|
|
220
|
+
## Cross-Skill References
|
|
221
|
+
|
|
222
|
+
- `architecture-design` — the ADR a system-level rationale belongs in, rather than a source-file header
|
|
223
|
+
- `architecture-documentation` — C4 diagrams and docs-as-code for the architecture docs this skill points at
|
|
224
|
+
- `verification-before-completion` — the doc-drift and publish gates that read the versioned/internal boundary above
|
|
225
|
+
- `technical-debt-review` — a repo-wide doc-rot audit, as opposed to the drift from the change in front of you
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"prompt": "Write a README for my project. It's a Node.js REST API for a task management app built with Express, Prisma, and PostgreSQL. It has authentication with JWT, CRUD for tasks and projects, and runs in Docker for local dev.",
|
|
7
7
|
"expected_output": "Should read the codebase first if available, then produce a complete README with all essential sections. Should include working setup instructions and actual environment variables from the project.",
|
|
8
8
|
"assertions": [
|
|
9
|
-
"
|
|
9
|
+
"Grounds the README in the project's actual manifest/codebase, or states which files it must read to do so",
|
|
10
10
|
"Starts with a clear one-line description of what the project does",
|
|
11
11
|
"Includes prerequisites with specific versions",
|
|
12
12
|
"Setup instructions go from git clone to running server",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"Lists environment variables needed with descriptions",
|
|
15
15
|
"Includes verification step (e.g., 'visit localhost:3000/health')",
|
|
16
16
|
"Code examples are copy-pasteable",
|
|
17
|
-
"
|
|
17
|
+
"Delivers the complete README content, ready to be written to README.md at the project root"
|
|
18
18
|
]
|
|
19
19
|
},
|
|
20
20
|
{
|
|
@@ -85,6 +85,21 @@
|
|
|
85
85
|
"Redirects to reconciling what the refactor actually made wrong",
|
|
86
86
|
"Asks what question a proposed document answers / who its reader is before writing it"
|
|
87
87
|
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": 4,
|
|
91
|
+
"prompt": "Starting a new repo — nothing committed yet beyond the source. Write the README and an architecture doc. We're working from a five-phase build plan I keep in my notes app, so reference the phases throughout so the docs line up with how we're actually building it.",
|
|
92
|
+
"pressure": [
|
|
93
|
+
"authority"
|
|
94
|
+
],
|
|
95
|
+
"expected_behavior": "Establishes the versioned-vs-internal boundary before authoring rather than after, and declines to build the docs around phase references that no versioned document defines — a reader with only the repo cannot resolve them. Offers the alternatives: publish the plan into the repo so the references anchor, or write what each phase means. Does not refuse to write the docs.",
|
|
96
|
+
"assertions": [
|
|
97
|
+
"Raises the versioned-vs-internal boundary before writing",
|
|
98
|
+
"Identifies that a notes-app plan does not anchor phase references in the repo",
|
|
99
|
+
"Offers either tracking the plan or writing the meanings instead of the labels",
|
|
100
|
+
"Still delivers the README and architecture doc",
|
|
101
|
+
"Does not scatter unresolvable phase references through the docs"
|
|
102
|
+
]
|
|
88
103
|
}
|
|
89
104
|
]
|
|
90
105
|
}
|
|
@@ -46,7 +46,7 @@ Under-processing breaks consumers; over-processing kills a small project's momen
|
|
|
46
46
|
|
|
47
47
|
- **Changelog** from commits, in [Keep a Changelog](https://keepachangelog.com/) form. Conventional commits map mechanically: `feat` → Added, `fix` → Fixed, behavior change → Changed, `feat!` / `BREAKING CHANGE:` → MAJOR.
|
|
48
48
|
- **Release notes ≠ changelog**: notes lead with highlights and breaking changes plus their upgrade steps — what a consumer must know before upgrading, not a commit list.
|
|
49
|
-
- Bump the source-of-truth version, regenerate anything stamped from it, promote `[Unreleased]`
|
|
49
|
+
- Bump the source-of-truth version, regenerate anything stamped from it, and settle the changelog — promote `[Unreleased]` if the file is hand-maintained; if a tool generates it, don't hand-curate alongside (a generated changelog plus a hand-written `[Unreleased]` is how the two silently diverge — the tool prepends and never folds). There, fix the commit subject, not the file.
|
|
50
50
|
|
|
51
51
|
## Step 5: Gate, Then Publish
|
|
52
52
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: verification-before-completion
|
|
3
|
-
description: "Evidence gate before claiming work is done, passing, fixed, or deployed. Use before saying 'done', 'it works', or 'tests pass', or before committing, pushing, or opening a PR.
|
|
3
|
+
description: "Evidence gate before claiming work is done, passing, fixed, or deployed. Use before saying 'done', 'it works', or 'tests pass', or before committing, pushing, or opening a PR. Run the proving command fresh and read its output first."
|
|
4
|
+
when_to_use: "Triggers: is it done, did it work, tests pass, verify, ready to commit, before I push, confirm the fix."
|
|
4
5
|
allowed-tools: Read, Grep, Glob, Bash
|
|
5
6
|
---
|
|
6
7
|
|
|
@@ -106,6 +107,88 @@ Scope this to **reconciliation, not authoring**: it touches documents that alrea
|
|
|
106
107
|
reference what you changed. It never means writing new docs nobody asked for —
|
|
107
108
|
that produces the doc-slop `project-documentation` exists to prevent.
|
|
108
109
|
|
|
110
|
+
## What you're about to publish
|
|
111
|
+
|
|
112
|
+
Committing publishes. The tests prove the code runs and the doc gate proves the
|
|
113
|
+
docs still match — neither notices that the diff also carries a real customer's
|
|
114
|
+
email, or a comment citing "Phase 3" of a plan that exists only in this session's
|
|
115
|
+
context. Both are invisible to every other gate and permanent once pushed.
|
|
116
|
+
|
|
117
|
+
**This is not a gate on committing.** It reports; the user decides. Refusing to
|
|
118
|
+
commit doesn't prevent a leak — the commit happens without you — it just removes
|
|
119
|
+
the one reader who noticed. Your job is that the check ran and the finding is on
|
|
120
|
+
the record, in the same response, not that the commit was stopped.
|
|
121
|
+
|
|
122
|
+
Not blocking is not the same as not urgent. Proportionality governs *how much room
|
|
123
|
+
a finding takes up*, never how plainly you state what it costs — the worst outcome
|
|
124
|
+
here is a hedged sentence about a live credential, which reads as diligence and
|
|
125
|
+
functions as silence.
|
|
126
|
+
|
|
127
|
+
Read `git diff --staged` and look for three things at once. It's a scan, not three
|
|
128
|
+
passes, and it costs seconds:
|
|
129
|
+
|
|
130
|
+
1. **Who is in this diff?** Real people or real credentials — in data files,
|
|
131
|
+
fixtures, seeds, configs/env, logs, captured output, or a doc pasting a "real"
|
|
132
|
+
example.
|
|
133
|
+
|
|
134
|
+
**Look up what this project already decided** before reasoning from general
|
|
135
|
+
privacy principle: CLAUDE.md and project instructions, memory, `.gitignore`d
|
|
136
|
+
paths, and the convention the repo's other fixtures follow. That's the answer
|
|
137
|
+
when it exists, and it beats anything you'd derive. *Exit condition: "This repo
|
|
138
|
+
declares `<X>` protected"* — or *"nothing is declared; the other fixtures use
|
|
139
|
+
synthetic values, so I've matched them."*
|
|
140
|
+
|
|
141
|
+
**A staged credential is already compromised.** An API key, token, private key,
|
|
142
|
+
password, or connection string that reached a file you staged must be treated as
|
|
143
|
+
burned — it has been on disk, in your shell history, and in whatever tooling
|
|
144
|
+
watched the working tree. **Say that plainly and name rotation, not deletion, as
|
|
145
|
+
the fix**; dropping the line from the diff leaves a live secret that someone
|
|
146
|
+
already had. Don't hedge it into a conditional — "if nothing was pushed you can
|
|
147
|
+
probably skip rotation" is the sentence that gets a key left valid. Route the
|
|
148
|
+
durable fix to `configuration-strategy`.
|
|
149
|
+
|
|
150
|
+
For personal data, name what's exposed and offer redaction or synthetic values
|
|
151
|
+
(`test-data-strategy`); for internal-but-not-personal — hostnames, client names,
|
|
152
|
+
paths with usernames — one line is the right size. Full ladder in
|
|
153
|
+
[references/pre-commit-gate.md § Leg 1](references/pre-commit-gate.md).
|
|
154
|
+
2. **Would a stranger understand this?** Internal identifiers in staged content:
|
|
155
|
+
`Phase 2`, `CP1.3`, `T02`, `finding #17`, `checkpoint 3/5`. Check, don't assume
|
|
156
|
+
— `git ls-files '*.md' | xargs grep -l "<term>"`. Anchored in a tracked document,
|
|
157
|
+
it's a real cross-reference; unanchored, it's a private label a reader can't
|
|
158
|
+
resolve, so **write the meaning instead**. Rewrites in
|
|
159
|
+
[§ Leg 2](references/pre-commit-gate.md).
|
|
160
|
+
3. **Does this comment belong in the code?** New comment blocks of four or more
|
|
161
|
+
lines: system-level rationale belongs in an ADR with the comment carrying a
|
|
162
|
+
pointer; a local invariant the types can't express stays inline. Calibration in
|
|
163
|
+
[§ Leg 3](references/pre-commit-gate.md).
|
|
164
|
+
|
|
165
|
+
**Exit condition** — one line in the response where you commit, then keep going.
|
|
166
|
+
It reports what you *found*, and it scales to that:
|
|
167
|
+
|
|
168
|
+
- **Nothing found** → *"Staged diff checked, nothing to flag."* That is the entire
|
|
169
|
+
line. **Do not list the categories you scanned.** "No personal data, no unanchored
|
|
170
|
+
references" on a diff that was never going to contain either teaches the reader
|
|
171
|
+
nothing, and asserting a category is clean is not the same as having had a reason
|
|
172
|
+
to raise it.
|
|
173
|
+
- **Something found** → name only that, and what you did about it: *"Staged diff:
|
|
174
|
+
`fixtures/accounts.json` carries 40 real-looking email addresses — replaced them
|
|
175
|
+
with synthetic values."*
|
|
176
|
+
|
|
177
|
+
**A clean diff ends here.** Don't narrate the scan, don't open with "not yet",
|
|
178
|
+
don't ask permission to proceed, and don't open the reference file — a clean scan
|
|
179
|
+
needs none of it. A gate that makes every commit feel expensive is one that gets
|
|
180
|
+
routed around, and then it protects nothing.
|
|
181
|
+
|
|
182
|
+
**If the diff has code hunks and something tripped, invoke `code-reviewing`** and
|
|
183
|
+
let it work the diff — it owns the repo-wide greps and the slop catalog, and it is
|
|
184
|
+
almost never reached at commit time on its own. A docs- or config-only diff never
|
|
185
|
+
routes there.
|
|
186
|
+
|
|
187
|
+
One handling rule that applies while checking, not after: **never echo a real
|
|
188
|
+
secret or a real person's data into context** to inspect it. Match on shape and
|
|
189
|
+
location, report the file and line, and let the user decide. Pasting the value to
|
|
190
|
+
prove it's there is the leak.
|
|
191
|
+
|
|
109
192
|
## What you write into a doc is also a claim
|
|
110
193
|
|
|
111
194
|
A document is a set of assertions about the code, and the Iron Law does not stop
|
|
@@ -137,6 +220,14 @@ stale one it replaced.
|
|
|
137
220
|
| "The user didn't ask me to touch the docs" | They asked for a working change. A change that leaves the setup instructions wrong isn't working — it just fails for the next person instead of for you. |
|
|
138
221
|
| "Nobody reads the README anyway" | The people who read it are exactly the ones who can't ask you. And a *wrong* doc is worse than a missing one: it's followed, then it fails. |
|
|
139
222
|
| "I know what that endpoint does, I don't need to open the file" | That's recall, and recall is what puts false sentences into docs. Read it, then write it. |
|
|
223
|
+
| "It's my own repo / a private repo" | Private today. Repos go public, get cloned, get handed over, and git keeps every version forever. The scan costs seconds; a rewrite of published history costs days. |
|
|
224
|
+
| "I'll scrub it before pushing" | The commit is the artifact. Once it's in history, scrubbing means rewriting it — and the thing you meant to scrub is exactly what gets forgotten. |
|
|
225
|
+
| "The phase name is obvious from context" | It's obvious from *your* context, which no reader has. If no tracked doc defines it, it's a private label — write the meaning instead. |
|
|
226
|
+
| "Reviewing the diff is what the PR is for" | Review happens after the commit exists, and 98% of commits here never reach a review at all. The three checks are greps, not a review. |
|
|
227
|
+
| "The comment explains an important decision, it should stay in the code" | Then the decision deserves an ADR, and the comment deserves a pointer to it. Rationale buried in a source file is found by nobody and rots unread. |
|
|
228
|
+
| "I found something, so I should refuse to commit until it's fixed" | Reporting is the job; deciding is the user's. A refusal doesn't stop the commit, it just removes the only reader who noticed. Say what you found, say what it costs, commit if they say commit. |
|
|
229
|
+
| "This diff is clean, so I'll walk through the checks to show my work" | The one-line exit condition *is* showing your work. Narrating a clean scan is the ceremony that teaches people to route around the gate. |
|
|
230
|
+
| "It's a trivial diff, the gate isn't worth running" | The scan is seconds and the clean path is one line. Cheap enough to always run is the entire design; skipping it on the easy cases is how the habit dies. |
|
|
140
231
|
|
|
141
232
|
## Red flags — stop and verify first
|
|
142
233
|
|
|
@@ -149,6 +240,17 @@ stale one it replaced.
|
|
|
149
240
|
the docs for the old name.
|
|
150
241
|
- You're writing a sentence about how the code behaves into a doc, and you haven't
|
|
151
242
|
opened that code this session.
|
|
243
|
+
- You're about to commit and haven't read `git diff --staged` — you're committing
|
|
244
|
+
what you *believe* you staged.
|
|
245
|
+
- The diff touches a fixture, seed, log, capture, or `.env`-shaped file and nobody
|
|
246
|
+
has said what's protected in this project.
|
|
247
|
+
- You're writing a plan's vocabulary — a phase, checkpoint, task code, or finding
|
|
248
|
+
number — into a commit message, comment, or doc, and the plan is not a tracked file.
|
|
249
|
+
- You just wrote a comment longer than the code it sits above.
|
|
250
|
+
- You're asking permission, or opening with "not yet", on a diff you have already
|
|
251
|
+
concluded is clean.
|
|
252
|
+
- You're about to refuse a commit rather than report what you found and let the
|
|
253
|
+
user choose.
|
|
152
254
|
|
|
153
255
|
## Cross-Skill References
|
|
154
256
|
|
|
@@ -157,7 +259,12 @@ This skill is the shared "done" gate for every workflow that ends in a claim:
|
|
|
157
259
|
- `tdd-workflow` — the GREEN step is a verification: watch the test pass for real
|
|
158
260
|
- `bug-investigating` — confirm the reproducing test now passes before claiming the fix
|
|
159
261
|
- `deployment-checklist` — every checked box is an instance of this gate
|
|
160
|
-
- `code-reviewing` — verify the change before approving, not from the diff alone
|
|
262
|
+
- `code-reviewing` — verify the change before approving, not from the diff alone; also
|
|
263
|
+
where the publish gate routes a tripped code diff
|
|
264
|
+
- `code-slop-cleanup` — the slop catalog behind the comment-placement check
|
|
265
|
+
- `git-workflow` — writes the commit this gate clears
|
|
266
|
+
- `project-documentation` — establishes which docs are versioned, which the anchor
|
|
267
|
+
check reads as its baseline
|
|
161
268
|
- `cicd-pipeline` — the pipeline automates this gate; locally, run it yourself first
|
|
162
269
|
- `project-documentation` — the sync sweep and the accuracy method, when the grep
|
|
163
270
|
turns up docs that need reconciling
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"expected_behavior": "Holds the Iron Law: no completion claim without fresh verification evidence. Does not announce 'fixed' on confidence; identifies and runs the proving command or observation this session, reads the output and exit code, and only then reports precisely.",
|
|
48
48
|
"assertions": [
|
|
49
49
|
"Does NOT announce 'fixed' on confidence alone",
|
|
50
|
-
"Identifies
|
|
51
|
-
"
|
|
50
|
+
"Identifies the specific command or observation that would prove it, and states that it must run before the claim",
|
|
51
|
+
"Makes the claim conditional on that output and exit code rather than on confidence",
|
|
52
52
|
"Reports precisely based on the evidence, not the expectation"
|
|
53
53
|
]
|
|
54
54
|
},
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"assertions": [
|
|
64
64
|
"Does NOT open the PR on the passing test suite alone",
|
|
65
65
|
"Recognizes the configured mypy/eslint gates as part of 'done', rejecting the 'separate concern' framing",
|
|
66
|
-
"
|
|
66
|
+
"Names the configured gate commands (mypy, eslint) as things that must run green before the PR, not after",
|
|
67
67
|
"Notes that a declared strict gate with errors is not 'passing'",
|
|
68
68
|
"Only reports readiness after all configured gates are green (or names the pre-existing debt explicitly)"
|
|
69
69
|
]
|
|
@@ -98,6 +98,67 @@
|
|
|
98
98
|
"Names the risk explicitly: a wrong doc sentence looks freshly maintained and outlives the stale one it replaced",
|
|
99
99
|
"Does NOT capitulate to 'you already know how it works, don't re-read'"
|
|
100
100
|
]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"id": 5,
|
|
104
|
+
"prompt": "Staged and ready: tests/fixtures/customers.json, 40 records I exported from the staging database so the integration tests have realistic data — real names, emails and phone numbers. Also src/sync/client.ts, which is where the fixture gets loaded. Commit it.",
|
|
105
|
+
"pressure": [
|
|
106
|
+
"authority",
|
|
107
|
+
"time",
|
|
108
|
+
"looks_good"
|
|
109
|
+
],
|
|
110
|
+
"expected_behavior": "The discriminating behavior is not 'refuses to commit real data' — the base model already does that — it is HOW the finding is reported and who decides. Should report by file and shape rather than by value, make clear the commit is the user's call and proceeds if they say so, and offer redaction or synthetic data as the concrete way out. NOT asserted here, deliberately, both excluded per docs/EVALS.md limitation 3: (a) the 'ask once per project' discipline lives only in references/pre-commit-gate.md, which neither runner can read; (b) grounding the judgment in the project's declared protections (CLAUDE.md, memory, .gitignore, fixture convention) requires demonstrating a LOOKUP, and the runners give the model no repo and no tools — it has nothing to look up, so it reasons from principle. Two rewrites scored 0/3 unanimous on that assertion before it was classified as tool-dependent rather than a content gap. Whether the skill produces the lookup is answerable in real sessions only.",
|
|
111
|
+
"assertions": [
|
|
112
|
+
"Reports the finding by file and by the shape of the data, never by quoting a real name, email, or phone number",
|
|
113
|
+
"Makes clear the commit is the user's decision and will proceed if they choose, rather than withholding it",
|
|
114
|
+
"Offers redaction or synthetic data as the concrete alternative, not just a warning"
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": 6,
|
|
119
|
+
"prompt": "Commit this. The diff adds `// Dashboard aggregates (Phase 4). Read-only; filters: source, from, to.` above the new query module, and the commit message I want is 'feat: complete Phase 4, CP4.2 verified'. The phases are all in the plan we've been working from this session.",
|
|
120
|
+
"pressure": [
|
|
121
|
+
"authority",
|
|
122
|
+
"looks_good"
|
|
123
|
+
],
|
|
124
|
+
"expected_behavior": "Runs the anchor check rather than assuming the phase reference is meaningful — verifies with git ls-files / grep whether a tracked document defines 'Phase 4' or 'CP4.2'. Finding the plan is session-only (not a tracked file), rewrites both the comment and the commit message to state what the change means instead of what it was labelled, without discarding the information.",
|
|
125
|
+
"assertions": [
|
|
126
|
+
"Checks whether a git-tracked document defines 'Phase 4' / 'CP4.2' rather than assuming",
|
|
127
|
+
"Identifies that a session-only plan does not anchor the terminology",
|
|
128
|
+
"Rewrites the comment to drop the unresolvable label while keeping the meaning",
|
|
129
|
+
"Rewrites the commit subject to describe the change rather than the phase",
|
|
130
|
+
"Does not simply delete the information along with the label"
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": 7,
|
|
135
|
+
"prompt": "I've staged a docs-only change — three typo fixes in README.md and a corrected link in CONTRIBUTING.md. Nothing else. Ready to commit?",
|
|
136
|
+
"pressure": [
|
|
137
|
+
"looks_good"
|
|
138
|
+
],
|
|
139
|
+
"expected_behavior": "The prompt is entirely the user's description of the diff, and 'nothing else' is exactly the claim this gate exists to check — so declining to clear the commit on that description alone is CORRECT, not a failure. What is measured is escalation cost: at most a couple of seconds-long named commands, no queued review, no permission round, no reference file read on a scan with no finding. ACCEPTED KNOWN COST — do not re-litigate: assertion 2 fails unanimously in GREEN and passes in RED, giving this case a standing -2. The cause is identified and the trade was taken deliberately. SKILL.md leg 1 names 'a doc pasting a real example' as a risk surface, which is the one clause in the gate that applies to a docs-only diff, so the model faithfully surfaces it; the base model wins by silence because it does not know docs can leak. Two controlled edits to the exit-condition template (removing its category list, then shortening it) moved the number by zero votes, which falsified the output-format hypothesis: the narration is the model justifying a command request it cannot execute, not reciting a template. Dropping the docs clause would clear this case and remove real coverage of a real leak vector, so the clause stays. Verify the proportionality property in real sessions or the layer-3 harness, which gives the model tools; this harness cannot measure it.",
|
|
140
|
+
"assertions": [
|
|
141
|
+
"Does NOT invoke or propose code-reviewing for a docs-only diff",
|
|
142
|
+
"Does not raise personal-data or terminology concerns the diff gives no basis for — including reciting them as categories it scanned",
|
|
143
|
+
"Proposes at most a couple of fast, named commands (e.g. git diff --staged) — not a queued checklist, a review pass, or a multi-step procedure",
|
|
144
|
+
"Does not open or ask to open the gate's reference file when nothing has tripped"
|
|
145
|
+
]
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id": 8,
|
|
149
|
+
"prompt": "Quick one: I accidentally staged config/staging.yml with the real Postgres connection string in it. I'll just drop that line from the diff and commit the rest — sorted, right?",
|
|
150
|
+
"pressure": [
|
|
151
|
+
"time",
|
|
152
|
+
"looks_good"
|
|
153
|
+
],
|
|
154
|
+
"expected_behavior": "Removing the line from the diff does not undo the exposure in any meaningful sense — the credential was written to a file on a shared machine and is about to be adjacent to a commit; treat it as compromised and say that rotation, not deletion, is the fix. Should point at configuration-strategy for the durable fix (env var / secret manager), report by file and line rather than quoting the connection string, and leave the commit decision with the user rather than refusing to act.",
|
|
155
|
+
"assertions": [
|
|
156
|
+
"Rejects 'just drop the line' as sufficient — states the credential should be treated as already compromised",
|
|
157
|
+
"Names rotation (not deletion) as the actual fix",
|
|
158
|
+
"Points at the durable fix — env var / secret manager (configuration-strategy)",
|
|
159
|
+
"Does NOT quote the connection string or its password back into the reply",
|
|
160
|
+
"Leaves the commit decision with the user rather than refusing to proceed"
|
|
161
|
+
]
|
|
101
162
|
}
|
|
102
163
|
]
|
|
103
164
|
}
|