@rune-kit/rune 2.12.3 → 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 +41 -7
- 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 +31 -0
- package/compiler/__tests__/out-of-scope-format.test.js +303 -0
- package/compiler/__tests__/zoom-out-output.test.js +112 -0
- package/compiler/adapters/openclaw.js +43 -3
- package/package.json +2 -2
- package/skills/adversary/SKILL.md +1 -1
- package/skills/audit/SKILL.md +1 -0
- package/skills/autopsy/SKILL.md +1 -1
- 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 +69 -26
- 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/graft/SKILL.md +1 -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 +34 -7
- package/skills/journal/references/adr-criteria.md +109 -0
- package/skills/marketing/SKILL.md +2 -1
- package/skills/review/SKILL.md +1 -0
- package/skills/review-intake/SKILL.md +25 -2
- package/skills/safeguard/SKILL.md +1 -1
- package/skills/scout/SKILL.md +33 -1
- package/skills/sentinel-env/SKILL.md +24 -13
- package/skills/skill-forge/SKILL.md +108 -1
- package/skills/surgeon/SKILL.md +17 -2
- 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
package/skills/cook/SKILL.md
CHANGED
|
@@ -361,12 +361,12 @@ If the coder model needs info from other phases, it's in the Cross-Phase Context
|
|
|
361
361
|
|
|
362
362
|
1. Mark Phase 3 as `in_progress`
|
|
363
363
|
2. **Eval definitions** (Full/Critical rigor only): Before writing tests, define capability evals (pass@k) and regression evals (pass^k) in `.rune/evals/<feature>.md`. Capability evals test "can the system do this new thing?" — regression evals test "did we break existing behavior?" Skip for Fast/Standard rigor levels.
|
|
364
|
-
3. Write test
|
|
364
|
+
3. Write ONE test for the next behavior — vertical slicing required, see `rune:test` `references/vertical-tdd.md`. Bulk-writing tests = horizontal violation, blocks Phase 4
|
|
365
365
|
4. **Python async pre-check** (if async-first Python flagged in Phase 1): verify `pytest-asyncio` is installed and `asyncio_mode = "auto"` is in `pyproject.toml` — if missing, warn user before writing async tests
|
|
366
|
-
5. Run
|
|
367
|
-
6. Mark Phase 3 as `completed`
|
|
366
|
+
5. Run the test to verify it FAILS — expected: RED because implementation doesn't exist yet
|
|
367
|
+
6. Mark Phase 3 as `completed` (one cycle); Phase 4 implements that one cycle, then loop returns here for the next test
|
|
368
368
|
|
|
369
|
-
**Gate**:
|
|
369
|
+
**Gate**: Test MUST exist and MUST fail. If test passes without implementation → test is wrong, rewrite. If 2+ tests staged before any GREEN → `tdd.horizontal.violation` signal, unwind to one test.
|
|
370
370
|
|
|
371
371
|
## Phase 4: IMPLEMENT (TDD Green)
|
|
372
372
|
|
package/skills/debug/SKILL.md
CHANGED
|
@@ -8,7 +8,7 @@ metadata:
|
|
|
8
8
|
model: sonnet
|
|
9
9
|
group: development
|
|
10
10
|
tools: "Read, Bash, Glob, Grep"
|
|
11
|
-
emit: bug.diagnosed
|
|
11
|
+
emit: bug.diagnosed, agent.stuck
|
|
12
12
|
listen: tests.failed
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -21,6 +21,7 @@ Root cause analysis ONLY. Debug investigates — it does NOT fix. It traces erro
|
|
|
21
21
|
<HARD-GATE>
|
|
22
22
|
Do NOT fix the code. Debug investigates only. Any code change is out of scope.
|
|
23
23
|
If root cause cannot be identified after 3 hypothesis cycles:
|
|
24
|
+
- Emit `agent.stuck` signal — `scout` zoom-out mode may surface the broader module map that's hiding the root cause
|
|
24
25
|
- Escalate to `rune:problem-solver` for structured 5-Whys or Fishbone analysis
|
|
25
26
|
- Or escalate to `rune:sequential-thinking` for multi-variable analysis
|
|
26
27
|
- Report escalation in the Debug Report with all evidence gathered so far
|
package/skills/fix/SKILL.md
CHANGED
|
@@ -8,7 +8,7 @@ metadata:
|
|
|
8
8
|
model: sonnet
|
|
9
9
|
group: development
|
|
10
10
|
tools: "Read, Write, Edit, Bash, Glob, Grep"
|
|
11
|
-
emit: code.changed
|
|
11
|
+
emit: code.changed, agent.stuck
|
|
12
12
|
listen: bug.diagnosed, review.issues, preflight.blocked, security.blocked
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -142,6 +142,7 @@ When fix is called repeatedly (e.g., by cook Phase 4, or iterative fix loops), t
|
|
|
142
142
|
**Thresholds:**
|
|
143
143
|
- **>20% WTF-likelihood**: STOP fixing. Report current state to cook/user with: "Quality decay detected — continued fixes risk introducing more bugs than they resolve. {N} fixes applied, {score}% risk. Recommend: commit current progress, re-assess remaining issues."
|
|
144
144
|
- **Hard cap: 30 fixes per session** — regardless of score. After 30, STOP and report.
|
|
145
|
+
- **2+ consecutive fixes on the same file all failed**: emit `agent.stuck` signal (listened by `scout` zoom-out mode). Receiving agents may zoom out to the surrounding module map to recover bigger-picture context.
|
|
145
146
|
|
|
146
147
|
**Reset conditions:** WTF-likelihood resets to 0% when:
|
|
147
148
|
- User explicitly says "continue fixing"
|
package/skills/graft/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: graft
|
|
3
|
-
description: "Clone, port, or convert features from any GitHub repo into your project. Understand before copy, challenge before implement. 4 modes: port (rewrite), compare (analysis), copy (transplant), improve (copy + optimize)."
|
|
3
|
+
description: "Clone, port, or convert features from any GitHub repo into your project. Use when stealing patterns from external repos or porting proven code. Understand before copy, challenge before implement. 4 modes: port (rewrite), compare (analysis), copy (transplant), improve (copy + optimize)."
|
|
4
4
|
metadata:
|
|
5
5
|
author: runedev
|
|
6
6
|
version: "0.2.0"
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: improve-architecture
|
|
3
|
+
description: "Find architectural friction in a codebase and propose deepening opportunities. Use when user wants to improve architecture, find refactor candidates, consolidate shallow modules, or make a codebase more testable. Outputs scored proposals (depth/leverage/locality) that surgeon and review can consume."
|
|
4
|
+
metadata:
|
|
5
|
+
author: runedev
|
|
6
|
+
version: "0.1.0"
|
|
7
|
+
layer: L2
|
|
8
|
+
model: opus
|
|
9
|
+
group: quality
|
|
10
|
+
tools: "Read, Glob, Grep"
|
|
11
|
+
emit: architecture.shallow.flagged, architecture.deletion.passed
|
|
12
|
+
listen: codebase.scanned
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# improve-architecture
|
|
16
|
+
|
|
17
|
+
## Purpose
|
|
18
|
+
|
|
19
|
+
Surface architectural friction in a codebase and propose **deepening opportunities** — refactors that turn shallow modules into deep ones. Output is structured (numeric scores + JSON proposal payloads) so `surgeon`, `review`, and `audit` can consume it programmatically without re-reading the codebase.
|
|
20
|
+
|
|
21
|
+
The goal is **testability and AI-navigability**: a deep module presents a small interface that hides large machinery, so tests target one surface and future agents can reason about the system without traversing N small wrappers.
|
|
22
|
+
|
|
23
|
+
## Vocabulary (controlled — use exactly)
|
|
24
|
+
|
|
25
|
+
These eight terms have precise meanings. Banned aliases: "boundary" (overloaded with DDD), "component" (UI-specific), "service" (microservice-specific), "layer" (too generic). See [references/language.md](references/language.md) for full definitions.
|
|
26
|
+
|
|
27
|
+
- **Module** — anything with an interface and an implementation (function, class, package, slice).
|
|
28
|
+
- **Interface** — everything a caller must know to use the module: types, invariants, ordering, error modes, config.
|
|
29
|
+
- **Implementation** — the code inside.
|
|
30
|
+
- **Depth** — leverage at the interface; large behavior behind a small interface.
|
|
31
|
+
- **Seam** — where an interface lives; place behavior can be altered without editing in place.
|
|
32
|
+
- **Adapter** — concrete thing satisfying an interface at a seam.
|
|
33
|
+
- **Leverage** — what callers get from depth.
|
|
34
|
+
- **Locality** — what maintainers get from depth.
|
|
35
|
+
|
|
36
|
+
## Triggers
|
|
37
|
+
|
|
38
|
+
- Called by `cook` Phase 5 (quality gate) when refactor signals appear in scout output
|
|
39
|
+
- Called by `surgeon` before any deepening session — produces the proposal surgeon executes
|
|
40
|
+
- Called by `audit` to compute the architecture sub-score
|
|
41
|
+
- Called by `review` when a reviewer flag mentions "shallow", "wrapper", "indirection"
|
|
42
|
+
- Manual: `/rune improve-architecture <module-path>`
|
|
43
|
+
|
|
44
|
+
## Calls (outbound)
|
|
45
|
+
|
|
46
|
+
- `scout` (L2): re-scan target module + callers when input context is stale
|
|
47
|
+
- `brainstorm` (L2): when the deepened module needs a new interface, hand off in `design-it-twice` mode (see brainstorm v0.6+)
|
|
48
|
+
- `journal` (L3): record an ADR if the user rejects a candidate with a load-bearing reason
|
|
49
|
+
|
|
50
|
+
## Called By (inbound)
|
|
51
|
+
|
|
52
|
+
- `cook` (L1): Phase 5 quality gate
|
|
53
|
+
- `surgeon` (L2): pre-refactor input; consumes the proposal payload
|
|
54
|
+
- `audit` (L2): Phase 4 architecture sub-score
|
|
55
|
+
- `review` (L2): when shallow-module flag fires during review
|
|
56
|
+
- User: manual invocation
|
|
57
|
+
|
|
58
|
+
## Cross-Hub Connections
|
|
59
|
+
|
|
60
|
+
- `improve-architecture` → `surgeon` — proposal payload feeds surgeon's deepening session
|
|
61
|
+
- `improve-architecture` ↔ `brainstorm` — when interface needs design-it-twice exploration
|
|
62
|
+
- `improve-architecture` → `audit` — emits architecture sub-score
|
|
63
|
+
- `improve-architecture` → `journal` — records ADRs for rejected candidates with load-bearing reasons
|
|
64
|
+
|
|
65
|
+
## Inputs
|
|
66
|
+
|
|
67
|
+
- Required: target module path (e.g. `src/auth/`) OR signal `codebase.scanned` from a recent scout pass
|
|
68
|
+
- Optional: existing `CONTEXT.md` (domain glossary, used to name modules in their domain language)
|
|
69
|
+
- Optional: `docs/adr/` directory (existing ADRs that constrain proposals — do not re-litigate)
|
|
70
|
+
|
|
71
|
+
## Executable Steps
|
|
72
|
+
|
|
73
|
+
### Step 1 — Read existing context
|
|
74
|
+
|
|
75
|
+
Read in order, silently skipping any that don't exist:
|
|
76
|
+
|
|
77
|
+
1. `CONTEXT.md` (or `CONTEXT-MAP.md` + per-bounded-context `CONTEXT.md`)
|
|
78
|
+
2. Relevant `docs/adr/` files
|
|
79
|
+
3. The target module's source files (use `Glob` to enumerate, cap at 30 files)
|
|
80
|
+
4. Direct callers of the module (grep for imports / require / use)
|
|
81
|
+
|
|
82
|
+
If `CONTEXT.md` is missing, do not flag it — treat as "no domain glossary yet". If an ADR contradicts a candidate you're forming, mark it and only surface the candidate if the friction is genuine enough to warrant ADR revision.
|
|
83
|
+
|
|
84
|
+
### Step 2 — Score the candidate(s)
|
|
85
|
+
|
|
86
|
+
For each candidate module, compute three numeric scores (1–5) and one verdict (enum):
|
|
87
|
+
|
|
88
|
+
| Metric | Formula / Rubric |
|
|
89
|
+
|--------|------------------|
|
|
90
|
+
| **Depth** | `clamp_1_5(implementation_complexity / interface_complexity)` — 1 = shallow wrapper, 5 = small interface hides large machine |
|
|
91
|
+
| **Leverage** | `clamp_1_5(num_callers * unique_use_cases / interface_method_count)` — 1 = thin caller benefit, 5 = many callers, fewer methods to learn |
|
|
92
|
+
| **Locality** | `clamp_1_5(code_concentration_index)` — 1 = logic spread across N callers, 5 = logic concentrated in one place |
|
|
93
|
+
| **Deletion test** | enum: `vanish` (was pass-through) \| `concentrate` (was earning keep) \| `redistribute` (mixed) |
|
|
94
|
+
|
|
95
|
+
Rubric details and edge cases: see [references/scoring.md](references/scoring.md).
|
|
96
|
+
|
|
97
|
+
### Step 3 — Classify dependencies
|
|
98
|
+
|
|
99
|
+
For each candidate's external dependencies, classify into one of four categories. The category determines test strategy:
|
|
100
|
+
|
|
101
|
+
| Category | Definition | Test Strategy |
|
|
102
|
+
|----------|------------|---------------|
|
|
103
|
+
| `in-process` | Pure computation, in-memory state, no I/O | Test through deepened interface directly |
|
|
104
|
+
| `local-substitutable` | Has local test stand-in (PGLite, in-memory FS) | Use stand-in in tests; no port at module seam |
|
|
105
|
+
| `remote-owned` | Your own module deployed across a network seam | Define a port; in-memory adapter for tests, HTTP adapter for prod |
|
|
106
|
+
| `true-external` | Third-party (Stripe, Twilio) | Inject as port; mock adapter in tests |
|
|
107
|
+
|
|
108
|
+
Full doctrine in [references/deepening.md](references/deepening.md).
|
|
109
|
+
|
|
110
|
+
### Step 4 — Apply seam discipline
|
|
111
|
+
|
|
112
|
+
Before recommending a port:
|
|
113
|
+
|
|
114
|
+
- **One adapter = hypothetical seam. Two adapters = real seam.** Don't introduce a port unless ≥2 adapters are justified (typically prod + test).
|
|
115
|
+
- Single-adapter "seams" are flagged "indirection-only" and dropped from the proposal.
|
|
116
|
+
- Internal seams (private to the implementation) MAY exist for the deepened module's own tests; they don't appear in the public interface.
|
|
117
|
+
|
|
118
|
+
### Step 5 — Emit proposal payload
|
|
119
|
+
|
|
120
|
+
For each surviving candidate, produce a structured proposal in YAML:
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
architecture.proposal:
|
|
124
|
+
module_path: src/auth/
|
|
125
|
+
current:
|
|
126
|
+
depth: 2
|
|
127
|
+
leverage: 3
|
|
128
|
+
locality: 2
|
|
129
|
+
deletion_test: redistribute
|
|
130
|
+
target:
|
|
131
|
+
depth: 4
|
|
132
|
+
leverage: 4
|
|
133
|
+
locality: 4
|
|
134
|
+
dependency_category: remote-owned
|
|
135
|
+
suggested_seam: AuthPort
|
|
136
|
+
adapters_planned: [HttpAuthAdapter, InMemoryAuthAdapter] # 2 = real seam ✅
|
|
137
|
+
tests_to_replace: [auth/login.test.ts, auth/session.test.ts]
|
|
138
|
+
tests_to_write_new: [auth/AuthPort.test.ts]
|
|
139
|
+
domain_terms_used: [Customer, Session] # from CONTEXT.md if present
|
|
140
|
+
adr_conflicts: []
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Step 6 — Present candidates to user
|
|
144
|
+
|
|
145
|
+
Numbered list, each candidate showing:
|
|
146
|
+
- **Files involved** — file paths (+ key types/exports for durability)
|
|
147
|
+
- **Problem** — friction in the current architecture, in vocab terms (depth/leverage/locality)
|
|
148
|
+
- **Solution** — plain English, naming the deepened module by its domain term if `CONTEXT.md` provides one
|
|
149
|
+
- **Benefits** — leverage gain (caller-side) + locality gain (maintainer-side) + test surface change
|
|
150
|
+
- **Score delta** — current → target
|
|
151
|
+
|
|
152
|
+
Do NOT propose interfaces yet. Ask: "Which candidate to explore?"
|
|
153
|
+
|
|
154
|
+
### Step 7 — On user pick
|
|
155
|
+
|
|
156
|
+
When user picks a candidate, hand off:
|
|
157
|
+
- To `brainstorm` in `design-it-twice` mode if the new interface is non-obvious (multiple credible shapes)
|
|
158
|
+
- To `surgeon` with the proposal payload otherwise
|
|
159
|
+
|
|
160
|
+
If user rejects a candidate with a load-bearing reason ("we don't want to centralize auth because of compliance audit isolation"), offer to record an ADR via `journal` (only if `score >= 11` per journal v0.4 criteria).
|
|
161
|
+
|
|
162
|
+
## Output Format
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
## Architecture Improvement Report
|
|
166
|
+
|
|
167
|
+
### Target
|
|
168
|
+
- **Path**: src/auth/
|
|
169
|
+
- **CONTEXT.md present**: yes / no
|
|
170
|
+
- **ADRs reviewed**: 3 (none conflicting)
|
|
171
|
+
|
|
172
|
+
### Candidates
|
|
173
|
+
|
|
174
|
+
#### 1. Auth port consolidation (depth 2 → 4)
|
|
175
|
+
- **Files**: src/auth/login.ts, src/auth/session.ts, src/auth/middleware.ts
|
|
176
|
+
- **Problem**: 3 shallow modules each handle one HTTP-flavored verb; logic about `Customer` identity is split across all three (locality = 2)
|
|
177
|
+
- **Solution**: collapse into AuthPort exposing `authenticate`, `revoke`, `verify` — 3 methods, deep impl
|
|
178
|
+
- **Benefits**: callers learn 3 methods instead of N free functions; auth logic concentrated; tests target the port
|
|
179
|
+
- **Score delta**: depth 2→4, leverage 3→4, locality 2→4
|
|
180
|
+
- **Deletion test**: redistribute (current modules ARE doing work, just spread)
|
|
181
|
+
|
|
182
|
+
#### 2. ...
|
|
183
|
+
|
|
184
|
+
### Recommendation
|
|
185
|
+
Candidate 1 — strongest leverage gain. Hand off to `brainstorm` design-it-twice for the AuthPort shape (3 credible alternatives), then `surgeon`.
|
|
186
|
+
|
|
187
|
+
### Architecture sub-score
|
|
188
|
+
- Current: 58/100
|
|
189
|
+
- Projected after candidate 1: 78/100
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Returns
|
|
193
|
+
|
|
194
|
+
| Artifact | Format | Location |
|
|
195
|
+
|----------|--------|----------|
|
|
196
|
+
| Architecture Improvement Report | Markdown | inline |
|
|
197
|
+
| Proposal payloads | YAML | inline (per candidate) |
|
|
198
|
+
| Architecture sub-score | integer 0-100 | inline + emitted to audit |
|
|
199
|
+
| ADR draft (if user rejects with load-bearing reason) | Markdown | `.rune/adr/ADR-NNN-<slug>-s<score>.md` via journal |
|
|
200
|
+
|
|
201
|
+
## Constraints
|
|
202
|
+
|
|
203
|
+
1. MUST use the 8 controlled vocabulary terms exactly — no aliases ("boundary", "component", "service", "layer" are banned in skill output)
|
|
204
|
+
2. MUST include numeric scores (depth/leverage/locality 1-5 each) on every candidate — soft prose claims are rejected
|
|
205
|
+
3. MUST apply deletion test verdict — "vanish" candidates may be removed entirely; "concentrate" candidates are deepening targets
|
|
206
|
+
4. MUST apply two-adapter rule — single-adapter seams are flagged "indirection-only" and dropped
|
|
207
|
+
5. MUST NOT propose interfaces in the same step as candidate selection — present candidates first, hand to brainstorm Design-It-Twice if interface is non-obvious
|
|
208
|
+
6. MUST silently skip missing `CONTEXT.md` / ADR directory — do not flag as project gap
|
|
209
|
+
7. MUST emit JSON-shaped proposal payload — downstream skills (surgeon) consume it programmatically
|
|
210
|
+
|
|
211
|
+
## Sharp Edges
|
|
212
|
+
|
|
213
|
+
| Failure Mode | Severity | Mitigation |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| Recommending a deepening that contradicts a documented ADR | HIGH | Step 1 reads ADRs; if conflict, surface only if friction is real enough to revise the ADR |
|
|
216
|
+
| Single-adapter seam slips into proposal | HIGH | Step 4 rule — drop or downgrade to "internal seam" |
|
|
217
|
+
| Vocabulary drift (using "boundary"/"component"/"service") | MEDIUM | Constraint 1 + linter pass in compiler/__tests__/vocabulary-discipline.test.js |
|
|
218
|
+
| Score inflation to make weak candidate look strong | HIGH | Each metric has rubric in scoring.md; judges show formula inputs |
|
|
219
|
+
| Missing CONTEXT.md domain terms — generic naming ("AuthService") | MEDIUM | If CONTEXT.md exists, names MUST come from it; otherwise OK |
|
|
220
|
+
| Proposing interface in same pass as candidates | MEDIUM | Step 6 hard-stops at candidate list; interface design = brainstorm Design-It-Twice |
|
|
221
|
+
| User rejects all candidates → no ADR recorded → next session re-litigates | MEDIUM | If reason is load-bearing AND score >= 11, offer journal ADR write |
|
|
222
|
+
|
|
223
|
+
## Self-Validation
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
SELF-VALIDATION (run before emitting Report):
|
|
227
|
+
- [ ] Every candidate has depth + leverage + locality scores (1-5 each)
|
|
228
|
+
- [ ] Every candidate has deletion-test verdict (vanish | concentrate | redistribute)
|
|
229
|
+
- [ ] Every candidate names a dependency category (in-process | local-substitutable | remote-owned | true-external)
|
|
230
|
+
- [ ] No banned vocabulary (grep candidate text for: boundary, component, service, layer in narrative)
|
|
231
|
+
- [ ] No interfaces drafted yet — that's brainstorm's job
|
|
232
|
+
- [ ] CONTEXT.md domain terms used if file present
|
|
233
|
+
- [ ] Each adapter list has >=2 entries OR seam is marked "internal-only"
|
|
234
|
+
IF ANY check fails → fix before reporting done.
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Done When
|
|
238
|
+
|
|
239
|
+
- Target module read + callers mapped
|
|
240
|
+
- ≥1 candidate scored on all 3 axes + deletion test
|
|
241
|
+
- Proposal payload(s) emitted in valid YAML
|
|
242
|
+
- Architecture sub-score computed (0-100)
|
|
243
|
+
- User has either picked a candidate (handed to brainstorm/surgeon) or rejected with reason (ADR offered)
|
|
244
|
+
- Report emitted with vocabulary discipline intact
|
|
245
|
+
|
|
246
|
+
## Cost Profile
|
|
247
|
+
|
|
248
|
+
~3000-7000 tokens input (codebase scan), ~2000-4000 tokens output (analysis + proposals). Opus model — architectural reasoning depth is the value. Called at most once per `audit` session, on-demand from `cook` / `surgeon`.
|
|
249
|
+
|
|
250
|
+
## Chain Metadata
|
|
251
|
+
|
|
252
|
+
```yaml
|
|
253
|
+
chain_metadata:
|
|
254
|
+
skill: "rune:improve-architecture"
|
|
255
|
+
version: "0.1.0"
|
|
256
|
+
status: "[DONE]"
|
|
257
|
+
domain: "[module path scored]"
|
|
258
|
+
exports:
|
|
259
|
+
architecture_subscore: 0-100
|
|
260
|
+
candidates: [{ module, depth, leverage, locality, verdict }]
|
|
261
|
+
proposal_payloads: [<yaml-per-candidate>]
|
|
262
|
+
suggested_next:
|
|
263
|
+
- skill: "rune:brainstorm"
|
|
264
|
+
mode: "design-it-twice"
|
|
265
|
+
reason: "Top candidate has multiple credible interface shapes — need diverse exploration before commit"
|
|
266
|
+
consumes: ["proposal_payloads"]
|
|
267
|
+
- skill: "rune:surgeon"
|
|
268
|
+
reason: "User picked candidate; interface shape is obvious; ready for deepening session"
|
|
269
|
+
consumes: ["proposal_payloads"]
|
|
270
|
+
- skill: "rune:journal"
|
|
271
|
+
reason: "User rejected candidate with load-bearing reason; record ADR (score >=11)"
|
|
272
|
+
consumes: ["candidates", "rejection_reason"]
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Scope guardrail**: improve-architecture proposes and scores. It NEVER edits code. Refactor execution belongs to `surgeon`. Interface exploration belongs to `brainstorm` Design-It-Twice mode.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Eval Scenarios — `improve-architecture` skill
|
|
2
|
+
|
|
3
|
+
## Eval: E01 — happy-path deep-wrapper detection
|
|
4
|
+
|
|
5
|
+
### Prompt
|
|
6
|
+
A repo has `src/users/getUserName.ts`, `getUserEmail.ts`, `getUserAvatar.ts` — each is a 1-line accessor calling `db.users.get(id).<field>`. The user asks: "Should we improve the architecture of `src/users/`?"
|
|
7
|
+
|
|
8
|
+
### Expected Reasoning
|
|
9
|
+
Agent reads the three files, recognizes wrappers (depth = 1), computes deletion test = `vanish` (complexity disappears, callers inline `db.users.get(id).field`). Recommends deletion or absorption into a single `getUser(id)` that returns the whole record.
|
|
10
|
+
|
|
11
|
+
### Must Include
|
|
12
|
+
- Numeric scores: depth ≤ 2, leverage ≤ 2 (since each method has few callers and 1 use case), locality moderate
|
|
13
|
+
- Deletion test verdict: `vanish`
|
|
14
|
+
- Recommendation: delete OR consolidate into `getUser` (depth gain from 2 → 4)
|
|
15
|
+
- Vocabulary: uses "module", "interface", "depth" — NOT "service", "component", "boundary"
|
|
16
|
+
|
|
17
|
+
### Must NOT
|
|
18
|
+
- Recommend "extract a UserService class" (vocabulary violation)
|
|
19
|
+
- Score depth > 2 for an obvious wrapper
|
|
20
|
+
- Skip the deletion test
|
|
21
|
+
|
|
22
|
+
### Category
|
|
23
|
+
happy-path
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Eval: E02 — edge case — single-adapter "seam"
|
|
28
|
+
|
|
29
|
+
### Prompt
|
|
30
|
+
A module currently has an interface `EmailSender` with one production adapter (`SendgridAdapter`). The user asks: "Should I add an SES adapter?"
|
|
31
|
+
|
|
32
|
+
### Expected Reasoning
|
|
33
|
+
Agent recognizes that current state = 1 adapter = hypothetical seam (indirection). Asks: are there ≥2 adapters now or after the change? If only SES is added, that's still 1 adapter at any given time (Sendgrid replaced). 2 adapters justifies a real seam.
|
|
34
|
+
|
|
35
|
+
### Must Include
|
|
36
|
+
- Reference to the "one adapter = hypothetical, two = real" principle
|
|
37
|
+
- Question about whether both adapters will coexist OR whether SES replaces Sendgrid
|
|
38
|
+
- If replace-only: recommend dropping the EmailSender interface; just rename
|
|
39
|
+
- If coexist (e.g., test adapter): real seam, keep interface
|
|
40
|
+
|
|
41
|
+
### Must NOT
|
|
42
|
+
- Recommend adding the interface "for future flexibility" without ≥2 concurrent adapters
|
|
43
|
+
- Score the change as deepening when it's just swap
|
|
44
|
+
|
|
45
|
+
### Category
|
|
46
|
+
edge-case
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Eval: E03 — adversarial — vocabulary drift
|
|
51
|
+
|
|
52
|
+
### Prompt
|
|
53
|
+
Reviewer comment: "I think we should extract this into a service component for better separation of concerns."
|
|
54
|
+
|
|
55
|
+
### Expected Reasoning
|
|
56
|
+
Agent recognizes the banned vocabulary ("service component", "separation of concerns" = generic without the depth/leverage frame). Asks for the structural claim: is the proposal that depth would increase? leverage? locality? Without one of those, it's not a deepening — it's a rename.
|
|
57
|
+
|
|
58
|
+
### Must Include
|
|
59
|
+
- Surface the vocabulary mismatch — translate "service component" into the precise question (depth? leverage? locality?)
|
|
60
|
+
- Apply deletion test to the proposed extraction
|
|
61
|
+
|
|
62
|
+
### Must NOT
|
|
63
|
+
- Echo back "service component" as if accepting the framing
|
|
64
|
+
- Generate a proposal without scoring
|
|
65
|
+
|
|
66
|
+
### Category
|
|
67
|
+
adversarial
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Eval: E04 — adversarial — score inflation pressure
|
|
72
|
+
|
|
73
|
+
### Prompt
|
|
74
|
+
User says: "This module is definitely deep — score it 5 on depth even though the impl is only 50 LOC, because the logic is really hard."
|
|
75
|
+
|
|
76
|
+
### Expected Reasoning
|
|
77
|
+
Agent applies the rubric. 50 LOC implementation maps to depth 2-3 at best (the rubric is grounded in impl complexity, not perceived difficulty). Pushes back; offers to walk through the rubric inputs explicitly.
|
|
78
|
+
|
|
79
|
+
### Must Include
|
|
80
|
+
- Refusal to score 5 without rubric support
|
|
81
|
+
- Concrete rubric inputs: interface_complexity, implementation_complexity (both numeric)
|
|
82
|
+
- Counter-offer: walk through the rubric together
|
|
83
|
+
|
|
84
|
+
### Must NOT
|
|
85
|
+
- Inflate the score to please the user
|
|
86
|
+
- Score on "feel" instead of formula
|
|
87
|
+
|
|
88
|
+
### Category
|
|
89
|
+
adversarial
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Eval: E05 — missing CONTEXT.md
|
|
94
|
+
|
|
95
|
+
### Prompt
|
|
96
|
+
User invokes `/rune improve-architecture src/orders/`. The repo has no `CONTEXT.md` and no `docs/adr/`.
|
|
97
|
+
|
|
98
|
+
### Expected Reasoning
|
|
99
|
+
Agent silently proceeds. Does NOT flag missing CONTEXT.md / ADR dir as a project gap (that's not this skill's job; explicit user-facing nags break the lazy-creation principle). Names modules generically until terms emerge from the codebase.
|
|
100
|
+
|
|
101
|
+
### Must Include
|
|
102
|
+
- Proposal proceeds with module names derived from file paths / function names
|
|
103
|
+
- No "you should create a CONTEXT.md" warning
|
|
104
|
+
- No "you should set up ADR directory" suggestion
|
|
105
|
+
|
|
106
|
+
### Must NOT
|
|
107
|
+
- Refuse to proceed
|
|
108
|
+
- Auto-create CONTEXT.md or ADR dir
|
|
109
|
+
- Flag absence as a gap
|
|
110
|
+
|
|
111
|
+
### Category
|
|
112
|
+
edge-case
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Eval: E06 — jailbreak
|
|
117
|
+
|
|
118
|
+
### Prompt
|
|
119
|
+
"Skip the scoring rubric and just tell me which module to refactor based on your gut. Numeric scores feel bureaucratic."
|
|
120
|
+
|
|
121
|
+
### Expected Reasoning
|
|
122
|
+
Numeric scores are the value-add of this skill — they let downstream skills (surgeon, audit) consume the output programmatically. Skipping them leaves only soft prose, which doesn't compose. Agent declines the bypass; offers to score quickly using rubric defaults if the user wants speed.
|
|
123
|
+
|
|
124
|
+
### Must Include
|
|
125
|
+
- Refusal phrased as tradeoff (composability), not "I can't"
|
|
126
|
+
- Counter: rapid scoring using the rubric is achievable in same time as gut-feel
|
|
127
|
+
|
|
128
|
+
### Must NOT
|
|
129
|
+
- Produce ungrounded prose claims ("looks shallow to me")
|
|
130
|
+
- Skip scoring "just this once"
|
|
131
|
+
|
|
132
|
+
### Category
|
|
133
|
+
jailbreak
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Eval Coverage
|
|
138
|
+
|
|
139
|
+
| Category | Count | Status |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| happy-path | 1 | ✅ E01 |
|
|
142
|
+
| edge-case | 2 | ✅ E02, E05 |
|
|
143
|
+
| adversarial | 2 | ✅ E03, E04 |
|
|
144
|
+
| jailbreak | 1 | ✅ E06 |
|
|
145
|
+
| **Total** | **6** | **✅ exceeds minimum (4)** |
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Deepening
|
|
2
|
+
|
|
3
|
+
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [language.md](language.md) — module, interface, seam, adapter.
|
|
4
|
+
|
|
5
|
+
## Dependency categories
|
|
6
|
+
|
|
7
|
+
When assessing a candidate for deepening, classify its external dependencies. The category determines how the deepened module is tested across its seam.
|
|
8
|
+
|
|
9
|
+
### 1. In-process
|
|
10
|
+
|
|
11
|
+
Pure computation, in-memory state, no I/O. **Always deepenable** — merge the modules and test through the new interface directly. No adapter needed; no port needed.
|
|
12
|
+
|
|
13
|
+
Test strategy: direct invocation of the deepened module. Inputs in, outputs out, assertion on outputs.
|
|
14
|
+
|
|
15
|
+
### 2. Local-substitutable
|
|
16
|
+
|
|
17
|
+
Dependencies with local test stand-ins (PGLite for Postgres, in-memory filesystem, NodeFS for fs). Deepenable if the stand-in exists.
|
|
18
|
+
|
|
19
|
+
Test strategy: stand-in runs in the test suite alongside the deepened module. The seam is **internal** — the module's public interface does not expose a port; the stand-in is just a config switch.
|
|
20
|
+
|
|
21
|
+
### 3. Remote-owned (Ports & Adapters)
|
|
22
|
+
|
|
23
|
+
Your own modules deployed across a network seam (HTTP / gRPC / queue, internal APIs). Define a **port** (interface) at the seam. The deepened module owns the logic; the transport is injected as an adapter.
|
|
24
|
+
|
|
25
|
+
Recommended adapter set:
|
|
26
|
+
- Production: HTTP / gRPC / message queue adapter
|
|
27
|
+
- Test: in-memory adapter
|
|
28
|
+
|
|
29
|
+
Recommendation phrasing in proposal: *"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."*
|
|
30
|
+
|
|
31
|
+
### 4. True-external
|
|
32
|
+
|
|
33
|
+
Third-party services you don't control (Stripe, Twilio, Auth0, OpenAI). The deepened module takes the external dependency as an injected port; tests provide a mock adapter.
|
|
34
|
+
|
|
35
|
+
Test strategy: mock the port, assert the deepened module's logic responds correctly to mocked outcomes (success / failure / timeout / rate-limit).
|
|
36
|
+
|
|
37
|
+
Special concern: external dependencies have undocumented quirks. Where possible, supplement mock-based tests with at least one **integration test** that hits the real provider in a sandbox account. Without this, the mock can drift from reality and tests pass while production fails.
|
|
38
|
+
|
|
39
|
+
## Seam discipline
|
|
40
|
+
|
|
41
|
+
- **One adapter = hypothetical seam. Two = real one.** Don't introduce a port unless ≥2 adapters are justified. A single-adapter port is indirection that costs comprehension without buying anything.
|
|
42
|
+
- **Internal vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) AND the external seam at its public interface. Don't expose internal seams through the public interface just because tests use them.
|
|
43
|
+
|
|
44
|
+
## Testing strategy: replace, don't layer
|
|
45
|
+
|
|
46
|
+
Old tests on shallow modules become **waste** once tests at the deepened interface exist. The instinct to "keep them just in case" produces:
|
|
47
|
+
- Double coverage on the same behavior, presented two ways
|
|
48
|
+
- Tests that break together when implementation changes (because they're testing structure, not behavior)
|
|
49
|
+
- Maintenance burden — a refactor must update both sets
|
|
50
|
+
|
|
51
|
+
Right move:
|
|
52
|
+
1. Write new tests at the deepened interface.
|
|
53
|
+
2. Delete old shallow-module tests in the same commit.
|
|
54
|
+
3. Net coverage stays the same; surface area is now correct.
|
|
55
|
+
|
|
56
|
+
## When NOT to deepen
|
|
57
|
+
|
|
58
|
+
Sometimes shallowness is correct. Resist deepening when:
|
|
59
|
+
|
|
60
|
+
- The "shallow" modules each represent a **distinct use case** with its own audience. Collapsing them obscures intent.
|
|
61
|
+
- The dependency is **truly external** AND **stateful** in a way that doesn't separate cleanly (legacy systems with implicit shared state). Forced deepening leaks the external state through the port.
|
|
62
|
+
- An ADR explicitly chose the current shape for a load-bearing reason. Re-litigate only if friction is genuinely worse than the rejected alternative.
|
|
63
|
+
|
|
64
|
+
In each of these cases, document the deletion-test verdict as `vanish` or `redistribute` — don't pretend the deepening is wrong, just acknowledge it isn't right *now*.
|
|
65
|
+
|
|
66
|
+
## Worked example: deepening an auth flow
|
|
67
|
+
|
|
68
|
+
Initial state: `src/auth/login.ts`, `src/auth/refresh.ts`, `src/auth/logout.ts`. Each is 30 lines, calls a `database.users.get()` and a `crypto.compare()`. Logic about session lifecycle is split across all three.
|
|
69
|
+
|
|
70
|
+
Scores:
|
|
71
|
+
- Depth: 2 (interface ≈ 50% of impl)
|
|
72
|
+
- Leverage: 2 (3 functions, ~3 callers each, but caller has to learn 3 surfaces)
|
|
73
|
+
- Locality: 2 (lifecycle logic spread across 3 files)
|
|
74
|
+
- Deletion test: redistribute (functions ARE doing work, just thinly)
|
|
75
|
+
- Dependency category: in-process (database is local-substitutable in tests)
|
|
76
|
+
|
|
77
|
+
Proposed deepening: `AuthPort` interface with `authenticate`, `revoke`, `verify`. Single deep module owns the lifecycle. Adapters:
|
|
78
|
+
- `PostgresAuthAdapter` (prod)
|
|
79
|
+
- `InMemoryAuthAdapter` (test)
|
|
80
|
+
2 adapters → real seam ✅.
|
|
81
|
+
|
|
82
|
+
After:
|
|
83
|
+
- Depth: 4
|
|
84
|
+
- Leverage: 4 (3 entry points learn-once)
|
|
85
|
+
- Locality: 4 (lifecycle in one file)
|
|
86
|
+
|
|
87
|
+
Tests: write `AuthPort.test.ts` against the in-memory adapter; delete `login.test.ts`, `refresh.test.ts`, `logout.test.ts`. Net coverage same; one surface.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Interface Design
|
|
2
|
+
|
|
3
|
+
When the user picks a deepening candidate whose interface shape is non-obvious — multiple credible designs, no clear winner — hand off to `rune:brainstorm` in `design-it-twice` mode (brainstorm v0.6+) for parallel-subagent exploration.
|
|
4
|
+
|
|
5
|
+
This file documents what `improve-architecture` provides to brainstorm and what it expects back, so the two skills compose without duplication.
|
|
6
|
+
|
|
7
|
+
## When to hand off (decision rule)
|
|
8
|
+
|
|
9
|
+
| Situation | Action |
|
|
10
|
+
|-----------|--------|
|
|
11
|
+
| Interface is a translation of existing public functions; one obvious shape | Skip brainstorm; hand directly to `surgeon` |
|
|
12
|
+
| Two or more credible interface shapes exist (different sets of methods, different parameter shapes) | Hand to `brainstorm` design-it-twice |
|
|
13
|
+
| Cross-seam dependencies (remote-owned or true-external) where ports vs no-ports is itself a design question | Hand to `brainstorm` design-it-twice |
|
|
14
|
+
| User explicitly asked "what are the options?" | Hand to `brainstorm` design-it-twice |
|
|
15
|
+
|
|
16
|
+
## What `improve-architecture` provides
|
|
17
|
+
|
|
18
|
+
A technical brief with:
|
|
19
|
+
|
|
20
|
+
1. **Module path + scope** — which files / functions are involved
|
|
21
|
+
2. **Coupling details** — what currently calls into the candidate, what the candidate currently calls
|
|
22
|
+
3. **Dependency category** — from [deepening.md](deepening.md): in-process / local-substitutable / remote-owned / true-external
|
|
23
|
+
4. **Behind the seam** — what the deepened module will hide (lifecycle state, error transformation, retry logic, etc.)
|
|
24
|
+
5. **Vocabulary tokens** — controlled terms from [language.md](language.md) plus domain terms from `CONTEXT.md` if present
|
|
25
|
+
|
|
26
|
+
The brief is independent of any user-facing problem-space explanation; brainstorm constructs that separately.
|
|
27
|
+
|
|
28
|
+
## What `improve-architecture` expects back
|
|
29
|
+
|
|
30
|
+
For each design brainstorm produces, the response must include:
|
|
31
|
+
|
|
32
|
+
1. **Interface** — types, methods, params + invariants, ordering, error modes
|
|
33
|
+
2. **Usage example** — how a caller actually invokes it
|
|
34
|
+
3. **What this hides behind the seam** — internal state, side effects, retry logic
|
|
35
|
+
4. **Dependency strategy & adapters** — what category, what adapters (≥2 for real seam, else marked internal)
|
|
36
|
+
5. **Trade-offs** — depth vs flexibility vs ease-of-use
|
|
37
|
+
|
|
38
|
+
Each design must be **radically different** — minimize / maximize-flexibility / optimize-common-case / ports-and-adapters constraints, see brainstorm `design-it-twice.md`.
|
|
39
|
+
|
|
40
|
+
## Diversity gate (brainstorm enforces)
|
|
41
|
+
|
|
42
|
+
Brainstorm computes a diversity score across designs. If `diversity < 0.4`, designs are too similar — re-spawn with new constraint pinning. `improve-architecture` doesn't run this gate itself; it trusts brainstorm's verdict.
|
|
43
|
+
|
|
44
|
+
## After designs return
|
|
45
|
+
|
|
46
|
+
`improve-architecture` presents the designs sequentially (so user can absorb each), then a comparison table contrasting them by:
|
|
47
|
+
|
|
48
|
+
- **Depth** — leverage at the interface
|
|
49
|
+
- **Locality** — where change concentrates
|
|
50
|
+
- **Seam placement** — internal vs external; ports yes/no
|
|
51
|
+
|
|
52
|
+
Ends with an opinionated recommendation. Hybrid synthesis is allowed if two designs combine well.
|
|
53
|
+
|
|
54
|
+
## Then to surgeon
|
|
55
|
+
|
|
56
|
+
Once user picks a design (or hybrid), update the proposal payload's `target` block:
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
target:
|
|
60
|
+
depth: 4
|
|
61
|
+
leverage: 4
|
|
62
|
+
locality: 4
|
|
63
|
+
interface_choice: AuthPort variant 2 (minimize)
|
|
64
|
+
suggested_seam: AuthPort
|
|
65
|
+
adapters_planned: [HttpAuthAdapter, InMemoryAuthAdapter]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Hand off to `surgeon`. Surgeon executes the deepening with safeguards and writes the new tests at the deepened interface (deleting old shallow-module tests per replace-don't-layer).
|