ralphctl 0.26.0 → 0.28.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 (46) hide show
  1. package/README.md +11 -4
  2. package/THIRD-PARTY-NOTICES.md +65 -2
  3. package/dist/agent-definitions/ralphctl-generator.md +3 -2
  4. package/dist/{cli-P7D6G5NI.mjs → chunk-WAHQPVTG.mjs} +16782 -40661
  5. package/dist/cli-W3M7L4TP.mjs +2772 -0
  6. package/dist/cli.mjs +1 -1
  7. package/dist/launch-VBRTQP4L.mjs +20602 -0
  8. package/dist/manifest.json +16 -3
  9. package/dist/prompts/_partials/autonomous-operation.md +18 -7
  10. package/dist/prompts/_partials/conventions-agents-md.md +2 -2
  11. package/dist/prompts/_partials/conventions-claude-md.md +2 -0
  12. package/dist/prompts/_partials/decisions.md +0 -1
  13. package/dist/prompts/_partials/evaluator-failure-modes.md +8 -5
  14. package/dist/prompts/_partials/evaluator-grading-rules.md +9 -5
  15. package/dist/prompts/_partials/one-shot-operation.md +6 -0
  16. package/dist/prompts/apply-feedback/template.md +5 -4
  17. package/dist/prompts/create-pr/template.md +10 -8
  18. package/dist/prompts/detect-scripts/template.md +7 -4
  19. package/dist/prompts/detect-skills/template.md +2 -0
  20. package/dist/prompts/evaluate/template.md +4 -2
  21. package/dist/prompts/evaluate-continuation/template.md +1 -1
  22. package/dist/prompts/ideate/template.md +2 -3
  23. package/dist/prompts/implement/template.md +21 -14
  24. package/dist/prompts/plan/template.md +3 -4
  25. package/dist/prompts/readiness/template.md +9 -4
  26. package/dist/prompts/refine/template.md +3 -6
  27. package/dist/prompts/reproduce/template.md +7 -0
  28. package/dist/skills/ralphctl-api-and-interface-design/SKILL.md +117 -0
  29. package/dist/skills/ralphctl-code-review-and-quality/SKILL.md +119 -8
  30. package/dist/skills/ralphctl-code-simplification/SKILL.md +100 -0
  31. package/dist/skills/ralphctl-codebase-design/SKILL.md +82 -0
  32. package/dist/skills/ralphctl-debugging-and-error-recovery/SKILL.md +23 -5
  33. package/dist/skills/ralphctl-deprecation-and-migration/SKILL.md +106 -0
  34. package/dist/skills/ralphctl-frontend-ui-engineering/SKILL.md +94 -0
  35. package/dist/skills/ralphctl-humanizer/SKILL.md +137 -0
  36. package/dist/skills/ralphctl-idea-refinement/SKILL.md +2 -0
  37. package/dist/skills/ralphctl-iterative-review/SKILL.md +10 -4
  38. package/dist/skills/ralphctl-observability-and-instrumentation/SKILL.md +104 -0
  39. package/dist/skills/ralphctl-performance-optimization/SKILL.md +123 -0
  40. package/dist/skills/ralphctl-ponytail/SKILL.md +38 -28
  41. package/dist/skills/ralphctl-security-and-hardening/SKILL.md +259 -0
  42. package/dist/skills/ralphctl-source-driven-development/SKILL.md +103 -0
  43. package/dist/skills/ralphctl-spec-driven-development/SKILL.md +148 -0
  44. package/dist/skills/ralphctl-test-driven-development/SKILL.md +29 -2
  45. package/dist/skills/ralphctl-writing-for-agents/SKILL.md +113 -0
  46. package/package.json +10 -10
@@ -7,7 +7,9 @@ license: MIT
7
7
  # Code Review and Quality
8
8
 
9
9
  > Concept from [addyosmani/agent-skills — "Code Review and Quality"](https://github.com/addyosmani/agent-skills),
10
- > MIT License. Adapted for ralphctl's evaluator role and review flow.
10
+ > MIT License. Adapted for ralphctl's evaluator role and review flow. The smell baseline draws on
11
+ > [mattpocock/skills](https://github.com/mattpocock/skills) and the concrete-case and expected-load rules on
12
+ > [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail) (both MIT).
11
13
 
12
14
  One-shot generation looks fast and is slow. Catching a correctness, architecture, or security problem at the
13
15
  seam between two changes is cheap; catching it at the end of a 200-line diff — or after the post-task gate
@@ -57,6 +59,10 @@ Can another engineer understand this code without the author explaining it?
57
59
  - Could this be done in fewer lines? (1 000 lines where 100 suffice is a failure.)
58
60
  - Are abstractions earning their complexity? Do not generalise until the third use case.
59
61
  - Are there dead code artefacts: no-op variables, backwards-compat shims, or `// removed` comments?
62
+ - **Is a new conditional bolted onto an unrelated flow?** That is a design smell, not a nit — push the logic
63
+ into its own helper, state, or policy instead of tangling an existing path.
64
+ - **Do repeated conditionals on the same shape appear?** They signal a missing model or dispatcher. A
65
+ "temporary" branch is usually permanent debt.
60
66
 
61
67
  ### 3. Architecture
62
68
 
@@ -67,6 +73,16 @@ Does the change fit the system's design?
67
73
  - Is there code duplication that should be shared?
68
74
  - Are dependencies flowing in the right direction — no circular dependencies?
69
75
  - Is the abstraction level appropriate — not over-engineered, not too coupled?
76
+ - **Does this refactor reduce complexity or just relocate it?** Count the concepts a reader must hold to
77
+ follow the change. If a "cleaner" version leaves that count unchanged, it is not cleaner — prefer the
78
+ restructuring that makes whole branches, modes, or layers disappear over one that re-centralises the same
79
+ logic. Prefer deleting an abstraction to polishing it.
80
+ - **Is feature-specific logic leaking into a shared or general-purpose module?** Keep logic in its owning
81
+ layer, reuse the existing canonical helper instead of a near-duplicate, and do not normalise architectural
82
+ drift.
83
+ - **Are type boundaries explicit?** Question gratuitous untyped escape hatches, optional fields, casts, and
84
+ silent fallbacks that paper over an unclear invariant — making the boundary explicit often makes the
85
+ surrounding control flow simpler.
70
86
 
71
87
  ### 4. Security
72
88
 
@@ -91,6 +107,47 @@ Does the change introduce performance problems?
91
107
  - Any missing pagination on list endpoints?
92
108
  - Any large objects created in hot paths?
93
109
 
110
+ Judge scale against the expected load, found in the repository (README, deploy configuration): a script one
111
+ person runs is not a service under concurrent traffic. Check-then-write races, work every process repeats,
112
+ collections that only grow, and per-process state that must be shared are findings at the load that
113
+ triggers them — say which load you assumed.
114
+
115
+ ## Structural Remedies
116
+
117
+ When you flag a structural problem, propose the move — not just the problem. A finding that only says "this
118
+ is complex" leaves the generator or author guessing. Reach for a named restructuring:
119
+
120
+ - **Replace a chain of conditionals** with a typed model or an explicit dispatcher.
121
+ - **Collapse duplicate branches** into a single clearer flow.
122
+ - **Separate orchestration from business logic** so each reads on its own.
123
+ - **Move feature-specific logic** out of a shared module into the module that owns the concept.
124
+ - **Reuse the canonical helper** instead of a bespoke near-duplicate.
125
+ - **Make a type boundary explicit** so downstream branching disappears.
126
+ - **Delete a pass-through wrapper** that adds indirection without clarifying the API.
127
+ - **Extract a helper, or split a large file** into focused modules.
128
+
129
+ Prefer the remedy that removes moving pieces over one that spreads the same complexity around.
130
+
131
+ ## Smell Baseline
132
+
133
+ On top of whatever the project documents, a fixed set of code smells (Fowler, _Refactoring_) applies even
134
+ where a repository documents nothing. Each is a labelled judgement call ("possible Feature Envy") at Minor or
135
+ Nit, never a hard violation. A documented project standard that endorses the pattern overrides the smell, and
136
+ anything tooling already enforces is skipped.
137
+
138
+ - **Mysterious Name** — the name does not say what it does or holds → rename; no honest name means murky design.
139
+ - **Duplicated Code** — the same logic shape in several hunks or files → extract it once.
140
+ - **Feature Envy** — a function that works on another module's data more than its own → move it there.
141
+ - **Data Clumps** — the same few values always travel together → give them one type.
142
+ - **Primitive Obsession** — a string or number standing in for a domain concept → give the concept a type.
143
+ - **Repeated Switches** — the same branching on the same type in several places → one dispatch both share.
144
+ - **Shotgun Surgery** — one logical change forces scattered edits → gather what changes together.
145
+ - **Divergent Change** — one module edited for several unrelated reasons → split by reason.
146
+ - **Speculative Generality** — hooks, parameters, or abstractions for needs nobody has → delete them.
147
+ - **Message Chains** — callers walking a long chain of navigation → hide the walk behind one call.
148
+ - **Middle Man** — a layer that mostly delegates → call the real target directly.
149
+ - **Refused Bequest** — an implementer ignoring most of what it inherits → compose instead of inheriting.
150
+
94
151
  ## Severity Vocabulary
95
152
 
96
153
  Label every finding with its severity so the generator or author knows what is required versus optional:
@@ -105,6 +162,12 @@ Label every finding with its severity so the generator or author knows what is r
105
162
  Using explicit severity prevents treating all findings as equally urgent — a nit should not consume the
106
163
  same budget as a Critical.
107
164
 
165
+ **Presumptive structural findings.** Raise each of these as at least Minor and propose the simpler design;
166
+ escalate to Major only when the change actively makes the structure worse: a refactor that relocates
167
+ complexity instead of reducing it; a change that pushes a file past a healthy size with no decomposition;
168
+ feature logic added to a shared module; a near-duplicate of an existing canonical helper; a silent fallback
169
+ that hides an unclear invariant.
170
+
108
171
  ## Review Process
109
172
 
110
173
  ### Step 1: Understand the Context
@@ -124,6 +187,12 @@ Tests reveal intent and coverage:
124
187
  - Are edge cases covered?
125
188
  - Would the tests catch a regression if the code changed?
126
189
 
190
+ Answer the last question by experiment, not by reading, when your session may edit the working tree (the
191
+ generator): invert one condition the change adds (drop a negation, swap `&&` for `||`), run the focused
192
+ test, then restore the file from a copy. A mutation that stays green is a finding — name the missing test
193
+ case. When your session is read-only (the evaluator), reason through the same inversion and name the test
194
+ case that would be missing as a finding.
195
+
127
196
  ### Step 3: Review the Implementation
128
197
 
129
198
  Walk through the code with the five axes in mind. For each file changed:
@@ -153,6 +222,11 @@ section names the exact file and shape):
153
222
  the severity of each finding) in the evaluator's output as directed by the task prompt — not in a
154
223
  separate file or report, and not as a `decision` signal.
155
224
 
225
+ **Lead with what matters.** Order findings by leverage: correctness and security first, then structural
226
+ regressions and missed simplifications, then everything else. Do not bury a real issue under cosmetic nits —
227
+ a few high-conviction findings beat a long list. If you have one structural problem and ten nits, the
228
+ structural problem _is_ the review.
229
+
156
230
  Do not write a standalone review report to a file. The harness's signal pipeline and the evaluator's
157
231
  structured output are the authoritative record.
158
232
 
@@ -178,6 +252,11 @@ Small, focused changes are easier to review, faster to evaluate, and safer to fo
178
252
  ~1000 lines changed → Too large. Split it.
179
253
  ```
180
254
 
255
+ **Watch file size, not just diff size.** A small diff can still push a file past a healthy boundary —
256
+ around 1 000 _total_ lines in a single file (distinct from the ~1 000 _changed_-lines threshold above) is a
257
+ common inspection signal, not a hard cap. When a change materially grows an already-large file, ask whether
258
+ to extract helpers, subcomponents, or modules _first_, before piling more on. Decompose, then add.
259
+
181
260
  **What counts as "one change":** A single self-contained modification that addresses one thing, includes
182
261
  related tests, and keeps the system functional after submission.
183
262
 
@@ -208,11 +287,30 @@ Before adding any dependency:
208
287
 
209
288
  Prefer the standard library and existing utilities over new dependencies. Every dependency is a liability.
210
289
 
290
+ **Upgrading an existing dependency** is a code change like any other, and the riskiest upgrades are bulk
291
+ "bump deps" changes. Review them with the same discipline:
292
+
293
+ - **Read the changelog, not just the version number.** Semver is a promise the maintainer may not have
294
+ kept — a "patch" can carry a behavioural change. For a major bump, read the migration notes and find what
295
+ breaks.
296
+ - **One dependency per change** (or a small related group). When a bulk bump breaks the build, you lose which
297
+ package did it; a single-package change makes the cause obvious and the revert clean.
298
+ - **Let the tests decide.** The upgrade is verified by a green check before _and_ after, not by "it
299
+ installed." If coverage around the dependency's behaviour is thin, that gap is the real finding — add a
300
+ test first.
301
+ - **Mind the transitive graph.** Review the lockfile diff, not just the dependency manifest; a single direct
302
+ bump can pull in dozens of indirect changes.
303
+ - **Keep the lockfile honest.** Keep it in the change, review its diff, and never hand-edit it — the lockfile
304
+ is what actually pins what ships.
305
+
211
306
  ## Honesty in Review
212
307
 
213
308
  Whether reviewing code you wrote, code a generator produced, or a human's change:
214
309
 
215
310
  - Do not rubber-stamp. "Looks fine" without evidence of review helps no one.
311
+ - Back every correctness, security, or scale finding with a concrete case — this input or situation leads to
312
+ this wrong result — and re-read the lines to confirm it: the caller exists, the value can really be empty,
313
+ the code really is unused. No case, no finding. Structural findings follow the presumptive rules above.
216
314
  - Do not soften real issues. "This might be a minor concern" when it is a bug that will hit production is
217
315
  misleading.
218
316
  - Quantify problems when possible. "This N+1 query will add ~50 ms per item in the list" is better than
@@ -224,13 +322,17 @@ Whether reviewing code you wrote, code a generator produced, or a human's change
224
322
 
225
323
  ## Common Rationalisations
226
324
 
227
- | Rationalisation | Reality |
228
- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
229
- | "It works, that's good enough" | Working code that is unreadable, insecure, or architecturally wrong creates debt that compounds. |
230
- | "I wrote it, so I know it is correct" | Authors are blind to their own assumptions. |
231
- | "We will clean it up later" | Later rarely comes. The review is the quality gate — use it. |
232
- | "AI-generated code is probably fine" | AI code needs more scrutiny, not less. It is confident and plausible, even when wrong. |
233
- | "The tests pass, so it is good" | Tests are necessary but not sufficient. They do not catch architecture problems, security issues, or readability concerns. |
325
+ | Rationalisation | Reality |
326
+ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
327
+ | "It works, that's good enough" | Working code that is unreadable, insecure, or architecturally wrong creates debt that compounds. |
328
+ | "I wrote it, so I know it is correct" | Authors are blind to their own assumptions. |
329
+ | "We will clean it up later" | Later rarely comes. The review is the quality gate — use it. |
330
+ | "AI-generated code is probably fine" | AI code needs more scrutiny, not less. It is confident and plausible, even when wrong. |
331
+ | "The tests pass, so it is good" | Tests are necessary but not sufficient. They do not catch architecture problems, security issues, or readability concerns. |
332
+ | "The refactor makes it cleaner" | Relocating complexity is not reducing it. If the reader still holds the same number of concepts, the structure did not improve — look for the version where branches disappear. |
333
+ | "It is only a small addition to this file" | Small diffs still push files past a healthy size and bolt branches onto unrelated flows. Judge the resulting structure, not the diff size. |
334
+ | "It is just a version bump" | A bump is a behaviour change you did not write. Read the changelog; semver does not guarantee no breakage. |
335
+ | "Upgrade everything at once to save time" | A bulk bump that breaks the build hides which package did it. One dependency per change keeps the cause and the revert clean. |
234
336
 
235
337
  ## Review Checklist
236
338
 
@@ -243,6 +345,9 @@ Before signalling completion or a passing evaluator verdict, run through:
243
345
  - [ ] Names are clear and consistent with project conventions.
244
346
  - [ ] No unnecessary complexity.
245
347
  - [ ] Follows existing architectural patterns.
348
+ - [ ] Refactors reduce complexity rather than relocate it.
349
+ - [ ] No feature logic in shared modules; touched files stay within a healthy size.
350
+ - [ ] Dependency upgrades (if any) were checked against their changelog and the lockfile diff.
246
351
  - [ ] No secrets in code; input validated at boundaries.
247
352
  - [ ] No N+1 patterns or unbounded operations.
248
353
  - [ ] Findings surfaced per Step 4's signal guidance, with severity labels intact.
@@ -255,3 +360,9 @@ Before signalling completion or a passing evaluator verdict, run through:
255
360
  - No regression tests alongside a bug fix.
256
361
  - Review comments without severity labels — makes it unclear what is required versus optional.
257
362
  - Accepting "I will fix it later" — it rarely happens.
363
+ - A refactor that moves code around without reducing the number of concepts a reader must hold.
364
+ - A change that grows an already-large file instead of decomposing it.
365
+ - New conditionals scattered into unrelated code paths (a missing abstraction).
366
+ - A bespoke helper that duplicates an existing canonical one, or feature logic placed in a shared module.
367
+ - A bulk dependency bump with no changelog review and no per-package isolation.
368
+ - A lockfile change that is hand-edited or accepted without reviewing its diff.
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: ralphctl-code-simplification
3
+ description: Behaviour-preserving simplification of existing code — understand why the code exists before changing it, then reduce nesting, unclear names, duplication, dead code, and needless indirection one step at a time with the existing tests unchanged and green after each. Use when a task asks to refactor or clean up working code, or when code you just made work is heavier than it needs to be; for keeping a new change small from the start, see ralphctl-surgical-simplicity and ralphctl-ponytail when installed.
4
+ license: MIT
5
+ ---
6
+
7
+ # Code Simplification
8
+
9
+ > Adapted from [addyosmani/agent-skills — "Code Simplification"](https://github.com/addyosmani/agent-skills)
10
+ > (MIT). Adapted for ralphctl's harness contract.
11
+
12
+ Simplify by reducing complexity while preserving behaviour exactly. The goal is not fewer lines — it is
13
+ code a new reader understands faster than the original. Every simplification passes one test: would
14
+ someone new to this code follow the result more easily?
15
+
16
+ ## When this applies
17
+
18
+ - **Execute** — when the task asks for a refactor or cleanup, and after a change works, on the code that
19
+ change touched. Simplification outside the task's scope is a finding to surface, not an edit to make —
20
+ record it in a `note` signal when the prompt's output-contract section lists it; otherwise fold it into
21
+ the required signal's own fields.
22
+
23
+ **When not to use:** the code is already clear; you do not yet understand what it does; the simpler form
24
+ is measurably slower on a hot path; the module is about to be replaced.
25
+
26
+ ## Principles
27
+
28
+ 1. **Preserve behaviour exactly.** Same outputs for every input, same errors, same side effects and their
29
+ order. The existing tests pass without modification. If you are not sure a change preserves
30
+ behaviour, do not make it.
31
+ 2. **Follow the project's conventions.** Read the project's context file when present and the
32
+ neighbouring code; simplification that breaks local consistency is churn.
33
+ 3. **Clarity over cleverness.** A chain of nested conditional expressions becomes early returns or a
34
+ lookup; a dense chained transform with inline logic becomes a named intermediate step.
35
+ 4. **Keep the balance.** Do not inline a helper that gives a concept its name, merge unrelated logic into
36
+ one function, or remove an abstraction that exists for testability. Line count is not the measure.
37
+ 5. **Scope to what changed.** Default to the code the task touched.
38
+
39
+ ## The process
40
+
41
+ ### 1. Understand before touching (Chesterton's fence)
42
+
43
+ Before changing or removing anything, know why it exists: its responsibility, its callers and callees,
44
+ its edge cases and error paths, the tests that pin its behaviour, and why it might have been written this
45
+ way (a performance constraint, a platform quirk, history visible in `git log` or `git blame`). If you
46
+ cannot answer these, read more first.
47
+
48
+ ### 2. Find concrete opportunities
49
+
50
+ | Pattern | Simplification |
51
+ | ------------------------------------ | ----------------------------------------------------- |
52
+ | Nesting three or more levels deep | Guard clauses or an extracted, well-named condition |
53
+ | A long function doing several jobs | Split by job, never by line count |
54
+ | Boolean flag parameters | Separate functions, or a named options value |
55
+ | The same condition in several places | One named predicate |
56
+ | Generic or misleading names | Names that describe the content or the real behaviour |
57
+ | A comment explaining _what_ | Delete it; keep comments that explain _why_ |
58
+ | Duplicated logic | One shared function |
59
+ | Dead code | Remove it, after confirming nothing reaches it |
60
+ | A wrapper that only forwards | Call the underlying function directly |
61
+ | An abstraction with one variant | The direct approach |
62
+
63
+ ### 3. Apply one change at a time
64
+
65
+ Make one simplification, run the focused tests, and continue only when they are green; when they fail,
66
+ undo that step and reconsider. Never batch several simplifications into one untested change — when
67
+ something breaks, you need to know which one did it. Keep refactoring and behaviour change apart: a
68
+ refactor task adds no behaviour, and a feature task does not absorb a broad refactor. For a change
69
+ touching many sites, prefer a mechanical transform (a structured search-and-replace or a codemod the
70
+ project already uses) over hand edits.
71
+
72
+ ### 4. Judge the whole
73
+
74
+ Compare before and after: is the result genuinely easier to follow, consistent with the codebase, and a
75
+ clean reviewable diff? If not, undo it. Not every attempt succeeds.
76
+
77
+ ## Common rationalisations
78
+
79
+ | Rationalisation | Reality |
80
+ | ---------------------------------------- | --------------------------------------------------------------------------------- |
81
+ | "Fewer lines is always simpler" | A one-line nested conditional is not simpler than five readable lines. |
82
+ | "I'll quickly tidy this unrelated code" | Unscoped cleanup inflates the diff and risks regressions you did not intend. |
83
+ | "This abstraction might be useful later" | Speculative abstractions are complexity without value. Remove it; re-add on need. |
84
+ | "The tests needed a small tweak" | A simplification that needs test changes probably changed behaviour. |
85
+
86
+ ## Red flags
87
+
88
+ - Tests modified to make a "simplification" pass.
89
+ - A "simplified" version that is longer or harder to follow.
90
+ - Renames that follow your preference rather than the project's conventions.
91
+ - Error handling removed because it "looked noisy".
92
+ - Simplifying code you do not fully understand.
93
+
94
+ ## Self-check
95
+
96
+ - [ ] The existing tests pass without modification.
97
+ - [ ] No error handling was removed or weakened.
98
+ - [ ] The result follows the project's conventions.
99
+ - [ ] No dead code was left behind (unused imports, unreachable branches).
100
+ - [ ] The diff stays inside the task's scope.
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: ralphctl-codebase-design
3
+ description: Shared vocabulary and tests for module design — deep modules (much behaviour behind a small interface), seams placed where behaviour actually varies, the deletion test for pass-through layers, and the interface as the test surface. Use when planning module boundaries, deciding where a seam or abstraction belongs, judging whether a layer earns its keep, or making code easier to test through its interface.
4
+ license: MIT
5
+ ---
6
+
7
+ # Codebase Design
8
+
9
+ > Adapted from [mattpocock/skills — "Codebase Design"](https://github.com/mattpocock/skills) (MIT).
10
+ > Adapted for ralphctl's harness contract.
11
+
12
+ Design **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam, testable
13
+ through that interface. The aim is leverage for callers, locality for maintainers, and testability for
14
+ everyone. Reason with the vocabulary below; in code and in signals, keep the project's own terms when it
15
+ has established ones.
16
+
17
+ ## When this applies
18
+
19
+ - **Plan** — when splitting work, prefer tasks that deepen one module behind a small interface over tasks
20
+ that spread one concept across several shallow ones. When a task introduces a seam, name it in the
21
+ steps along with what varies across it.
22
+ - **Execute** — whenever you add a module, an interface, or an abstraction. When reviewing, apply the
23
+ deletion test and the one-adapter rule below to every new layer.
24
+
25
+ ## Vocabulary
26
+
27
+ - **Module** — anything with an interface and an implementation, at any scale: a function, a type, a
28
+ package, a slice spanning several layers.
29
+ - **Interface** — everything a caller must know to use the module correctly: the type signature, plus its
30
+ invariants, ordering constraints, error modes, required configuration, and performance characteristics.
31
+ - **Implementation** — the code inside the module.
32
+ - **Depth** — leverage at the interface: how much behaviour a caller or test can exercise per unit of
33
+ interface it has to learn. **Deep** when much sits behind little; **shallow** when the interface is
34
+ nearly as complex as what it hides.
35
+ - **Seam** (Michael Feathers) — a place where behaviour can be altered without editing in that place; the
36
+ location where a module's interface lives. Where to put the seam is its own decision.
37
+ - **Adapter** — a concrete thing that satisfies an interface at a seam. It names a role, not a size.
38
+ - **Leverage** — what callers gain from depth: more capability per thing they learn.
39
+ - **Locality** — what maintainers gain from depth: change, bugs, and knowledge concentrated in one place.
40
+ Fix once, fixed everywhere.
41
+
42
+ ## Principles
43
+
44
+ - **Depth is a property of the interface.** A deep module can be built from small, swappable internal
45
+ parts; they are just not part of its interface. It may have internal seams for its own tests as well as
46
+ the external seam callers use.
47
+ - **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If
48
+ the complexity reappears across many callers, it was earning its keep.
49
+ - **The interface is the test surface.** Callers and tests cross the same seam. Needing to test past the
50
+ interface means the module is the wrong shape.
51
+ - **One adapter is a hypothetical seam; two adapters is a real one.** Introduce a seam only where
52
+ something actually varies across it — a second implementation, or a test fake standing in for slow or
53
+ non-deterministic infrastructure.
54
+
55
+ When designing an interface, ask: can it have fewer operations, simpler parameters, more hidden inside?
56
+ Before committing to one shape, sketch two or three genuinely different interfaces for the same job and
57
+ compare them on depth, locality, and where the seam falls.
58
+
59
+ ## Designing for testability
60
+
61
+ - **Accept dependencies instead of creating them.** A function that receives its payment gateway or
62
+ clock can be tested with a fake; one that constructs the real thing internally cannot.
63
+ - **Return results instead of producing side effects.** Computing a discount and returning it is testable
64
+ by assertion; mutating a shared total in place is testable only by inspection.
65
+ - **Keep the surface small.** Fewer operations mean fewer tests; fewer parameters mean simpler setup.
66
+
67
+ ## Rejected framings
68
+
69
+ - **Depth as a ratio of implementation lines to interface lines** — it rewards padding the implementation.
70
+ Depth here means leverage.
71
+ - **"Interface" as only a language keyword or a list of public methods** — too narrow; every fact a caller
72
+ must know is part of it.
73
+ - **"Boundary"** for a seam — overloaded with domain-driven design's bounded context. Say seam or
74
+ interface.
75
+
76
+ ## Red flags
77
+
78
+ - A module whose interface mirrors its implementation one-to-one.
79
+ - A wrapper that only forwards calls.
80
+ - An interface with exactly one implementation and no test fake — a seam nothing varies across.
81
+ - A test that reaches past the interface into internals.
82
+ - One concept spread across several shallow modules that must always change together.
@@ -1,13 +1,14 @@
1
1
  ---
2
2
  name: ralphctl-debugging-and-error-recovery
3
- description: Systematic root-cause debugging. Use when tests fail, builds break, or behaviour does not match expectations. Follow stop-the-line → reproduce → localize → reduce → root-cause → guard-with-regression-test → verify, not guessing; the reproduction and regression steps follow the same red-green discipline as ralphctl-test-driven-development.
3
+ description: Systematic root-cause debugging. Use when tests fail, builds break, something that worked before broke, or behaviour does not match expectations — when you need to figure out what broke and why. Follow stop-the-line → reproduce → localize → reduce → root-cause → guard-with-regression-test → verify, not guessing; the reproduction and regression steps follow the same red-green discipline as ralphctl-test-driven-development.
4
4
  license: MIT
5
5
  ---
6
6
 
7
7
  # Debugging and Error Recovery
8
8
 
9
- > Adapted from [addyosmani/agent-skills](https://github.com/addyosmani/agent-skills) (MIT).
10
- > Adapted for ralphctl's harness contract.
9
+ > Adapted from [addyosmani/agent-skills](https://github.com/addyosmani/agent-skills) (MIT), with the
10
+ > feedback-loop, ranked-hypothesis, and tagged-log practices drawn from
11
+ > [mattpocock/skills](https://github.com/mattpocock/skills) (MIT). Adapted for ralphctl's harness contract.
11
12
 
12
13
  Systematic debugging with structured triage. When something breaks, stop adding features, preserve
13
14
  evidence, and follow a structured process to find and fix the root cause. Guessing wastes time. The
@@ -32,7 +33,7 @@ When anything unexpected happens:
32
33
  6. **Resume** only after the fix is verified with the project's narrow check gate.
33
34
 
34
35
  Do not push past a failing test or broken build to work on the next feature. Errors compound — a
35
- bug at Step 3 that goes unfixed makes Steps 4–10 wrong.
36
+ bug at Step 3 that goes unfixed makes Steps 4–6 wrong.
36
37
 
37
38
  ## The Triage Checklist
38
39
 
@@ -42,6 +43,15 @@ Work through these steps in order. Do not skip steps.
42
43
 
43
44
  Make the failure happen reliably. If you cannot reproduce it, you cannot fix it with confidence.
44
45
 
46
+ **Build a tight, red-capable loop before forming any theory.** When your session can run commands, the
47
+ first deliverable is one command you have already run that drives the real code path and asserts the
48
+ exact reported symptom — a failing test at the seam that reaches the bug, a script with a fixture input, a
49
+ captured payload replayed through the code, the same input run through the old and new versions. Tight
50
+ means fast (seconds) and deterministic, or for a flaky bug a pinned, high reproduction rate. Reading code
51
+ to build a theory before that command exists is the failure this step prevents. When no loop can be built
52
+ in this session, list what you tried and what would make it possible rather than guessing — in a `note`
53
+ signal when the prompt's output-contract section lists it, otherwise in the required signal's own fields.
54
+
45
55
  When a bug is non-reproducible, work through these branches:
46
56
 
47
57
  - **Timing-dependent** — add timestamps to logs near the suspected area; try with artificial delays to widen race windows; run under load or concurrency to increase collision probability.
@@ -79,7 +89,12 @@ Create the minimal failing case:
79
89
 
80
90
  A minimal reproduction makes the root cause obvious and prevents fixing symptoms instead of causes.
81
91
 
82
- ### Step 4: Fix the Root Cause
92
+ ### Step 4: Hypothesise, then Fix the Root Cause
93
+
94
+ Before testing any explanation, write down three to five ranked hypotheses — a single one anchors on the
95
+ first plausible idea. Each must be falsifiable: "if X is the cause, changing Y makes the symptom disappear".
96
+ A hypothesis with no prediction is a hunch; sharpen it or drop it. Test them in rank order against the
97
+ loop, changing one variable at a time.
83
98
 
84
99
  Fix the underlying issue, not the symptom.
85
100
 
@@ -149,6 +164,9 @@ when the prompt's output-contract section lists it, otherwise in the required si
149
164
 
150
165
  Add logging only when it helps. Remove it when done.
151
166
 
167
+ - **Tag temporary logs** with one unique prefix (for example `[DEBUG-a4f2]`), so removal is a single
168
+ search. Untagged temporary logs survive into the diff; search for the prefix and remove every hit
169
+ before you signal the work complete.
152
170
  - **When to add** — you cannot localize the failure to a specific line; the issue is intermittent; the fix involves multiple interacting components.
153
171
  - **When to remove** — the bug is fixed and a regression test guards against recurrence; the log is only useful during development.
154
172
  - **Permanent instrumentation (keep)** — error boundaries with error reporting; API error logging with request context; performance metrics at key user flows.
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: ralphctl-deprecation-and-migration
3
+ description: Discipline for removing or replacing code, interfaces, stored data shapes, and dependencies safely — confirm the replacement covers every consumer, migrate consumers incrementally behind an adapter or switch, change persisted data in additive expand-then-contract phases with a tested way back, and remove the old path only once nothing uses it. Use when retiring an API, module, feature, flag, or dependency, renaming or dropping a stored field, or moving callers from one implementation to another.
4
+ license: MIT
5
+ ---
6
+
7
+ # Deprecation and Migration
8
+
9
+ > Adapted from [addyosmani/agent-skills — "Deprecation and Migration"](https://github.com/addyosmani/agent-skills)
10
+ > (MIT). Adapted for ralphctl's harness contract.
11
+
12
+ Code is a liability, not an asset: every line needs tests, upgrades, and attention from anyone working
13
+ nearby. Deprecation removes code that no longer earns its keep; migration moves its consumers safely to
14
+ what replaces it. Most teams are good at adding things and bad at removing them — this skill is the
15
+ removal half.
16
+
17
+ ## When this applies
18
+
19
+ - **Plan** — sequence the work so each step ships on its own: the replacement first, consumers next,
20
+ removal last and alone. Give the removal task the verification criterion "no remaining consumers", and
21
+ keep each data-shape phase below a separate task.
22
+ - **Execute** — implement one phase per task. Do not fold an additive step and its destructive follow-up
23
+ into one change, and do not remove anything a consumer still reaches.
24
+
25
+ ## Before removing anything
26
+
27
+ Hyrum's law makes removal hard: consumers depend on behaviour the replacement may not reproduce —
28
+ ordering, defaults, error text, side effects. Answer first:
29
+
30
+ 1. Does the old thing still provide something nothing else does? If so, keep it.
31
+ 2. Who consumes it? Search code, configuration, scripts, docs, and tests, including dynamic lookups by
32
+ name. Consumers outside this repository may exist — say so rather than assume none.
33
+ 3. Does a replacement exist and cover every critical use? If not, build that first.
34
+ 4. What does each consumer's move cost, against the ongoing cost of keeping both?
35
+
36
+ ## The process
37
+
38
+ 1. **Replacement first.** It covers the critical cases and is proven, not just "theoretically better".
39
+ 2. **Mark the old path deprecated** with the project's own mechanism — a deprecation annotation, a
40
+ runtime warning, a changelog entry — when it has one. Do not invent a new notice file.
41
+ 3. **Migrate incrementally.** One consumer or area per change: find its touchpoints, switch it, confirm
42
+ behaviour matches with its tests, remove its reference to the old path. Whoever retires a thing
43
+ migrates its consumers or ships a compatible shim — never leave them to discover the break.
44
+ 4. **Remove only at zero.** Once no consumer remains: the code, its tests, docs, configuration, and the
45
+ deprecation markers themselves.
46
+
47
+ ## Migration patterns
48
+
49
+ - **Strangler** — run old and new side by side and route a growing share to the new path; remove the old
50
+ one when its share is zero.
51
+ - **Adapter** — keep the old interface as a thin layer over the new implementation, so consumers keep
52
+ working while the backend moves.
53
+ - **Switch per consumer** — cut consumers over one at a time with the project's existing flag or
54
+ configuration mechanism.
55
+
56
+ ## Persisted data: expand, then contract
57
+
58
+ A stored shape is the riskiest thing to change — reverting the code does not revert the data, and during a
59
+ rollout old and new code run against the same store. Never change a stored shape in place:
60
+
61
+ ```
62
+ EXPAND → MIGRATE → CONTRACT
63
+ add the new shape write both, backfill old records, stop writing the old shape,
64
+ beside the old one then switch reads to the new one then drop it in a later change
65
+ ```
66
+
67
+ - Additive first, destructive last and alone. Adds are safe in any release; drops and renames ship on
68
+ their own, after nothing reads the old shape.
69
+ - Every migration has a tested way back — a down migration, or readers that tolerate both shapes.
70
+ - A migration is safe to re-run and safe to interrupt; stamp what has been migrated.
71
+ - Backfill in batches, off the hot path, so it does not lock or starve the store.
72
+ - The same rules hold for files on disk: version the format, and keep readers tolerant of the old shape.
73
+
74
+ ## Zombie code
75
+
76
+ Code nobody owns but something still depends on — no maintainer, failing tests nobody fixes, outdated
77
+ dependencies. Either give it an owner and maintain it, or deprecate it with a concrete migration. It
78
+ cannot stay in limbo.
79
+
80
+ ## Common rationalisations
81
+
82
+ | Rationalisation | Reality |
83
+ | ------------------------------------------------- | ----------------------------------------------------------------------------------------- |
84
+ | "It still works, why remove it?" | Unmaintained working code accumulates risk and complexity silently. |
85
+ | "Someone might need it later" | It can be rebuilt if needed. Keeping it "just in case" costs more. |
86
+ | "Consumers will migrate on their own" | They will not. Migrate them, or ship a shim that needs no migration. |
87
+ | "Just rename the field, it's one line" | During rollout, old and new code run together and one of them reads a field that is gone. |
88
+ | "Add the new field and drop the old one together" | That couples a safe add to a destructive drop. Drops ship alone, later. |
89
+ | "We'll write the way back if we need it" | A migration with no way back is a release you cannot undo. |
90
+
91
+ ## Red flags
92
+
93
+ - A deprecation with no working replacement.
94
+ - Removal without a search for remaining consumers.
95
+ - New features added to the deprecated path.
96
+ - A stored field renamed or dropped in place.
97
+ - A schema change and the code that depends on it shipped as one step.
98
+ - A migration with no way back, or a backfill that locks the store.
99
+
100
+ ## Self-check
101
+
102
+ - [ ] The replacement covers every critical use of the old path.
103
+ - [ ] Every known consumer is migrated; unknown external consumers are named as a risk.
104
+ - [ ] Persisted-shape changes are phased: expand, migrate, contract.
105
+ - [ ] Each migration has a tested way back and is safe to re-run.
106
+ - [ ] Removal deletes the code, its tests, docs, configuration, and deprecation markers.