@rune-kit/rune 2.13.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -12
- package/compiler/__tests__/adr-scoring.test.js +91 -0
- package/compiler/__tests__/context-md-format.test.js +180 -0
- package/compiler/__tests__/context-pack-smell-tests.test.js +215 -0
- package/compiler/__tests__/diversity-score.test.js +117 -0
- package/compiler/__tests__/improve-architecture.test.js +171 -0
- package/compiler/__tests__/openclaw-adapter.test.js +11 -6
- package/compiler/__tests__/out-of-scope-format.test.js +303 -0
- package/compiler/__tests__/zoom-out-output.test.js +112 -0
- package/package.json +2 -2
- package/skills/audit/SKILL.md +1 -0
- package/skills/ba/SKILL.md +241 -82
- package/skills/ba/references/context-md-format.md +136 -0
- package/skills/ba/references/explore-first.md +107 -0
- package/skills/ba/references/out-of-scope-format.md +152 -0
- package/skills/brainstorm/SKILL.md +77 -1
- package/skills/brainstorm/references/design-it-twice.md +155 -0
- package/skills/context-pack/SKILL.md +68 -25
- package/skills/context-pack/evals.md +122 -0
- package/skills/context-pack/references/brief-template.md +121 -0
- package/skills/context-pack/references/durability-rules.md +109 -0
- package/skills/cook/SKILL.md +4 -4
- package/skills/debug/SKILL.md +2 -1
- package/skills/fix/SKILL.md +2 -1
- package/skills/improve-architecture/SKILL.md +275 -0
- package/skills/improve-architecture/evals.md +145 -0
- package/skills/improve-architecture/references/deepening.md +87 -0
- package/skills/improve-architecture/references/interface-design.md +68 -0
- package/skills/improve-architecture/references/language.md +81 -0
- package/skills/improve-architecture/references/scoring.md +122 -0
- package/skills/journal/SKILL.md +33 -6
- package/skills/journal/references/adr-criteria.md +109 -0
- package/skills/review/SKILL.md +1 -0
- package/skills/review-intake/SKILL.md +25 -2
- package/skills/scout/SKILL.md +33 -1
- package/skills/surgeon/SKILL.md +16 -1
- package/skills/test/SKILL.md +48 -1
- package/skills/test/evals.md +137 -0
- package/skills/test/references/mocking-policy.md +121 -0
- package/skills/test/references/test-quality.md +124 -0
- package/skills/test/references/vertical-tdd.md +110 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Language
|
|
2
|
+
|
|
3
|
+
Shared vocabulary every output of this skill uses. These eight terms are precise. Substitutes ("component", "service", "API", "boundary", "layer") are banned in skill output because they carry baggage from other paradigms (DDD, microservices, n-tier).
|
|
4
|
+
|
|
5
|
+
## Terms
|
|
6
|
+
|
|
7
|
+
### Module
|
|
8
|
+
Anything with an interface and an implementation. Scale-agnostic on purpose: a function, a class, a package, or a tier-spanning slice can each be a module.
|
|
9
|
+
*Avoid*: unit, component, service.
|
|
10
|
+
|
|
11
|
+
### Interface
|
|
12
|
+
Everything a caller must know to use the module correctly. Includes the type signature plus invariants, ordering constraints, error modes, required configuration, and performance characteristics.
|
|
13
|
+
*Avoid*: API, signature (those refer only to the type-level surface).
|
|
14
|
+
|
|
15
|
+
### Implementation
|
|
16
|
+
The body of code inside the module. Distinct from **adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake).
|
|
17
|
+
|
|
18
|
+
### Depth
|
|
19
|
+
Leverage at the interface — how much behavior a caller can exercise per unit of interface they have to learn.
|
|
20
|
+
- **Deep**: large behavior, small interface.
|
|
21
|
+
- **Shallow**: interface nearly as complex as the implementation (often a wrapper or pass-through).
|
|
22
|
+
|
|
23
|
+
Numeric scoring rubric (1–5):
|
|
24
|
+
| Score | Interface Complexity vs Implementation |
|
|
25
|
+
|-------|----------------------------------------|
|
|
26
|
+
| 1 | Wrapper / pass-through (interface ≈ impl) |
|
|
27
|
+
| 2 | Thin (interface > 50% of impl) |
|
|
28
|
+
| 3 | Modest (interface ≈ 1/3 of impl) |
|
|
29
|
+
| 4 | Deep (interface ≈ 1/5 of impl) |
|
|
30
|
+
| 5 | Very deep (interface ≪ impl) |
|
|
31
|
+
|
|
32
|
+
### Seam *(from Michael Feathers)*
|
|
33
|
+
A place where you can alter behavior without editing in that place. The *location* of an interface. Choosing where to put the seam is its own design decision, distinct from what goes behind it.
|
|
34
|
+
*Avoid*: boundary (overloaded with DDD's bounded context).
|
|
35
|
+
|
|
36
|
+
### Adapter
|
|
37
|
+
A concrete thing that satisfies an interface at a seam. Describes role (what slot it fills), not substance (what's inside).
|
|
38
|
+
|
|
39
|
+
### Leverage
|
|
40
|
+
What callers get from depth. More capability per unit of interface they have to learn. One implementation pays back across N call sites and M tests.
|
|
41
|
+
|
|
42
|
+
### Locality
|
|
43
|
+
What maintainers get from depth. Change, bugs, knowledge, and verification concentrate at one place rather than spreading across callers. Fix once, fixed everywhere.
|
|
44
|
+
|
|
45
|
+
## Principles
|
|
46
|
+
|
|
47
|
+
### Depth is a property of the interface, not the implementation
|
|
48
|
+
A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its public interface.
|
|
49
|
+
|
|
50
|
+
### The deletion test
|
|
51
|
+
Imagine deleting the module.
|
|
52
|
+
- If complexity vanishes, the module wasn't hiding anything — it was a pass-through. Verdict: `vanish`.
|
|
53
|
+
- If complexity reappears across N callers, the module was earning its keep. Verdict: `concentrate`.
|
|
54
|
+
- If complexity moves to some callers and dissolves at others — verdict: `redistribute`. Common case for partially-deepened modules.
|
|
55
|
+
|
|
56
|
+
### The interface is the test surface
|
|
57
|
+
Callers and tests cross the same seam. If you want to test *past* the interface (peek at internal state, count internal calls), the module is the wrong shape — not the test.
|
|
58
|
+
|
|
59
|
+
### One adapter is hypothetical, two are real
|
|
60
|
+
Don't introduce a port unless something actually varies across it (typically prod + test). A single-adapter seam is just indirection that costs comprehension without buying flexibility.
|
|
61
|
+
|
|
62
|
+
## Relationships
|
|
63
|
+
|
|
64
|
+
- A **Module** has exactly one **Interface** (its public surface).
|
|
65
|
+
- **Depth** is a property of a **Module**, measured against its **Interface**.
|
|
66
|
+
- A **Seam** is where a **Module**'s **Interface** lives.
|
|
67
|
+
- An **Adapter** sits at a **Seam** and satisfies the **Interface**.
|
|
68
|
+
- **Depth** produces **Leverage** for callers and **Locality** for maintainers.
|
|
69
|
+
|
|
70
|
+
## Banned framings (and why)
|
|
71
|
+
|
|
72
|
+
- **Depth as ratio of impl-lines to interface-lines** — rewards padding the implementation. Use depth-as-leverage instead.
|
|
73
|
+
- **"Interface" as the TypeScript `interface` keyword or a class's public methods** — too narrow. Interface here includes every fact a caller must know, including invariants and error modes.
|
|
74
|
+
- **"Boundary"** — overloaded with DDD's bounded context. Say *seam* or *interface* instead.
|
|
75
|
+
- **"Component"** — UI-centric. Use *module*.
|
|
76
|
+
- **"Service"** — microservice-centric. Use *module*.
|
|
77
|
+
- **"Layer"** — too generic, often confused with horizontal n-tier slicing. Use *module* + *seam*.
|
|
78
|
+
|
|
79
|
+
## Vocabulary discipline (mechanical check)
|
|
80
|
+
|
|
81
|
+
The compiler test `compiler/__tests__/vocabulary-discipline.test.js` greps this skill's body and references for the banned aliases. Any hit fails the build. Fix by substituting the precise term.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Scoring Rubric
|
|
2
|
+
|
|
3
|
+
Numeric scoring is the value-add. Soft prose ("this looks shallow") doesn't compose. Numeric scores let `surgeon`, `audit`, `review` gate decisions programmatically.
|
|
4
|
+
|
|
5
|
+
Three metrics + one verdict per candidate.
|
|
6
|
+
|
|
7
|
+
## Depth (1–5)
|
|
8
|
+
|
|
9
|
+
Measures how much behavior the interface hides.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
depth = clamp_1_5( implementation_complexity / interface_complexity )
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Interface complexity** — count of unique entry points (functions / methods) × average parameter count. Plus penalty (+1) for each invariant or ordering rule a caller must remember.
|
|
16
|
+
|
|
17
|
+
**Implementation complexity** — total LOC inside the module + count of distinct branches + count of distinct internal collaborators.
|
|
18
|
+
|
|
19
|
+
| Score | Description | Example |
|
|
20
|
+
|-------|-------------|---------|
|
|
21
|
+
| 1 | Wrapper / pass-through; interface ≈ impl | `getUserName(u) => u.name` |
|
|
22
|
+
| 2 | Thin; interface > 50% of impl | Function that does light validation + delegates |
|
|
23
|
+
| 3 | Modest; interface ≈ 1/3 of impl | Module with 5 methods over 200 LOC of state-machine logic |
|
|
24
|
+
| 4 | Deep; interface ≈ 1/5 of impl | Port with 3 methods over 800 LOC of state machine |
|
|
25
|
+
| 5 | Very deep; interface ≪ impl | Single-method JIT compiler interface |
|
|
26
|
+
|
|
27
|
+
## Leverage (1–5)
|
|
28
|
+
|
|
29
|
+
Measures caller benefit — how much capability callers get per unit of interface they have to learn.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
leverage = clamp_1_5( num_callers * unique_use_cases / interface_method_count )
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
| Score | Description | Example |
|
|
36
|
+
|-------|-------------|---------|
|
|
37
|
+
| 1 | Few callers, many methods to learn | 1 caller, 8-method object |
|
|
38
|
+
| 2 | Modest reach per surface | 3 callers, 5 methods |
|
|
39
|
+
| 3 | Balanced | 10 callers, 4 methods |
|
|
40
|
+
| 4 | Strong leverage | 30 callers, 3 methods |
|
|
41
|
+
| 5 | Exceptional leverage | 100+ callers, 1-2 methods |
|
|
42
|
+
|
|
43
|
+
Edge cases:
|
|
44
|
+
- Internal-only modules (callers all in same package) — score capped at 4 unless used by multiple packages.
|
|
45
|
+
- External public API — leverage is per-consumer; cap at 5 because ecosystem reach is exponential.
|
|
46
|
+
|
|
47
|
+
## Locality (1–5)
|
|
48
|
+
|
|
49
|
+
Measures maintainer benefit — where change/bugs concentrate.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
locality = clamp_1_5( code_concentration_index )
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`code_concentration_index` ≈ 5 - (entropy of where related logic lives). Pragmatic scoring:
|
|
56
|
+
|
|
57
|
+
| Score | Description |
|
|
58
|
+
|-------|-------------|
|
|
59
|
+
| 1 | Logic spread across N callers; "fix once, fix N times" |
|
|
60
|
+
| 2 | Logic in 2-3 modules; some duplication |
|
|
61
|
+
| 3 | Logic mostly in one module, some leakage |
|
|
62
|
+
| 4 | Logic concentrated in one module; clear single source |
|
|
63
|
+
| 5 | Logic in one module AND callers don't reimplement it |
|
|
64
|
+
|
|
65
|
+
## Deletion test (verdict, not score)
|
|
66
|
+
|
|
67
|
+
Imagine deleting the module. What happens to the codebase?
|
|
68
|
+
|
|
69
|
+
| Verdict | Meaning |
|
|
70
|
+
|---------|---------|
|
|
71
|
+
| `vanish` | Complexity disappears; module was a pass-through. Often accompanies depth ≤ 2. Action: delete entirely, inline at callers, OR deepen by absorbing more responsibility. |
|
|
72
|
+
| `concentrate` | Complexity reappears across N callers. Module was earning its keep. Action: KEEP. May still benefit from deepening if depth < 4. |
|
|
73
|
+
| `redistribute` | Complexity moves — some absorbed by callers, some dissolved. Common case for partially-shallow modules. Action: deepen (most likely target) OR refine into a smaller, more focused module. |
|
|
74
|
+
|
|
75
|
+
## Aggregate score (architecture sub-score)
|
|
76
|
+
|
|
77
|
+
For a target module, the aggregate is:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
candidate_score = depth + leverage + locality # 3-15
|
|
81
|
+
sub_score_contribution = (candidate_score / 15) * 100 # 0-100 normalized
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`audit` may aggregate across many candidates by averaging sub-score contributions weighted by callers (modules with more callers have more architectural impact).
|
|
85
|
+
|
|
86
|
+
## Score gating (used by other skills)
|
|
87
|
+
|
|
88
|
+
| Score Range | Interpretation | Suggested Action |
|
|
89
|
+
|-------------|----------------|------------------|
|
|
90
|
+
| 12-15 | Already deep; small gains possible | Skip deepening; tag as "healthy" |
|
|
91
|
+
| 8-11 | Modest; deepening yields measurable gain | Candidate for `surgeon` |
|
|
92
|
+
| 3-7 | Shallow; high-priority deepening target | Strong recommendation; flag in `audit` |
|
|
93
|
+
| 0-2 | Pass-through or wrapper; consider deletion | Verify with deletion test before delete |
|
|
94
|
+
|
|
95
|
+
## Worked scoring example
|
|
96
|
+
|
|
97
|
+
Module: `src/auth/login.ts`
|
|
98
|
+
- 1 function `login(email, password) → SessionToken | null`
|
|
99
|
+
- 30 LOC, 3 branches, calls `db.users.get` + `crypto.compare`
|
|
100
|
+
- Used by 4 routes
|
|
101
|
+
|
|
102
|
+
Calculate:
|
|
103
|
+
- Interface complexity: 1 entry × 2 params = 2; +0 invariants → 2
|
|
104
|
+
- Implementation complexity: 30 LOC + 3 branches + 2 collaborators = ~35
|
|
105
|
+
- Depth: clamp_1_5(35/2 ÷ 5) ≈ 3 (modest, not very deep)
|
|
106
|
+
- Leverage: clamp_1_5(4 callers × 1 use case / 1 method) = 4 (strong leverage already!)
|
|
107
|
+
- Locality: 5 (logic in one file)
|
|
108
|
+
- Deletion test: concentrate (deleting it scatters auth across 4 routes)
|
|
109
|
+
|
|
110
|
+
Aggregate: 3 + 4 + 5 = **12 / 15** = "healthy". Improvement effort better spent elsewhere.
|
|
111
|
+
|
|
112
|
+
The single-function "login" was actually fine. The shallowness signal might come from `login + refresh + logout` being three separate small modules — score them as a candidate cluster, not individually.
|
|
113
|
+
|
|
114
|
+
## Cluster scoring
|
|
115
|
+
|
|
116
|
+
When the friction is a cluster of related shallow modules (auth, session, refresh), score the *cluster as a single hypothetical deepened module*:
|
|
117
|
+
|
|
118
|
+
- Depth: what the deepened interface would be
|
|
119
|
+
- Leverage: callers across all current modules combined / new method count
|
|
120
|
+
- Locality: maintainer benefit if all logic concentrated
|
|
121
|
+
|
|
122
|
+
The current state's score is the *baseline*; the cluster score is the *target*. Delta = potential gain.
|
package/skills/journal/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: journal
|
|
|
3
3
|
description: Persistent state tracking and Architecture Decision Records across sessions. Use when recording a decision, ADR, or progress that must survive session boundaries. Manages progress state, module health, dependency graphs, and ADRs for any workflow.
|
|
4
4
|
metadata:
|
|
5
5
|
author: runedev
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.4.0"
|
|
7
7
|
layer: L3
|
|
8
8
|
model: haiku
|
|
9
9
|
group: state
|
|
@@ -38,6 +38,7 @@ None — pure L3 state management utility.
|
|
|
38
38
|
- `skill-forge` (L2): record skill creation decisions and rationale
|
|
39
39
|
- `graft` (L2): auto-log graft operations — source URL, mode, challenge score, files changed
|
|
40
40
|
- `retro` (L2): record retrospective insights and decisions
|
|
41
|
+
- `improve-architecture` (L2): record an ADR when the user rejects a deepening candidate with a load-bearing reason
|
|
41
42
|
|
|
42
43
|
## Files Managed
|
|
43
44
|
|
|
@@ -82,11 +83,32 @@ Use `Write` to save the updated `module-status.json`.
|
|
|
82
83
|
|
|
83
84
|
Use `Edit` to update the relevant lines in `RESCUE-STATE.md` (current phase, current module, counts of completed vs pending).
|
|
84
85
|
|
|
85
|
-
### Step 3 — Record decisions
|
|
86
|
+
### Step 3 — Record decisions (gated by 3-criteria scoring)
|
|
86
87
|
|
|
87
88
|
For each architectural decision or trade-off made during this session (applies to any workflow — feature development, deploy, rescue, audit):
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
#### Step 3.0 — Score the decision
|
|
91
|
+
|
|
92
|
+
Compute three numeric scores (1–5 each) before opening any ADR file. See [references/adr-criteria.md](references/adr-criteria.md) for full rubric.
|
|
93
|
+
|
|
94
|
+
| Axis | What it measures |
|
|
95
|
+
|------|------------------|
|
|
96
|
+
| `reversibility` | 1 = next-sprint reversible; 5 = practically irreversible |
|
|
97
|
+
| `surprisingness` | 1 = obvious to any reader; 5 = future engineer would "fix" without context |
|
|
98
|
+
| `tradeoff_strength` | 1 = no real alternative; 5 = genuinely difficult choice |
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
score = reversibility + surprisingness + tradeoff_strength # range 3–15
|
|
102
|
+
open_adr = (score >= 11) AND (each axis >= 3)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### Step 3.1 — Counter-test (anti-fake)
|
|
106
|
+
|
|
107
|
+
Before writing the ADR, fill in **at least one rejected alternative + why**. If no credible alternative was actually considered, the decision wasn't a real tradeoff — re-classify as a **convention** (record in CLAUDE.md or comment, not in `.rune/adr/`) and skip ADR creation.
|
|
108
|
+
|
|
109
|
+
#### Step 3.2 — Open the ADR (if gate passed)
|
|
110
|
+
|
|
111
|
+
1. Generate filename including the score: `.rune/adr/ADR-[NNN]-[slug]-s[score].md` where NNN is sequential and `score` is the 3–15 sum (e.g., `ADR-007-postgres-write-model-s13.md`)
|
|
90
112
|
2. Use `Write` to create the ADR file with this format:
|
|
91
113
|
|
|
92
114
|
```markdown
|
|
@@ -96,6 +118,7 @@ For each architectural decision or trade-off made during this session (applies t
|
|
|
96
118
|
**Status**: Accepted
|
|
97
119
|
**Workflow**: [rescue | cook | deploy | audit | other]
|
|
98
120
|
**Scope**: [affected module, feature, or system area]
|
|
121
|
+
**Score**: reversibility=[1-5] / surprisingness=[1-5] / tradeoff_strength=[1-5] / total=[3-15]
|
|
99
122
|
|
|
100
123
|
## Context
|
|
101
124
|
[Why this decision was needed — what problem or trade-off prompted it]
|
|
@@ -109,8 +132,8 @@ For each architectural decision or trade-off made during this session (applies t
|
|
|
109
132
|
## Consequences
|
|
110
133
|
[Impact on files/modules/future work — include rollback path if relevant]
|
|
111
134
|
|
|
112
|
-
## Rejected Alternatives
|
|
113
|
-
[List what was considered but NOT chosen, and why. This prevents future sessions from re-visiting dead ends.]
|
|
135
|
+
## Rejected Alternatives (counter-test — MUST have at least one)
|
|
136
|
+
[List what was considered but NOT chosen, and why. This prevents future sessions from re-visiting dead ends. If you cannot fill in this section, the decision wasn't a real tradeoff — DO NOT open this ADR.]
|
|
114
137
|
- **[Alternative A]**: Rejected because [specific reason — constraint, performance, complexity]
|
|
115
138
|
- **[Alternative B]**: Rejected because [specific reason]. May reconsider if [condition changes].
|
|
116
139
|
```
|
|
@@ -226,10 +249,14 @@ Known failure modes for this skill. Check these before declaring done.
|
|
|
226
249
|
| RESCUE-STATE.md initialized without content when called from non-rescue workflows | MEDIUM | If caller is not rescue/surgeon, skip RESCUE-STATE.md initialization — use progress.md instead |
|
|
227
250
|
| Overwriting human-written ADR content on re-run | CRITICAL | MUST check if ADR-[NNN].md exists before writing — never overwrite, increment NNN |
|
|
228
251
|
| Empty ADR Rationale field ("decided to use X") | MEDIUM | Constraint 1 blocks this — re-prompt for rationale before writing |
|
|
252
|
+
| Opening an ADR for a decision that scores below threshold (sum < 11 or any axis < 3) | HIGH | Step 3.0 gate — if score fails, classify as "convention" and record in CLAUDE.md instead |
|
|
253
|
+
| Score inflation to reach threshold | MEDIUM | Step 3.1 counter-test — must name a credible rejected alternative; cannot be faked |
|
|
254
|
+
| ADR for a deferral ("we'll do X later") | MEDIUM | Deferrals are not decisions; route to backlog or `.out-of-scope/` (if rejection) |
|
|
229
255
|
|
|
230
256
|
## Done When
|
|
231
257
|
|
|
232
|
-
- All decisions from the session recorded as ADR files
|
|
258
|
+
- All decisions from the session that pass the 3-criteria gate (sum >= 11, each axis >= 3, counter-test filled) recorded as ADR files
|
|
259
|
+
- Decisions failing the gate classified as conventions (logged in CLAUDE.md or code comment, NOT in `.rune/adr/`)
|
|
233
260
|
- All identified risks recorded as RISK files with severity, mitigation, and trigger conditions
|
|
234
261
|
- Progress state updated (module status, phase, or deploy event as appropriate)
|
|
235
262
|
- Dependency graph updated if module relationships changed
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# ADR Criteria — When to Open an ADR
|
|
2
|
+
|
|
3
|
+
ADRs (Architecture Decision Records) are durable. They survive sessions, codebases, and team turnover. That power has a cost: writing one for every minor pick fills the directory with noise, and the genuinely load-bearing decisions get lost.
|
|
4
|
+
|
|
5
|
+
The ADR gate ensures that every entry in `.rune/adr/` *earned* its place.
|
|
6
|
+
|
|
7
|
+
## The 3-criteria gate
|
|
8
|
+
|
|
9
|
+
An ADR is offered only if **all three** are true:
|
|
10
|
+
|
|
11
|
+
### 1. Hard to reverse (`reversibility`)
|
|
12
|
+
|
|
13
|
+
Score 1–5: how expensive is it to change your mind later?
|
|
14
|
+
|
|
15
|
+
| Score | Description |
|
|
16
|
+
|-------|-------------|
|
|
17
|
+
| 1 | Reversible next sprint (one PR, no migration) |
|
|
18
|
+
| 2 | Reversible this quarter (a few PRs, simple migration) |
|
|
19
|
+
| 3 | Significant cost (data migration, multi-PR rollout) |
|
|
20
|
+
| 4 | Quarter-or-more to reverse (schema change, integration rewrite) |
|
|
21
|
+
| 5 | Practically irreversible (architectural commitment, lock-in to vendor) |
|
|
22
|
+
|
|
23
|
+
### 2. Surprising without context (`surprisingness`)
|
|
24
|
+
|
|
25
|
+
Score 1–5: how likely is a future reader to wonder "why did they do it this way?"
|
|
26
|
+
|
|
27
|
+
| Score | Description |
|
|
28
|
+
|-------|-------------|
|
|
29
|
+
| 1 | Obvious — anyone would do it this way |
|
|
30
|
+
| 2 | Common, but with one minor detail |
|
|
31
|
+
| 3 | Mildly unusual — half of practitioners might pick differently |
|
|
32
|
+
| 4 | Strongly counter to common practice |
|
|
33
|
+
| 5 | Rare or counter-intuitive — without explanation, future engineer would "fix" it |
|
|
34
|
+
|
|
35
|
+
### 3. Real tradeoff (`tradeoff_strength`)
|
|
36
|
+
|
|
37
|
+
Score 1–5: how credible were the rejected alternatives?
|
|
38
|
+
|
|
39
|
+
| Score | Description |
|
|
40
|
+
|-------|-------------|
|
|
41
|
+
| 1 | No real alternative — the obvious thing |
|
|
42
|
+
| 2 | One alternative considered briefly |
|
|
43
|
+
| 3 | 2–3 alternatives evaluated; pick was clear |
|
|
44
|
+
| 4 | Multiple credible alternatives; pick required real analysis |
|
|
45
|
+
| 5 | Genuinely difficult choice; reasonable people disagreed |
|
|
46
|
+
|
|
47
|
+
### Threshold
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
score = reversibility + surprisingness + tradeoff_strength # range 3–15
|
|
51
|
+
open_adr = (score >= 11) AND (each axis >= 3)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The "each axis >= 3" rule prevents single-axis cheating. A decision that's hard-to-reverse but obvious AND has no real alternatives (e.g., "we're using SQL for our SQL database") shouldn't be an ADR even if reversibility=5.
|
|
55
|
+
|
|
56
|
+
## Counter-test (anti-fake)
|
|
57
|
+
|
|
58
|
+
Before opening an ADR, the agent MUST be able to fill in **rejected alternatives + why**. If the agent can't name at least one credible alternative *that was actually considered*, the decision wasn't a real tradeoff. Re-classify as a "convention" — record it in CLAUDE.md or a comment, not in `.rune/adr/`.
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
Rejected alternative: PostgreSQL JSON columns
|
|
62
|
+
Why rejected: schema migrations harder; no JSON-path indexing in the version we use; team's tooling stack favors structured columns.
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
If you can't write that section, don't open the ADR.
|
|
66
|
+
|
|
67
|
+
## ADR file naming
|
|
68
|
+
|
|
69
|
+
Filename includes the score, so future reviewers see at a glance why this one was kept:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
.rune/adr/ADR-007-postgres-write-model-s13.md
|
|
73
|
+
.rune/adr/ADR-008-event-sourced-orders-s14.md
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Format: `ADR-NNN-<slug>-s<score>.md` where `NNN` is the sequential number and `score` is the 3–15 sum.
|
|
77
|
+
|
|
78
|
+
## What qualifies (examples)
|
|
79
|
+
|
|
80
|
+
- **Architectural shape**: "We're using a monorepo." "The write model is event-sourced; the read model is projected into Postgres." (s ≈ 12–14)
|
|
81
|
+
- **Integration patterns between modules**: "Ordering and Billing communicate via domain events, not synchronous HTTP." (s ≈ 11–13)
|
|
82
|
+
- **Technology choices that carry lock-in**: database, message bus, auth provider, deployment target — only the ones that would take a quarter to swap out. (s ≈ 11–14)
|
|
83
|
+
- **Boundary-and-scope decisions**: "Customer data is owned by the Customer module; other modules reference it by ID only." The explicit no-s are as valuable as the yes-s. (s ≈ 10–12 — borderline, judge case-by-case)
|
|
84
|
+
- **Deliberate deviations from the obvious path**: "We're using manual SQL instead of an ORM because X." (s ≈ 11–13 — high surprisingness)
|
|
85
|
+
- **Constraints not visible in the code**: "We can't use AWS because of compliance requirements." (s ≈ 11–13)
|
|
86
|
+
- **Rejected alternatives when the rejection is non-obvious**: considered GraphQL, picked REST for subtle reasons. (s ≈ 10–12 — if rejection is documented elsewhere, may not need ADR)
|
|
87
|
+
|
|
88
|
+
## What does NOT qualify (examples)
|
|
89
|
+
|
|
90
|
+
- "We chose lodash over underscore." (reversibility ≤ 2; not surprising; weak tradeoff) — s ≈ 5
|
|
91
|
+
- "This function uses async/await instead of Promises." (reversibility 1; not surprising; convention) — s ≈ 3
|
|
92
|
+
- "We're using TypeScript." (reversibility 5; not surprising; obvious for the stack) — s ≈ 7
|
|
93
|
+
- "We deferred dark mode." (this is a deferral, not a decision — goes to backlog or `.out-of-scope/`) — N/A
|
|
94
|
+
|
|
95
|
+
## When score is 8–10 (borderline)
|
|
96
|
+
|
|
97
|
+
Don't auto-open. Ask the user: "This decision scores 9/15 — borderline. Do you want it as an ADR, or is a comment in the code sufficient?" Default to the lighter touch.
|
|
98
|
+
|
|
99
|
+
## Score gaming detection
|
|
100
|
+
|
|
101
|
+
The score can be inflated, but the counter-test (rejected alternative) cannot be faked without lying about history. If the agent fills out scores ≥ 4 on each axis but can't name a credible rejected alternative, the gate fails and no ADR is opened.
|
|
102
|
+
|
|
103
|
+
`audit` later cross-references ADR scores — if the average score across `.rune/adr/` files is < 11, it flags "ADR inflation" as a quality concern.
|
|
104
|
+
|
|
105
|
+
## Convention vs Decision
|
|
106
|
+
|
|
107
|
+
Decisions are tradeoffs at fork points. **Conventions are choices everyone makes the same way** — naming, formatting, simple defaults. Conventions go in CLAUDE.md or code style guides, not ADRs.
|
|
108
|
+
|
|
109
|
+
A test: if you can imagine the team coming back next quarter and saying "yeah obvious, of course we did it this way" — it's a convention. If they'd say "wait, why did we do *that*?" — it's a decision and probably qualifies.
|
package/skills/review/SKILL.md
CHANGED
|
@@ -60,6 +60,7 @@ Every review MUST cite at least one specific concern, suggestion, or explicit ap
|
|
|
60
60
|
- `review` → `test` — untested edge case found → test writes it
|
|
61
61
|
- `review` → `fix` — bug found during review → fix applies correction
|
|
62
62
|
- `review` → `scout` — needs more context → scout finds related code
|
|
63
|
+
- `review` → `improve-architecture` — when reviewer flag mentions "shallow", "wrapper", "indirection", or pass-through pattern
|
|
63
64
|
- `review` ← `fix` — complex fix requests self-review
|
|
64
65
|
- `review` → `sentinel` — security-critical code → sentinel deep scan
|
|
65
66
|
|
|
@@ -3,11 +3,12 @@ name: review-intake
|
|
|
3
3
|
description: Use when receiving code review feedback, PR comments, or external suggestions before implementing any changes. Prevents blind implementation, enforces verification-first discipline.
|
|
4
4
|
metadata:
|
|
5
5
|
author: runedev
|
|
6
|
-
version: "1.
|
|
6
|
+
version: "1.2.0"
|
|
7
7
|
layer: L2
|
|
8
8
|
model: sonnet
|
|
9
9
|
group: quality
|
|
10
|
-
tools: "Read, Glob, Grep"
|
|
10
|
+
tools: "Read, Write, Edit, Glob, Grep"
|
|
11
|
+
listen: outofscope.match
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
# review-intake
|
|
@@ -137,6 +138,24 @@ gh api repos/{owner}/{repo}/pulls/{pr}/comments/{id}/replies \
|
|
|
137
138
|
-f body="Fixed — [description]"
|
|
138
139
|
```
|
|
139
140
|
|
|
141
|
+
### Phase 4.5 — Rejection KB Write (when verdict = OUT OF SCOPE)
|
|
142
|
+
|
|
143
|
+
For every item with verdict `OUT OF SCOPE`, write a durable record to `.out-of-scope/`. Oral-only rejections leave no trace and force re-litigation in future sessions.
|
|
144
|
+
|
|
145
|
+
<HARD-GATE>
|
|
146
|
+
Every OUT OF SCOPE verdict MUST produce a `.out-of-scope/<slug>.md` file (or append to an existing one).
|
|
147
|
+
A rejection without a written record is a rejection that didn't happen.
|
|
148
|
+
</HARD-GATE>
|
|
149
|
+
|
|
150
|
+
**Procedure**:
|
|
151
|
+
|
|
152
|
+
1. Generate `slug` from the rejected concept (kebab-case, lowercase, max 40 chars, recognizable without opening the file).
|
|
153
|
+
2. Lexical-similarity check: `Glob` `.out-of-scope/*.md`, parse each frontmatter's `concept` + `aliases`, compute overlap with the new slug's tokens. If any existing concept has ≥0.7 overlap → APPEND to that file's `prior_requests` list instead of creating a new one.
|
|
154
|
+
3. If new file: write the format from [`ba/references/out-of-scope-format.md`](../ba/references/out-of-scope-format.md) — YAML frontmatter (concept / aliases / decision: rejected / rejected_at / rejected_by: review-intake / prior_requests / revisit_if) + Markdown body (concept name, "Why out of scope" reasoning, "What would change our mind" signals).
|
|
155
|
+
4. The reasoning MUST be substantive — not "we don't want this" but *why*. Reference project scope, technical constraints, or strategic decisions. Reject deferrals ("we're busy") — those don't belong here.
|
|
156
|
+
|
|
157
|
+
Only **enhancement** rejections produce `.out-of-scope/` entries. Bug rejections (won't fix because already fixed / not reproducible / not a bug) get a comment on the issue, not a KB file.
|
|
158
|
+
|
|
140
159
|
### Phase 6 — IMPLEMENT
|
|
141
160
|
|
|
142
161
|
Execute in priority order: P0 → P1 → P2 → P3 → P4.
|
|
@@ -223,6 +242,9 @@ How to push back:
|
|
|
223
242
|
| Implementing 4/6 items, leaving 2 unclear | HIGH | HARD-GATE: all-or-nothing comprehension |
|
|
224
243
|
| Performative agreement masking misunderstanding | MEDIUM | Banned phrases list + restate-in-own-words requirement |
|
|
225
244
|
| Fixing tests instead of code to make review pass | HIGH | Defer to `fix` constraints: fix CODE, not TESTS |
|
|
245
|
+
| OUT OF SCOPE verdict with no `.out-of-scope/` file written | HIGH | Phase 4.5 HARD-GATE — oral-only rejections force re-litigation in future sessions |
|
|
246
|
+
| Writing a deferral ("busy this quarter") to `.out-of-scope/` | MEDIUM | Deferrals belong in backlog, not the rejection KB. KB entries must cite durable reasons (scope, tech constraint, strategy) |
|
|
247
|
+
| Creating duplicate `.out-of-scope/` files for the same concept | MEDIUM | Lexical-similarity gate (≥0.7 overlap) — append to existing file's `prior_requests` instead of duplicating |
|
|
226
248
|
|
|
227
249
|
## Done When
|
|
228
250
|
|
|
@@ -231,6 +253,7 @@ How to push back:
|
|
|
231
253
|
- Verdicts assigned (correct/pushback/yagni/defer)
|
|
232
254
|
- Approved items implemented in priority order
|
|
233
255
|
- Tests pass after each individual fix
|
|
256
|
+
- Every OUT OF SCOPE verdict has produced a `.out-of-scope/<slug>.md` file (new or appended)
|
|
234
257
|
- Review Intake Report emitted
|
|
235
258
|
|
|
236
259
|
## Returns
|
package/skills/scout/SKILL.md
CHANGED
|
@@ -3,12 +3,13 @@ name: scout
|
|
|
3
3
|
description: "Fast codebase scanner. Use when any skill needs codebase context. Finds files, patterns, dependencies, project structure. Pure read-only — never modifies files."
|
|
4
4
|
metadata:
|
|
5
5
|
author: runedev
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.4.0"
|
|
7
7
|
layer: L2
|
|
8
8
|
model: haiku
|
|
9
9
|
group: creation
|
|
10
10
|
tools: "Read, Glob, Grep"
|
|
11
11
|
emit: codebase.scanned
|
|
12
|
+
listen: agent.stuck
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
# scout
|
|
@@ -117,6 +118,36 @@ Scout's default is "max 10 file reads" — but the real question is whether addi
|
|
|
117
118
|
3. Find existing tests with `Glob`: `**/*.test.*`, `**/*.spec.*`, `**/test_*`
|
|
118
119
|
4. Determine test framework: `jest.config.*`, `vitest.config.*`, `pytest.ini`
|
|
119
120
|
|
|
121
|
+
### Phase 4.5: Zoom-Out Mode
|
|
122
|
+
|
|
123
|
+
Triggered by `mode="zoom-out"` from the caller, OR auto-triggered by listening on `agent.stuck` signal (emitted by `fix` after 2+ failed attempts on the same file, or by `debug` after 3+ disproved hypothesis cycles).
|
|
124
|
+
|
|
125
|
+
When activated, scout produces a 3-layer ascent map:
|
|
126
|
+
|
|
127
|
+
| Layer | What it includes | Cap |
|
|
128
|
+
|-------|------------------|-----|
|
|
129
|
+
| L0 (target) | The stuck file's symbols + immediate imports | unlimited |
|
|
130
|
+
| L1 (siblings) | Files in the same directory + their public exports | 8 files |
|
|
131
|
+
| L2 (callers/neighbors) | Modules that import L0's exports + neighboring modules in the same domain | 8 modules |
|
|
132
|
+
|
|
133
|
+
Output is a Mermaid diagram, NOT just a file list — visual is the value-add when an agent is stuck.
|
|
134
|
+
|
|
135
|
+
```mermaid
|
|
136
|
+
graph LR
|
|
137
|
+
target[src/auth/login.ts]:::stuck
|
|
138
|
+
target --> dep1[crypto.compare]
|
|
139
|
+
target --> dep2[db.users.get]
|
|
140
|
+
caller1[src/routes/auth.ts] --> target
|
|
141
|
+
caller2[src/middleware/protect.ts] --> target
|
|
142
|
+
sibling1[src/auth/refresh.ts] -.same-dir.- target
|
|
143
|
+
sibling2[src/auth/logout.ts] -.same-dir.- target
|
|
144
|
+
classDef stuck fill:#ff6b6b
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Bounded** — L2 ascent caps at 8 modules. If exceeded, collapse to "showing top 8 by import-frequency". Never blow past the cap silently.
|
|
148
|
+
|
|
149
|
+
After emitting the map, scout returns to its normal Phase 6 (Generate Report) with the zoom-out section as the primary output.
|
|
150
|
+
|
|
120
151
|
### Phase 5: Codebase Map (Optional)
|
|
121
152
|
|
|
122
153
|
When called by `cook`, `team`, `onboard`, or `autopsy` (skills that need full project understanding), generate a structured codebase map:
|
|
@@ -204,6 +235,7 @@ None — pure scanner using Glob, Grep, Read, and Bash tools directly. Does not
|
|
|
204
235
|
- `docs` (L2): scan codebase structure for documentation generation
|
|
205
236
|
- `logic-guardian` (L2): scan business logic modules for protection mapping
|
|
206
237
|
- `adversary` (L2): scan codebase before red-team analysis
|
|
238
|
+
- `improve-architecture` (L2): re-scan target module + callers when input context is stale
|
|
207
239
|
|
|
208
240
|
## Output Format
|
|
209
241
|
|
package/skills/surgeon/SKILL.md
CHANGED
|
@@ -26,17 +26,32 @@ Incremental refactorer that operates on ONE module per session using proven refa
|
|
|
26
26
|
## Called By (inbound)
|
|
27
27
|
|
|
28
28
|
- `rescue` (L1): Phase 2-N SURGERY — one surgery session per module
|
|
29
|
+
- `improve-architecture` (L2): hand-off with proposal payload (depth/leverage/locality target + adapter list) — surgeon executes the deepening
|
|
29
30
|
|
|
30
31
|
## Calls (outbound)
|
|
31
32
|
|
|
32
33
|
- `scout` (L2): understand module dependencies, consumers, and blast radius
|
|
33
34
|
- `safeguard` (L2): if untested module found, build safety net first
|
|
35
|
+
- `improve-architecture` (L2): if no proposal payload provided, request one before refactoring
|
|
34
36
|
- `debug` (L2): when refactoring reveals hidden bugs
|
|
35
37
|
- `fix` (L2): apply refactoring changes
|
|
36
|
-
- `test` (L2): verify after each change
|
|
38
|
+
- `test` (L2): verify after each change (REPLACE old shallow-module tests with deepened-interface tests, don't layer)
|
|
37
39
|
- `review` (L2): quality check on refactored code
|
|
38
40
|
- `journal` (L3): update rescue progress
|
|
39
41
|
|
|
42
|
+
## Consuming proposal payloads
|
|
43
|
+
|
|
44
|
+
When invoked by `improve-architecture`, surgeon receives a proposal payload (YAML) containing:
|
|
45
|
+
- `module_path` — target
|
|
46
|
+
- `current` / `target` scores (depth/leverage/locality)
|
|
47
|
+
- `dependency_category` — informs test strategy
|
|
48
|
+
- `suggested_seam` — name of the deepened interface
|
|
49
|
+
- `adapters_planned` — at least 2 adapters means a real seam; surgeon implements all listed
|
|
50
|
+
- `tests_to_replace` — old shallow-module tests; DELETE in same commit as new tests land
|
|
51
|
+
- `tests_to_write_new` — at the deepened interface
|
|
52
|
+
|
|
53
|
+
Honor the payload. If the payload's `adapters_planned` lists only 1 adapter, push back — single-adapter seam is indirection.
|
|
54
|
+
|
|
40
55
|
## Execution Steps
|
|
41
56
|
|
|
42
57
|
### Step 1 — Pre-surgery scan
|
package/skills/test/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: test
|
|
|
3
3
|
description: "TDD test writer. Writes failing tests FIRST (red), then verifies they pass after implementation (green). Covers unit, integration, and e2e tests."
|
|
4
4
|
metadata:
|
|
5
5
|
author: runedev
|
|
6
|
-
version: "1.
|
|
6
|
+
version: "1.3.0"
|
|
7
7
|
layer: L2
|
|
8
8
|
model: sonnet
|
|
9
9
|
group: development
|
|
@@ -32,6 +32,15 @@ ROLE BOUNDARY: Test writes TEST FILES only. NEVER modify source/implementation f
|
|
|
32
32
|
- Do NOT add missing exports to source files
|
|
33
33
|
- If source needs changes → hand off to `rune:fix`. Test's job ends at the test file.
|
|
34
34
|
This separation ensures test never writes code biased toward passing its own tests.
|
|
35
|
+
|
|
36
|
+
VERTICAL SLICING (Iron Law extension): one test → GREEN → one test → GREEN. Never bulk.
|
|
37
|
+
- bulk_test_count MUST stay <= 1 before the first GREEN in a session
|
|
38
|
+
- After each GREEN, bulk_test_count resets to 0; writing 2+ tests before the next GREEN = HORIZONTAL VIOLATION
|
|
39
|
+
- Each cycle MUST emit a commit pair: `test(scope): <behavior>` + `feat(scope): <behavior>`
|
|
40
|
+
- Claim "I did TDD" is verified by `completion-gate` against `git log --oneline` — no paired commits = REJECTED
|
|
41
|
+
- Horizontal slicing produces tests-of-imagination, not tests-of-behavior. See [references/vertical-tdd.md](references/vertical-tdd.md).
|
|
42
|
+
- Emit signal `tdd.horizontal.violation` when triggered; preflight blocks merge until cycles are unwound.
|
|
43
|
+
Exceptions (narrow, must be documented in test header): retrofitting characterization tests for legacy untested code; spec-driven scaffolding where the contract is external (OpenAPI, wire protocol).
|
|
35
44
|
</HARD-GATE>
|
|
36
45
|
|
|
37
46
|
## Instructions
|
|
@@ -119,6 +128,34 @@ When writing tests for async Python code:
|
|
|
119
128
|
- Missing `pytest-asyncio` makes `async def test_*` silently pass as empty coroutines
|
|
120
129
|
- Mixing sync and async fixtures can cause event loop errors
|
|
121
130
|
|
|
131
|
+
### Phase 3.5: Cycle Discipline (Vertical Slicing Gate)
|
|
132
|
+
|
|
133
|
+
Before running the new test in Phase 4, count what's about to be added to the working tree:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
bulk_test_count = (test files staged + test files unstaged but new) since the last GREEN commit
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Gate**: `bulk_test_count` MUST be exactly 1.
|
|
140
|
+
|
|
141
|
+
| State | Action |
|
|
142
|
+
|-------|--------|
|
|
143
|
+
| `bulk_test_count == 1` | Proceed to Phase 4 (run RED). |
|
|
144
|
+
| `bulk_test_count >= 2` AND no prior GREEN this session | HORIZONTAL VIOLATION — pause, keep one test, defer the rest. |
|
|
145
|
+
| `bulk_test_count >= 2` AND last GREEN exists in `git log` | HORIZONTAL VIOLATION — same. |
|
|
146
|
+
| `bulk_test_count == 0` | No test to run; this phase is a no-op. |
|
|
147
|
+
|
|
148
|
+
**Cycle audit log** — append to TEST.md (or create) one line per cycle:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
cycle 1 — RED: test_validates_email_rejects_empty | GREEN: validateEmail handles empty | commit: 4f3a1c
|
|
152
|
+
cycle 2 — RED: test_validates_email_requires_at_sign | GREEN: validateEmail checks @ | commit: a92e0d
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The audit log is the receipt. `completion-gate` reads it.
|
|
156
|
+
|
|
157
|
+
When the violation fires, do NOT delete tests automatically — surface to the calling agent: "horizontal slicing detected (N tests before first GREEN). Recommend keeping test K, deferring N-1 to subsequent cycles."
|
|
158
|
+
|
|
122
159
|
### Phase 4: Run Tests — Verify They FAIL (RED)
|
|
123
160
|
|
|
124
161
|
Use `Bash` to run ONLY the newly created test files (not full suite):
|
|
@@ -350,6 +387,8 @@ Save eval files as `skills/<name>/evals.md`. Each eval is a numbered scenario (E
|
|
|
350
387
|
| "It's about spirit not ritual" | Violating the letter IS violating the spirit. Write the test first. |
|
|
351
388
|
| "I mentally tested it" | Mental testing is not testing. Run the command, show the output. |
|
|
352
389
|
| "This is different because..." | It's not. Write the test first. |
|
|
390
|
+
| "I'll batch the tests since they're related" | Batched tests = tests of imagination. Each cycle reacts to the prior. Write one, GREEN it, then the next. |
|
|
391
|
+
| "All five tests are already written, let me just review them with you" | Same fallacy as code-before-test. Keep the first one, defer the others to subsequent cycles. |
|
|
353
392
|
|
|
354
393
|
## Advanced: Oracle-Injection E2E Testing
|
|
355
394
|
|
|
@@ -466,6 +505,8 @@ If you catch yourself with ANY of these, delete implementation code and restart
|
|
|
466
505
|
8. MUST delete implementation code written before tests — Iron Law, no exceptions
|
|
467
506
|
9. MUST show RED phase output (actual failure) — "I confirmed they fail" without output is REJECTED
|
|
468
507
|
10. MUST NOT modify source/implementation files — test writes test files ONLY, hand off source changes to rune:fix
|
|
508
|
+
11. MUST NOT write a 2nd test until the 1st test reaches GREEN — vertical slicing only, bulk_test_count <= 1 enforced
|
|
509
|
+
12. MUST emit commit pair per cycle (`test:` then `feat:`) — git log is the audit trail for "I did TDD" claims
|
|
469
510
|
|
|
470
511
|
## Mesh Gates
|
|
471
512
|
|
|
@@ -590,6 +631,10 @@ Known failure modes for this skill. Check these before declaring done.
|
|
|
590
631
|
| Introducing a new test framework instead of using existing one | MEDIUM | Constraint 6: detect framework first, use project's existing one always |
|
|
591
632
|
| Modifying source files to make tests work | HIGH | Role boundary: test writes test files ONLY — source changes go to rune:fix |
|
|
592
633
|
| Test-only methods leaking into production code | MEDIUM | Anti-Pattern 2 gate: if method only called by tests → move to test utilities |
|
|
634
|
+
| Bulk test writing before first GREEN (horizontal slicing) | CRITICAL | Phase 3.5 gate — bulk_test_count <= 1, defer additional tests to subsequent cycles |
|
|
635
|
+
| Test names describe shape (`returns boolean`, `has property`) instead of behavior | MEDIUM | Scan names for shape-words; rewrite to behavior verbs (accepts/rejects/produces). See [references/test-quality.md](references/test-quality.md) |
|
|
636
|
+
| Mocking internal collaborators in same module | HIGH | System-boundary rule from [references/mocking-policy.md](references/mocking-policy.md) — mock only what you don't own |
|
|
637
|
+
| Layering old shallow-module tests on top of new deepened-interface tests | MEDIUM | After improve-architecture deepens a module, REPLACE tests don't ADD them; one interface = one test surface |
|
|
593
638
|
|
|
594
639
|
## Self-Validation
|
|
595
640
|
|
|
@@ -612,6 +657,8 @@ SELF-VALIDATION (run before emitting Test Report):
|
|
|
612
657
|
- Coverage ≥80% verified via verification
|
|
613
658
|
- Test Report emitted with framework, test count, RED/GREEN status, and coverage
|
|
614
659
|
- Self-Validation: all checks passed
|
|
660
|
+
- Cycle audit trail intact — every RED has a paired GREEN in `git log`, no orphan tests pre-first-GREEN
|
|
661
|
+
- Test names use behavior-words (accepts/rejects/produces/...) not shape-words (returns/has property/is defined)
|
|
615
662
|
|
|
616
663
|
## Cost Profile
|
|
617
664
|
|