@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.
Files changed (41) hide show
  1. package/README.md +23 -12
  2. package/compiler/__tests__/adr-scoring.test.js +91 -0
  3. package/compiler/__tests__/context-md-format.test.js +180 -0
  4. package/compiler/__tests__/context-pack-smell-tests.test.js +215 -0
  5. package/compiler/__tests__/diversity-score.test.js +117 -0
  6. package/compiler/__tests__/improve-architecture.test.js +171 -0
  7. package/compiler/__tests__/openclaw-adapter.test.js +11 -6
  8. package/compiler/__tests__/out-of-scope-format.test.js +303 -0
  9. package/compiler/__tests__/zoom-out-output.test.js +112 -0
  10. package/package.json +2 -2
  11. package/skills/audit/SKILL.md +1 -0
  12. package/skills/ba/SKILL.md +241 -82
  13. package/skills/ba/references/context-md-format.md +136 -0
  14. package/skills/ba/references/explore-first.md +107 -0
  15. package/skills/ba/references/out-of-scope-format.md +152 -0
  16. package/skills/brainstorm/SKILL.md +77 -1
  17. package/skills/brainstorm/references/design-it-twice.md +155 -0
  18. package/skills/context-pack/SKILL.md +68 -25
  19. package/skills/context-pack/evals.md +122 -0
  20. package/skills/context-pack/references/brief-template.md +121 -0
  21. package/skills/context-pack/references/durability-rules.md +109 -0
  22. package/skills/cook/SKILL.md +4 -4
  23. package/skills/debug/SKILL.md +2 -1
  24. package/skills/fix/SKILL.md +2 -1
  25. package/skills/improve-architecture/SKILL.md +275 -0
  26. package/skills/improve-architecture/evals.md +145 -0
  27. package/skills/improve-architecture/references/deepening.md +87 -0
  28. package/skills/improve-architecture/references/interface-design.md +68 -0
  29. package/skills/improve-architecture/references/language.md +81 -0
  30. package/skills/improve-architecture/references/scoring.md +122 -0
  31. package/skills/journal/SKILL.md +33 -6
  32. package/skills/journal/references/adr-criteria.md +109 -0
  33. package/skills/review/SKILL.md +1 -0
  34. package/skills/review-intake/SKILL.md +25 -2
  35. package/skills/scout/SKILL.md +33 -1
  36. package/skills/surgeon/SKILL.md +16 -1
  37. package/skills/test/SKILL.md +48 -1
  38. package/skills/test/evals.md +137 -0
  39. package/skills/test/references/mocking-policy.md +121 -0
  40. package/skills/test/references/test-quality.md +124 -0
  41. 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.
@@ -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.3.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
- 1. Generate an ADR filename: `.rune/adr/ADR-[NNN]-[slug].md` where NNN is the next sequential number
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 with rationale
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.
@@ -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.1.0"
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
@@ -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.3.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
 
@@ -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
@@ -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.2.0"
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