@martinffx/atelier 3.3.0 → 3.4.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/CHANGELOG.md CHANGED
@@ -4,16 +4,21 @@
4
4
 
5
5
  - **breaking:** rename the `recon` agent to `sentinel`. Existing Atelier configuration is migrated automatically and legacy generated files are removed during the next command.
6
6
 
7
+ ## [3.4.0](https://github.com/martinffx/atelier/compare/v3.3.0...v3.4.0) (2026-10-09)
8
+
9
+
10
+ ### Features
11
+
12
+ * **skills:** add oracle-codebase-design ([#80](https://github.com/martinffx/atelier/issues/80)) ([3672e9c](https://github.com/martinffx/atelier/commit/3672e9c655fa93d704473ebba8d2c194605f39c7))
13
+
7
14
  ## [3.3.0](https://github.com/martinffx/atelier/compare/v3.2.1...v3.3.0) (2026-10-09)
8
15
 
9
16
 
10
17
  ### Features
11
18
 
12
- * **agents:** let the harness select agents from descriptions ([5fb7eba](https://github.com/martinffx/atelier/commit/5fb7eba11f96f7af9c48f8663c6e853f22de6149))
13
19
  * **agents:** let the harness select agents from descriptions ([6793dde](https://github.com/martinffx/atelier/commit/6793dde9afebb7ccbc6efb3efa3e3e1e24bd2fa5))
14
20
  * **claude:** oracle on opus/xhigh and claude.ai opt-outs in user settings ([#76](https://github.com/martinffx/atelier/issues/76)) ([d79208f](https://github.com/martinffx/atelier/commit/d79208fec17801dd041e202ee9ba6738f0071724))
15
21
  * **claude:** support graded thinking for Haiku 5.5 ([#77](https://github.com/martinffx/atelier/issues/77)) ([6cc6992](https://github.com/martinffx/atelier/commit/6cc699274e08ef9ff116ffa22e895194b85fbb06))
16
- * **skills:** authorise delegation without naming agents ([d63e4c2](https://github.com/martinffx/atelier/commit/d63e4c27d24bf7fe82722546bb28e913a1af6b01))
17
22
  * **skills:** authorise delegation without naming agents ([81af084](https://github.com/martinffx/atelier/commit/81af08494f736375e10fcdedb44192cfe0299d87))
18
23
 
19
24
  ## [3.2.1](https://github.com/martinffx/atelier/compare/v3.2.0...v3.2.1) (2026-10-03)
@@ -22,7 +27,6 @@
22
27
  ### Bug Fixes
23
28
 
24
29
  * **code-review:** align simplicity trust boundary and aggregation ([04ad861](https://github.com/martinffx/atelier/commit/04ad861aaef0d5048b11a4945c53628dc99f102c))
25
- * **code-review:** run simplicity gate once and add trust boundary ([4d34d2a](https://github.com/martinffx/atelier/commit/4d34d2af7612fac1cb907681800fc6d1a9493e4c))
26
30
  * **code-review:** run simplicity gate once and add trust boundary ([fe09d49](https://github.com/martinffx/atelier/commit/fe09d49c5ce230859f81591783e88650d25a85bb)), closes [#67](https://github.com/martinffx/atelier/issues/67) [#68](https://github.com/martinffx/atelier/issues/68)
27
31
 
28
32
  ## [3.2.0](https://github.com/martinffx/atelier/compare/v3.1.2...v3.2.0) (2026-09-28)
@@ -30,7 +34,6 @@
30
34
 
31
35
  ### Features
32
36
 
33
- * **config:** add per-model thinking defaults across adapters ([756e698](https://github.com/martinffx/atelier/commit/756e698ccc0c466dc496a07c32c2e92508a58149))
34
37
  * **config:** add per-model thinking defaults across adapters ([319196e](https://github.com/martinffx/atelier/commit/319196eb0e37454551a3589a712ca8650fd8e57f))
35
38
  * **models:** update sonnet to 5.5 ([781d99f](https://github.com/martinffx/atelier/commit/781d99ff58600cb3ade16183f62814e40b7b73ee))
36
39
 
@@ -126,10 +129,8 @@
126
129
  ### Features
127
130
 
128
131
  * **code-pull-request:** add comment and merge workflows with progressive disclosure ([53e8957](https://github.com/martinffx/atelier/commit/53e89574ae1c37d0c3e868c7bbecee560e38c573))
129
- * **code:** add code-pull-request skill for PR creation ([62e32a6](https://github.com/martinffx/atelier/commit/62e32a6373be02cfad5fd3cb3fa248efcf3cc06c))
130
132
  * **code:** add code-pull-request skill for PR creation ([e4d2475](https://github.com/martinffx/atelier/commit/e4d24752f610177d6706cf382f3db3c9f5406355))
131
133
  * **skills:** split oracle-grillme into oracle-grill-me and oracle-domain-modelling ([#40](https://github.com/martinffx/atelier/issues/40)) ([e373c12](https://github.com/martinffx/atelier/commit/e373c12d05d9cde3ddb02fb0fc26ee770fb959a2))
132
- * **spec-brainstorm:** add section-by-section design approval ([f66eb62](https://github.com/martinffx/atelier/commit/f66eb6275780768300218d329bff8882b6d20e5d))
133
134
  * **spec-brainstorm:** add section-by-section design approval ([9cfb7e7](https://github.com/martinffx/atelier/commit/9cfb7e732fe20c546c2465218a8392dcba7859ad))
134
135
 
135
136
 
@@ -144,7 +145,6 @@
144
145
 
145
146
  ### Bug Fixes
146
147
 
147
- * **skills:** remove user-invocable from code-docs ([beaaaee](https://github.com/martinffx/atelier/commit/beaaaee03d64955a3e8092d250cd4ab318c5d55d))
148
148
  * **skills:** remove user-invocable from code-docs ([00a2a82](https://github.com/martinffx/atelier/commit/00a2a82ce064bf0a88d2d13de796c4c7e120e472))
149
149
 
150
150
  ## [1.2.1](https://github.com/martinffx/atelier/compare/v1.2.0...v1.2.1) (2026-05-23)
@@ -153,7 +153,6 @@
153
153
  ### Bug Fixes
154
154
 
155
155
  * **cli:** correct skills directory path and add legacy config migration ([14f9611](https://github.com/martinffx/atelier/commit/14f9611bf4d8876844ef86ccc3fce55b203f2bed))
156
- * register missing skills in marketplace.json ([06da766](https://github.com/martinffx/atelier/commit/06da76647ed7c6721a2bc283f9bbd1c212b08456))
157
156
  * register missing skills in marketplace.json ([9f48099](https://github.com/martinffx/atelier/commit/9f48099e0be5de184c6200105e9b0b839fbcda1a))
158
157
 
159
158
  ## [1.2.0](https://github.com/martinffx/atelier/compare/v1.1.0...v1.2.0) (2026-05-23)
@@ -161,15 +160,10 @@
161
160
 
162
161
  ### Features
163
162
 
164
- * **code-debug:** upgrade to six-phase diagnose workflow ([62dec10](https://github.com/martinffx/atelier/commit/62dec1045555947462a447f4579e83b0dee63d17))
165
163
  * **code-debug:** upgrade to six-phase diagnose workflow ([8df277d](https://github.com/martinffx/atelier/commit/8df277d425ca16dfa63a8bf1949003e3e6aaf87c))
166
- * **code-handoff:** add code-handoff skill ([5ab6f5f](https://github.com/martinffx/atelier/commit/5ab6f5f5d890b024718e3b69103b23c3eb1205ef))
167
- * **oracle-architect:** add vocabulary, evaluation heuristics, and interface design reference ([7c528d3](https://github.com/martinffx/atelier/commit/7c528d308ebc98929cfc6be17e8d5c7444b36607))
168
164
  * **oracle-architect:** add vocabulary, evaluation heuristics, and interface design reference ([63ee753](https://github.com/martinffx/atelier/commit/63ee75380c4d4be92708539173534566f2033dea))
169
- * **oracle-security:** add security architecture and threat modeling skill ([8fcbd87](https://github.com/martinffx/atelier/commit/8fcbd87943bcb23d51480ed9e9bd702f19817096))
170
165
  * **oracle-security:** add security architecture and threat modeling skill ([69b6fdc](https://github.com/martinffx/atelier/commit/69b6fdcdf1f2b7732fb339cbf1d64c1fb7252eb7))
171
166
  * **skills:** add code-handoff skill ([012f467](https://github.com/martinffx/atelier/commit/012f4676d48c7f6799361ca6bdfef12f33a8849e))
172
- * **skills:** add oracle-doubt skill ([adf118b](https://github.com/martinffx/atelier/commit/adf118be197da43195c9ddd052b53f8c714405b5))
173
167
  * **skills:** add oracle-doubt skill for adversarial review ([447673e](https://github.com/martinffx/atelier/commit/447673eb7904e4d28306360f64329f7874db5b2b))
174
168
 
175
169
  ## [1.1.0](https://github.com/martinffx/atelier/compare/v1.0.2...v1.1.0) (2026-05-23)
@@ -177,7 +171,6 @@
177
171
 
178
172
  ### Features
179
173
 
180
- * **skills:** add oracle-grillme socratic interrogation skill ([6ad5ce5](https://github.com/martinffx/atelier/commit/6ad5ce52428863b51fec83880ce8083bb80aa3a0))
181
174
  * **skills:** add oracle-grillme socratic interrogation skill ([fd21606](https://github.com/martinffx/atelier/commit/fd2160639b82ba335963bec3128d9c6a5b5801b6))
182
175
  * **skills:** add PR creation workflow to code-commit ([25bb826](https://github.com/martinffx/atelier/commit/25bb8264364cb1c5ee843baea0127eaba3935c78))
183
176
 
@@ -186,7 +179,6 @@
186
179
 
187
180
  ### Bug Fixes
188
181
 
189
- * **package:** remove publish script to prevent recursive npm publish ([cbb1420](https://github.com/martinffx/atelier/commit/cbb14200785f0bf73c6e9f60714e3bf774bac5dd))
190
182
  * **package:** remove publish script to prevent recursive npm publish in CI ([d2a62dc](https://github.com/martinffx/atelier/commit/d2a62dc3c40301abdf7ddfce86db71c60724b575))
191
183
 
192
184
  ## [1.0.1](https://github.com/martinffx/atelier/compare/v1.0.0...v1.0.1) (2026-05-23)
@@ -194,7 +186,6 @@
194
186
 
195
187
  ### Bug Fixes
196
188
 
197
- * **ci:** resolve npm publish authentication failure ([7c57b85](https://github.com/martinffx/atelier/commit/7c57b8504e1f8045b9efeb7ccc5aebfb98e80050))
198
189
  * **ci:** resolve npm publish authentication failure in release workflow ([5e584bb](https://github.com/martinffx/atelier/commit/5e584bb7bea0f261152cc057dfab444e4c9c1402))
199
190
 
200
191
  ## 1.0.0 (2026-05-22)
package/README.md CHANGED
@@ -101,7 +101,7 @@ Atelier installs a focused set of skills for the full development loop:
101
101
  | Area | Capabilities |
102
102
  |------|--------------|
103
103
  | Spec workflow | Discovery, research, planning, implementation, validation, and finishing |
104
- | Thinking | Root-cause debugging, decision grilling, and domain modelling |
104
+ | Thinking | Root-cause debugging, decision grilling, domain modelling, and codebase design |
105
105
  | Delivery | Multi-agent review, subagent coordination, commits, handoffs, and pull requests |
106
106
 
107
107
  The CLI also configures four specialist agents for Claude Code, OpenCode, Codex, or Cursor:
@@ -179,6 +179,7 @@ Some Atelier skills have more direct lineage:
179
179
  | [`code-handoff`](skills/code-handoff/SKILL.md) | Matt Pocock's [`handoff`](https://github.com/mattpocock/skills/tree/main/skills/productivity/handoff) | Adapted from its context-preserving handoff format. |
180
180
  | [`oracle-grill-me`](skills/oracle-grill-me/SKILL.md) | Matt Pocock's [`grilling`](https://github.com/mattpocock/skills/tree/main/skills/productivity/grilling) and [`grill-with-docs`](https://github.com/mattpocock/skills/tree/main/skills/engineering/grill-with-docs) | Adapted from its rigorous interview loop and integration with living domain documentation. |
181
181
  | [`oracle-domain-modelling`](skills/oracle-domain-modelling/SKILL.md) | Matt Pocock's [`domain-modeling`](https://github.com/mattpocock/skills/tree/main/skills/engineering/domain-modeling) | Adapted from its active domain-modelling discipline, `CONTEXT.md`, and lightweight ADRs. |
182
+ | [`oracle-codebase-design`](skills/oracle-codebase-design/SKILL.md) | Matt Pocock's [`codebase-design`](https://github.com/mattpocock/skills/tree/main/skills/engineering/codebase-design) and John Ousterhout's *A Philosophy of Software Design* | Adapted from its deep-module vocabulary, deletion test, and design-it-twice. Extended with Ousterhout's principles and red flags, plus Alexis King's "parse, don't validate", Yaron Minsky's "make illegal states unrepresentable", and Gary Bernhardt's "functional core, imperative shell". |
182
183
  | [`oracle-debug`](skills/oracle-debug/SKILL.md) | Superpowers [`systematic-debugging`](https://github.com/obra/superpowers/tree/main/skills/systematic-debugging) and Matt Pocock's [`diagnosing-bugs`](https://github.com/mattpocock/skills/tree/main/skills/engineering/diagnosing-bugs) | Adapted from their root-cause-first debugging workflows. |
183
184
 
184
185
  [`code-commit`](skills/code-commit/SKILL.md) follows the [Conventional Commits](https://www.conventionalcommits.org/) specification.
@@ -14,7 +14,7 @@ You are the **Architect**, a senior technical designer and systems thinker. Your
14
14
 
15
15
  ## Skills
16
16
 
17
- Before beginning work, scan your environment for relevant skills and load any that apply to the task at hand. Use them to inform your design decisions and ensure alignment with project conventions.
17
+ Before beginning work, scan your environment for relevant skills and load any that apply to the task at hand. Always load `oracle-codebase-design` when available. Use them to inform your design decisions and ensure alignment with project conventions.
18
18
 
19
19
  ## Checklist
20
20
 
@@ -23,7 +23,8 @@ Before finishing, confirm you have:
23
23
  - [ ] Identified all entities, value objects, aggregates, and their relationships
24
24
  - [ ] Defined properties, types, and validation rules for each model
25
25
  - [ ] Specified API endpoints with methods, paths, and request/response contracts
26
- - [ ] Listed error cases and handling strategy
26
+ - [ ] Listed error cases and handling strategy (defined away where possible, otherwise returned as values)
27
+ - [ ] Identified where untrusted input is parsed into domain types (the external seam)
27
28
  - [ ] For Spec-backed Plan work, provided dependency-ordered task recommendations (entity → repository → service → router)
28
29
  - [ ] For Spec-backed Plan work, written or updated the Technical Design section in `design.md`
29
30
 
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@martinffx/atelier",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "description": "Personal development toolkit - spec-driven development, code quality, deep thinking, and ecosystem patterns",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "atelier": "dist/atelier.js"
8
8
  },
9
- "repository": "github:martinffx/atelier",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/martinffx/atelier.git"
12
+ },
10
13
  "keywords": [
11
14
  "cli",
12
15
  "claude-code",
@@ -198,7 +198,7 @@ If you loop 2+ times on the same issue, stop and ask the human:
198
198
  **Process skills** (spec-brainstorm, spec-plan, spec-implement, spec-finish): Follow exactly.
199
199
  Don't adapt away discipline.
200
200
 
201
- **Knowledge skills** (oracle-grill-me, oracle-domain-modelling): Adapt principles to
201
+ **Knowledge skills** (oracle-grill-me, oracle-domain-modelling, oracle-codebase-design): Adapt principles to
202
202
  context. These inform decisions within the workflow.
203
203
 
204
204
  **Discipline skills** (oracle-debug): Strict methodology that must be followed
@@ -247,6 +247,8 @@ Focus areas:
247
247
  - Test coverage gaps
248
248
  - Coupling and cohesion
249
249
  - DRY violations
250
+ - Tests that reach past the interface
251
+ - Vague or inconsistent names
250
252
 
251
253
  Output findings in this format:
252
254
  - **Location**: file:line
@@ -257,7 +259,7 @@ Output findings in this format:
257
259
  - **Pre-existing**: Yes/No
258
260
  ```
259
261
 
260
- Loads: Look for relevant testing and language-specific pattern skills; load them if available.
262
+ Loads: Look for `oracle-codebase-design` and relevant testing and language-specific pattern skills; load them if available.
261
263
 
262
264
  ---
263
265
 
@@ -278,6 +280,8 @@ Focus areas:
278
280
  - Dependency direction
279
281
  - Layer separation
280
282
  - SOLID violations
283
+ - Shallow modules and pass-throughs, information leakage across modules
284
+ - Untrusted input crossing a seam unparsed, I/O mixed into decision logic
281
285
 
282
286
  Output findings in this format:
283
287
  - **Location**: file:line
@@ -288,7 +292,7 @@ Output findings in this format:
288
292
  - **Pre-existing**: Yes/No
289
293
  ```
290
294
 
291
- Loads: Look for relevant architecture and language architecture skills; load them if available.
295
+ Loads: Look for `oracle-codebase-design` and relevant architecture and language architecture skills; load them if available.
292
296
 
293
297
  ---
294
298
 
@@ -121,7 +121,7 @@ prompt: |
121
121
  "context": { "language": "typescript", "framework": "fastify", "domain": "web-api", "change_type": "refactor" },
122
122
  "simplicity_required": true,
123
123
  "reviewers": ["Security", "Correctness", "PerformanceOperator"],
124
- "skills_to_load": ["ponytail", "relevant installed testing skill"]
124
+ "skills_to_load": ["ponytail", "oracle-codebase-design", "relevant installed testing skill"]
125
125
  }
126
126
  ```
127
127
 
@@ -363,7 +363,7 @@ prompt: |
363
363
  independently and leave final decision reconciliation to the challenge step.
364
364
 
365
365
  **PRE-STEP: Look for Relevant Skills**
366
- Before reviewing, look for relevant architecture and language architecture skills.
366
+ Before reviewing, look for `oracle-codebase-design` and relevant architecture and language architecture skills.
367
367
  Load relevant installed language, framework, testing, architecture, security, or tooling skills.
368
368
  If no relevant skill is available or a skill cannot be loaded, continue with this architect prompt.
369
369
  Failure to find or load a skill is not a review failure.
@@ -376,6 +376,8 @@ prompt: |
376
376
  - SOLID violations
377
377
  - Data model design
378
378
  - API contract design
379
+ - Shallow modules and pass-throughs, information leakage across modules
380
+ - Untrusted input crossing a seam unparsed, I/O mixed into decision logic
379
381
 
380
382
  Return findings as JSON:
381
383
  {
@@ -63,6 +63,7 @@ Review your work with fresh eyes:
63
63
  - Is this my best work?
64
64
  - Are names clear and accurate?
65
65
  - Is the code clean and maintainable?
66
+ - If `oracle-codebase-design` is available, did I check its red flags (shallow modules, leakage, pass-throughs)?
66
67
 
67
68
  **Discipline:**
68
69
  - Did I avoid overbuilding (YAGNI)?
@@ -71,6 +72,7 @@ Review your work with fresh eyes:
71
72
 
72
73
  **Testing:**
73
74
  - Do tests actually verify behaviour (not just mock behaviour)?
75
+ - Do tests go through the module's interface rather than past it?
74
76
  - Did I follow TDD?
75
77
  - Are tests comprehensive?
76
78
 
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: oracle-codebase-design
3
+ description: >
4
+ Shared vocabulary and principles for designing deep modules. Use when designing or changing
5
+ a module's interface, deciding where a seam goes, handling untrusted input at the edges,
6
+ choosing the level to test at, naming modules, or making code more testable. Also use when
7
+ another skill needs the deep-module vocabulary.
8
+ user-invocable: false
9
+ ---
10
+
11
+ # Codebase Design
12
+
13
+ Design **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. The aim is leverage for callers, locality for maintainers, and testability for everyone.
14
+
15
+ ## Why
16
+
17
+ Complexity is the enemy. It shows up as:
18
+
19
+ - **Change amplification**: a simple change touches many places.
20
+ - **Cognitive load**: you must hold a lot in your head to change anything safely.
21
+ - **Unknown unknowns**: it is not obvious what you need to change or know.
22
+
23
+ It has two causes: **dependencies** and **obscurity**. Good design removes both.
24
+
25
+ Work **strategically, not tactically**. Working code is not enough. Each change is a small, continual investment in the design, not a patch on top of it.
26
+
27
+ ## Glossary
28
+
29
+ Use these terms exactly. Don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point.
30
+
31
+ **Module**: anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. _Avoid_: unit, component, service.
32
+
33
+ **Interface**: everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. _Avoid_: API, signature (too narrow, they refer only to the type-level surface).
34
+
35
+ **Implementation**: what's inside a module, its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.
36
+
37
+ **Depth**: leverage at the interface. The amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface, **shallow** when the interface is nearly as complex as the implementation.
38
+
39
+ **Seam** _(Michael Feathers)_: a place where you can alter behaviour without editing in that place; the *location* at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. _Avoid_: boundary (overloaded with DDD's bounded context).
40
+
41
+ **Adapter**: a concrete thing that satisfies an interface at a seam. Describes *role* (what slot it fills), not substance (what's inside).
42
+
43
+ **Leverage**: what callers get from depth. More capability per unit of interface they learn. One implementation pays back across N call sites and M tests.
44
+
45
+ **Locality**: what maintainers get from depth. Change, bugs, knowledge, and verification concentrate in one place rather than spreading across callers. Fix once, fixed everywhere.
46
+
47
+ ### Project names
48
+
49
+ When the project's own pattern names a layer (Router, Service, Repository, Entity), keep that name for the concrete thing: say "the `OrderService`". Describe its *design* with the glossary: is that module deep, where is its seam, what is its interface?
50
+
51
+ ## Deep vs shallow
52
+
53
+ **Deep module** = small interface + lots of implementation:
54
+
55
+ ```
56
+ ┌─────────────────────┐
57
+ │ Small Interface │ ← Few methods, simple params
58
+ ├─────────────────────┤
59
+ │ │
60
+ │ Deep Implementation│ ← Complex logic hidden
61
+ │ │
62
+ └─────────────────────┘
63
+ ```
64
+
65
+ **Shallow module** = large interface + little implementation (avoid):
66
+
67
+ ```
68
+ ┌─────────────────────────────────┐
69
+ │ Large Interface │ ← Many methods, complex params
70
+ ├─────────────────────────────────┤
71
+ │ Thin Implementation │ ← Just passes through
72
+ └─────────────────────────────────┘
73
+ ```
74
+
75
+ When designing an interface, ask:
76
+
77
+ - Can I reduce the number of methods?
78
+ - Can I simplify the parameters?
79
+ - Can I hide more complexity inside?
80
+ - Can I define an error out of existence?
81
+
82
+ ## Principles
83
+
84
+ Details, rationale, and examples in [principles.md](references/principles.md).
85
+
86
+ - **Deep modules and the deletion test.** If deleting the module makes complexity vanish, it was a pass-through.
87
+ - **Test at the correct level.** The interface is the test surface. Test at seams, not every function; replace tests, don't layer them.
88
+ - **Parse, don't validate.** Turn untrusted input into domain types at the external seam. The core never re-checks.
89
+ - **Make illegal states unrepresentable.** Shape the types so invalid combinations can't be built.
90
+ - **Functional core, imperative shell.** Pure decisions inside, I/O at the edges.
91
+ - **Errors as values.** Expected failures are part of the interface and are returned, not thrown.
92
+ - **Define errors out of existence.** Change the semantics so the error cannot occur. Do this first.
93
+ - **Information hiding.** Each design decision lives in one module. Duplicated knowledge is leakage.
94
+ - **Pull complexity downward.** A simple interface matters more than a simple implementation.
95
+ - **Somewhat general-purpose modules are deeper.** Keep general and special-purpose code apart.
96
+ - **Different layers, different abstractions.** No pass-through methods or variables.
97
+ - **Together or apart.** Combine what shares information; split general mechanism from specific use.
98
+ - **Make the common case simple.** Defaults over configuration.
99
+ - **Comments and names carry the design.** Describe what isn't obvious; write interface comments first.
100
+ - **Seam discipline.** One adapter means a hypothetical seam, two means a real one. Accept dependencies, don't create them.
101
+
102
+ ## Red flags
103
+
104
+ Before finalising a design, check it against [red-flags.md](references/red-flags.md): shallow module, information leakage, pass-through method, vague name, and the rest.
105
+
106
+ ## Names and domain language
107
+
108
+ Name modules with the project's domain terms from `CONTEXT.md`. A name that is hard to pick or hard to describe is a design smell: the concept is probably unclear. Resolve it with the `oracle-domain-modelling` skill, and take contested design decisions through `oracle-grill-me`.
109
+
110
+ ## Relationships
111
+
112
+ - A **Module** has exactly one **Interface** (the surface it presents to callers and tests).
113
+ - **Depth** is a property of a **Module**, measured against its **Interface**.
114
+ - A **Seam** is where a **Module**'s **Interface** lives.
115
+ - An **Adapter** sits at a **Seam** and satisfies the **Interface**.
116
+ - **Depth** produces **Leverage** for callers and **Locality** for maintainers.
117
+
118
+ ## Rejected framings
119
+
120
+ - **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.
121
+ - **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow: interface here includes every fact a caller must know.
122
+ - **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**.
123
+
124
+ ## Going deeper
125
+
126
+ - **Principles with examples**, see [principles.md](references/principles.md).
127
+ - **Red-flags checklist**, see [red-flags.md](references/red-flags.md).
128
+ - **Deepening a cluster given its dependencies**, see [deepening.md](references/deepening.md): dependency categories, seam discipline, and replace-don't-layer testing.
129
+ - **Exploring alternative interfaces**, see [design-it-twice.md](references/design-it-twice.md): spin up parallel sub-agents to design the interface several radically different ways, then compare.
@@ -0,0 +1,37 @@
1
+ # Deepening
2
+
3
+ How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [SKILL.md](../SKILL.md): **module**, **interface**, **seam**, **adapter**.
4
+
5
+ ## Dependency categories
6
+
7
+ When assessing a candidate for deepening, classify its dependencies. The category determines how the deepened module is tested across its seam.
8
+
9
+ ### 1. In-process
10
+
11
+ Pure computation, in-memory state, no I/O. Always deepenable: merge the modules and test through the new interface directly. No adapter needed.
12
+
13
+ ### 2. Local-substitutable
14
+
15
+ Dependencies that have local test stand-ins (PGLite for Postgres, in-memory filesystem). Deepenable if the stand-in exists. The deepened module is tested with the stand-in running in the test suite. The seam is internal; no port at the module's external interface.
16
+
17
+ ### 3. Remote but owned (Ports & Adapters)
18
+
19
+ Your own services across a network boundary (microservices, internal APIs). Define a **port** (interface) at the seam. The deep module owns the logic; the transport is injected as an **adapter**. Tests use an in-memory adapter. Production uses an HTTP/gRPC/queue adapter.
20
+
21
+ Recommendation shape: *"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."*
22
+
23
+ ### 4. True external (Mock)
24
+
25
+ Third-party services (Stripe, Twilio, etc.) you don't control. The deepened module takes the external dependency as an injected port; tests provide a mock adapter.
26
+
27
+ ## Seam discipline
28
+
29
+ - **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection.
30
+ - **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them.
31
+
32
+ ## Testing strategy: replace, don't layer
33
+
34
+ - Old unit tests on shallow modules become waste once tests at the deepened module's interface exist; delete them.
35
+ - Write new tests at the deepened module's interface. The **interface is the test surface**.
36
+ - Tests assert on observable outcomes through the interface, not internal state.
37
+ - Tests should survive internal refactors, since they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface.
@@ -0,0 +1,44 @@
1
+ # Design It Twice
2
+
3
+ When the user wants to explore alternative interfaces for a module, use this parallel sub-agent pattern. Based on "Design It Twice" (John Ousterhout, *A Philosophy of Software Design*): your first idea is unlikely to be the best.
4
+
5
+ Uses the vocabulary in [SKILL.md](../SKILL.md): **module**, **interface**, **seam**, **adapter**, **leverage**.
6
+
7
+ ## Process
8
+
9
+ ### 1. Frame the problem space
10
+
11
+ Before spawning sub-agents, write a user-facing explanation of the problem space:
12
+
13
+ - The constraints any new interface would need to satisfy
14
+ - The dependencies it would rely on, and which category they fall into (see [deepening.md](deepening.md))
15
+ - A rough illustrative code sketch to ground the constraints, not a proposal, just a way to make the constraints concrete
16
+
17
+ Show this to the user, then immediately proceed to Step 2. The user reads and thinks while the sub-agents work in parallel.
18
+
19
+ ### 2. Spawn sub-agents
20
+
21
+ Spawn 3+ sub-agents in parallel. Each must produce a **radically different** interface for the module.
22
+
23
+ Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [deepening.md](deepening.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
24
+
25
+ - Agent 1: "Minimize the interface: aim for 1–3 entry points max. Maximise leverage per entry point."
26
+ - Agent 2: "Maximise flexibility: support many use cases and extension."
27
+ - Agent 3: "Optimise for the most common caller: make the default case trivial."
28
+ - Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies."
29
+
30
+ Include both [SKILL.md](../SKILL.md) vocabulary and the project's `CONTEXT.md` vocabulary in the brief so each sub-agent names things consistently with the design language and the project's domain language.
31
+
32
+ Each sub-agent outputs:
33
+
34
+ 1. Interface (types, methods, params, plus invariants, ordering, error modes)
35
+ 2. Usage example showing how callers use it
36
+ 3. What the implementation hides behind the seam
37
+ 4. Dependency strategy and adapters (see [deepening.md](deepening.md))
38
+ 5. Trade-offs: where leverage is high, where it's thin
39
+
40
+ ### 3. Present and compare
41
+
42
+ Present designs sequentially so the user can absorb each one, then compare them in prose. Contrast by **depth** (leverage at the interface), **locality** (where change concentrates), and **seam placement**. Check each against [red-flags.md](red-flags.md).
43
+
44
+ After comparing, give your own recommendation: which design you think is strongest and why. If elements from different designs would combine well, propose a hybrid. Be opinionated: the user wants a strong read, not a menu.
@@ -0,0 +1,205 @@
1
+ # Principles
2
+
3
+ Each principle: the rule, why it matters in glossary terms (see [SKILL.md](../SKILL.md)), and a short example. Examples are TypeScript.
4
+
5
+ ## 1. Deep modules and the deletion test
6
+
7
+ **Rule.** Put a lot of behaviour behind a small interface. Imagine deleting the module: if complexity vanishes, it was a pass-through; if it reappears across N callers, it was earning its keep.
8
+
9
+ **Why.** Depth gives callers leverage and maintainers locality.
10
+
11
+ ```typescript
12
+ // Shallow: the interface is the implementation
13
+ class UserRepo {
14
+ getTable() { return this.db.table("users"); }
15
+ runQuery(q: Query) { return this.db.run(q); }
16
+ }
17
+
18
+ // Deep: callers say what they want
19
+ class UserRepo {
20
+ findByEmail(email: Email): Promise<User | undefined> { /* query, mapping, caching */ }
21
+ }
22
+ ```
23
+
24
+ ## 2. Test at the correct level
25
+
26
+ **Rule.** The interface is the test surface. Test through the module's interface at its seam, not each internal function. When you deepen a module, replace the old tests; don't layer new ones on top.
27
+
28
+ **Why.** Tests that reach past the interface break on every refactor and prove nothing the interface doesn't. If you want to test past the interface, the module is probably the wrong shape.
29
+
30
+ - Unit-test the functional core directly; it has no I/O.
31
+ - Integration-test the shell with a local stand-in (see [deepening.md](deepening.md)).
32
+ - Don't mock your own modules. Mock only true external dependencies at a port.
33
+ - Assert on observable outcomes, not internal state.
34
+
35
+ **Smell.** A test that changes whenever the implementation changes; many tiny tests of pure helpers while the real bugs hide in how they're called.
36
+
37
+ ## 3. Parse, don't validate
38
+
39
+ **Rule.** At the external seam, turn untrusted input into a domain type that can only exist if valid. The core accepts the parsed type and never re-checks.
40
+
41
+ **Why.** Validation returns a boolean and discards what it learned, so every downstream caller must re-validate or hope. Parsing keeps the knowledge in the type. Locality: the check lives in one place.
42
+
43
+ ```typescript
44
+ // Validate: knowledge is lost, callers re-check
45
+ function isEmail(s: string): boolean { /* ... */ }
46
+ function sendWelcome(to: string) { if (!isEmail(to)) throw new Error("bad email"); /* ... */ }
47
+
48
+ // Parse: knowledge is kept in the type
49
+ type Email = string & { readonly __brand: "Email" };
50
+ function parseEmail(s: string): Result<Email, InvalidEmail> { /* ... */ }
51
+ function sendWelcome(to: Email) { /* no check needed */ }
52
+ ```
53
+
54
+ In a layered codebase this is `Entity.fromRequest`: the router hands raw input to the Entity, which parses it into domain values, and everything below works with parsed types.
55
+
56
+ **Smell.** The same field checked in router, service, and repository; `string` parameters that must be "a valid X".
57
+
58
+ ## 4. Make illegal states unrepresentable
59
+
60
+ **Rule.** Shape the types so invalid combinations cannot be constructed. Prefer discriminated unions to a bag of flags and optionals.
61
+
62
+ **Why.** Every representable-but-invalid state is a case every caller must handle, which is interface complexity. Removing it shrinks the interface.
63
+
64
+ ```typescript
65
+ // Illegal states possible: loading with an error, data with no result
66
+ type Fetch = { loading: boolean; error?: Error; data?: Data };
67
+
68
+ // Only legal states exist
69
+ type Fetch =
70
+ | { status: "loading" }
71
+ | { status: "failed"; error: Error }
72
+ | { status: "loaded"; data: Data };
73
+ ```
74
+
75
+ **Smell.** Comments like "only set when `kind` is X"; several booleans that can't all be true; optional fields that are required in some states.
76
+
77
+ ## 5. Functional core, imperative shell
78
+
79
+ **Rule.** Keep decisions in pure functions that take values and return values. Push I/O (database, network, clock, randomness) to a thin shell that gathers inputs, calls the core, and applies the result.
80
+
81
+ **Why.** The core is testable without mocks and holds the logic, so bugs concentrate there (locality). The shell is simple enough to cover with a few integration tests.
82
+
83
+ ```typescript
84
+ // Core: pure decision
85
+ function decideRenewal(sub: Subscription, now: Date): RenewalDecision { /* ... */ }
86
+
87
+ // Shell: I/O around it
88
+ async function renew(id: SubscriptionId) {
89
+ const sub = await repo.get(id);
90
+ const decision = decideRenewal(sub, clock.now());
91
+ await apply(decision);
92
+ }
93
+ ```
94
+
95
+ **Smell.** Business rules interleaved with queries; tests that need a mocked database to check a calculation. Counter-smell: a pure helper extracted only for testability while the real bugs sit in how it's called. Keep decisions and their orchestration close.
96
+
97
+ ## 6. Errors as values
98
+
99
+ **Rule.** Expected failures (invalid input, not found, conflict) are part of the interface and are returned as typed values, such as `Result<T, E>`. Exceptions are for bugs and unrecoverable states.
100
+
101
+ **Why.** Error modes are part of the interface. If they're hidden in `throw`, the caller can't see what to handle and the compiler can't help.
102
+
103
+ ```typescript
104
+ function placeOrder(cmd: PlaceOrder): Result<Order, OutOfStock | PaymentDeclined> { /* ... */ }
105
+ ```
106
+
107
+ But first, try principle 7: if the error can be defined away, it should not be in the interface at all.
108
+
109
+ **Smell.** `catch` blocks that parse error messages; functions documented with "may throw X, Y, Z".
110
+
111
+ ## 7. Define errors out of existence
112
+
113
+ **Rule.** Change the semantics so the error condition is not an error. Do this before reaching for `Result`.
114
+
115
+ **Why.** Every error is interface surface callers must handle. The best error handling is none.
116
+
117
+ - `delete(key)` on a missing key succeeds; the postcondition (key absent) holds.
118
+ - `substring(start, end)` clamps out-of-range indices instead of throwing.
119
+ - Return an empty collection, not `null`.
120
+
121
+ **Caution.** Don't swallow errors that matter. Define away only when the caller's intent is satisfied either way.
122
+
123
+ ## 8. Information hiding
124
+
125
+ **Rule.** Each design decision (a file format, a protocol, an algorithm, a table layout) lives in exactly one module.
126
+
127
+ **Why.** Knowledge that appears in two modules is a leak: change one and you must change both (change amplification). Locality means a decision changes in one place.
128
+
129
+ **Smell.** Two modules that both know the wire format; callers that must call methods in a particular order (temporal decomposition: structure follows the order of operations rather than the knowledge involved).
130
+
131
+ ## 9. Pull complexity downward
132
+
133
+ **Rule.** When complexity must live somewhere, put it in the module, not its callers. A simple interface matters more than a simple implementation.
134
+
135
+ **Why.** There are many callers and one module. Complexity pushed up is paid N times.
136
+
137
+ **Smell.** Config parameters that make callers decide what the module could decide; exceptions the caller can only rethrow.
138
+
139
+ ## 10. Somewhat general-purpose modules are deeper
140
+
141
+ **Rule.** Design the interface for the underlying capability, not for today's single use. Keep it general enough to cover related uses, but implement only what's needed now. Keep general-purpose code apart from special-purpose code.
142
+
143
+ **Why.** A general interface is usually smaller and simpler than a stack of special cases, and it survives the next feature.
144
+
145
+ **Smell.** Methods named for one screen or one caller (`deleteSelectedTextFromEditor`); a general mechanism with feature-specific branches inside it.
146
+
147
+ ## 11. Different layers, different abstractions
148
+
149
+ **Rule.** Each layer should offer an abstraction distinct from the ones above and below. A method that only forwards to another method with the same signature is a pass-through; so is a variable threaded unchanged through a chain of calls.
150
+
151
+ **Why.** A pass-through adds interface without depth. The deletion test flags it.
152
+
153
+ If a layer exists because the project's architecture demands it (Router → Service → Repository), make it earn its place: give it behaviour the layer below doesn't have, or fold the behaviour down. For a pass-through variable, put it in a context object or shared module.
154
+
155
+ ## 12. Together or apart
156
+
157
+ **Rule.** Combine modules that share information, are always used together, or overlap conceptually. Separate general mechanism from specific use. Don't split just to make things short.
158
+
159
+ **Why.** Splitting adds interface and separates things that need each other. Combining adds locality. Judge by interface complexity and dependencies, not by line count.
160
+
161
+ **Smell.** Conjoined methods: you can't understand one without reading the other.
162
+
163
+ ## 13. Make the common case simple
164
+
165
+ **Rule.** Give parameters sensible defaults and design the default path to need no configuration. Rare needs may cost more.
166
+
167
+ **Why.** Interface complexity is paid by every caller; the common caller shouldn't pay for the rare one.
168
+
169
+ ```typescript
170
+ // Common case: one argument
171
+ createClient(url);
172
+ // Rare case: opt in
173
+ createClient(url, { retries: 5, timeoutMs: 2_000 });
174
+ ```
175
+
176
+ ## 14. Comments and names carry the design
177
+
178
+ **Rule.**
179
+ - Comments describe what isn't obvious from the code. Interface comments state the abstraction (what it does, invariants, error modes); implementation comments explain *why*.
180
+ - Write the interface comment first. If it is hard to write, the design is unclear: fix the design.
181
+ - Names are precise and used consistently for the same thing.
182
+ - Design for ease of reading, not ease of writing.
183
+
184
+ **Why.** A comment that repeats the code adds nothing; a comment that states the abstraction is the interface's documentation. Names are the cheapest interface.
185
+
186
+ **Link.** A name you can't pick, or a concept you can't describe simply, usually means the domain language isn't settled. Resolve it with `oracle-domain-modelling` and record it in `CONTEXT.md`. If the decision is contested, run it through `oracle-grill-me`.
187
+
188
+ ## 15. Seam discipline
189
+
190
+ **Rule.**
191
+ - Accept dependencies; don't create them.
192
+ - Return results; don't produce side effects.
193
+ - One adapter means a hypothetical seam. Two means a real one. Don't introduce a port unless something actually varies across it.
194
+
195
+ **Why.** Seams cost interface. Pay only where behaviour varies (typically production and test).
196
+
197
+ ```typescript
198
+ // Testable
199
+ function processOrder(order: Order, paymentGateway: PaymentGateway) {}
200
+
201
+ // Hard to test
202
+ function processOrder(order: Order) {
203
+ const gateway = new StripeGateway();
204
+ }
205
+ ```
@@ -0,0 +1,32 @@
1
+ # Red Flags
2
+
3
+ A checklist to run before finalising a design, and when reviewing one. Each flag points to the principle in [principles.md](principles.md) that fixes it. Terms follow [SKILL.md](../SKILL.md).
4
+
5
+ | Red flag | What it looks like | Fix |
6
+ |----------|--------------------|-----|
7
+ | **Shallow module** | The interface is nearly as complex as the implementation. Passes the deletion test the wrong way: deleting it removes nothing. | Deep modules (1). Merge, or move behaviour in. |
8
+ | **Information leakage** | The same design decision (format, protocol, table layout) appears in two modules. | Information hiding (8). |
9
+ | **Temporal decomposition** | Structure follows the order operations run in (read, process, write) instead of the knowledge involved. Shared knowledge ends up in several steps. | Information hiding (8); together or apart (12). |
10
+ | **Overexposure** | The interface forces callers to learn rarely used features to use the common ones. | Make the common case simple (13). |
11
+ | **Pass-through method** | A method that only forwards to another with a similar signature. | Different layers, different abstractions (11). |
12
+ | **Pass-through variable** | An argument threaded unchanged through a chain of calls. | Different layers, different abstractions (11): context object or shared module. |
13
+ | **Repetition** | The same code or check appears in many places. | Parse, don't validate (3); information hiding (8); pull complexity downward (9). |
14
+ | **Special-general mixture** | A general mechanism contains feature-specific branches. | Somewhat general-purpose modules (10). |
15
+ | **Conjoined methods** | You can't understand one method without reading another. | Together or apart (12). |
16
+ | **Comment repeats code** | The comment says what the next line plainly says. | Comments and names (14). |
17
+ | **Implementation contaminates interface** | The interface comment must describe how it works inside. | Information hiding (8); rewrite the interface comment first (14). |
18
+ | **Vague name** | `data`, `info`, `manager`, `handle`, `process`. | Comments and names (14); resolve with `oracle-domain-modelling`. |
19
+ | **Hard to pick a name** | You can't find a precise name for the thing. | The concept is unclear; settle it in `CONTEXT.md`. |
20
+ | **Hard to describe** | The interface comment is long or awkward. | The design is unclear. Redesign before documenting (14). |
21
+ | **Nonobvious code** | A reader can't tell what it does or why without effort. | Names and structure for reading (14). |
22
+
23
+ ## Added for this toolkit
24
+
25
+ | Red flag | What it looks like | Fix |
26
+ |----------|--------------------|-----|
27
+ | **Stringly-typed core** | Core logic takes raw `string` or `any` and re-checks it. | Parse, don't validate (3). |
28
+ | **Flag-and-optional bag** | Several booleans and optionals where only some combinations are legal. | Make illegal states unrepresentable (4). |
29
+ | **I/O in the decision** | Business rules interleaved with queries or network calls. | Functional core, imperative shell (5). |
30
+ | **Throwing for expected failure** | `catch` blocks that parse messages; "may throw X, Y, Z". | Define errors out of existence (7), else errors as values (6). |
31
+ | **Testing past the interface** | Tests break on every refactor; many tests of internal helpers. | Test at the correct level (2). |
32
+ | **Single-adapter port** | An interface with one implementation and no test double. | Seam discipline (15). |
@@ -145,7 +145,7 @@ Fix the root cause, not the symptom.
145
145
 
146
146
  1. **Create a failing test case.** The simplest possible reproduction. MUST exist before the fix.
147
147
 
148
- A **correct seam** is one where the test exercises the real bug pattern as it occurs at the call site. If the only available seam is too shallow, note that the codebase architecture is preventing the bug from being locked down.
148
+ A **correct seam** is one where the test exercises the real bug pattern as it occurs at the call site. If the only available seam is too shallow, note that the codebase architecture is preventing the bug from being locked down. Use the seam and depth vocabulary from `oracle-codebase-design` when you raise it.
149
149
 
150
150
  2. **Implement a single fix.** Address the root cause. One change at a time. No "while I'm here" improvements. No bundled refactoring.
151
151
  3. **Verify the fix.** Does the test pass? Do other tests still pass? Does the original repro no longer reproduce?
@@ -153,7 +153,7 @@ Fix the root cause, not the symptom.
153
153
  - STOP
154
154
  - Count the failed fix attempts
155
155
  - If < 3: return to Phase 1 with the new information
156
- - If ≥ 3: **question the architecture**. Pattern problems, hidden coupling, and shared state that each fix reveals are signs of a wrong pattern. Discuss with the user before attempting Fix #4.
156
+ - If ≥ 3: **question the architecture**. Pattern problems, hidden coupling, and shared state that each fix reveals are signs of a wrong pattern (see the red flags in `oracle-codebase-design`). Discuss with the user before attempting Fix #4.
157
157
 
158
158
  ### Cleanup + post-mortem
159
159
 
@@ -20,4 +20,5 @@ understanding. Update domain documentation as terminology and decisions are reso
20
20
  session is nested in spec-brainstorm, return changed assumptions to that workflow for any required
21
21
  design update.
22
22
 
23
- Run this session using the `oracle-domain-modelling` skill.
23
+ Run this session using the `oracle-domain-modelling` skill. When the decision is about a module's
24
+ interface, seams, or test level, also use the `oracle-codebase-design` skill.
@@ -55,7 +55,8 @@ it touches multiple files or takes time. That work belongs in an Inline Plan.
55
55
 
56
56
  Break the system into units with one clear purpose each. Well-defined interfaces between
57
57
  them. Each unit independently understandable and independently testable. If you can't
58
- explain a unit's job in one sentence, it's doing too much.
58
+ explain a unit's job in one sentence, it's doing too much. Apply **oracle-codebase-design**:
59
+ deep modules, seams placed where behaviour varies, and the interface as the test surface.
59
60
 
60
61
  ### Working in existing codebases
61
62
 
@@ -203,6 +204,8 @@ Before settling on a design, present **2-3 approaches** with trade-offs.
203
204
 
204
205
  The first approach must keep the existing architecture and make the smallest correct change.
205
206
  Present broader approaches only when a current requirement makes their extra cost relevant.
207
+ When approaches differ mainly in interface shape, use the design-it-twice reference in
208
+ **oracle-codebase-design**.
206
209
 
207
210
  For each approach, address:
208
211
 
@@ -250,9 +253,10 @@ with acceptance criteria and priorities. If rejected: revise. If the rejection
250
253
  reveals a scope misunderstanding, loop back to Discovery (Step 2).
251
254
 
252
255
  **Batch B: Architecture** — component design, domain modeling, and layer
253
- boundaries. Use installed language-specific architecture or API-design skills as relevant to
254
- your stack. Then present: component structure, domain model, where business
255
- logic lives, where IO lives. If rejected: revise. If the rejection undermines
256
+ boundaries. Use **oracle-codebase-design** and any installed language-specific architecture or
257
+ API-design skills relevant to your stack. Then present: component structure, domain model, where
258
+ business logic lives, where IO lives, where untrusted input is parsed (the external seam), and
259
+ the seam each module is tested through. If rejected: revise. If the rejection undermines
256
260
  the chosen approach, offer to return to approach exploration (4a). If it
257
261
  reveals a fundamental gap, loop back to Research (Step 3). If the detail reveals
258
262
  the work is far more complex than estimated, say so and offer to revisit the
@@ -128,6 +128,8 @@ Read the task's **inputs** and **description** first.
128
128
  For behavior-changing code tasks, write tests that cover the validation criteria before writing
129
129
  implementation. For documentation, configuration, migration, or verification-only tasks, use the
130
130
  task's stated validation instead. Invoke an installed language-specific testing skill when needed.
131
+ Write tests at the module's interface (see **oracle-codebase-design**), and use its red flags
132
+ when refactoring.
131
133
 
132
134
  ```
133
135
  1. Read task inputs and description
@@ -43,6 +43,7 @@ request. Implementation requires a later, explicit request after this skill has
43
43
  same need.
44
44
  - Group tests by changed contract and active boundary. Do not repeat the CRUD matrix across
45
45
  layers.
46
+ - Plan tests at each module's interface, not past it (see **oracle-codebase-design**).
46
47
 
47
48
  ### Proportionality Gate
48
49