@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,155 @@
|
|
|
1
|
+
# Design-It-Twice Mode
|
|
2
|
+
|
|
3
|
+
Force genuine architectural diversity when exploring alternative interfaces or module shapes. Spawns parallel subagents, each pinned to a *radically different* design constraint, then computes a diversity score before presenting results.
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
| Situation | Use Design-It-Twice |
|
|
8
|
+
|-----------|---------------------|
|
|
9
|
+
| Multiple credible interface shapes for a deepening candidate (from `improve-architecture`) | ✅ |
|
|
10
|
+
| User asked "what are the options for designing X?" | ✅ |
|
|
11
|
+
| Ports vs no-ports decision is itself a design question | ✅ |
|
|
12
|
+
| Cross-seam dependencies (remote-owned, true-external) where adapter choice matters | ✅ |
|
|
13
|
+
| One obvious interface shape — translation of existing public functions | ❌ Skip; go directly to surgeon/fix |
|
|
14
|
+
| Single-method utility | ❌ Skip; not enough surface to design twice |
|
|
15
|
+
|
|
16
|
+
## The four standard constraints
|
|
17
|
+
|
|
18
|
+
Each parallel subagent is pinned to exactly one constraint via the spawn prompt. The constraints are deliberately incompatible — that's where the diversity comes from.
|
|
19
|
+
|
|
20
|
+
| ID | Constraint | What it produces |
|
|
21
|
+
|----|------------|------------------|
|
|
22
|
+
| `C1` | **Minimize interface** — aim for 1–3 entry points; maximize leverage per entry | Smallest interface; deep impl; few callers learn the surface |
|
|
23
|
+
| `C2` | **Maximize flexibility** — support many use cases, plugin/extension surface | Wide interface; configurable; extension points |
|
|
24
|
+
| `C3` | **Optimize common case** — make default trivial; rare cases pay cost | Tiny default; opt-in complexity for power users |
|
|
25
|
+
| `C4` | **Ports & adapters** — design seams for cross-boundary swap | Explicit ports; multiple adapter slots |
|
|
26
|
+
|
|
27
|
+
For most cases pick 3 of 4. Add C4 only when the dependency category (from `improve-architecture/references/deepening.md`) is `remote-owned` or `true-external`.
|
|
28
|
+
|
|
29
|
+
## Subagent spawn template
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
You are designing an interface for: <module description>
|
|
33
|
+
|
|
34
|
+
Current state:
|
|
35
|
+
files: <file list>
|
|
36
|
+
callers: <caller summary>
|
|
37
|
+
current_depth: <1-5>
|
|
38
|
+
dependency_category: <in-process | local-substitutable | remote-owned | true-external>
|
|
39
|
+
what_to_hide: <state, lifecycle, retry, error transformation>
|
|
40
|
+
|
|
41
|
+
Constraint: <C1 | C2 | C3 | C4>
|
|
42
|
+
<constraint description from the table above>
|
|
43
|
+
|
|
44
|
+
Output (YAML):
|
|
45
|
+
interface:
|
|
46
|
+
name: <DeepenedModuleName>
|
|
47
|
+
methods:
|
|
48
|
+
- signature: <method signature>
|
|
49
|
+
invariants: [<invariant 1>, <invariant 2>]
|
|
50
|
+
errors: [<error case 1>, <error case 2>]
|
|
51
|
+
usage_example: |
|
|
52
|
+
<code showing how a caller invokes the interface>
|
|
53
|
+
hides_behind_seam:
|
|
54
|
+
- <complexity 1 hidden inside the implementation>
|
|
55
|
+
- <complexity 2>
|
|
56
|
+
dependency_strategy:
|
|
57
|
+
category: <category>
|
|
58
|
+
adapters: [<adapter1>, <adapter2>]
|
|
59
|
+
seam_real: <true if adapters >= 2, false if 1 (downgrade to internal seam)>
|
|
60
|
+
tradeoffs:
|
|
61
|
+
leverage: <1-5 + 1-line justification>
|
|
62
|
+
flexibility: <1-5 + 1-line justification>
|
|
63
|
+
common_case_simplicity: <1-5 + 1-line justification>
|
|
64
|
+
|
|
65
|
+
Vocabulary: use the controlled terms from rune:improve-architecture/references/language.md
|
|
66
|
+
(module, interface, seam, adapter, leverage, locality)
|
|
67
|
+
Do NOT use "boundary", "component", "service", or "layer" in narrative.
|
|
68
|
+
|
|
69
|
+
Domain terms: <if CONTEXT.md present, list its glossary terms here so the design uses them>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Diversity gate (machine-checked)
|
|
73
|
+
|
|
74
|
+
After all subagents return, compute pairwise similarity over feature vectors:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
feature_vector(design) = [
|
|
78
|
+
count(interface.methods),
|
|
79
|
+
count(distinct_return_types),
|
|
80
|
+
count(unique_adapter_kinds),
|
|
81
|
+
count(unique_dependencies),
|
|
82
|
+
paradigm_tag, // "minimal" | "extensible" | "default-light" | "ports-adapters"
|
|
83
|
+
has_async_methods, // bool → 0/1
|
|
84
|
+
has_streaming, // bool → 0/1
|
|
85
|
+
]
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Diversity score:
|
|
89
|
+
```
|
|
90
|
+
similarity(d_i, d_j) = jaccard(feature_vector(d_i), feature_vector(d_j))
|
|
91
|
+
diversity = 1 - mean(similarity(d_i, d_j) for all i < j)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
| Diversity | Action |
|
|
95
|
+
|-----------|--------|
|
|
96
|
+
| ≥ 0.6 | Proceed to presentation |
|
|
97
|
+
| 0.4 – 0.59 | Marginal; surface to user — "designs are similar in [shared trait]; want me to re-spawn with different constraints?" |
|
|
98
|
+
| < 0.4 | Re-spawn with rotated constraints (e.g., swap C2 → C4); 1 retry max before giving up |
|
|
99
|
+
|
|
100
|
+
`diversity_floor = 0.4` is conservative; tune in v0.7+ once usage telemetry exists.
|
|
101
|
+
|
|
102
|
+
## Presentation order
|
|
103
|
+
|
|
104
|
+
1. Each design alone (sequential, so user can absorb each in isolation)
|
|
105
|
+
2. Comparison table contrasting designs by:
|
|
106
|
+
- **Depth** — leverage at the interface
|
|
107
|
+
- **Locality** — where change concentrates
|
|
108
|
+
- **Seam placement** — internal vs external; ports yes/no
|
|
109
|
+
- **Common-case trivial-ness** — how much work for the default path
|
|
110
|
+
3. **Opinionated recommendation** — strongest design + concrete hedge condition for when to pick a different one
|
|
111
|
+
4. **Hybrid synthesis (optional Step 4.5)** — if 2 designs have complementary strengths, propose a 4th synthesized option that combines them
|
|
112
|
+
|
|
113
|
+
Skip the comparison table if N=2 (just 1 contrast, prose handles it).
|
|
114
|
+
|
|
115
|
+
## "It depends" is BLOCKED
|
|
116
|
+
|
|
117
|
+
The recommendation step requires a concrete recommendation with a hedge:
|
|
118
|
+
|
|
119
|
+
✅ "Recommend C1 (minimize interface). Choose C3 (optimize common case) if you discover most callers only need the default path."
|
|
120
|
+
|
|
121
|
+
❌ "It depends on your priorities."
|
|
122
|
+
|
|
123
|
+
If you genuinely can't pick between two designs, propose the hybrid (Step 4.5) and recommend that as the default.
|
|
124
|
+
|
|
125
|
+
## Hybrid synthesis (Step 4.5 — optional)
|
|
126
|
+
|
|
127
|
+
When two designs have complementary strengths (e.g., C1's leverage + C4's seam discipline), propose a 4th option that combines them:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
Option D (Hybrid C1 + C4):
|
|
131
|
+
- Interface: 3 methods (from C1's minimization)
|
|
132
|
+
- Adapters: HttpAdapter + InMemoryAdapter (from C4's port discipline)
|
|
133
|
+
- Pros: small surface AND testable across the seam
|
|
134
|
+
- Cons: more upfront design work; locks the port early
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Hybrid synthesis is **opt-in**. If no two designs have clear complementary strengths, skip this step.
|
|
138
|
+
|
|
139
|
+
## Cost note
|
|
140
|
+
|
|
141
|
+
4 parallel opus subagents is the most expensive thing this skill does. Use Design-It-Twice mode only when `improve-architecture` flags a candidate worth deepening (multiple credible interfaces). Default Discovery mode is cheaper for ordinary brainstorming.
|
|
142
|
+
|
|
143
|
+
## Output schema (chain_metadata)
|
|
144
|
+
|
|
145
|
+
```yaml
|
|
146
|
+
chain_metadata:
|
|
147
|
+
skill: "rune:brainstorm"
|
|
148
|
+
mode: "design-it-twice"
|
|
149
|
+
exports:
|
|
150
|
+
designs: [<yaml-per-design>]
|
|
151
|
+
diversity_score: 0-1
|
|
152
|
+
constraints_used: [C1, C2, C4]
|
|
153
|
+
recommendation: <design-id>
|
|
154
|
+
hybrid_proposed: <true|false>
|
|
155
|
+
```
|
|
@@ -4,7 +4,7 @@ description: "Creates structured handoff briefings between agents. Use when dele
|
|
|
4
4
|
user-invocable: false
|
|
5
5
|
metadata:
|
|
6
6
|
author: runedev
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.2.0"
|
|
8
8
|
layer: L3
|
|
9
9
|
model: haiku
|
|
10
10
|
group: state
|
|
@@ -52,12 +52,13 @@ When a parent agent delegates work to a subagent, critical context gets lost —
|
|
|
52
52
|
## Workflow
|
|
53
53
|
|
|
54
54
|
1. **COLLECT** — Gather context from the current conversation:
|
|
55
|
-
- Task description and user intent
|
|
55
|
+
- Task description and user intent (verb-led behavioral phrasing)
|
|
56
56
|
- Decisions already made (and WHY)
|
|
57
57
|
- Constraints and hard-stops
|
|
58
58
|
- Failed attempts (what NOT to do)
|
|
59
59
|
- Files already read or modified
|
|
60
60
|
- Current progress state
|
|
61
|
+
- **Type Surface** — types / function signatures / contracts that callers cross. These are the durable spine of the brief.
|
|
61
62
|
|
|
62
63
|
2. **COMPRESS** — Reduce to essential information:
|
|
63
64
|
- Strip conversational noise
|
|
@@ -65,46 +66,74 @@ When a parent agent delegates work to a subagent, critical context gets lost —
|
|
|
65
66
|
- Prioritize by relevance to the delegated task
|
|
66
67
|
- Target: <500 tokens for simple tasks, <1500 tokens for complex
|
|
67
68
|
|
|
68
|
-
3. **STRUCTURE** — Format as a context packet (see Output Format)
|
|
69
|
+
3. **STRUCTURE** — Format as a context packet (v2 — see Output Format and [references/brief-template.md](references/brief-template.md))
|
|
69
70
|
|
|
70
71
|
4. **VALIDATE** — Check packet completeness:
|
|
71
72
|
- Does it include the task goal?
|
|
72
73
|
- Does it include constraints that could cause failure?
|
|
73
74
|
- Does it include what was already tried?
|
|
75
|
+
- Does it include `### Out of scope`? (mandatory)
|
|
76
|
+
- Does it include `### Type Surface` (mandatory if task >= 300 tokens)?
|
|
74
77
|
- Is it small enough for the target agent's context budget?
|
|
75
78
|
|
|
76
|
-
|
|
79
|
+
5. **PHASE 4.5 — SMELL TESTS** — Run mechanical regex gates before emit. See [references/durability-rules.md](references/durability-rules.md).
|
|
80
|
+
|
|
81
|
+
| Regex | Tier | Reason |
|
|
82
|
+
|-------|------|--------|
|
|
83
|
+
| `\b\S+\.[a-z]{1,4}:\d+\b` | BLOCK | file:line reference (e.g., `login.ts:42`) — line numbers go stale |
|
|
84
|
+
| `^- \S*[\\/]\S+\.(ts\|js\|py\|go\|rs\|java)\b` outside `### Files Touched` | BLOCK | Path-only bullet in narrative |
|
|
85
|
+
| `\b(line \|on line )\d+\b` | BLOCK | "line 42" / "on line 100" |
|
|
86
|
+
| `\b(src\|lib\|app)/\S+` in narrative paragraphs | WARN | Path mention; verify it belongs in Files Touched section |
|
|
87
|
+
|
|
88
|
+
<HARD-GATE>
|
|
89
|
+
Any BLOCK-tier match → DO NOT emit. Rewrite the offending lines to use type/function/module names.
|
|
90
|
+
Missing `### Out of scope` section → DO NOT emit (completion-gate rejects).
|
|
91
|
+
Missing `### Type Surface` for tasks >= 300 tokens → DO NOT emit.
|
|
92
|
+
</HARD-GATE>
|
|
93
|
+
|
|
94
|
+
6. **EMIT** — Send the validated packet to the receiving agent.
|
|
95
|
+
|
|
96
|
+
## Output Format (v2)
|
|
77
97
|
|
|
78
98
|
```markdown
|
|
79
99
|
## Context Packet
|
|
80
100
|
|
|
81
|
-
**Task**: [One-line description
|
|
82
|
-
**Parent**: [
|
|
83
|
-
**Scope**: [
|
|
101
|
+
**Task**: [One-line behavioral description, verb-led]
|
|
102
|
+
**Parent**: [delegating skill]
|
|
103
|
+
**Scope**: [type names / module names — NOT file paths]
|
|
84
104
|
|
|
85
105
|
### Decisions Made
|
|
86
|
-
- [Decision
|
|
87
|
-
- [Decision 2]: [choice] — because [reason]
|
|
106
|
+
- [Decision]: chose [X] over [Y] because [reason]
|
|
88
107
|
|
|
89
108
|
### Constraints
|
|
90
|
-
- MUST: [
|
|
91
|
-
- MUST NOT: [prohibition
|
|
92
|
-
- BLOCKED BY: [dependency,
|
|
109
|
+
- MUST: [behavioral assertion]
|
|
110
|
+
- MUST NOT: [behavioral prohibition]
|
|
111
|
+
- BLOCKED BY: [contract dependency, not file path]
|
|
93
112
|
|
|
94
113
|
### Already Tried
|
|
95
|
-
- [
|
|
114
|
+
- [approach] — [observable failure mode]
|
|
96
115
|
|
|
97
|
-
###
|
|
98
|
-
- `
|
|
116
|
+
### Type Surface (durable)
|
|
117
|
+
- `TypeName { field: type }` — [what it represents]
|
|
118
|
+
- `Module.method(input: T): Result<O, E>` — [contract]
|
|
99
119
|
|
|
100
|
-
###
|
|
101
|
-
-
|
|
102
|
-
|
|
120
|
+
### Files Touched (locator-only, may rename)
|
|
121
|
+
- `path/to/file.ts` (TypeName, Module.method) — [behavioral hint]
|
|
122
|
+
|
|
123
|
+
### Acceptance Criteria
|
|
124
|
+
- [ ] [verb-led testable statement starting with: accepts, rejects, produces, notifies, persists, retries, times-out, validates, returns, dispatches, redirects, throws, logs, increments, decrements, retrieves, emits, caches, invalidates, authenticates]
|
|
125
|
+
- [ ] ...
|
|
126
|
+
|
|
127
|
+
### Out of scope
|
|
128
|
+
- [Thing the receiver should NOT do]
|
|
129
|
+
- (or "(none)" if explicitly empty)
|
|
103
130
|
|
|
104
131
|
### Progress
|
|
105
|
-
- [
|
|
132
|
+
- [partial state if mid-handoff — omit if fresh start]
|
|
106
133
|
```
|
|
107
134
|
|
|
135
|
+
Full template + worked examples: [references/brief-template.md](references/brief-template.md).
|
|
136
|
+
|
|
108
137
|
## Returns
|
|
109
138
|
|
|
110
139
|
| Field | Type | Description |
|
|
@@ -116,32 +145,46 @@ When a parent agent delegates work to a subagent, critical context gets lost —
|
|
|
116
145
|
|
|
117
146
|
## Constraints
|
|
118
147
|
|
|
119
|
-
1. MUST include task goal and
|
|
148
|
+
1. MUST include task goal and acceptance criteria — subagent needs to know when it's done
|
|
120
149
|
2. MUST include failed attempts — prevents subagent from repeating mistakes
|
|
121
150
|
3. MUST include hard-stop constraints — prevents constraint violations in delegated work
|
|
122
151
|
4. MUST NOT exceed 2000 tokens — context packets that are too large defeat the purpose
|
|
123
|
-
5. MUST NOT include full file contents — use
|
|
152
|
+
5. MUST NOT include full file contents — use type names + summaries instead
|
|
124
153
|
6. MUST NOT fabricate context — only include information from the actual conversation
|
|
154
|
+
7. MUST emit `### Out of scope` section — empty `(none)` allowed, missing section is rejected by completion-gate
|
|
155
|
+
8. MUST emit `### Type Surface` section for tasks >= 300 tokens — durable contract spine
|
|
156
|
+
9. MUST pass all BLOCK-tier smell tests — no file:line references, no "line N", no narrative path-only bullets
|
|
157
|
+
10. MUST use behavior verbs in Acceptance Criteria — shape verbs ("is defined", "has property") rejected
|
|
125
158
|
|
|
126
159
|
## Sharp Edges
|
|
127
160
|
|
|
128
161
|
| Failure Mode | Severity | Mitigation |
|
|
129
162
|
|---|---|---|
|
|
130
|
-
| Packet too large (>2000 tokens) | HIGH | Compress aggressively —
|
|
163
|
+
| Packet too large (>2000 tokens) | HIGH | Compress aggressively — type names not file contents, decisions not discussions |
|
|
131
164
|
| Missing constraint causes subagent violation | CRITICAL | Always scan for MUST/MUST NOT in parent conversation |
|
|
132
165
|
| Stale context from prior session included | MEDIUM | Cross-check session-bridge state with current files |
|
|
133
166
|
| Over-constraining subagent with parent's approach | MEDIUM | Include constraints and goals, not implementation approach (unless approach is the constraint) |
|
|
167
|
+
| File:line references in packet (rotting briefs) | CRITICAL | Phase 4.5 BLOCK gate — regex `\b\S+\.[a-z]{1,4}:\d+\b` catches them; rewrite to type/function names |
|
|
168
|
+
| Narrative paragraphs with bare paths (`src/auth/`) | MEDIUM | WARN tier — surface and rewrite or move to Files Touched table |
|
|
169
|
+
| Missing Type Surface section for non-trivial task | HIGH | Mandatory for tasks >= 300 tokens; the durable spine is what survives file moves |
|
|
170
|
+
| Missing Out of scope section | HIGH | Always required (even "(none)"); completion-gate rejects briefs without it |
|
|
171
|
+
| Acceptance Criteria using shape verbs ("is defined", "has property") | MEDIUM | Rewrite to behavior verbs from the whitelist |
|
|
134
172
|
|
|
135
173
|
## Self-Validation
|
|
136
174
|
|
|
137
175
|
```
|
|
138
176
|
SELF-VALIDATION (run before emitting output):
|
|
139
|
-
- [ ] Packet includes a clear task goal
|
|
140
|
-
- [ ] Packet includes
|
|
177
|
+
- [ ] Packet includes a clear task goal (verb-led)
|
|
178
|
+
- [ ] Packet includes acceptance criteria (verb-led, testable, not vague)
|
|
141
179
|
- [ ] All MUST/MUST NOT constraints from parent are present
|
|
142
180
|
- [ ] Failed attempts are listed (if any exist)
|
|
143
181
|
- [ ] Token estimate is under 2000
|
|
144
|
-
- [ ] No full file contents embedded (paths only)
|
|
182
|
+
- [ ] No full file contents embedded (type names + paths only)
|
|
183
|
+
- [ ] No file:line references anywhere (regex check)
|
|
184
|
+
- [ ] No bare-path narrative bullets outside Files Touched
|
|
185
|
+
- [ ] ### Out of scope section present (even if "(none)")
|
|
186
|
+
- [ ] ### Type Surface section present (if task >= 300 tokens)
|
|
187
|
+
- [ ] Files Touched entries include (TypeName, function) annotations
|
|
145
188
|
IF ANY check fails → fix before reporting done. Do NOT defer to completion-gate.
|
|
146
189
|
```
|
|
147
190
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Eval Scenarios — `context-pack` skill
|
|
2
|
+
|
|
3
|
+
## Eval: E01 — happy-path good packet emits cleanly
|
|
4
|
+
|
|
5
|
+
### Prompt
|
|
6
|
+
Cook calls context-pack to hand off a feature: "Add device_id field to login flow." Decisions: track at login, optional field. Constraints: preserve backward compat, don't touch rate limits.
|
|
7
|
+
|
|
8
|
+
### Expected Reasoning
|
|
9
|
+
Agent emits a v2-format packet with all required sections (Task / Parent / Scope / Decisions / Constraints / Type Surface / Files Touched / Acceptance Criteria / Out of scope). Acceptance criteria use behavior verbs. Type Surface lists `LoginInput`, `AuthService.authenticate`, `Session`. Files Touched annotated with type names.
|
|
10
|
+
|
|
11
|
+
### Must Include
|
|
12
|
+
- `### Type Surface (durable)` section with at least 2 type entries
|
|
13
|
+
- `### Out of scope` section (even if "(none)")
|
|
14
|
+
- All ACs start with whitelisted behavior verbs
|
|
15
|
+
- Files Touched entries include `(TypeName, function)` annotations
|
|
16
|
+
|
|
17
|
+
### Must NOT
|
|
18
|
+
- Reference file:line (e.g., `login.ts:42`)
|
|
19
|
+
- Use shape verbs ("should be defined", "has property")
|
|
20
|
+
- Skip Out of scope section
|
|
21
|
+
|
|
22
|
+
### Category
|
|
23
|
+
happy-path
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Eval: E02 — file:line BLOCK violation caught
|
|
28
|
+
|
|
29
|
+
### Prompt
|
|
30
|
+
A draft packet contains: "Modify the function at `src/auth/login.ts:42` to handle the new field."
|
|
31
|
+
|
|
32
|
+
### Expected Reasoning
|
|
33
|
+
Agent runs the smell-test regex `\b\S+\.[a-z]{1,4}:\d+\b` and matches `login.ts:42`. BLOCK tier. Refuses to emit. Rewrites the prose to use type/function names: "Modify `AuthService.authenticate` to handle the new field."
|
|
34
|
+
|
|
35
|
+
### Must Include
|
|
36
|
+
- Smell-test BLOCK verdict surfaced
|
|
37
|
+
- Specific regex match cited
|
|
38
|
+
- Rewrite suggestion that uses behavioral language
|
|
39
|
+
|
|
40
|
+
### Must NOT
|
|
41
|
+
- Emit the packet with the file:line still present
|
|
42
|
+
- "Just this once" exception language
|
|
43
|
+
|
|
44
|
+
### Category
|
|
45
|
+
adversarial
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Eval: E03 — narrative path WARN handling
|
|
50
|
+
|
|
51
|
+
### Prompt
|
|
52
|
+
A draft packet contains a narrative paragraph: "The work is centered around `src/auth/`, particularly the login flow."
|
|
53
|
+
|
|
54
|
+
### Expected Reasoning
|
|
55
|
+
Agent matches narrative path regex (WARN tier). Surfaces the warning, asks: is this narrative the right section? If it belongs in `### Files Touched`, move it; if it stays in narrative, rewrite to a type/module name.
|
|
56
|
+
|
|
57
|
+
### Must Include
|
|
58
|
+
- WARN verdict (not BLOCK — narrative paths are softer)
|
|
59
|
+
- Suggestion to either move or rewrite
|
|
60
|
+
- No automatic emission until resolved
|
|
61
|
+
|
|
62
|
+
### Must NOT
|
|
63
|
+
- BLOCK on a WARN-tier match
|
|
64
|
+
- Auto-rewrite without surfacing
|
|
65
|
+
|
|
66
|
+
### Category
|
|
67
|
+
edge-case
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Eval: E04 — missing Out of scope section
|
|
72
|
+
|
|
73
|
+
### Prompt
|
|
74
|
+
A draft packet has all sections except Out of scope.
|
|
75
|
+
|
|
76
|
+
### Expected Reasoning
|
|
77
|
+
Agent recognizes mandatory section. Either prompts the parent for the out-of-scope list, OR explicitly emits `### Out of scope\n- (none)` if the parent confirms there's nothing to exclude. Never silently omits.
|
|
78
|
+
|
|
79
|
+
### Must Include
|
|
80
|
+
- Either an Out of scope section (potentially empty with explicit "(none)")
|
|
81
|
+
- OR a request back to parent for the exclusion list
|
|
82
|
+
- Reference to Phase 4.5 / `completion-gate` rejection rule
|
|
83
|
+
|
|
84
|
+
### Must NOT
|
|
85
|
+
- Emit the packet without Out of scope
|
|
86
|
+
- Auto-fill with assumed exclusions
|
|
87
|
+
|
|
88
|
+
### Category
|
|
89
|
+
adversarial
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Eval: E05 — Type Surface optional for short task
|
|
94
|
+
|
|
95
|
+
### Prompt
|
|
96
|
+
A simple bug fix handoff: "Fix typo in error message — '404 Note Found' → '404 Not Found'." Task body is ~80 tokens.
|
|
97
|
+
|
|
98
|
+
### Expected Reasoning
|
|
99
|
+
Agent recognizes that the task is below the 300-token threshold where Type Surface becomes mandatory. Emits a packet without Type Surface, but still includes Out of scope and behavioral ACs.
|
|
100
|
+
|
|
101
|
+
### Must Include
|
|
102
|
+
- Out of scope section (mandatory regardless of task size)
|
|
103
|
+
- AC with behavior verb (e.g., "Returns the corrected error message on 404")
|
|
104
|
+
- Note in packet header that Type Surface is omitted because task is below threshold
|
|
105
|
+
|
|
106
|
+
### Must NOT
|
|
107
|
+
- Force a Type Surface section for a one-line text fix
|
|
108
|
+
- Skip Out of scope (still mandatory)
|
|
109
|
+
|
|
110
|
+
### Category
|
|
111
|
+
edge-case
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Eval Coverage
|
|
116
|
+
|
|
117
|
+
| Category | Count | Status |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| happy-path | 1 | ✅ E01 |
|
|
120
|
+
| edge-case | 2 | ✅ E03, E05 |
|
|
121
|
+
| adversarial | 2 | ✅ E02, E04 |
|
|
122
|
+
| **Total** | **5** | **✅ above minimum (4)** |
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Brief Template (v2)
|
|
2
|
+
|
|
3
|
+
Use this verbatim. Receivers expect every section. Sections marked optional may be omitted only if there's nothing to record (not because the writer didn't bother).
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
## Context Packet
|
|
7
|
+
|
|
8
|
+
**Task**: [One-line behavioral description, verb-led: "Add rate limiting to login route"]
|
|
9
|
+
**Parent**: [delegating skill — e.g., cook]
|
|
10
|
+
**Scope**: [type names / module names — NOT file paths]
|
|
11
|
+
|
|
12
|
+
### Decisions Made
|
|
13
|
+
- [Decision]: chose [X] over [Y] because [reason]
|
|
14
|
+
- ...
|
|
15
|
+
|
|
16
|
+
### Constraints
|
|
17
|
+
- MUST: [behavioral assertion — "preserve existing 1hr rate-limit window"]
|
|
18
|
+
- MUST NOT: [behavioral prohibition — "modify the audit log writer"]
|
|
19
|
+
- BLOCKED BY: [contract dependency — "the auth.token-refresh contract finalized in PR #42"]
|
|
20
|
+
|
|
21
|
+
### Already Tried
|
|
22
|
+
- [Approach] — [observable failure mode]
|
|
23
|
+
|
|
24
|
+
### Type Surface (durable)
|
|
25
|
+
- `TypeName { field: type; field: type }` — what it represents
|
|
26
|
+
- `Module.method(input: T): Result<O, E>` — the contract
|
|
27
|
+
- `ErrorEnum = "case_a" | "case_b"` — what callers switch on
|
|
28
|
+
|
|
29
|
+
### Files Touched (locator-only, may rename)
|
|
30
|
+
- `path/to/file.ts` (TypeName, Module.method) — [behavioral hint]
|
|
31
|
+
- ...
|
|
32
|
+
|
|
33
|
+
### Acceptance Criteria
|
|
34
|
+
- [ ] [Verb-led testable statement — "Rejects login attempts with 429 after 5 failures within 1 hour"]
|
|
35
|
+
- [ ] ...
|
|
36
|
+
|
|
37
|
+
### Out of scope
|
|
38
|
+
- [Thing the receiver should NOT do]
|
|
39
|
+
- [Adjacent feature that might seem related but is separate]
|
|
40
|
+
- (or "(none)" if nothing to exclude)
|
|
41
|
+
|
|
42
|
+
### Progress
|
|
43
|
+
- [What's done so far, if partial handoff — omit if fresh start]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Behavioral verb whitelist
|
|
47
|
+
|
|
48
|
+
Every Acceptance Criterion must start with one of these:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
accepts dispatches logs redirects retrieves
|
|
52
|
+
rejects throws increments retries returns
|
|
53
|
+
produces times-out decrements notifies validates
|
|
54
|
+
persists emits caches invalidates authenticates
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Verbs not on the whitelist may still be valid; check whether the criterion describes *observable behavior* (good) or *shape* ("is defined", "has property", "exists") — shape verbs are banned.
|
|
58
|
+
|
|
59
|
+
## Worked example
|
|
60
|
+
|
|
61
|
+
### ✅ Good packet
|
|
62
|
+
|
|
63
|
+
```markdown
|
|
64
|
+
## Context Packet
|
|
65
|
+
|
|
66
|
+
**Task**: Add device tracking to login flow
|
|
67
|
+
**Parent**: cook
|
|
68
|
+
**Scope**: AuthService, LoginInput, sessions table
|
|
69
|
+
|
|
70
|
+
### Decisions Made
|
|
71
|
+
- Track device_id at login: chose passing through to session storage over hashing in-app, because compliance requires preserving raw values for audit window
|
|
72
|
+
- Optional field: chose nullable rather than required, because mobile clients prior to v3.2 don't send it
|
|
73
|
+
|
|
74
|
+
### Constraints
|
|
75
|
+
- MUST: preserve backward-compatible login for clients without device_id
|
|
76
|
+
- MUST NOT: change rate-limit window (currently 1hr)
|
|
77
|
+
|
|
78
|
+
### Already Tried
|
|
79
|
+
- Storing in JWT claims — rejected because tokens grow past mobile size limit
|
|
80
|
+
|
|
81
|
+
### Type Surface (durable)
|
|
82
|
+
- `LoginInput { email: string; password: string; device_id?: string }` — payload accepted by login route
|
|
83
|
+
- `AuthService.authenticate(input: LoginInput): Result<Session, AuthError>` — primary contract
|
|
84
|
+
- `Session { user_id: string; created_at: Date; device_id: string | null }` — issued on success
|
|
85
|
+
|
|
86
|
+
### Files Touched (locator-only, may rename)
|
|
87
|
+
- `src/auth/login.ts` (LoginInput, AuthService.authenticate) — route handler
|
|
88
|
+
- `src/db/migrations/sessions.sql` (sessions table) — schema
|
|
89
|
+
|
|
90
|
+
### Acceptance Criteria
|
|
91
|
+
- [ ] Persists device_id to sessions table when login succeeds and device_id is provided
|
|
92
|
+
- [ ] Persists null when device_id is absent
|
|
93
|
+
- [ ] Returns AuthError 'invalid_credentials' on bad password (existing behavior unchanged)
|
|
94
|
+
|
|
95
|
+
### Out of scope
|
|
96
|
+
- Changing rate-limit window
|
|
97
|
+
- Updating mobile client SDKs
|
|
98
|
+
- Audit log writer
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### ❌ Bad packet (would fail smell tests)
|
|
102
|
+
|
|
103
|
+
```markdown
|
|
104
|
+
## Context Packet
|
|
105
|
+
|
|
106
|
+
**Task**: fix the login
|
|
107
|
+
|
|
108
|
+
**Files**: src/auth/login.ts:42, src/types.ts:18
|
|
109
|
+
|
|
110
|
+
The function around line 100 has a bug. Add a device field. See `src/handlers/`.
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Failures:
|
|
114
|
+
- No section structure
|
|
115
|
+
- File:line references (`login.ts:42`)
|
|
116
|
+
- "line 100" — line-number reference
|
|
117
|
+
- "around line" — narrative path
|
|
118
|
+
- No Type Surface
|
|
119
|
+
- No Out of scope
|
|
120
|
+
- No Acceptance Criteria with behavior verbs
|
|
121
|
+
- Vague task description ("fix the login")
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Durability Rules — Why Briefs Rot, How to Stop It
|
|
2
|
+
|
|
3
|
+
A subagent receives a context packet. A day later, after a refactor, that packet's file paths point to renamed files, line numbers point to shifted code, and "the function in `src/auth/login.ts:42`" no longer exists. The subagent burns tokens grepping to recover or — worse — generates hallucinated edits matching the stale brief.
|
|
4
|
+
|
|
5
|
+
The fix is to write briefs that describe **types and contracts**, which survive moves, instead of **paths and line numbers**, which don't.
|
|
6
|
+
|
|
7
|
+
## The 5 rules
|
|
8
|
+
|
|
9
|
+
### 1. Behavioral over procedural
|
|
10
|
+
|
|
11
|
+
Describe what the system *does*, not *where* the code lives.
|
|
12
|
+
|
|
13
|
+
| ❌ Bad | ✅ Good |
|
|
14
|
+
|--------|---------|
|
|
15
|
+
| "Open `src/handlers/login.ts` and modify line 42" | "When a login fails 5 times, the rate limiter should reject the next attempt with a 429 response and a `Retry-After` header" |
|
|
16
|
+
| "Add the field to the type at `src/types.ts:18`" | "The `LoginInput` type should accept an optional `device_id: string`" |
|
|
17
|
+
| "Refactor the function around line 150 in `main.ts`" | "Extract the password-hashing path into its own module so it can be tested independently" |
|
|
18
|
+
|
|
19
|
+
### 2. Type names over file paths in narrative
|
|
20
|
+
|
|
21
|
+
When you must reference code in narrative prose, refer to **type names, function names, or contracts** — not file paths.
|
|
22
|
+
|
|
23
|
+
| ❌ Bad | ✅ Good |
|
|
24
|
+
|--------|---------|
|
|
25
|
+
| "Update the function in `src/auth/`" | "Update the `authenticate` method on `AuthService`" |
|
|
26
|
+
| "Modify `src/db/migrations/0042.sql`" | "The new migration should add a `device_id` column to the `sessions` table, nullable, with a default of `NULL`" |
|
|
27
|
+
|
|
28
|
+
File paths may appear in a clearly-marked `### Files Touched` table — never in narrative prose.
|
|
29
|
+
|
|
30
|
+
### 3. Type Surface section
|
|
31
|
+
|
|
32
|
+
Add a `### Type Surface` section listing the contracts that *won't* change even if files do. This is the durable spine of the brief.
|
|
33
|
+
|
|
34
|
+
```markdown
|
|
35
|
+
### Type Surface (durable)
|
|
36
|
+
- `LoginInput { email: string; password: string; device_id?: string }` — payload accepted by the login route
|
|
37
|
+
- `AuthService.authenticate(input: LoginInput): Result<Session, AuthError>` — primary contract
|
|
38
|
+
- `AuthError = "invalid_credentials" | "rate_limited" | "account_locked"` — error union the caller switches on
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If a file gets renamed but `AuthService.authenticate` keeps its shape, the brief still applies. If the contract changes, the brief is invalidated — that's a feature, not a bug.
|
|
42
|
+
|
|
43
|
+
### 4. Out of scope is mandatory
|
|
44
|
+
|
|
45
|
+
Every brief includes `### Out of scope`. Receivers expand into adjacent work without this anchor. Empty list is fine *if explicitly empty* (`### Out of scope\n- (none)`); missing section is rejected by completion-gate.
|
|
46
|
+
|
|
47
|
+
```markdown
|
|
48
|
+
### Out of scope
|
|
49
|
+
- Changing the rate-limit window (currently 1 hour — keep it)
|
|
50
|
+
- Touching the audit log writer (separate ticket)
|
|
51
|
+
- Anything in `src/billing/` — different domain
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 5. Behavioral verbs in acceptance criteria
|
|
55
|
+
|
|
56
|
+
Each acceptance criterion must start with a verb from the whitelist:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
accepts, rejects, produces, notifies, persists, retries, times-out, validates,
|
|
60
|
+
returns, dispatches, redirects, throws, logs, increments, decrements, retrieves
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Banned verb-less constructs ("the field should be present", "the type is exported") describe shape, not behavior.
|
|
64
|
+
|
|
65
|
+
| ❌ Bad | ✅ Good |
|
|
66
|
+
|--------|---------|
|
|
67
|
+
| "The new field should exist" | "Persists the device_id when login succeeds" |
|
|
68
|
+
| "An error type should be defined" | "Returns AuthError 'rate_limited' when 5 failures occur within 1 hour" |
|
|
69
|
+
|
|
70
|
+
## Smell tests (mechanical regex gates)
|
|
71
|
+
|
|
72
|
+
`context-pack` Phase 4.5 runs these regex against the packet body before emit. Any BLOCK-tier hit fails the gate.
|
|
73
|
+
|
|
74
|
+
| Regex | Tier | Reason |
|
|
75
|
+
|-------|------|--------|
|
|
76
|
+
| `\b\S+\.[a-z]{1,4}:\d+\b` | BLOCK | file:line reference (e.g., `login.ts:42`) — line numbers go stale |
|
|
77
|
+
| `^- \S*[\\/]\S+\.(ts\|js\|py\|go\|rs\|java)\b` (in non-`Files Touched` sections) | BLOCK | Path-only bullet in narrative |
|
|
78
|
+
| `\b(line \|on line )\d+\b` | BLOCK | "line 42" / "on line 100" |
|
|
79
|
+
| `\b(src\|lib\|app)/\S+` (in narrative paragraphs) | WARN | Path mention; check if it's in the right section |
|
|
80
|
+
|
|
81
|
+
Whitelist for `### Files Touched` table — paths there must include the type/function name in parens for durability:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
- `src/auth/login.ts` (LoginInput, AuthService.authenticate) — the route handler
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Without the parens annotation, even the table entry is too brittle.
|
|
88
|
+
|
|
89
|
+
## When durability rules can be relaxed
|
|
90
|
+
|
|
91
|
+
Two narrow exceptions:
|
|
92
|
+
|
|
93
|
+
1. **Single-cycle short tasks** (<300 tokens, <3 files) — the brief lives only as long as one cycle, and the receiving agent will execute immediately. Type Surface section becomes optional.
|
|
94
|
+
2. **Bug-fix briefs with concrete repro** — sometimes the bug *is* on a specific line of a specific file as it exists right now. In that case, paths may appear in narrative IF accompanied by the type/function name. Example: *"In `AuthService.authenticate` (currently `src/auth/service.ts`), the comparison uses `<` instead of `<=`."*
|
|
95
|
+
|
|
96
|
+
The rules above are defaults; the exceptions are explicit and rare. When in doubt, follow the rules.
|
|
97
|
+
|
|
98
|
+
## Self-check before emit
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
[ ] Every narrative reference uses type/function names, not file paths
|
|
102
|
+
[ ] Type Surface section lists contracts that won't change with file moves
|
|
103
|
+
[ ] Out of scope section exists (even if "(none)")
|
|
104
|
+
[ ] Every Acceptance Criterion starts with a behavior verb
|
|
105
|
+
[ ] No file:line references appear anywhere
|
|
106
|
+
[ ] Files Touched table entries have (Type, function) annotations
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
If any check fails, fix before the receiving agent gets the packet. A stale brief is worse than no brief at all.
|