@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,77 @@
|
|
|
1
|
+
# Build vs Buy Research
|
|
2
|
+
|
|
3
|
+
Research methodology for evaluating existing solutions before designing custom code. Used by draft (conduct research), plan (validate decision), review (check prior art).
|
|
4
|
+
|
|
5
|
+
## When to Research
|
|
6
|
+
|
|
7
|
+
- **Level 1 (Trivial)**: Skip entirely
|
|
8
|
+
- **Level 2 (Simple)**: Check built-ins and first-party ecosystem only
|
|
9
|
+
- **Level 3-4 (Moderate/Complex)**: Full research across all categories
|
|
10
|
+
|
|
11
|
+
## Research Categories
|
|
12
|
+
|
|
13
|
+
Search for existing solutions across these categories (skip categories that clearly don't apply):
|
|
14
|
+
|
|
15
|
+
- **Language/framework built-ins**: Does the framework already have this? (e.g., Django has auth, React has context, Express has middleware). Check official docs.
|
|
16
|
+
- **First-party ecosystem**: Official plugins, extensions, or companion packages from the framework maintainers.
|
|
17
|
+
- **Popular libraries**: Search the relevant package registry (npm, PyPI, crates.io, etc.) for well-maintained packages. Use web search to find comparison articles, "best of" lists, and Stack Overflow recommendations.
|
|
18
|
+
- **Open-source projects**: GitHub repos that solve the same problem as a standalone tool or reference implementation.
|
|
19
|
+
- **SaaS/managed services**: Hosted solutions that handle the problem as a service (e.g., Auth0 for auth, Stripe for payments, Algolia for search).
|
|
20
|
+
|
|
21
|
+
For each candidate found, gather:
|
|
22
|
+
- **Name and link** to docs/repo
|
|
23
|
+
- **Maintenance signals**: last release date, commit frequency, open issues, download count
|
|
24
|
+
- **Fit**: does it match the project's language, framework, and deployment constraints?
|
|
25
|
+
- **Scope match**: does it solve 100% of the need, 80%, or just a part?
|
|
26
|
+
- **Trade-offs**: what design decisions does it impose? What would the project give up by adopting it?
|
|
27
|
+
|
|
28
|
+
## Decision Framework
|
|
29
|
+
|
|
30
|
+
| Signal | Points toward **adopt** | Points toward **build** |
|
|
31
|
+
|--------|------------------------|------------------------|
|
|
32
|
+
| Scope match | Solves ≥80% of the need | Solves <50% or forces unwanted constraints |
|
|
33
|
+
| Maintenance | Active, >1 maintainer, regular releases | Abandoned, single maintainer, or unmaintained fork |
|
|
34
|
+
| Integration cost | Drop-in or <1 day to integrate | Requires significant adapter code or workarounds |
|
|
35
|
+
| Customization | Configurable or extensible where needed | Core behavior can't be changed without forking |
|
|
36
|
+
| Dependencies | Few, well-known transitive deps | Heavy dependency tree or conflicts with project deps |
|
|
37
|
+
| Security | Audited, follows best practices, no known CVEs | Unaudited, handles sensitive data unsafely |
|
|
38
|
+
| Licensing | Compatible with project license | Incompatible or ambiguous license |
|
|
39
|
+
| Project constraints | Fits deployment target, bundle size, performance needs | Doesn't fit runtime environment or adds unacceptable overhead |
|
|
40
|
+
|
|
41
|
+
When the decision is close, **prefer adopting** — maintaining custom code is almost always more expensive than people expect.
|
|
42
|
+
|
|
43
|
+
## If Building: Learn from What Exists
|
|
44
|
+
|
|
45
|
+
When the decision is to build custom code, **study existing implementations before designing**:
|
|
46
|
+
|
|
47
|
+
- **Document the prior art**: For each relevant existing tool, note its architecture, data flows, API design, and key abstractions. What patterns does it use? What did its maintainers learn over time (check changelogs, migration guides, design docs)?
|
|
48
|
+
- **Identify what's different**: Be precise about why the project's needs diverge. "We need something different" is not enough — state the specific requirements that existing tools don't meet.
|
|
49
|
+
- **Borrow deliberately**: List specific design patterns, data flow approaches, API shapes, or architectural decisions from existing tools that should inform the custom implementation. This prevents reinventing what others have already refined.
|
|
50
|
+
- **Scope the custom work**: Define the minimum viable version. If an existing tool does 10 things and you only need 3, build those 3. Don't replicate the full feature set.
|
|
51
|
+
|
|
52
|
+
## Present Findings Format
|
|
53
|
+
|
|
54
|
+
Present a structured summary **before drafting any artifacts**:
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
## Prior Art Research
|
|
58
|
+
|
|
59
|
+
### Existing Solutions Found
|
|
60
|
+
1. **[name]** — [one-line description]. [fit assessment]. [key trade-off].
|
|
61
|
+
2. **[name]** — ...
|
|
62
|
+
|
|
63
|
+
### Recommendation
|
|
64
|
+
- **Adopt [name]** because [reasons] → draft becomes an ADR documenting the adoption
|
|
65
|
+
- OR **Build custom** because [specific gaps: requirement X isn't met by any option, constraint Y rules out adoption]. Borrowing [patterns/flows] from [existing tool].
|
|
66
|
+
- OR **Hybrid**: adopt [name] for [scope] and build custom [scope] because [reasons]
|
|
67
|
+
|
|
68
|
+
### If Building: What Makes This Different
|
|
69
|
+
- [Requirement that no existing tool meets]
|
|
70
|
+
- [Constraint that rules out adoption]
|
|
71
|
+
- [Design decision that must differ from prior art, and why]
|
|
72
|
+
|
|
73
|
+
### If Building: Borrowed from Prior Art
|
|
74
|
+
- [Pattern/flow/API shape] from [tool] — because [reason it's proven]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Wait for user agreement on the direction before proceeding.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Elicitation Personas
|
|
2
|
+
|
|
3
|
+
Persona-driven questions to surface requirements. Used by draft (gather requirements), plan (check completeness), review (evaluate design).
|
|
4
|
+
|
|
5
|
+
## How to Use
|
|
6
|
+
|
|
7
|
+
- **In draft**: Ask these questions to gather requirements before drafting.
|
|
8
|
+
- **In plan**: Use as a completeness checklist — flag gaps in the specs, don't ask the user.
|
|
9
|
+
- **In review**: Use as evaluation criteria — check if the design addresses each concern.
|
|
10
|
+
|
|
11
|
+
## Depth by Complexity Level
|
|
12
|
+
|
|
13
|
+
| Level | Depth |
|
|
14
|
+
|-------|-------|
|
|
15
|
+
| 1 (Trivial) | Skip entirely |
|
|
16
|
+
| 2 (Simple) | Outcome + non-goals, then 1-3 targeted questions from the most relevant persona |
|
|
17
|
+
| 3 (Moderate) | Outcome + non-goals, then applicable personas in a single focused batch |
|
|
18
|
+
| 4 (Complex) | Outcome + non-goals, then all applicable personas in batches of 3-5, wait between batches |
|
|
19
|
+
|
|
20
|
+
Don't ask every question — only ask questions whose answers aren't already clear.
|
|
21
|
+
|
|
22
|
+
## Outcome & Scope — Always Ask First
|
|
23
|
+
|
|
24
|
+
Before diving into persona questions, establish the outcome and boundaries. These two questions prevent the most common spec failures — building the wrong thing and building too much:
|
|
25
|
+
|
|
26
|
+
- **Outcome**: What problem are you solving, and how will you know it's solved? What does the user or system look like *after* this change that's different from today?
|
|
27
|
+
- **Non-goals**: What is explicitly out of scope? What should this change NOT do, NOT handle, or NOT affect? Are there adjacent features, edge cases, or future plans that we should deliberately leave alone?
|
|
28
|
+
|
|
29
|
+
Record the answers. Non-goals become constraints in the manifest and guard rails during drafting — if a scenario starts creeping into a non-goal, stop and flag it.
|
|
30
|
+
|
|
31
|
+
## Product Manager — Functional Completeness
|
|
32
|
+
|
|
33
|
+
Ask when: the change has user-facing behavior.
|
|
34
|
+
|
|
35
|
+
- Who are the actors? Is there more than one user role involved? Do they see/do different things?
|
|
36
|
+
- What triggers this — user action, scheduled job, external event, or another system?
|
|
37
|
+
- What does success look like from the user's perspective? What do they see/receive?
|
|
38
|
+
- What are the business rules? Validation constraints, conditional logic, calculations, limits?
|
|
39
|
+
- What happens when the user makes a mistake? Invalid input, wrong state, missing data?
|
|
40
|
+
- Are there state transitions? What states can this entity be in, and what moves it between them?
|
|
41
|
+
- Is there a UI component? What does each state look like — loading, empty, error, success, partial?
|
|
42
|
+
- *(If UI)* Do you have designs or mockups? Check `.grimoire/config.yaml` under `project.design_tool` for where designs live. Ask the user to point to the specific screen/flow — reference it in the requirements summary so downstream skills can consult it.
|
|
43
|
+
- Does this interact with existing features? Could it conflict with or depend on other workflows?
|
|
44
|
+
- Does this need to support multiple languages or locales? If so, which ones?
|
|
45
|
+
- What accessibility standard applies? (WCAG 2.1 AA is the most common default. If the project has no standard, ask.)
|
|
46
|
+
|
|
47
|
+
## Senior Engineer — Architecture & Integration
|
|
48
|
+
|
|
49
|
+
Ask when: the change introduces new components, services, dependencies, or data flows.
|
|
50
|
+
|
|
51
|
+
- What's the deployment context? Does this run in the same service or cross service boundaries?
|
|
52
|
+
- What existing components does this touch? Are there shared modules, APIs, or databases involved?
|
|
53
|
+
- Are there concurrency concerns? Multiple users or processes acting on the same data?
|
|
54
|
+
- What's the data flow? Where does data enter, how is it transformed, where does it end up?
|
|
55
|
+
- Are there ordering or idempotency requirements? What happens if this runs twice?
|
|
56
|
+
- Does this need to be backwards-compatible with existing clients, APIs, or data formats?
|
|
57
|
+
- Is there a rollout concern? Can this be deployed incrementally, or is it all-or-nothing? Feature flag needed?
|
|
58
|
+
- What are the performance expectations? Response time target, expected throughput, data volume at scale?
|
|
59
|
+
- How will you observe this in production? What metrics, logs, or alerts should exist? What does "healthy" look like on a dashboard?
|
|
60
|
+
- What's the availability target? What happens during partial outages — degrade gracefully or fail fast?
|
|
61
|
+
- *(If adopting)* What customization or configuration does the library need for this project's constraints?
|
|
62
|
+
- *(If adopting)* Where does the library's responsibility end and custom code begin?
|
|
63
|
+
|
|
64
|
+
## Security Engineer — Security & Compliance
|
|
65
|
+
|
|
66
|
+
Ask when: the change involves authentication, authorization, user input, sensitive data, or external-facing endpoints.
|
|
67
|
+
|
|
68
|
+
- Who should have access to this? Are there roles, permissions, or ownership rules?
|
|
69
|
+
- Does this handle sensitive data (PII, credentials, financial, health)? Where is it stored and transmitted?
|
|
70
|
+
- Is there user-provided input? What's the attack surface — injection, XSS, CSRF, file upload?
|
|
71
|
+
- Are there compliance requirements (GDPR, HIPAA, PCI-DSS, SOC2)? Data residency or retention rules?
|
|
72
|
+
- Does this cross a trust boundary? Is data coming from an external system or untrusted source?
|
|
73
|
+
|
|
74
|
+
## QA Engineer — Testability & Edge Cases
|
|
75
|
+
|
|
76
|
+
Ask when: the change has complex behavior, multiple paths, or integration points.
|
|
77
|
+
|
|
78
|
+
- What are the boundary values? Min/max lengths, zero vs. one, empty collections, null states?
|
|
79
|
+
- What are the timing edge cases? Concurrent edits, race conditions, timeout during processing?
|
|
80
|
+
- What external dependencies could fail? How should the system behave when they do — retry, fallback, error?
|
|
81
|
+
- Is there existing behavior that could regress? What should still work exactly as before?
|
|
82
|
+
|
|
83
|
+
## Data Engineer — Data & Schema
|
|
84
|
+
|
|
85
|
+
Ask when: the change creates, modifies, or removes data models, or integrates with external APIs.
|
|
86
|
+
|
|
87
|
+
- What data entities are involved? What are the relationships between them?
|
|
88
|
+
- What are the field constraints? Required, unique, nullable, max length, valid ranges, enums?
|
|
89
|
+
- How does this data grow? Is there a retention policy, archival strategy, or cleanup needed?
|
|
90
|
+
- Is there existing data that needs migrating? Can the migration run live or does it need downtime?
|
|
91
|
+
- Are there external API contracts? What fields does the client read, and what happens if the schema changes?
|
|
92
|
+
|
|
93
|
+
## Requirements Summary Template
|
|
94
|
+
|
|
95
|
+
After elicitation, summarize what you learned in a short **Requirements Summary**. This becomes the foundation for scenarios and decisions. Format:
|
|
96
|
+
|
|
97
|
+
```markdown
|
|
98
|
+
## Requirements Summary
|
|
99
|
+
|
|
100
|
+
**Outcome**: [what problem this solves, how we'll know it's solved]
|
|
101
|
+
**Non-goals**: [what's explicitly out of scope — won't do, won't handle, won't affect]
|
|
102
|
+
**Actors**: [who]
|
|
103
|
+
**Trigger**: [what starts this]
|
|
104
|
+
**Happy path**: [what success looks like]
|
|
105
|
+
**Business rules**: [validation, constraints, logic]
|
|
106
|
+
**Error cases**: [what can go wrong]
|
|
107
|
+
**Data**: [what's created/modified, key constraints]
|
|
108
|
+
**Security**: [access control, sensitive data, compliance]
|
|
109
|
+
**Performance**: [response time, throughput, data volume targets — if applicable]
|
|
110
|
+
**Observability**: [key metrics, alerts, what "healthy" looks like — if applicable]
|
|
111
|
+
**Availability**: [uptime target, degradation strategy — if applicable]
|
|
112
|
+
**Accessibility**: [WCAG level, requirements — if applicable]
|
|
113
|
+
**i18n**: [supported locales — if applicable]
|
|
114
|
+
**Design reference**: [link to mockup/design, or "none" — if UI change]
|
|
115
|
+
**Open questions**: [anything the user couldn't answer yet — flag as unvalidated assumptions]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Wait for user confirmation of the summary before proceeding to draft.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Debt Register Format
|
|
2
|
+
|
|
3
|
+
Reference for `grimoire-refactor` step 4. The register is `.grimoire/docs/debt-register.yml`.
|
|
4
|
+
|
|
5
|
+
## Required Fields
|
|
6
|
+
|
|
7
|
+
- `id` — `debt-NNN`, monotonically increasing
|
|
8
|
+
- `category` — one of: `hotspot`, `structural_bloat`, `data_structure`, `circular_dependency`, `dependency_staleness`, `broken_promise`, `duplication`, `dead_code`, `test_debt`
|
|
9
|
+
- `severity` — `high`, `medium`, `low`
|
|
10
|
+
- `location` — file path (with optional `:line`), or `path <> path` for relationships
|
|
11
|
+
- `title` — short human-readable summary
|
|
12
|
+
- `detail` — evidence: what was measured, what threshold was exceeded, consequences
|
|
13
|
+
- `fingerprint` — `sha256(category + normalized_location)` for dedup across scans
|
|
14
|
+
- `status` — `open` | `triaged` | `in-progress` | `resolved` | `accepted`
|
|
15
|
+
|
|
16
|
+
## Optional Fields
|
|
17
|
+
|
|
18
|
+
- `metrics` — numeric measurements (churn count, complexity score, line count, etc.)
|
|
19
|
+
- `suggestion` — recommended refactoring approach
|
|
20
|
+
- `effort` — `small` (<1 hour), `medium` (1-4 hours), `large` (>4 hours)
|
|
21
|
+
- `consequences` — what happens if NOT addressed (forces articulation of impact)
|
|
22
|
+
- `causes` — `evolution`, `deadline`, `knowledge`, `dependency`
|
|
23
|
+
- `quadrant` — Fowler's: `deliberate-prudent`, `deliberate-reckless`, `inadvertent-prudent`, `inadvertent-reckless`
|
|
24
|
+
- `change_id` — grimoire change created to address this item
|
|
25
|
+
- `first_detected` / `last_detected` — date tracking
|
|
26
|
+
|
|
27
|
+
## Example
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
# Grimoire Debt Register
|
|
31
|
+
# Generated by /grimoire:refactor
|
|
32
|
+
# Last scanned: 2026-04-06
|
|
33
|
+
|
|
34
|
+
summary:
|
|
35
|
+
total: 12
|
|
36
|
+
high: 3
|
|
37
|
+
medium: 5
|
|
38
|
+
low: 4
|
|
39
|
+
open: 9
|
|
40
|
+
accepted: 2
|
|
41
|
+
in_progress: 1
|
|
42
|
+
resolved: 0
|
|
43
|
+
|
|
44
|
+
items:
|
|
45
|
+
- id: debt-001
|
|
46
|
+
fingerprint: a1b2c3d4
|
|
47
|
+
category: hotspot
|
|
48
|
+
severity: high
|
|
49
|
+
location: src/api/views.py
|
|
50
|
+
title: "High-churn, high-complexity API view module"
|
|
51
|
+
detail: "38 commits in 6 months, cyclomatic complexity 24. Handles 12 endpoints with mixed concerns."
|
|
52
|
+
consequences: "Every API change requires understanding 847 lines. Bug rate 3x project average."
|
|
53
|
+
causes: evolution
|
|
54
|
+
metrics: { churn: 38, complexity: 24, lines: 847 }
|
|
55
|
+
suggestion: "Split by resource: UserViews, OrderViews, ProductViews. Extract validation."
|
|
56
|
+
effort: medium
|
|
57
|
+
status: open
|
|
58
|
+
first_detected: 2026-04-06
|
|
59
|
+
last_detected: 2026-04-06
|
|
60
|
+
|
|
61
|
+
- id: debt-002
|
|
62
|
+
fingerprint: c9d0e1f2
|
|
63
|
+
category: data_structure
|
|
64
|
+
severity: medium
|
|
65
|
+
location: src/types/config.ts
|
|
66
|
+
title: "AppConfig interface with 28 optional fields"
|
|
67
|
+
detail: "28 fields, 22 optional. Used in 3 different contexts."
|
|
68
|
+
consequences: "Every consumer must null-check fields always present in its context."
|
|
69
|
+
causes: evolution
|
|
70
|
+
metrics: { fields: 28, optional_ratio: 0.79 }
|
|
71
|
+
suggestion: "Split into ServerConfig, ClientConfig, CLIConfig with shared BaseConfig."
|
|
72
|
+
effort: medium
|
|
73
|
+
status: accepted
|
|
74
|
+
quadrant: deliberate-prudent
|
|
75
|
+
exception_reason: "Splitting would break plugin API. Revisit in Q4."
|
|
76
|
+
first_detected: 2026-04-06
|
|
77
|
+
last_detected: 2026-04-06
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Register Rules
|
|
81
|
+
|
|
82
|
+
- Status lifecycle: `open` -> `triaged` -> `in-progress` -> `resolved` (or `accepted` via exception)
|
|
83
|
+
- `first_detected` set once, never updated. `last_detected` updated each scan.
|
|
84
|
+
- Items matched by exception: `status: accepted` with `quadrant` and `exception_reason`
|
|
85
|
+
- Expired exceptions: revert to `status: open` with note in detail
|
|
86
|
+
- `consequences` forces articulation of real impact, not just code aesthetics
|
|
87
|
+
- On refresh: match by fingerprint, preserve status/first_detected, update last_detected/metrics, mark undetected items as `resolved`
|
|
88
|
+
- Sort: severity (high first), then hotspot score within severity
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Refactor Scan Categories
|
|
2
|
+
|
|
3
|
+
Reference for `grimoire-refactor` step 2. Each category produces findings with a category, location, severity, and suggested action.
|
|
4
|
+
|
|
5
|
+
## 2a. Hotspots (churn x complexity)
|
|
6
|
+
|
|
7
|
+
Files that change frequently AND are hard to change. Highest-ROI refactoring targets.
|
|
8
|
+
|
|
9
|
+
**How to scan:**
|
|
10
|
+
1. Change frequency: `git log --format=format: --name-only --since="6 months ago" | sort | uniq -c | sort -rn | head -50`
|
|
11
|
+
2. Complexity: run `config.tools.complexity` (configured during init — e.g., radon, eslint complexity plugin, or line count + nesting depth as proxy)
|
|
12
|
+
3. Multiply: `churn_rank x complexity_rank = hotspot_score`
|
|
13
|
+
4. Top 10-20 files by hotspot score are targets
|
|
14
|
+
|
|
15
|
+
**Severity:** high = top 5 (churn >20 AND complexity above threshold), medium = 6-15, low = 16+
|
|
16
|
+
|
|
17
|
+
## 2b. Structural Bloat
|
|
18
|
+
|
|
19
|
+
| Signal | Threshold | Meaning |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Oversized files | >300 lines (Python), >500 (TS/JS), >400 (Go) | File does too much — split |
|
|
22
|
+
| Long functions | >50 lines or >4 nesting levels | Extract or flatten |
|
|
23
|
+
| God classes | >10 public methods or >500 lines | Split by responsibility |
|
|
24
|
+
| Too many exports | >15 from one module | Grab bag, not a module |
|
|
25
|
+
| Deep nesting | >4 levels of indentation in logic | Guard clauses, extract, pipeline |
|
|
26
|
+
| Wrapper-only layers | Function body is a single delegation call | Inline or remove |
|
|
27
|
+
| Large switch/if-else | >5 branches | Lookup table, strategy, polymorphism |
|
|
28
|
+
|
|
29
|
+
**Severity:** high = 2x+ threshold, medium = 1-2x, low = marginally over
|
|
30
|
+
|
|
31
|
+
## 2c. Data Structure Complexity
|
|
32
|
+
|
|
33
|
+
| Signal | Meaning |
|
|
34
|
+
|---|---|
|
|
35
|
+
| Models >15 fields | Represents multiple concepts — split |
|
|
36
|
+
| >3 nesting levels | Flatten or normalize |
|
|
37
|
+
| Type unions >4 variants | Separate types or polymorphism |
|
|
38
|
+
| >70% field overlap between types | Consolidate or extract shared base |
|
|
39
|
+
| Config with conditional logic | Business logic hiding as config |
|
|
40
|
+
| >50% optional fields | God DTO serving multiple use cases |
|
|
41
|
+
| Enums >10 values | Proper type hierarchy |
|
|
42
|
+
|
|
43
|
+
**How to scan:** Read `schema.yml` if exists, scan ORM models / interfaces / dataclasses, count fields and nesting.
|
|
44
|
+
|
|
45
|
+
**Severity:** high = >25 fields or >4 nesting, medium = 15-25 or 3-4 nesting, low = structural smell but manageable
|
|
46
|
+
|
|
47
|
+
## 2d. Circular Dependencies
|
|
48
|
+
|
|
49
|
+
**How to scan:**
|
|
50
|
+
- JS/TS: `dependency-cruiser` or `madge` if available, else trace imports from area docs
|
|
51
|
+
- Python: trace imports, look for `TYPE_CHECKING` blocks (circular import workaround signal)
|
|
52
|
+
- Go: circular imports are compile errors — look for oversized packages to split
|
|
53
|
+
|
|
54
|
+
**Severity:** high = >3 modules or crosses architecture boundaries, medium = 2-module cycles, low = within single area
|
|
55
|
+
|
|
56
|
+
## 2e. Dependency Staleness
|
|
57
|
+
|
|
58
|
+
**How to scan:** Run `config.tools.dep_audit` if configured, or:
|
|
59
|
+
- Node: `npm outdated --json`
|
|
60
|
+
- Python: `pip list --outdated --format=json`
|
|
61
|
+
- Count major versions behind, check last publish date
|
|
62
|
+
|
|
63
|
+
**Severity:** high = >2 major versions behind or unmaintained (2+ years no release), medium = 1-2 major behind, low = minor/patch behind
|
|
64
|
+
|
|
65
|
+
## 2f. Broken Promises
|
|
66
|
+
|
|
67
|
+
TODO/FIXME/HACK/XXX comments that have aged.
|
|
68
|
+
|
|
69
|
+
**How to scan:**
|
|
70
|
+
1. Find comments: `grep -rn 'TODO\|FIXME\|HACK\|XXX' --include="*.py" --include="*.ts" --include="*.js" --include="*.go" ...`
|
|
71
|
+
2. Age from `git blame` — when was this line last touched?
|
|
72
|
+
3. Older = higher priority
|
|
73
|
+
|
|
74
|
+
**Severity:** high = >1 year old, medium = 3 months to 1 year, low = <3 months
|
|
75
|
+
|
|
76
|
+
## 2g. Duplication
|
|
77
|
+
|
|
78
|
+
**How to scan:**
|
|
79
|
+
- Read `.grimoire/docs/.snapshot.json` `duplicates` section if present
|
|
80
|
+
- Or run `config.tools.duplicates` if configured (e.g., jscpd)
|
|
81
|
+
- Group by area — within-area dupes are easy to consolidate
|
|
82
|
+
|
|
83
|
+
**Severity:** high = >30 lines or >3 copies, medium = 10-30 lines or 2 copies, low = <10 lines
|
|
84
|
+
|
|
85
|
+
## 2h. Dead Code
|
|
86
|
+
|
|
87
|
+
**How to scan:**
|
|
88
|
+
- Run `config.tools.dead_code` if configured (e.g., knip, vulture)
|
|
89
|
+
- Cross-reference area docs' reusable code tables (in table but never imported = dead)
|
|
90
|
+
- If `codebase-memory-mcp` available: `query_graph` for functions with zero callers
|
|
91
|
+
|
|
92
|
+
**Severity:** high = entire unused modules/classes, medium = unused exported functions, low = unused imports/variables
|
|
93
|
+
|
|
94
|
+
## 2i. Test Debt
|
|
95
|
+
|
|
96
|
+
**How to scan:**
|
|
97
|
+
- Get coverage report if available — files <50% coverage
|
|
98
|
+
- Cross-reference with complexity — high complexity + low coverage = dangerous
|
|
99
|
+
- Check for trivial assertions (`assert True`, `expect(true).toBe(true)`)
|
|
100
|
+
- Check for over-mocked tests (testing mocks, not behavior)
|
|
101
|
+
|
|
102
|
+
**Severity:** high = complex code (top quartile) with <30% coverage, medium = moderate complexity with <50%, low = simple code with low coverage
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Data Schema Format
|
|
2
|
+
|
|
3
|
+
Reference for `grimoire-discover` step 5. The schema is `.grimoire/docs/data/schema.yml`.
|
|
4
|
+
|
|
5
|
+
## Format
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
# Grimoire Data Schema
|
|
9
|
+
# Auto-generated by /grimoire:discover
|
|
10
|
+
# Last updated: YYYY-MM-DD
|
|
11
|
+
# Source: <what was scanned>
|
|
12
|
+
|
|
13
|
+
users:
|
|
14
|
+
type: table # table | collection | document | external_api
|
|
15
|
+
source: src/models/user.py:12 # where defined in code
|
|
16
|
+
note: "Core user identity" # optional context
|
|
17
|
+
fields:
|
|
18
|
+
id: { type: integer, pk: true }
|
|
19
|
+
email: { type: varchar, unique: true, not_null: true }
|
|
20
|
+
role:
|
|
21
|
+
type: enum
|
|
22
|
+
values: [admin, member, guest]
|
|
23
|
+
default: member
|
|
24
|
+
preferences: # nested (Mongo, JSON column, etc.)
|
|
25
|
+
type: object
|
|
26
|
+
fields:
|
|
27
|
+
theme: { type: string, default: "light" }
|
|
28
|
+
indexes:
|
|
29
|
+
- fields: [email]
|
|
30
|
+
unique: true
|
|
31
|
+
relationships:
|
|
32
|
+
- type: has_many
|
|
33
|
+
target: posts
|
|
34
|
+
foreign_key: author_id
|
|
35
|
+
|
|
36
|
+
# --- External APIs ---
|
|
37
|
+
stripe_payments:
|
|
38
|
+
type: external_api
|
|
39
|
+
provider: Stripe
|
|
40
|
+
schema_ref: https://stripe.com/docs/api/charges # full spec location
|
|
41
|
+
client: src/integrations/stripe.py # where we call it
|
|
42
|
+
auth: api_key
|
|
43
|
+
endpoints:
|
|
44
|
+
create_charge:
|
|
45
|
+
method: POST
|
|
46
|
+
path: /v1/charges
|
|
47
|
+
fields:
|
|
48
|
+
amount: { type: integer, note: "in cents" }
|
|
49
|
+
currency: { type: string }
|
|
50
|
+
response:
|
|
51
|
+
id: { type: string }
|
|
52
|
+
status: { type: string, enum: [succeeded, failed] }
|
|
53
|
+
error_response:
|
|
54
|
+
message: { type: string }
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Rules
|
|
58
|
+
|
|
59
|
+
- Document what exists in the code, not what the database contains
|
|
60
|
+
- `source:` points to ORM model or migration file — schema.yml is a summary, code is truth
|
|
61
|
+
- `type:` — `table` for SQL, `collection` for Mongo/document, `document` for nested sub-documents, `external_api` for consumed APIs
|
|
62
|
+
- Nested `fields` for embedded objects/arrays (document DBs, JSON columns)
|
|
63
|
+
- `note:` only when field name isn't self-explanatory
|
|
64
|
+
- `relationships` when ORM defines them explicitly
|
|
65
|
+
- For external APIs: `schema_ref` is most important — point to the full spec
|
|
66
|
+
- For external APIs: `client` points to where the codebase calls the API
|
|
67
|
+
- Don't duplicate entire OpenAPI specs — summarize endpoints you actually use, point to full spec via `schema_ref`
|
|
68
|
+
- If project has no data layer, skip this step entirely
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Security & Compliance Reference
|
|
2
|
+
|
|
3
|
+
Loaded by skills when feature files have security tags or `project.compliance` is configured in `.grimoire/config.yaml`.
|
|
4
|
+
|
|
5
|
+
## Security Tags
|
|
6
|
+
|
|
7
|
+
Apply these Gherkin tags to scenarios with security implications. Downstream skills (plan, review, verify) use them to enforce stricter checks.
|
|
8
|
+
|
|
9
|
+
| Tag | When to apply |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `@security` | Authentication, authorization, access control, cryptographic operations |
|
|
12
|
+
| `@auth` | Login, logout, session management, token handling, role-based access |
|
|
13
|
+
| `@pii` | Create, read, update, or delete personally identifiable information |
|
|
14
|
+
| `@input-validation` | User input that could be malicious (forms, APIs, file uploads) |
|
|
15
|
+
| `@secrets` | API keys, credentials, tokens, or secret management |
|
|
16
|
+
|
|
17
|
+
### Compliance-specific tags (only when `project.compliance` is configured)
|
|
18
|
+
|
|
19
|
+
| Tag | When to apply |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `@pci-dss` | Payment card data, cardholder data environment, payment processing |
|
|
22
|
+
| `@hipaa` | Protected health information, patient data, healthcare records |
|
|
23
|
+
| `@gdpr` | EU personal data, consent management, data subject rights |
|
|
24
|
+
| `@soc2` | Audit logging, access controls, availability requirements |
|
|
25
|
+
|
|
26
|
+
Multiple tags can apply to one scenario.
|
|
27
|
+
|
|
28
|
+
## What Each Tag Requires
|
|
29
|
+
|
|
30
|
+
### In planning (grimoire-plan)
|
|
31
|
+
- `@security` / `@auth` — specify which auth library/framework; include a negative scenario task (assert 401/403)
|
|
32
|
+
- `@pii` — tasks for encryption at rest, access logging, data minimization; if GDPR in compliance, add consent + erasure tasks
|
|
33
|
+
- `@input-validation` — explicit validation/sanitization at boundary; negative test tasks for malicious input (SQLi, XSS, path traversal)
|
|
34
|
+
- `@secrets` — specify env vars or secret store, never hardcoded; add a task to verify no secrets in source
|
|
35
|
+
- `@pci-dss` — no card data in logs, TLS, tokenization, audit trail for cardholder data access
|
|
36
|
+
- `@hipaa` — access controls with audit logging, encryption at rest/transit, minimum necessary access
|
|
37
|
+
- `@gdpr` — lawful basis, consent mechanism if needed, data subject rights (access, rectify, erase, port), retention limits
|
|
38
|
+
- `@soc2` — audit logging for all access, change management documentation, availability monitoring
|
|
39
|
+
|
|
40
|
+
### In verification (grimoire-verify)
|
|
41
|
+
- `@security` / `@auth` — confirm auth checks exist in implementation, negative test covers unauthorized access (401/403)
|
|
42
|
+
- `@pii` — data encrypted at rest, access logged, no PII in log output
|
|
43
|
+
- `@input-validation` — validation at boundary, negative tests for malicious input exist
|
|
44
|
+
- `@secrets` — values from env/secret store, no hardcoded credentials in source
|
|
45
|
+
- `@pci-dss` — no card data in logs, TLS for transmission, audit trail present
|
|
46
|
+
- `@hipaa` — access controls + audit logging, encryption at rest/transit
|
|
47
|
+
- `@gdpr` — consent mechanism if applicable, erasure support, data retention limits
|
|
48
|
+
- `@soc2` — audit logging, access controls, availability monitoring
|
|
49
|
+
|
|
50
|
+
A security-tagged scenario with no corresponding security verification in the tests is a **CRITICAL** issue.
|
|
51
|
+
|
|
52
|
+
## STRIDE Threat Analysis
|
|
53
|
+
|
|
54
|
+
For each new endpoint, data flow, or trust boundary a change introduces:
|
|
55
|
+
|
|
56
|
+
| Threat | Question |
|
|
57
|
+
|---|---|
|
|
58
|
+
| **S**poofing | Can an attacker impersonate a user or service? Auth checks at every entry point? |
|
|
59
|
+
| **T**ampering | Can input or data in transit be modified? Integrity validated (checksums, signatures, CSRF)? |
|
|
60
|
+
| **R**epudiation | Are security-relevant actions logged? Could an attacker act without a trace? |
|
|
61
|
+
| **I**nfo Disclosure | Could errors, logs, or responses leak sensitive data (stack traces, PII, tokens)? |
|
|
62
|
+
| **D**enial of Service | Unbounded operations (large uploads, expensive queries, no rate limits)? |
|
|
63
|
+
| **E**levation of Privilege | Can a user escalate to admin? Role/permission checks at the right layer? |
|
|
64
|
+
|
|
65
|
+
Skip categories that don't apply. Don't manufacture threats.
|
|
66
|
+
|
|
67
|
+
## OWASP Top 10 Surface Scan
|
|
68
|
+
|
|
69
|
+
For changed files, do a lightweight scan:
|
|
70
|
+
|
|
71
|
+
| OWASP Category | What to check in the diff |
|
|
72
|
+
|---|---|
|
|
73
|
+
| A01: Broken Access Control | New endpoints missing auth decorators/middleware; direct object references without ownership checks |
|
|
74
|
+
| A02: Cryptographic Failures | Weak hashing, missing encryption for sensitive data, hardcoded keys |
|
|
75
|
+
| A03: Injection | String concatenation in SQL/commands/templates, `eval()`, `innerHTML` with user data |
|
|
76
|
+
| A04: Insecure Design | Missing rate limiting on auth endpoints, no account lockout |
|
|
77
|
+
| A05: Security Misconfiguration | Debug mode enabled, default credentials, overly permissive CORS |
|
|
78
|
+
| A06: Vulnerable Components | New dependencies without version pins, known-vulnerable packages |
|
|
79
|
+
| A07: Auth Failures | Weak password requirements, session tokens in URLs |
|
|
80
|
+
| A08: Data Integrity Failures | Insecure deserialization (`pickle`, `yaml.load`), missing integrity checks |
|
|
81
|
+
| A09: Logging Failures | Security events not logged, PII/secrets in log output |
|
|
82
|
+
| A10: SSRF | User-controlled URLs in server-side HTTP requests without allowlist |
|
|
83
|
+
|
|
84
|
+
Tag each finding with OWASP category and CWE ID.
|
|
85
|
+
|
|
86
|
+
## CWE Quick Reference
|
|
87
|
+
|
|
88
|
+
| Finding | OWASP / CWE |
|
|
89
|
+
|---|---|
|
|
90
|
+
| Missing auth checks | A01:2021 / CWE-862 |
|
|
91
|
+
| SQL injection | A03:2021 / CWE-89 |
|
|
92
|
+
| Command injection | A03:2021 / CWE-78 |
|
|
93
|
+
| XSS | A03:2021 / CWE-79 |
|
|
94
|
+
| Custom/weak crypto | A02:2021 / CWE-327, CWE-328 |
|
|
95
|
+
| Hardcoded secrets | A07:2021 / CWE-798 |
|
|
96
|
+
| SSRF | A10:2021 / CWE-918 |
|
|
97
|
+
| Insecure deserialization | A08:2021 / CWE-502 |
|
|
98
|
+
|
|
99
|
+
## Compliance Framework Verification
|
|
100
|
+
|
|
101
|
+
Only applies when `project.compliance` is configured.
|
|
102
|
+
|
|
103
|
+
- **`owasp`** — OWASP Top 10 risks addressed (see surface scan above)
|
|
104
|
+
- **`pci-dss`** — No card numbers in logs, TLS for transmission, tokenization, audit trail, access controls on cardholder data
|
|
105
|
+
- **`hipaa`** — Access controls + audit logging, encryption at rest/transit, minimum necessary access, BAA implications for third-party services
|
|
106
|
+
- **`gdpr`** — Lawful basis identified, consent mechanism if needed, data subject rights (access, rectify, erase, port), retention limits, privacy by design
|
|
107
|
+
- **`soc2`** — Audit logging for access and changes, availability monitoring, logical access controls, change management documentation
|
|
108
|
+
- **`iso27001`** — Risk assessment documented, information classification applied, access control policy followed, incident response considered
|
|
109
|
+
|
|
110
|
+
Missing compliance coverage on a tagged scenario is a **blocker**.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Testing & Contract Reference
|
|
2
|
+
|
|
3
|
+
Loaded by skills that involve writing tests, mocking external services, or verifying contract compliance.
|
|
4
|
+
|
|
5
|
+
## Mocking Strategy
|
|
6
|
+
|
|
7
|
+
**Mock at the HTTP boundary, not at the client level.**
|
|
8
|
+
|
|
9
|
+
- **DO mock**: the HTTP transport layer using the project's HTTP mocking library (check `config.tools` or existing test imports for: `responses`, `httpx_mock`, `nock`, `msw`, `wiremock`). Fixture responses must match the contract in `schema.yml`.
|
|
10
|
+
- **DON'T mock**: your own client wrapper. If you mock `stripe_client.create_charge()`, you're testing that your code calls a function — not that it handles the real response shape. The client wrapper is the code under test.
|
|
11
|
+
- **DON'T mock**: internal services within the same repo. Use the real code. Mocking between internal modules hides integration bugs that only surface in production.
|
|
12
|
+
|
|
13
|
+
## Fixture Management
|
|
14
|
+
|
|
15
|
+
- Fixtures live alongside tests (e.g., `tests/fixtures/stripe_create_charge.json`)
|
|
16
|
+
- One fixture per endpoint, named after the endpoint, not the test
|
|
17
|
+
- Each fixture is a concrete instance of the `schema.yml` contract
|
|
18
|
+
- When the contract changes, the fixture must change — stale fixtures are false-positive tests
|
|
19
|
+
- Include at least one error response fixture per external API (matching `error_response` in `schema.yml`)
|
|
20
|
+
|
|
21
|
+
## Contract Test Requirements
|
|
22
|
+
|
|
23
|
+
Every external API integration needs contract tests that assert:
|
|
24
|
+
1. Every `required: true` response field is read and typed correctly in the client
|
|
25
|
+
2. Request payloads match the documented shape (required fields present, types correct)
|
|
26
|
+
3. Error response handling matches the documented `error_response` shape
|
|
27
|
+
4. Use recorded/fixture responses (not live calls) so tests run locally without network
|
|
28
|
+
|
|
29
|
+
For contract regression tests: if the client starts reading a new field or stops sending a required field, the test must fail.
|
|
30
|
+
|
|
31
|
+
## Mocking Anti-Patterns
|
|
32
|
+
|
|
33
|
+
- Mocking your own client wrapper and asserting it was called — tests wiring, not behavior
|
|
34
|
+
- `unittest.mock.patch` on the function under test — replacing the thing you're testing
|
|
35
|
+
- Fixture responses that don't match any documented contract — fictional, prove nothing
|
|
36
|
+
- Mocking so aggressively that removing production code still passes the test
|
|
37
|
+
- Test creates a mock and asserts against the mock's return value (circular)
|
|
38
|
+
|
|
39
|
+
## Verify Before Using
|
|
40
|
+
|
|
41
|
+
Before importing a module, calling a function, or adding a dependency — confirm it exists.
|
|
42
|
+
|
|
43
|
+
**Imports and functions:**
|
|
44
|
+
- Check area docs' Reusable Code table first (exact paths and line numbers)
|
|
45
|
+
- If importing from a file you haven't read, read it first
|
|
46
|
+
- If an import fails, don't guess — read the actual module for the real export name
|
|
47
|
+
|
|
48
|
+
**Dependencies and packages:**
|
|
49
|
+
- Only add packages already in `package.json` / `requirements.txt` / `pyproject.toml` / equivalent
|
|
50
|
+
- If a task requires a new package, verify it exists (should be specified in the plan)
|
|
51
|
+
- Never guess at a package name
|
|
52
|
+
|
|
53
|
+
**APIs and endpoints:**
|
|
54
|
+
- Check `schema.yml` for external API contracts (real endpoints, methods, field names)
|
|
55
|
+
- For internal APIs, read the area doc or route file — don't assume paths
|
|
56
|
+
|
|
57
|
+
## Step Definition Conventions
|
|
58
|
+
|
|
59
|
+
Step definitions are organized by **domain concept**, NOT by feature file. One step file per feature file is an anti-pattern — steps should be reusable across features.
|
|
60
|
+
|
|
61
|
+
**Before writing step definitions, check the project's existing test setup.** Read test config files, existing step definitions, and `package.json` / `requirements.txt` / `pyproject.toml` to determine which framework is in use and follow its conventions.
|
|
62
|
+
|
|
63
|
+
**Key rules:**
|
|
64
|
+
- NEVER create one step definition file per feature file
|
|
65
|
+
- Given steps are most likely to be shared — put them in a common location
|
|
66
|
+
- When/Then steps are more domain-specific — group by domain
|
|
67
|
+
- If a step is used by 2+ features, move it to the shared/common file
|
|
68
|
+
- Step definition bodies should be thin — delegate to helper functions, page objects, or API clients
|
|
69
|
+
- **Match the project's existing patterns.** Don't introduce a new framework.
|
|
70
|
+
|
|
71
|
+
Common patterns by ecosystem (use as reference, not gospel — follow the project's actual conventions):
|
|
72
|
+
|
|
73
|
+
**Python (Behave):** `features/steps/` with `auth_steps.py`, `common_steps.py`, `environment.py`
|
|
74
|
+
|
|
75
|
+
**Python (pytest-bdd):** `tests/conftest.py` for shared fixtures + `tests/step_defs/test_auth.py` per domain
|
|
76
|
+
|
|
77
|
+
**JavaScript/TypeScript (Cucumber.js):** `features/step_definitions/` with `auth.steps.ts`, `common.steps.ts`, `features/support/world.ts`
|
|
78
|
+
|
|
79
|
+
**React / Frontend (Playwright/Cypress + Cucumber):** `e2e/steps/` with domain step files + `e2e/pages/` for page objects
|
|
80
|
+
|
|
81
|
+
## Step Definition Quality
|
|
82
|
+
|
|
83
|
+
Every Then step must have a specific assertion with an exact expected value:
|
|
84
|
+
- **Strong:** `assert result == "expected_value"`, `expect(status).toBe(302)`
|
|
85
|
+
- **Weak:** `assert result is not None`, `expect(result).toBeDefined()`
|
|
86
|
+
- **Trivial:** `assert True`, `pass`, empty body — always CRITICAL
|
|
87
|
+
|
|
88
|
+
Anti-patterns:
|
|
89
|
+
- `def step_impl(): pass` — empty body, always passes
|
|
90
|
+
- Asserting against the return value of the function you just wrote (circular)
|
|
91
|
+
- `assert True` or `assert response is not None` — trivially true
|
|
92
|
+
- Catching exceptions in the step def so it never fails
|
|
93
|
+
- No `assert`/`expect` in a Then step — CRITICAL
|