@kiwidata/grimoire 0.1.1
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/.claude-plugin/plugin.json +8 -0
- package/AGENTS.md +217 -0
- package/README.md +748 -0
- package/bin/grimoire.js +2 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +42 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/archive.d.ts +3 -0
- package/dist/commands/archive.d.ts.map +1 -0
- package/dist/commands/archive.js +22 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/branch-check.d.ts +3 -0
- package/dist/commands/branch-check.d.ts.map +1 -0
- package/dist/commands/branch-check.js +16 -0
- package/dist/commands/branch-check.js.map +1 -0
- package/dist/commands/check.d.ts +3 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +22 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/ci.d.ts +3 -0
- package/dist/commands/ci.d.ts.map +1 -0
- package/dist/commands/ci.js +18 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/diff.d.ts +3 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +10 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/docs.d.ts +3 -0
- package/dist/commands/docs.d.ts.map +1 -0
- package/dist/commands/docs.js +11 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/health.d.ts +3 -0
- package/dist/commands/health.d.ts.map +1 -0
- package/dist/commands/health.js +13 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +21 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +22 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/log.d.ts +3 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +15 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/map.d.ts +3 -0
- package/dist/commands/map.d.ts.map +1 -0
- package/dist/commands/map.js +17 -0
- package/dist/commands/map.js.map +1 -0
- package/dist/commands/pr.d.ts +3 -0
- package/dist/commands/pr.d.ts.map +1 -0
- package/dist/commands/pr.js +17 -0
- package/dist/commands/pr.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +12 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/test-quality.d.ts +3 -0
- package/dist/commands/test-quality.d.ts.map +1 -0
- package/dist/commands/test-quality.js +37 -0
- package/dist/commands/test-quality.js.map +1 -0
- package/dist/commands/trace.d.ts +3 -0
- package/dist/commands/trace.d.ts.map +1 -0
- package/dist/commands/trace.js +12 -0
- package/dist/commands/trace.js.map +1 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +22 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +3 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +17 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/core/archive.d.ts +9 -0
- package/dist/core/archive.d.ts.map +1 -0
- package/dist/core/archive.js +92 -0
- package/dist/core/archive.js.map +1 -0
- package/dist/core/branch-check.d.ts +27 -0
- package/dist/core/branch-check.d.ts.map +1 -0
- package/dist/core/branch-check.js +205 -0
- package/dist/core/branch-check.js.map +1 -0
- package/dist/core/check.d.ts +24 -0
- package/dist/core/check.d.ts.map +1 -0
- package/dist/core/check.js +372 -0
- package/dist/core/check.js.map +1 -0
- package/dist/core/ci.d.ts +24 -0
- package/dist/core/ci.d.ts.map +1 -0
- package/dist/core/ci.js +162 -0
- package/dist/core/ci.js.map +1 -0
- package/dist/core/detect.d.ts +10 -0
- package/dist/core/detect.d.ts.map +1 -0
- package/dist/core/detect.js +368 -0
- package/dist/core/detect.js.map +1 -0
- package/dist/core/diff.d.ts +29 -0
- package/dist/core/diff.d.ts.map +1 -0
- package/dist/core/diff.js +197 -0
- package/dist/core/diff.js.map +1 -0
- package/dist/core/doc-style.d.ts +16 -0
- package/dist/core/doc-style.d.ts.map +1 -0
- package/dist/core/doc-style.js +192 -0
- package/dist/core/doc-style.js.map +1 -0
- package/dist/core/docs.d.ts +6 -0
- package/dist/core/docs.d.ts.map +1 -0
- package/dist/core/docs.js +478 -0
- package/dist/core/docs.js.map +1 -0
- package/dist/core/health.d.ts +7 -0
- package/dist/core/health.d.ts.map +1 -0
- package/dist/core/health.js +489 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/hooks.d.ts +5 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +168 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/init.d.ts +9 -0
- package/dist/core/init.d.ts.map +1 -0
- package/dist/core/init.js +563 -0
- package/dist/core/init.js.map +1 -0
- package/dist/core/list.d.ts +4 -0
- package/dist/core/list.d.ts.map +1 -0
- package/dist/core/list.js +170 -0
- package/dist/core/list.js.map +1 -0
- package/dist/core/log.d.ts +8 -0
- package/dist/core/log.d.ts.map +1 -0
- package/dist/core/log.js +150 -0
- package/dist/core/log.js.map +1 -0
- package/dist/core/map.d.ts +9 -0
- package/dist/core/map.d.ts.map +1 -0
- package/dist/core/map.js +302 -0
- package/dist/core/map.js.map +1 -0
- package/dist/core/pr.d.ts +9 -0
- package/dist/core/pr.d.ts.map +1 -0
- package/dist/core/pr.js +273 -0
- package/dist/core/pr.js.map +1 -0
- package/dist/core/shared-setup.d.ts +52 -0
- package/dist/core/shared-setup.d.ts.map +1 -0
- package/dist/core/shared-setup.js +221 -0
- package/dist/core/shared-setup.js.map +1 -0
- package/dist/core/status.d.ts +6 -0
- package/dist/core/status.d.ts.map +1 -0
- package/dist/core/status.js +114 -0
- package/dist/core/status.js.map +1 -0
- package/dist/core/test-quality.d.ts +33 -0
- package/dist/core/test-quality.d.ts.map +1 -0
- package/dist/core/test-quality.js +378 -0
- package/dist/core/test-quality.js.map +1 -0
- package/dist/core/trace.d.ts +6 -0
- package/dist/core/trace.d.ts.map +1 -0
- package/dist/core/trace.js +211 -0
- package/dist/core/trace.js.map +1 -0
- package/dist/core/update.d.ts +10 -0
- package/dist/core/update.d.ts.map +1 -0
- package/dist/core/update.js +149 -0
- package/dist/core/update.js.map +1 -0
- package/dist/core/validate.d.ts +20 -0
- package/dist/core/validate.d.ts.map +1 -0
- package/dist/core/validate.js +275 -0
- package/dist/core/validate.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/config.d.ts +61 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +172 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/fs.d.ts +17 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +38 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/paths.d.ts +10 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +35 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/spawn.d.ts +5 -0
- package/dist/utils/spawn.d.ts.map +1 -0
- package/dist/utils/spawn.js +34 -0
- package/dist/utils/spawn.js.map +1 -0
- package/package.json +68 -0
- package/skills/grimoire-apply/SKILL.md +274 -0
- package/skills/grimoire-audit/SKILL.md +129 -0
- package/skills/grimoire-branch-guard/SKILL.md +111 -0
- package/skills/grimoire-bug/SKILL.md +160 -0
- package/skills/grimoire-bug-explore/SKILL.md +242 -0
- package/skills/grimoire-bug-report/SKILL.md +237 -0
- package/skills/grimoire-bug-session/SKILL.md +222 -0
- package/skills/grimoire-bug-triage/SKILL.md +274 -0
- package/skills/grimoire-commit/SKILL.md +150 -0
- package/skills/grimoire-discover/SKILL.md +297 -0
- package/skills/grimoire-draft/SKILL.md +202 -0
- package/skills/grimoire-plan/SKILL.md +329 -0
- package/skills/grimoire-pr/SKILL.md +134 -0
- package/skills/grimoire-pr-review/SKILL.md +240 -0
- package/skills/grimoire-refactor/SKILL.md +251 -0
- package/skills/grimoire-remove/SKILL.md +112 -0
- package/skills/grimoire-review/SKILL.md +247 -0
- package/skills/grimoire-verify/SKILL.md +223 -0
- package/skills/references/bug-classification.md +154 -0
- package/skills/references/build-vs-buy.md +77 -0
- package/skills/references/elicitation-personas.md +118 -0
- package/skills/references/refactor-register-format.md +88 -0
- package/skills/references/refactor-scan-categories.md +102 -0
- package/skills/references/schema-format.md +68 -0
- package/skills/references/security-compliance.md +110 -0
- package/skills/references/testing-contracts.md +93 -0
- package/templates/context.yml +110 -0
- package/templates/debt-exceptions.yml +61 -0
- package/templates/decision.md +50 -0
- package/templates/dupignore +93 -0
- package/templates/example.feature +24 -0
- package/templates/manifest.md +29 -0
- package/templates/mapignore +58 -0
- package/templates/mapkeys +65 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grimoire-pr-review
|
|
3
|
+
description: Review a teammate's pull request using the same multi-persona lens as pre-commit review, but against the actual diff. Fetches the PR, loads linked grimoire artifacts via the Change trailer, and produces structured findings suitable for PR comments.
|
|
4
|
+
compatibility: Designed for Claude Code (or similar products)
|
|
5
|
+
metadata:
|
|
6
|
+
author: kiwi-data
|
|
7
|
+
version: "0.1"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# grimoire-pr-review
|
|
11
|
+
|
|
12
|
+
Review a pull request authored by someone else. Applies the same persona lens as `grimoire-review` (product, engineer, security, QA, data) to the real diff, cross-referenced with the PR's linked grimoire change (if any).
|
|
13
|
+
|
|
14
|
+
## Triggers
|
|
15
|
+
- User asks to review a teammate's PR / MR
|
|
16
|
+
- User supplies a PR number, URL, or branch and asks for review
|
|
17
|
+
- Loose match: "review this PR", "look at PR #123", "review <url>", "review teammate's branch", "code review"
|
|
18
|
+
|
|
19
|
+
## Routing
|
|
20
|
+
- Reviewing your own pre-merge change you just built → `grimoire-pr` (has optional post-impl review)
|
|
21
|
+
- Reviewing a design before any code exists → `grimoire-review`
|
|
22
|
+
- Verifying scenarios pass after merge → `grimoire-verify`
|
|
23
|
+
- Writing a bug report against merged behavior → `grimoire-bug-report`
|
|
24
|
+
|
|
25
|
+
## Prerequisites
|
|
26
|
+
- `gh` (GitHub) or `glab` (GitLab) CLI installed and authenticated, OR the PR's branch fetched locally
|
|
27
|
+
- Working directory is the repo the PR targets
|
|
28
|
+
- Optional: `.grimoire/` directory with baseline features/decisions for linked-change context
|
|
29
|
+
|
|
30
|
+
## Inputs
|
|
31
|
+
Accept any of:
|
|
32
|
+
- PR number: `123`
|
|
33
|
+
- PR URL: `https://github.com/org/repo/pull/123`
|
|
34
|
+
- Branch name: `feat/add-2fa-login`
|
|
35
|
+
- Base/head refs: `main...feat/add-2fa-login`
|
|
36
|
+
|
|
37
|
+
If nothing supplied, ask the user for one.
|
|
38
|
+
|
|
39
|
+
## Workflow
|
|
40
|
+
|
|
41
|
+
### 1. Fetch PR Metadata
|
|
42
|
+
Resolve the input to concrete refs.
|
|
43
|
+
|
|
44
|
+
- GitHub: `gh pr view <id> --json number,title,body,author,baseRefName,headRefName,files,commits,url`
|
|
45
|
+
- GitLab: `glab mr view <id> --output json`
|
|
46
|
+
- Branch only: derive base from default branch (`git remote show origin | grep 'HEAD branch'`) and head = supplied branch
|
|
47
|
+
|
|
48
|
+
Record: PR title, body, author, base branch, head branch, URL, file list, commit count.
|
|
49
|
+
|
|
50
|
+
### 2. Fetch the Diff
|
|
51
|
+
- GitHub: `gh pr diff <id>` (or `git fetch origin pull/<id>/head && git diff <base>...FETCH_HEAD`)
|
|
52
|
+
- GitLab: `glab mr diff <id>`
|
|
53
|
+
- Branch: `git fetch origin <head> && git diff origin/<base>...origin/<head>`
|
|
54
|
+
|
|
55
|
+
If the diff is very large (>2000 lines changed), ask the user whether to review the full diff, focus on a subset of files, or review commit-by-commit.
|
|
56
|
+
|
|
57
|
+
### 3. Find Linked Grimoire Change
|
|
58
|
+
Look for a `Change:` trailer in the PR commits:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
git log <base>..<head> --format="%B" | grep -E "^Change:"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
If present:
|
|
65
|
+
- Change ID = trailer value
|
|
66
|
+
- Load artifacts: first check `.grimoire/changes/<change-id>/` (in-progress), then `.grimoire/archive/*<change-id>*/` (archived). Try the PR's head branch checked out locally if needed.
|
|
67
|
+
- Read `manifest.md`, all `.feature` files in the change, decision records, `tasks.md`, `data.yml`
|
|
68
|
+
- Also grep for `Scenarios:` and `Decisions:` trailers to scope review to the named items
|
|
69
|
+
|
|
70
|
+
If no `Change:` trailer exists, that's itself a finding for a grimoire-managed repo: flag as **suggestion** ("commits missing audit trailer — `grimoire trace` won't find this PR") unless the project clearly doesn't use grimoire.
|
|
71
|
+
|
|
72
|
+
### 4. Gather Project Context
|
|
73
|
+
- `.grimoire/config.yaml` — language, tools, `commit_style`, `project.compliance`, `dep_audit`
|
|
74
|
+
- `.grimoire/docs/context.yml` — deployment environment, related services
|
|
75
|
+
- `.grimoire/docs/data/schema.yml` — current data baseline
|
|
76
|
+
- Relevant `.grimoire/docs/<area>.md` for the directories touched by the diff
|
|
77
|
+
|
|
78
|
+
### 5. Complexity-Gated Depth
|
|
79
|
+
Read `complexity` from the linked manifest frontmatter if available. Fall back to heuristics on the diff:
|
|
80
|
+
|
|
81
|
+
| Signal | Depth |
|
|
82
|
+
|---|---|
|
|
83
|
+
| Docs only, ≤50 lines | Senior engineer skim only |
|
|
84
|
+
| Linked manifest complexity 1-2, diff <200 lines, no security tags | Senior engineer + security quick scan |
|
|
85
|
+
| Linked manifest complexity 3, OR diff touches auth/data/API | All relevant personas (skip data if no schema change, skip QA if no user-facing change) |
|
|
86
|
+
| Linked manifest complexity 4, OR diff >500 lines, OR touches multiple domains | All personas mandatory |
|
|
87
|
+
|
|
88
|
+
User can override: "full review", "just security", "just engineer", etc.
|
|
89
|
+
|
|
90
|
+
### 6. Product Manager Review
|
|
91
|
+
*(Skip if PR is pure internal refactor with no user-facing change.)*
|
|
92
|
+
|
|
93
|
+
Evaluate against the linked feature files (if any) or the PR body:
|
|
94
|
+
|
|
95
|
+
- **Scenario coverage**: If a feature file exists in the change, does the diff implement every scenario? Any scenario with no matching code change?
|
|
96
|
+
- **Non-goals**: Does the diff touch anything the manifest's Non-goals section excludes?
|
|
97
|
+
- **Acceptance**: From the diff alone, could a PM validate this meets the feature's acceptance criteria?
|
|
98
|
+
- **Clarity**: Does the PR body (or linked manifest) make the user-visible outcome clear?
|
|
99
|
+
|
|
100
|
+
Flag as **blocker** or **suggestion**.
|
|
101
|
+
|
|
102
|
+
### 7. Senior Engineer Review
|
|
103
|
+
Review the actual code:
|
|
104
|
+
|
|
105
|
+
- **Simplicity**: Is this the simplest implementation? Any unnecessary abstraction, indirection, or config that could be inlined?
|
|
106
|
+
- **Conventions**: Does the new code match the file layout, naming, and patterns already in the touched areas? Check `.grimoire/docs/<area>.md` if present.
|
|
107
|
+
- **Reuse**: Are there existing utilities/functions that were re-implemented? `grep` for similar names or check the area doc's reusable-code list.
|
|
108
|
+
- **Dead code**: Functions added but not called, imports unused, commented-out code, stubs with no implementation.
|
|
109
|
+
- **Scope creep**: Files changed outside the scope implied by the change-id or manifest. Formatting-only changes to unrelated files = noise.
|
|
110
|
+
- **Error handling**: Are errors handled at boundaries? Internal code shouldn't be littered with defensive checks; external inputs must be validated.
|
|
111
|
+
- **Tests**: Do new behaviors have tests? Do the tests make real assertions (not just `assert true` / mock everything)? Check `../references/testing-contracts.md` if the framework matches.
|
|
112
|
+
- **Contract compatibility**: If `data.yml` / `schema.yml` exists, does the diff change request/response shape for a documented API? If yes, where's the contract test update?
|
|
113
|
+
- **Dependencies**: Any new packages in `package.json` / `requirements.txt` / `Cargo.toml` etc. not mentioned in tasks? Any version bumps that aren't noted?
|
|
114
|
+
- **Task alignment**: If `tasks.md` exists for the change, does the diff complete the tasks as written? Any task that was "done" but has no corresponding code?
|
|
115
|
+
|
|
116
|
+
Flag as **blocker** or **suggestion**.
|
|
117
|
+
|
|
118
|
+
### 8. Security Engineer Review
|
|
119
|
+
Apply `../references/security-compliance.md`.
|
|
120
|
+
|
|
121
|
+
#### 8a. STRIDE on the diff
|
|
122
|
+
For every new entry point, data flow, or trust boundary introduced by the diff:
|
|
123
|
+
|
|
124
|
+
| Threat | Question |
|
|
125
|
+
|---|---|
|
|
126
|
+
| **S**poofing | Auth check at every new route/handler? |
|
|
127
|
+
| **T**ampering | Input/message integrity validated? CSRF on state-changing requests? |
|
|
128
|
+
| **R**epudiation | Security-relevant actions logged? |
|
|
129
|
+
| **I**nfo disclosure | Error responses, logs, stack traces leaking PII/tokens/secrets? |
|
|
130
|
+
| **D**oS | Unbounded loops, unlimited file uploads, expensive queries on user input, no rate limit? |
|
|
131
|
+
| **E**oP | Role/permission checks at the right layer? Any bypass via missing middleware? |
|
|
132
|
+
|
|
133
|
+
Skip categories that don't apply.
|
|
134
|
+
|
|
135
|
+
#### 8b. Code-level scan
|
|
136
|
+
- **Secrets**: Grep the diff for hardcoded keys, tokens, passwords, cloud credentials, JWT secrets. Flag any hit as **blocker**.
|
|
137
|
+
- **Injection**: Raw SQL with string concatenation, shell-exec with user input, `eval`/`exec`, unsafe deserialization. Tag with OWASP + CWE.
|
|
138
|
+
- **Input validation**: New endpoints without schema validation, file uploads without size/type limits, path params used directly in filesystem calls (path traversal).
|
|
139
|
+
- **Auth**: New routes/handlers missing auth decorators / middleware. Compare against neighbors in the same file.
|
|
140
|
+
- **Dependencies**: New packages in lockfile — check the name is real (typosquat risk), check project's `dep_audit` tool output if committed. Flag packages with zero downloads or suspicious maintainers.
|
|
141
|
+
- **PII**: New logging statements that could emit PII; new storage of personal data without encryption.
|
|
142
|
+
- **Cross-service auth**: If `context.yml` lists related services, are service-to-service calls authenticated?
|
|
143
|
+
|
|
144
|
+
#### 8c. Compliance
|
|
145
|
+
If `project.compliance` configured, verify per `../references/security-compliance.md` section "Compliance Framework Verification". Any security-tagged scenario in the linked change with no corresponding verification in the diff = **blocker**.
|
|
146
|
+
|
|
147
|
+
#### 8d. Tag findings
|
|
148
|
+
Every security finding gets OWASP 2021 + CWE tags. See the CWE quick-reference in `../references/security-compliance.md`.
|
|
149
|
+
|
|
150
|
+
### 9. QA Engineer Review (optional)
|
|
151
|
+
Skip if PR is purely internal.
|
|
152
|
+
|
|
153
|
+
- **Test presence**: Every new user-facing behavior has a test? Every scenario from the linked feature file has step definitions?
|
|
154
|
+
- **Test quality**: Are tests asserting outputs, or just that code "ran"? Over-mocked tests are a red flag.
|
|
155
|
+
- **Negative paths**: For each happy path in the diff, is there a failure-path test?
|
|
156
|
+
- **Observability**: New feature — how will it be debugged in prod? Structured logs / metrics / error surfaces?
|
|
157
|
+
- **Regression risk**: Which existing tests cover the touched code? Were any tests removed or weakened in the diff?
|
|
158
|
+
- **Accessibility**: New UI — keyboard nav, aria labels, contrast?
|
|
159
|
+
|
|
160
|
+
### 10. Data Engineer Review (optional)
|
|
161
|
+
Skip unless diff touches migrations, models, schema files, or external API clients.
|
|
162
|
+
|
|
163
|
+
- **Migrations**: Safe to run on a live DB? Adding a NOT NULL without default on a large table = **blocker**. Renames without a two-step migration = **blocker**.
|
|
164
|
+
- **Indexes**: New foreign keys with no index? New query patterns against unindexed columns?
|
|
165
|
+
- **Naming**: New fields follow existing schema conventions?
|
|
166
|
+
- **Breaking contract**: Compare `data.yml` vs `schema.yml` — removed/renamed/retyped response fields or new required request fields = **blocker** unless a migration path is documented.
|
|
167
|
+
- **Transactions**: Multi-step writes wrapped in a transaction?
|
|
168
|
+
|
|
169
|
+
### 11. Present Findings
|
|
170
|
+
Compile into a single report structured for PR comments:
|
|
171
|
+
|
|
172
|
+
```markdown
|
|
173
|
+
# PR Review: <PR title> (#<number>)
|
|
174
|
+
|
|
175
|
+
**Author:** <author> **Base:** <base> **Head:** <head>
|
|
176
|
+
**Linked change:** <change-id or "none — missing Change: trailer">
|
|
177
|
+
**Complexity:** <1-4 or "inferred: moderate">
|
|
178
|
+
**Files changed:** <N> **Lines:** +<add> / -<del>
|
|
179
|
+
|
|
180
|
+
## Product Manager
|
|
181
|
+
- **[blocker]** Scenario "Login with expired TOTP code" is in the feature file but no corresponding code path in `auth/verify.py`
|
|
182
|
+
- **[suggestion]** PR body doesn't mention the rate-limit change — add it
|
|
183
|
+
|
|
184
|
+
## Senior Engineer
|
|
185
|
+
- **[blocker]** `utils/hash_helpers.py` duplicates `security/crypto.py::hash_password` — reuse instead
|
|
186
|
+
- **[suggestion]** New abstraction `AuthProviderFactory` has one caller; inline it
|
|
187
|
+
|
|
188
|
+
## Security Engineer
|
|
189
|
+
### STRIDE
|
|
190
|
+
- Spoofing: N/A
|
|
191
|
+
- Tampering: new `/api/profile` PATCH has no CSRF token check
|
|
192
|
+
- Info disclosure: `logger.info(f"login attempt for {email}")` emits PII
|
|
193
|
+
|
|
194
|
+
### Findings
|
|
195
|
+
- **[blocker]** [A01:2021 / CWE-352] Missing CSRF check on `/api/profile` PATCH (`views/profile.py:42`)
|
|
196
|
+
- **[blocker]** [A09:2021 / CWE-532] Email logged in plaintext (`auth/login.py:88`)
|
|
197
|
+
- **[suggestion]** [A07:2021 / CWE-307] No rate limiting on login handler
|
|
198
|
+
|
|
199
|
+
## QA Engineer
|
|
200
|
+
- **[blocker]** New TOTP verification path has no test (`auth/totp.py:15-48`)
|
|
201
|
+
- **[suggestion]** Add negative test for malformed TOTP string
|
|
202
|
+
|
|
203
|
+
## Data Engineer
|
|
204
|
+
- **[blocker]** Migration `0042_add_2fa.py` adds NOT NULL `totp_secret` on existing `users` table — will fail on deploy
|
|
205
|
+
(or: "No schema changes — skipped.")
|
|
206
|
+
|
|
207
|
+
## Summary
|
|
208
|
+
- **5 blockers** — must be addressed before merge
|
|
209
|
+
- **3 suggestions** — consider addressing
|
|
210
|
+
|
|
211
|
+
Recommendation: Request changes.
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 12. Post to PR (optional)
|
|
215
|
+
Offer three modes:
|
|
216
|
+
|
|
217
|
+
- **Print only** (default) — just show the report
|
|
218
|
+
- **Post single review comment**:
|
|
219
|
+
- GitHub: `gh pr review <id> --comment --body "<report>"` or `--request-changes` if there are blockers
|
|
220
|
+
- GitLab: `glab mr note <id> --message "<report>"`
|
|
221
|
+
- **Post inline comments** — for each finding with a file:line, post a line comment:
|
|
222
|
+
- GitHub: `gh api repos/<org>/<repo>/pulls/<id>/comments -f body=... -f path=... -f line=... -f commit_id=...`
|
|
223
|
+
- This requires the commit SHA — get it from `gh pr view --json commits`
|
|
224
|
+
|
|
225
|
+
Ask the user which mode before posting. Never post without confirmation — PR comments are visible to the whole team.
|
|
226
|
+
|
|
227
|
+
### 13. Link Back
|
|
228
|
+
If a linked grimoire change was found and the review surfaced blockers that need spec changes (not just code changes), suggest the author run `grimoire-draft` or `grimoire-plan` on that change to update the artifacts before pushing fixes.
|
|
229
|
+
|
|
230
|
+
## Important
|
|
231
|
+
- This is a code review against a real diff — reference specific files and line numbers for every finding.
|
|
232
|
+
- Be direct. Don't pad with praise. Blockers are things that should stop the merge; suggestions are things the author should consider.
|
|
233
|
+
- Respect the author. Findings describe the code, not the person. "This query is vulnerable to injection" not "you wrote an injection".
|
|
234
|
+
- A PR without a `Change:` trailer in a grimoire repo is a soft finding, not a hard blocker — the team may have reasons.
|
|
235
|
+
- Don't re-derive tasks or specs. If the linked change's artifacts are wrong, that's a separate `grimoire-draft` / `grimoire-plan` cycle.
|
|
236
|
+
- If the diff is too large or too sprawling to review meaningfully, say so — offer to focus on a subset rather than producing a shallow full-pass review.
|
|
237
|
+
- Never post to the PR without explicit user confirmation.
|
|
238
|
+
|
|
239
|
+
## Done
|
|
240
|
+
When the report is presented (and optionally posted), the workflow is complete. If blockers exist, suggest the author address them; if not, suggest approving via `gh pr review <id> --approve`.
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grimoire-refactor
|
|
3
|
+
description: Systematically find, prioritize, and plan tech debt reduction. Use when the user wants to identify and address code quality issues, complexity, or duplication.
|
|
4
|
+
compatibility: Designed for Claude Code (or similar products)
|
|
5
|
+
metadata:
|
|
6
|
+
author: kiwi-data
|
|
7
|
+
version: "0.1"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# grimoire-refactor
|
|
11
|
+
|
|
12
|
+
Systematically find, prioritize, and plan tech debt reduction. Combines automated scanning with LLM analysis to produce a prioritized debt register, then feeds approved items into the standard grimoire pipeline (draft → plan → apply).
|
|
13
|
+
|
|
14
|
+
## Triggers
|
|
15
|
+
- User asks about tech debt, code quality, refactoring opportunities, or simplification
|
|
16
|
+
- User wants to reduce complexity, lines of code, or structural bloat
|
|
17
|
+
- User asks "what should we clean up?" or "where's the tech debt?"
|
|
18
|
+
- Loose match: "refactor", "tech debt", "simplify", "clean up", "reduce complexity", "code smells"
|
|
19
|
+
|
|
20
|
+
## Routing
|
|
21
|
+
- Behavior change needed (not just code quality) → `grimoire-draft`
|
|
22
|
+
- Removing a feature → `grimoire-remove`
|
|
23
|
+
- Fixing a bug → `grimoire-bug`
|
|
24
|
+
- Documenting existing code → `grimoire-discover`
|
|
25
|
+
|
|
26
|
+
## Prerequisites
|
|
27
|
+
- A grimoire-initialized project (`.grimoire/` exists)
|
|
28
|
+
- Git history available (hotspot analysis needs `git log`)
|
|
29
|
+
- Ideally: `grimoire map` + `/grimoire:discover` already run (area docs help contextualize findings)
|
|
30
|
+
|
|
31
|
+
## Debt Item Format
|
|
32
|
+
|
|
33
|
+
Each debt item in the register follows a structured format influenced by the CodeClimate issue spec (categories, severity, remediation effort, fingerprint) and the SEI/CMU Technical Debt Item classification (consequences, causes, evidence of accumulation).
|
|
34
|
+
|
|
35
|
+
**Required fields:**
|
|
36
|
+
- `id` — unique identifier (debt-NNN, monotonically increasing)
|
|
37
|
+
- `category` — one of: `hotspot`, `structural_bloat`, `data_structure`, `circular_dependency`, `dependency_staleness`, `broken_promise`, `duplication`, `dead_code`, `test_debt`
|
|
38
|
+
- `severity` — `high`, `medium`, or `low`
|
|
39
|
+
- `location` — file path (with optional `:line`), or `path ↔ path` for relationships
|
|
40
|
+
- `title` — short human-readable summary
|
|
41
|
+
- `detail` — evidence: what was measured, what threshold was exceeded, what the consequences are
|
|
42
|
+
- `fingerprint` — stable hash of category + location for dedup across scans (so re-scans update existing items rather than creating duplicates)
|
|
43
|
+
- `status` — `open` | `triaged` | `in-progress` | `resolved` | `accepted`
|
|
44
|
+
|
|
45
|
+
**Optional fields:**
|
|
46
|
+
- `metrics` — numeric measurements (churn count, complexity score, line count, field count, age in days, etc.)
|
|
47
|
+
- `suggestion` — recommended refactoring approach
|
|
48
|
+
- `effort` — `small` (<1 hour), `medium` (1-4 hours), `large` (>4 hours)
|
|
49
|
+
- `consequences` — what happens if this debt is NOT addressed (SEI/CMU field — forces articulation of impact)
|
|
50
|
+
- `causes` — how this debt was introduced: `evolution` (grew over time), `deadline` (time pressure), `knowledge` (didn't know better), `dependency` (forced by external constraint)
|
|
51
|
+
- `quadrant` — Fowler's classification: `deliberate-prudent`, `deliberate-reckless`, `inadvertent-prudent`, `inadvertent-reckless`
|
|
52
|
+
- `change_id` — grimoire change created to address this item
|
|
53
|
+
- `first_detected` — date the scanner first found this item (set once, never updated)
|
|
54
|
+
- `last_detected` — date of most recent scan that confirmed this item still exists
|
|
55
|
+
|
|
56
|
+
## Debt Exceptions
|
|
57
|
+
|
|
58
|
+
The scanner respects `.grimoire/debt-exceptions.yml` — a file where the team explicitly accepts known debt. This is modeled on `.snyk`/`.trivyignore` policy files: accept specific items with a reason, an owner, and an optional expiry date.
|
|
59
|
+
|
|
60
|
+
**Exception matching (checked before any item is added to the register):**
|
|
61
|
+
|
|
62
|
+
1. **By item ID** — matches a specific debt register entry:
|
|
63
|
+
```yaml
|
|
64
|
+
- id: debt-003
|
|
65
|
+
reason: "Splitting config types would break the plugin API."
|
|
66
|
+
quadrant: deliberate-prudent
|
|
67
|
+
owner: fred
|
|
68
|
+
accepted: 2026-04-06
|
|
69
|
+
expires: 2026-10-01
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
2. **By pattern + category** — matches any finding in files matching the glob:
|
|
73
|
+
```yaml
|
|
74
|
+
- pattern: "src/vendor/**"
|
|
75
|
+
category: "*" # or a specific category
|
|
76
|
+
reason: "Vendored code — we don't own it"
|
|
77
|
+
quadrant: deliberate-prudent
|
|
78
|
+
owner: fred
|
|
79
|
+
accepted: 2026-04-06
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Exception rules:**
|
|
83
|
+
- Every exception MUST have `reason`, `quadrant`, `owner`, and `accepted` fields. Exceptions without a reason are rejected — the point is to force articulation of the trade-off.
|
|
84
|
+
- `expires` is optional. If set, the scanner re-flags the item after the expiry date and notes it as "exception expired" in the register.
|
|
85
|
+
- `quadrant` uses Fowler's Technical Debt Quadrant to classify the *intent* behind accepting the debt. This isn't just documentation — it helps the team spot patterns (too many `deliberate-reckless` exceptions = systemic problem).
|
|
86
|
+
- When the scanner finds a matching exception, the item is still recorded in the register but with `status: accepted` and a reference to the exception. This means the debt is visible and tracked, just not flagged for action.
|
|
87
|
+
- Expired exceptions cause the item's status to revert to `open` with a note: `"Exception expired YYYY-MM-DD — re-evaluate"`.
|
|
88
|
+
- When a user marks an item as "accept" during the triage flow (step 4), the skill writes the exception to `debt-exceptions.yml` automatically — the user provides the reason, quadrant, and optional expiry interactively.
|
|
89
|
+
|
|
90
|
+
**Scanner behavior:** For each finding, compute fingerprint → check exceptions (by id, then pattern+category) → check if expired → check existing register by fingerprint → add/update item.
|
|
91
|
+
|
|
92
|
+
## Workflow
|
|
93
|
+
|
|
94
|
+
### 1. Determine Scope
|
|
95
|
+
Ask the user what to scan:
|
|
96
|
+
- **Full scan** — all categories across the whole codebase (default for first run)
|
|
97
|
+
- **Category scan** — specific debt category (e.g., "just hotspots" or "just structural bloat")
|
|
98
|
+
- **Area scan** — specific directory or module (e.g., "just the API layer")
|
|
99
|
+
- **Refresh** — re-scan and update an existing debt register
|
|
100
|
+
|
|
101
|
+
Check if `.grimoire/docs/debt-register.yml` already exists — don't redo work unless refreshing.
|
|
102
|
+
|
|
103
|
+
### 2. Run Scans
|
|
104
|
+
|
|
105
|
+
Run applicable scans in parallel. Each scan produces a list of findings with a category, location, severity, and suggested action.
|
|
106
|
+
|
|
107
|
+
Run applicable scans from the categories in `../references/refactor-scan-categories.md`. Each category has specific signals, thresholds, severity levels, and scan commands referencing `config.tools.*` entries.
|
|
108
|
+
|
|
109
|
+
**Key categories** (details in reference):
|
|
110
|
+
- **Hotspots** (churn x complexity) — highest ROI, uses `git log` + `config.tools.complexity`
|
|
111
|
+
- **Structural bloat** — oversized files/functions/classes
|
|
112
|
+
- **Data structure complexity** — over-engineered models, deep nesting
|
|
113
|
+
- **Circular dependencies** — tight coupling between modules
|
|
114
|
+
- **Dependency staleness** — uses `config.tools.dep_audit` or package manager outdated commands
|
|
115
|
+
- **Broken promises** — aged TODO/FIXME/HACK comments via `grep` + `git blame`
|
|
116
|
+
- **Duplication** — uses `.snapshot.json` duplicates or `config.tools.duplicates`
|
|
117
|
+
- **Dead code** — uses `config.tools.dead_code` or `codebase-memory-mcp` graph queries
|
|
118
|
+
- **Test debt** — high complexity + low coverage
|
|
119
|
+
|
|
120
|
+
### 3. Load Exceptions
|
|
121
|
+
|
|
122
|
+
Before generating the register, read `.grimoire/debt-exceptions.yml`. Parse all exceptions and build a lookup:
|
|
123
|
+
- Index by `id` for direct item matches
|
|
124
|
+
- Index by `pattern` + `category` for glob matches
|
|
125
|
+
- Check `expires` dates — any exception past its expiry date is treated as not matching (the item will be flagged as `open` with a note)
|
|
126
|
+
|
|
127
|
+
If the exceptions file doesn't exist, proceed with no exceptions (all findings are flagged).
|
|
128
|
+
|
|
129
|
+
### 4. Generate Debt Register
|
|
130
|
+
|
|
131
|
+
Produce `.grimoire/docs/debt-register.yml`. This is the persistent record of known debt, what's been triaged, and what's been addressed.
|
|
132
|
+
|
|
133
|
+
For each finding from the scans:
|
|
134
|
+
1. Compute a fingerprint: `sha256(category + normalized_location)` — this is the stable identifier for dedup across scans
|
|
135
|
+
2. Check against exceptions (by id, then by pattern+category)
|
|
136
|
+
3. Check against existing register (by fingerprint) — preserve status and metadata for known items
|
|
137
|
+
4. Add or update the item in the register
|
|
138
|
+
|
|
139
|
+
See `../references/refactor-register-format.md` for the full field specification and example items.
|
|
140
|
+
|
|
141
|
+
**Register rules:**
|
|
142
|
+
- Each item has a unique `id` (debt-NNN, monotonically increasing) and a stable `fingerprint` for dedup
|
|
143
|
+
- `status` tracks lifecycle: `open` → `triaged` → `in-progress` → `resolved` (or `accepted` via exception)
|
|
144
|
+
- `first_detected` and `last_detected` track how long debt has been known — debt that persists across many scans is aging and may need escalation
|
|
145
|
+
- Items matched by an exception get `status: accepted` with `quadrant` and `exception_reason` copied from the exception file
|
|
146
|
+
- Items whose exception has expired revert to `status: open` with a note in `detail`: "Exception expired YYYY-MM-DD — re-evaluate"
|
|
147
|
+
- `consequences` should articulate what happens if this debt is NOT addressed — this forces the scanner (and the user) to think about real impact, not just code aesthetics
|
|
148
|
+
- `causes` classifies how the debt was introduced: `evolution` (grew incrementally), `deadline` (time pressure), `knowledge` (didn't know better at the time), `dependency` (forced by external constraint)
|
|
149
|
+
- `change_id` links to the grimoire change created to address it (populated when the user approves a refactoring)
|
|
150
|
+
- `effort` is a rough estimate: `small` (<1 hour), `medium` (1-4 hours), `large` (>4 hours / multiple sessions)
|
|
151
|
+
- On refresh: match by fingerprint, preserve status and first_detected for known items, update last_detected and metrics, add new items, mark items no longer detected as `resolved` automatically
|
|
152
|
+
- Sort by severity (high first), then by hotspot score within severity
|
|
153
|
+
|
|
154
|
+
### 5. Prioritize and Present
|
|
155
|
+
|
|
156
|
+
Present findings to the user grouped by severity, with recommended action order. Only show items with `status: open` — accepted items are tracked but not flagged.
|
|
157
|
+
|
|
158
|
+
**Prioritization heuristic (automated):**
|
|
159
|
+
1. **High-severity hotspots first** — highest ROI, every future change benefits
|
|
160
|
+
2. **High-severity structural bloat** — simplification unlocks everything else
|
|
161
|
+
3. **High-severity data structure complexity** — foundational, affects many layers
|
|
162
|
+
4. **Circular dependencies** — blocks clean architecture
|
|
163
|
+
5. **Everything else by severity**
|
|
164
|
+
|
|
165
|
+
**Present in batches** (same pattern as grimoire-audit — don't dump):
|
|
166
|
+
- Show top 5 items first with their category, location, suggestion, and consequences
|
|
167
|
+
- For each item, ask the user to choose one of:
|
|
168
|
+
- **fix** — create a grimoire change to address it (status → `in-progress`)
|
|
169
|
+
- **defer** — acknowledge but not now (status → `triaged`, revisit next scan)
|
|
170
|
+
- **accept** — the cost of fixing exceeds the benefit (status → `accepted`)
|
|
171
|
+
|
|
172
|
+
**When the user chooses "accept"**, collect exception details interactively:
|
|
173
|
+
1. Ask for a **reason** (required) — why is this debt acceptable? What's the trade-off?
|
|
174
|
+
2. Ask for the **Fowler quadrant** (required) — present the four options:
|
|
175
|
+
- `deliberate-prudent`: "We know, and it's the right trade-off for now"
|
|
176
|
+
- `deliberate-reckless`: "We know, and we're cutting corners"
|
|
177
|
+
- `inadvertent-prudent`: "We didn't know then, and fixing isn't worth it now"
|
|
178
|
+
- `inadvertent-reckless`: "We didn't know, and the cost to fix is too high right now"
|
|
179
|
+
3. Ask for an **expiry date** (optional) — when should this be re-evaluated? If set, the scanner re-flags after this date.
|
|
180
|
+
4. Write the exception to `.grimoire/debt-exceptions.yml` automatically
|
|
181
|
+
5. Update the register item: `status: accepted`, `quadrant`, `exception_reason`
|
|
182
|
+
|
|
183
|
+
**If the user chooses "accept" with quadrant `deliberate-reckless`**, flag it gently: "Noted. Just a heads-up — too many deliberate-reckless exceptions may indicate systemic time pressure. You might want to discuss capacity with the team." Don't block, just inform.
|
|
184
|
+
|
|
185
|
+
After the first batch, ask if the user wants to see more or start working on the approved items.
|
|
186
|
+
|
|
187
|
+
**Present a summary of existing exceptions** if any exist:
|
|
188
|
+
- "You have 5 accepted items in debt-exceptions.yml. 1 expires next month."
|
|
189
|
+
- This keeps the team aware of debt they've acknowledged but not resolved.
|
|
190
|
+
|
|
191
|
+
**When presenting, frame simplification opportunities concretely:**
|
|
192
|
+
- "This 847-line file could become 3 files of ~250 lines each"
|
|
193
|
+
- "This 34-method class has 5 distinct responsibilities — extracting them would make each class testable independently"
|
|
194
|
+
- "This 28-field config type is used in 3 contexts — splitting it eliminates 22 optional fields and makes each usage self-documenting"
|
|
195
|
+
- "Flattening this 4-level nested structure into 2 normalized types would eliminate the deep property chains throughout the codebase"
|
|
196
|
+
|
|
197
|
+
### 6. Create Grimoire Changes
|
|
198
|
+
|
|
199
|
+
For each item the user approves to fix:
|
|
200
|
+
|
|
201
|
+
1. Create a grimoire change: `refactor-<debt-id>` (e.g., `refactor-debt-001`)
|
|
202
|
+
2. Update the debt register item: set `status: in-progress`, set `change_id`
|
|
203
|
+
3. Draft the change using the standard grimoire format:
|
|
204
|
+
- **Manifest** with the refactoring rationale (what the debt is, why it matters, what "done" looks like)
|
|
205
|
+
- **Feature files** if the refactoring changes behavior boundaries (rare for pure refactors, but splitting a module may change its public API)
|
|
206
|
+
- **Decision record** if the refactoring involves an architectural choice (e.g., "extract event system to decouple orders and inventory")
|
|
207
|
+
4. Hand off to `/grimoire:plan` for task generation, then `/grimoire:apply` for implementation
|
|
208
|
+
|
|
209
|
+
**Refactoring-specific guidance for the plan/apply stages:**
|
|
210
|
+
- **All existing tests must keep passing.** A refactoring that breaks tests is not a refactoring.
|
|
211
|
+
- **Prefer incremental moves over big-bang rewrites.** Move one function at a time, run tests after each move.
|
|
212
|
+
- **Add tests before refactoring if test debt is part of the item.** You need a safety net before restructuring.
|
|
213
|
+
- **Update imports incrementally.** When moving code to a new module, re-export from the old location first, then update consumers, then remove the re-export.
|
|
214
|
+
- **Update area docs after refactoring.** File paths and reusable code locations will have changed.
|
|
215
|
+
|
|
216
|
+
### 7. Track Progress
|
|
217
|
+
|
|
218
|
+
After refactoring is complete (grimoire apply finishes):
|
|
219
|
+
1. Update the debt register item: set `status: resolved`
|
|
220
|
+
2. Update metrics if a re-scan shows improvement
|
|
221
|
+
3. Present a before/after summary:
|
|
222
|
+
- Lines of code: before → after
|
|
223
|
+
- Complexity: before → after
|
|
224
|
+
- Number of files/classes/functions: before → after
|
|
225
|
+
- Test coverage: before → after (if measurable)
|
|
226
|
+
|
|
227
|
+
### 8. Ongoing Maintenance
|
|
228
|
+
|
|
229
|
+
The debt register is a living document. Recommend:
|
|
230
|
+
- **Monthly re-scan** to catch new debt and verify resolved items stay resolved
|
|
231
|
+
- **Per-sprint planning** — pick 1-2 high-severity items each sprint alongside feature work
|
|
232
|
+
- **Gate new debt** — the existing grimoire check pipeline (complexity, duplication, best practices) catches debt at commit time. The refactor skill handles accumulated debt.
|
|
233
|
+
|
|
234
|
+
## Integration with Other Skills
|
|
235
|
+
|
|
236
|
+
- **grimoire-health** — the health score reflects some debt dimensions (coverage, complexity, duplicates). Refactoring should improve health scores.
|
|
237
|
+
- **grimoire-audit** — audit finds undocumented features/decisions. Refactor finds code quality issues. They're complementary — run audit first to understand what the code does, then refactor to improve how it does it.
|
|
238
|
+
- **grimoire-discover** — area docs provide context for refactoring. After refactoring, run discover to update docs.
|
|
239
|
+
- **grimoire-review** — the senior engineer persona already checks for simplicity and reuse. Refactor findings can inform review criteria.
|
|
240
|
+
- **grimoire-check** — the commit-time checks prevent new debt. Refactor addresses existing debt.
|
|
241
|
+
|
|
242
|
+
## Important
|
|
243
|
+
- **Don't boil the ocean.** Tech debt reduction is incremental. Pick the highest-impact items and make measurable progress. A codebase with zero debt is not the goal — a codebase where debt doesn't slow you down is.
|
|
244
|
+
- **Respect wont-fix.** Some debt is cheaper to live with than to fix. A 500-line file that changes once a year is not worth splitting. Acknowledge this and move on.
|
|
245
|
+
- **Simplification is the primary goal.** Every refactoring should make the codebase smaller, simpler, or more focused. If a refactoring adds complexity (more files, more abstractions, more indirection) without reducing something else, question whether it's actually an improvement.
|
|
246
|
+
- **Measure before and after.** A refactoring without measurable improvement is just code churn. Track lines, complexity, coverage, and file count.
|
|
247
|
+
- **Existing tests are your safety net.** Never refactor without tests. If tests don't exist, write them first (that's test debt — address it before or alongside the structural refactoring).
|
|
248
|
+
- **Present findings collaboratively** — same interview pattern as grimoire-audit. Batches of 3-5, let the user drive priority. Don't dump a 50-item list.
|
|
249
|
+
|
|
250
|
+
## Done
|
|
251
|
+
When debt items are triaged (fixed, deferred, or accepted) and grimoire changes are created for approved fixes, the workflow is complete. Each approved fix flows through the standard pipeline: `grimoire-plan` → `grimoire-apply`.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grimoire-remove
|
|
3
|
+
description: Remove a feature or deprecate a decision through a tracked, deliberate change. Use when the user wants to decommission functionality with full impact assessment.
|
|
4
|
+
compatibility: Designed for Claude Code (or similar products)
|
|
5
|
+
metadata:
|
|
6
|
+
author: kiwi-data
|
|
7
|
+
version: "0.1"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# grimoire-remove
|
|
11
|
+
|
|
12
|
+
Remove a feature or deprecate a decision through a tracked, deliberate change.
|
|
13
|
+
|
|
14
|
+
## Triggers
|
|
15
|
+
- User wants to remove, deprecate, or sunset a feature
|
|
16
|
+
- User wants to supersede or retire an architecture decision
|
|
17
|
+
- Loose match: "remove", "delete", "deprecate", "sunset", "retire" with feature/decision reference
|
|
18
|
+
|
|
19
|
+
## Routing
|
|
20
|
+
- Feature was never documented → `grimoire-audit` first to establish baseline
|
|
21
|
+
- Want to change behavior (not remove it) → `grimoire-draft`
|
|
22
|
+
- Want to clean up code quality → `grimoire-refactor`
|
|
23
|
+
|
|
24
|
+
## Workflow
|
|
25
|
+
|
|
26
|
+
### 1. Identify What's Being Removed
|
|
27
|
+
- Ask the user what they want to remove and why
|
|
28
|
+
- Read the existing `.feature` file(s) or ADR(s) being targeted
|
|
29
|
+
- Confirm scope: removing an entire feature? Specific scenarios? A decision?
|
|
30
|
+
|
|
31
|
+
### 2. Assess Impact
|
|
32
|
+
Before creating the change:
|
|
33
|
+
- **Search the codebase** for code implementing the feature/decision
|
|
34
|
+
- **Check other features** — does anything depend on the behavior being removed?
|
|
35
|
+
- **Check decisions** — does removing this feature invalidate any ADRs?
|
|
36
|
+
- **Check step definitions** — what test code will need to be removed?
|
|
37
|
+
|
|
38
|
+
Present the impact summary to the user:
|
|
39
|
+
> "Removing the document overview tab will affect: `document_review/views.py`, `templates/review/overview.html`, 3 step definitions in `test_document_review.py`, and the 'Document Overview Tab' requirement in `features/documents/review.feature`. The 'Error Detail Modal' feature in the same file is independent and won't be affected."
|
|
40
|
+
|
|
41
|
+
### 3. Create Removal Change
|
|
42
|
+
Scaffold `.grimoire/changes/<change-id>/`:
|
|
43
|
+
- Change ID: verb-led with `remove-` prefix (e.g., `remove-legacy-export`)
|
|
44
|
+
|
|
45
|
+
**Manifest** must include:
|
|
46
|
+
```markdown
|
|
47
|
+
# Change: Remove <feature/decision>
|
|
48
|
+
|
|
49
|
+
## Why
|
|
50
|
+
[Clear rationale for removal]
|
|
51
|
+
|
|
52
|
+
## Migration
|
|
53
|
+
[How users/systems should handle this going away]
|
|
54
|
+
[What replaces it, if anything]
|
|
55
|
+
[Timeline if gradual deprecation]
|
|
56
|
+
|
|
57
|
+
## Feature Changes
|
|
58
|
+
- **REMOVED** `<capability>/<name>.feature` — [or specific scenarios]
|
|
59
|
+
|
|
60
|
+
## Decisions
|
|
61
|
+
- **SUPERSEDED** `NNNN-title.md` — [if applicable]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Proposed feature files:**
|
|
65
|
+
- Copy the current baseline `.feature` file
|
|
66
|
+
- Remove the targeted Feature/Scenarios
|
|
67
|
+
- If removing specific scenarios from a feature, the proposed file is the feature WITHOUT those scenarios
|
|
68
|
+
- If removing an entire feature file, note it in manifest (no proposed file needed — absence is the proposal)
|
|
69
|
+
|
|
70
|
+
### 4. Generate Tasks
|
|
71
|
+
Create `tasks.md` covering:
|
|
72
|
+
|
|
73
|
+
```markdown
|
|
74
|
+
## 1. Remove Production Code
|
|
75
|
+
- [ ] 1.1 Remove <specific code implementing the feature>
|
|
76
|
+
- [ ] 1.2 Remove <related templates/components>
|
|
77
|
+
- [ ] 1.3 Clean up imports and dead references
|
|
78
|
+
|
|
79
|
+
## 2. Remove Tests
|
|
80
|
+
- [ ] 2.1 Remove step definitions for removed scenarios
|
|
81
|
+
- [ ] 2.2 Remove any unit/integration tests specific to this feature
|
|
82
|
+
- [ ] 2.3 Update shared steps if affected
|
|
83
|
+
|
|
84
|
+
## 3. Update Related Artifacts
|
|
85
|
+
- [ ] 3.1 Update ADR status to superseded (if applicable)
|
|
86
|
+
- [ ] 3.2 Update any features that referenced removed behavior
|
|
87
|
+
|
|
88
|
+
## 4. Verification
|
|
89
|
+
- [ ] 4.1 Remaining feature files still pass
|
|
90
|
+
- [ ] 4.2 No dead code / unused imports left behind
|
|
91
|
+
- [ ] 4.3 No broken references in other features
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 5. Review
|
|
95
|
+
Present the full removal plan to the user:
|
|
96
|
+
- What's being removed (features, scenarios, decisions)
|
|
97
|
+
- What code will be deleted
|
|
98
|
+
- What remains untouched
|
|
99
|
+
- Migration path
|
|
100
|
+
|
|
101
|
+
Do NOT proceed without user approval. Removal is destructive.
|
|
102
|
+
|
|
103
|
+
## Important
|
|
104
|
+
- Removal is a first-class operation, not a hack. It gets the same rigor as adding a feature.
|
|
105
|
+
- The manifest MUST document WHY something is being removed and what the migration path is.
|
|
106
|
+
- Always check for dependencies before removing. Don't orphan related features or break shared steps.
|
|
107
|
+
- When removing scenarios from a feature (not the whole feature), the proposed `.feature` file represents the desired end state — the feature minus the removed scenarios.
|
|
108
|
+
- After removal, remaining features must still pass. This is verified in the apply stage.
|
|
109
|
+
- Archive preserves the removal rationale forever — future developers can understand why something was removed.
|
|
110
|
+
|
|
111
|
+
## Done
|
|
112
|
+
When the removal plan is approved and ready for implementation, the workflow is complete. Proceed to `grimoire-apply` to execute the removal tasks.
|