@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,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.1.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
- ## Output Format
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 of what the subagent must do]
82
- **Parent**: [Which skill/agent is delegating]
83
- **Scope**: [Specific files, modules, or boundaries]
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 1]: [choice] because [reason]
87
- - [Decision 2]: [choice] — because [reason]
106
+ - [Decision]: chose [X] over [Y] because [reason]
88
107
 
89
108
  ### Constraints
90
- - MUST: [requirement 1]
91
- - MUST NOT: [prohibition 1]
92
- - BLOCKED BY: [dependency, if any]
109
+ - MUST: [behavioral assertion]
110
+ - MUST NOT: [behavioral prohibition]
111
+ - BLOCKED BY: [contract dependency, not file path]
93
112
 
94
113
  ### Already Tried
95
- - [Approach that failed] — [why it failed]
114
+ - [approach] — [observable failure mode]
96
115
 
97
- ### Files Touched
98
- - `path/to/file.ts` [what was done / what needs doing]
116
+ ### Type Surface (durable)
117
+ - `TypeName { field: type }` [what it represents]
118
+ - `Module.method(input: T): Result<O, E>` — [contract]
99
119
 
100
- ### Success Criteria
101
- - [ ] [Verifiable criterion 1]
102
- - [ ] [Verifiable criterion 2]
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
- - [What's done so far, if partial handoff]
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 success criteria — subagent needs to know when it's done
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 file paths and summaries instead
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 — file paths not contents, decisions not discussions |
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 success criteria (verifiable, not vague)
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.