@martinffx/atelier 1.1.0 → 1.2.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.
@@ -6,6 +6,24 @@ user-invocable: false
6
6
 
7
7
  # Architect Skill
8
8
 
9
+ ## Glossary
10
+
11
+ Precise vocabulary for every architectural decision. Use these terms exactly — consistency is the point.
12
+
13
+ - **Module** — anything with an interface and an implementation (function, class, package, layer). Router, Service, Entity, and Repository are all modules.
14
+ - **Interface** — everything a caller must know to use the module: types, invariants, error modes, ordering, config. Not just the type signature.
15
+ - **Seam** — where a module's interface lives; a place behaviour can be altered without editing in place. The functional core / effectful edge boundary is the primary seam.
16
+ - **Depth** — leverage at the interface. A module is **deep** when a lot of behaviour sits behind a small interface. A module is **shallow** when the interface is nearly as complex as the implementation.
17
+ - **Adapter** — a concrete thing satisfying an interface at a seam. A Postgres repository is an adapter; an in-memory fake for testing is another adapter at the same seam.
18
+ - **Leverage** — what callers get from depth: more capability per unit of interface they learn.
19
+ - **Locality** — what maintainers get from depth: change, bugs, and knowledge concentrate in one place.
20
+
21
+ Key principles (apply to every decision):
22
+
23
+ - **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
24
+ - **The interface is the test surface.** Callers and tests cross the same seam. If you want to test past the interface, the module is probably the wrong shape.
25
+ - **One adapter = hypothetical seam. Two adapters = real seam.** Don't introduce a seam unless something actually varies across it.
26
+
9
27
  Domain-Driven Design and hexagonal architecture with functional core pattern for feature design.
10
28
 
11
29
  ## Architecture Model
@@ -25,6 +43,68 @@ Unified view of functional core and effectful edge:
25
43
 
26
44
  **Key Principle:** Business logic lives in the functional core (Service + Entity). IO operations live in the effectful edge. Core defines interfaces; edge implements them (dependency inversion).
27
45
 
46
+ ## Evaluating Architecture Decisions
47
+
48
+ Before creating a new module, run these checks:
49
+
50
+ ### Deletion Test
51
+
52
+ > *Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.*
53
+
54
+ **When to apply:** Before extracting a new Service, Repository, or utility class.
55
+
56
+ **Example:**
57
+ ```
58
+ ❌ Shallow: OrderFormatterService with 1 method per field
59
+ → Deleting it just moves 6 lines into the Router
60
+ → Interface is as complex as implementation
61
+
62
+ ✅ Deep: OrderService with validate → reserve → save → publish
63
+ → Deleting it replicates orchestration across N handlers
64
+ → Small interface (createOrder), large implementation
65
+ ```
66
+
67
+ ### Interface as Test Surface
68
+
69
+ > *Callers and tests cross the same seam. If you want to test past the interface, the module is probably the wrong shape.*
70
+
71
+ **Implication:**
72
+ - Unit tests for Entities test the public interface (validate, transform)
73
+ - Unit tests for Services test through the seam with stub repositories
74
+ - Integration tests for Repositories test the actual adapter
75
+ - If you find yourself testing "internal" methods, the module needs redrawing
76
+
77
+ ### Adapter Rule
78
+
79
+ > *One adapter = hypothetical seam. Two adapters = real seam.*
80
+
81
+ **When to apply:** Deciding whether to extract an interface.
82
+
83
+ **Examples:**
84
+ ```typescript
85
+ // ❌ Hypothetical seam — only one adapter exists
86
+ interface IEmailClient { send(email: Email): Promise<void>; }
87
+ class SendgridClient implements IEmailClient { ... }
88
+ // No second adapter. The interface adds indirection without value.
89
+
90
+ // ✅ Real seam — two adapters exist
91
+ interface IOrderRepository { save(order: Order): Promise<Order>; }
92
+ class PostgresOrderRepository implements IOrderRepository { ... }
93
+ class InMemoryOrderRepository implements IOrderRepository { ... } // for tests
94
+ // The seam earns its keep because callers vary (production vs test).
95
+ ```
96
+
97
+ ### Depth Check
98
+
99
+ Prefer deep modules over shallow ones:
100
+
101
+ | Module | Interface Size | Implementation | Depth |
102
+ |--------|--------------|----------------|-------|
103
+ | `OrderValidator` | 3 methods (validate, validateItems, validateAddress) | 30 lines each | Shallow |
104
+ | `Order` (entity) | 4 methods (fromRequest, toRecord, toResponse, validate) | 200 lines of rules, transforms, invariants | **Deep** |
105
+
106
+ **Rule of thumb:** A module's interface should hide at least 3x the complexity it exposes.
107
+
28
108
  ## Functional Core
29
109
 
30
110
  Pure, deterministic components containing all business logic.
@@ -241,6 +321,7 @@ The testing skill uses architectural structure to determine:
241
321
 
242
322
  For detailed patterns and examples:
243
323
 
244
- - **See [references/ddd-patterns.md](references/ddd-patterns.md)** - Aggregates, Value Objects, Domain Events, Bounded Contexts, composition patterns
324
+ - **See [references/ddd-patterns.md](references/ddd-patterns.md)** - Aggregates, Value Objects, Domain Events, Bounded Contexts, composition patterns, seam placement
245
325
  - **See [references/data-modeling.md](references/data-modeling.md)** - Entity design principles, schema patterns, access pattern optimization, data transformation
246
326
  - **See [references/api-design.md](references/api-design.md)** - REST conventions, request/response contracts, error handling, versioning patterns
327
+ - **See [references/interface-design.md](references/interface-design.md)** - Designing module interfaces, "Design It Twice" pattern, depth heuristics, dependency categories, anti-patterns
@@ -245,3 +245,104 @@ Bounded Context: "Orders"
245
245
  3. **Aggregate → Repository**: Service uses repository to persist aggregate
246
246
  4. **Service → Producer**: Service publishes domain events after state change
247
247
  5. **Consumer → Service**: Events from other contexts trigger service operations
248
+
249
+ ## Seam Placement
250
+
251
+ Where you put the seam matters as much as what goes behind it.
252
+
253
+ ### Core/Edge Seam
254
+
255
+ The primary seam runs between the functional core and the effectful edge:
256
+
257
+ ```
258
+ ┌─────────────────────────────────┐
259
+ │ Functional Core (pure) │
260
+ │ ┌──────────────────────────┐ │
261
+ │ │ OrderService │ │
262
+ │ │ createOrder() ────────┼───┼──▶ (seam)
263
+ │ │ processPayment() │ │
264
+ │ └──────────────────────────┘ │
265
+ └─────────────────────────────────┘
266
+ │
267
+ ▼ seam
268
+ ┌─────────────────────────────────┐
269
+ │ Effectful Edge (IO) │
270
+ │ ┌──────────────────────────┐ │
271
+ │ │ PostgresOrderRepository │◀──┼── adapter
272
+ │ │ HttpPaymentClient │ │ adapter
273
+ │ │ InMemoryOrderRepository │ │ adapter (test)
274
+ │ └──────────────────────────┘ │
275
+ └─────────────────────────────────┘
276
+ ```
277
+
278
+ **Rules:**
279
+ - Core defines the interface; edge implements it (dependency inversion)
280
+ - The seam must have **at least two adapters** to be real (production + test)
281
+ - Core never imports edge code; edge imports core interfaces
282
+
283
+ ### Internal Seams
284
+
285
+ A deep module can have **internal seams** — private to its implementation, used by its own tests:
286
+
287
+ ```typescript
288
+ class Order {
289
+ // External seam (public interface)
290
+ validate(): Result<Order> { ... }
291
+
292
+ // Internal seam (private, tested directly)
293
+ private calculateTax(subtotal: number): Money { ... }
294
+ }
295
+ ```
296
+
297
+ Internal seams let you test complex logic without exposing it in the public interface.
298
+
299
+ ### When to Create a Seam
300
+
301
+ Use the **adapter rule**: one adapter = hypothetical; two = real.
302
+
303
+ | Scenario | Action |
304
+ |----------|--------|
305
+ | One database implementation, no test fake | No seam needed. Direct dependency is simpler. |
306
+ | One database implementation, test fake exists | Extract interface. The fake is the second adapter. |
307
+ | Multiple database implementations (Postgres + DynamoDB) | Extract interface. The implementations are the adapters. |
308
+ | External API with one client | Direct dependency. Introduce seam only when you need a mock/stub for testing. |
309
+
310
+ ### Anti-Patterns
311
+
312
+ **Seam at every dependency:**
313
+ ```typescript
314
+ // ❌ Too many seams — every dependency gets an interface
315
+ interface IValidator { ... }
316
+ interface IFormatter { ... }
317
+ interface IConverter { ... }
318
+ // Each has one adapter. Indirection without value.
319
+ ```
320
+
321
+ **No seam at the core/edge boundary:**
322
+ ```typescript
323
+ // ❌ Core imports edge directly
324
+ import { db } from '../edge/postgres';
325
+ class OrderService {
326
+ async createOrder(req) {
327
+ await db.orders.create(...); // Core knows about Postgres
328
+ }
329
+ }
330
+ ```
331
+
332
+ **Leaky seam:**
333
+ ```typescript
334
+ // ❌ Interface exposes implementation details
335
+ interface OrderRepository {
336
+ queryRaw(sql: string): Promise<Row[]>; // Caller knows SQL
337
+ beginTransaction(): Promise<Transaction>; // Caller manages transactions
338
+ }
339
+ // The seam leaks. Callers become coupled to the database.
340
+ ```
341
+
342
+ ### Seam Placement Checklist
343
+
344
+ Before introducing a new seam, verify:
345
+ - [ ] At least two adapters will exist (production + test, or multiple production)
346
+ - [ ] The interface hides implementation details (no SQL, no HTTP, no framework types)
347
+ - [ ] The core doesn't import edge code
348
+ - [ ] Deleting the module would re-appear complexity across N callers
@@ -0,0 +1,203 @@
1
+ # Interface Design Reference
2
+
3
+ Patterns for designing module interfaces that maximize depth, leverage, and locality.
4
+
5
+ Based on "Design It Twice" (Ousterhout) — your first idea is unlikely to be the best.
6
+
7
+ ## Design It Twice
8
+
9
+ Before committing to a module's interface, sketch at least two alternatives with different trade-offs.
10
+
11
+ ### Process
12
+
13
+ 1. **Frame the problem space**
14
+ - List constraints any interface must satisfy
15
+ - Identify dependencies and which category they fall into
16
+ - Write a rough illustrative code sketch to ground the constraints
17
+
18
+ 2. **Sketch alternatives**
19
+ - Alternative A: Minimize the interface (1–3 entry points max)
20
+ - Alternative B: Maximize flexibility (support many use cases)
21
+ - Alternative C: Optimize for the most common caller (default case trivial)
22
+
23
+ 3. **Compare by depth**
24
+ - Which alternative has the smallest interface for the most behaviour?
25
+ - Which concentrates the most knowledge in one place?
26
+ - Which has the best test surface?
27
+
28
+ ### Example: Order Creation Interface
29
+
30
+ **Problem:** Design the interface for creating an order.
31
+
32
+ **Alternative A — Minimal interface:**
33
+ ```typescript
34
+ interface OrderService {
35
+ createOrder(request: CreateOrderRequest): Promise<Result<Order>>;
36
+ }
37
+ ```
38
+ - **Pros:** Tiny surface. One seam. Easy to mock.
39
+ - **Cons:** All complexity hidden inside. Hard to test partial flows (e.g. validation without persistence).
40
+ - **Depth:** Very deep. High leverage, high locality.
41
+
42
+ **Alternative B — Flexible interface:**
43
+ ```typescript
44
+ interface OrderService {
45
+ validate(request: CreateOrderRequest): Promise<Result<Order>>;
46
+ reserveInventory(order: Order): Promise<Result<Order>>;
47
+ save(order: Order): Promise<Result<Order>>;
48
+ publishEvents(order: Order): Promise<void>;
49
+ }
50
+ ```
51
+ - **Pros:** Callers compose their own flows. Easy to test each step.
52
+ - **Cons:** Interface is as complex as implementation. Callers must know ordering constraints (reserve before save).
53
+ - **Depth:** Shallow. Low leverage — callers replicate orchestration.
54
+
55
+ **Alternative C — Optimized for common case:**
56
+ ```typescript
57
+ interface OrderService {
58
+ createOrder(request: CreateOrderRequest): Promise<Result<Order>>;
59
+ createOrderDraft(request: CreateOrderRequest): Promise<Result<Order>>; // no inventory check
60
+ confirmOrder(orderId: string): Promise<Result<Order>>; // draft → confirmed
61
+ }
62
+ ```
63
+ - **Pros:** Common case (createOrder) is trivial. Draft pattern supports async workflows.
64
+ - **Cons:** More surface area than Alternative A. Callers must understand draft vs confirmed.
65
+ - **Depth:** Moderate. Good leverage for the common case.
66
+
67
+ **Recommendation:** Alternative C. It balances depth with real workflow needs. The draft/confirm split is a real seam (two callers: interactive vs batch).
68
+
69
+ ## Interface Size Heuristics
70
+
71
+ ### The Rule of Three
72
+
73
+ A module's public interface should have no more than 3 primary entry points for each responsibility:
74
+
75
+ ```typescript
76
+ // ❌ Too wide
77
+ interface OrderService {
78
+ createOrder(...): Promise<Order>;
79
+ updateOrder(...): Promise<Order>;
80
+ deleteOrder(...): Promise<void>;
81
+ getOrder(...): Promise<Order>;
82
+ listOrders(...): Promise<Order[]>;
83
+ searchOrders(...): Promise<Order[]>;
84
+ cancelOrder(...): Promise<Order>;
85
+ shipOrder(...): Promise<Order>;
86
+ refundOrder(...): Promise<Order>;
87
+ }
88
+
89
+ // ✅ Split by responsibility (2 modules, each with ~3 methods)
90
+ interface OrderLifecycleService {
91
+ create(...): Promise<Order>;
92
+ cancel(...): Promise<Order>;
93
+ ship(...): Promise<Order>;
94
+ }
95
+
96
+ interface OrderQueryService {
97
+ get(id: string): Promise<Order>;
98
+ list(filters: OrderFilters): Promise<Order[]>;
99
+ search(query: string): Promise<Order[]>;
100
+ }
101
+ ```
102
+
103
+ ### Invariants in the Interface
104
+
105
+ The interface includes not just types, but everything a caller must know:
106
+
107
+ ```typescript
108
+ interface PaymentService {
109
+ // ❌ Interface hides invariants
110
+ processPayment(orderId: string, amount: number): Promise<Receipt>;
111
+ // Caller must discover: amount must match order total, order must be confirmed,
112
+ // can't process twice, throws if payment gateway is down.
113
+
114
+ // ✅ Interface encodes invariants in types
115
+ processPayment(
116
+ order: ConfirmedOrder, // type encodes "must be confirmed"
117
+ payment: PaymentMethod // type encodes valid methods
118
+ ): Promise<Result<Receipt, PaymentError>>;
119
+ // Error mode explicit in return type. Ordering implicit in input types.
120
+ ```
121
+
122
+ ## Dependency Categories
123
+
124
+ The shape of an interface depends on what it depends on.
125
+
126
+ | Category | Description | Interface Impact |
127
+ |----------|-------------|------------------|
128
+ | **In-process** | Same memory space, no serialization | Can pass rich types, callbacks, streams |
129
+ | **Local-substitutable** | Same interface, different implementations (real vs test) | Seam is real. Interface must hide implementation |
130
+ | **Ports & adapters** | Crosses a real boundary (DB, HTTP, message queue) | Interface must be narrow. Errors are part of the contract |
131
+ | **Mock** | Test-only dependency, no production equivalent | Don't create a seam. Test the real module |
132
+
133
+ ## Common Interface Anti-Patterns
134
+
135
+ ### Leaky Abstraction
136
+
137
+ ```typescript
138
+ // ❌ Interface exposes implementation
139
+ interface UserRepository {
140
+ query(sql: string, params: any[]): Promise<Row[]>;
141
+ }
142
+
143
+ // ✅ Interface hides implementation
144
+ interface UserRepository {
145
+ findByEmail(email: Email): Promise<User | null>;
146
+ save(user: User): Promise<User>;
147
+ }
148
+ ```
149
+
150
+ ### Pass-Through Interface
151
+
152
+ ```typescript
153
+ // ❌ Every method delegates 1:1 to another module
154
+ class OrderService {
155
+ async findById(id: string) { return this.repo.findById(id); }
156
+ async save(order: Order) { return this.repo.save(order); }
157
+ async delete(id: string) { return this.repo.delete(id); }
158
+ }
159
+ // Deletion test: delete OrderService → complexity doesn't reappear.
160
+ // It's a pass-through. Remove it and call repo directly.
161
+ ```
162
+
163
+ ### God Interface
164
+
165
+ ```typescript
166
+ // ❌ One module does everything
167
+ interface PlatformService {
168
+ createUser(...): Promise<User>;
169
+ sendEmail(...): Promise<void>;
170
+ processPayment(...): Promise<Receipt>;
171
+ generateReport(...): Promise<PDF>;
172
+ }
173
+ // No cohesion. Deleting it would reappear complexity, but in unrelated places.
174
+ // Split by domain responsibility instead.
175
+ ```
176
+
177
+ ### Chatty Interface
178
+
179
+ ```typescript
180
+ // ❌ Many small methods that must be called in sequence
181
+ interface OrderBuilder {
182
+ setCustomer(customerId: string): this;
183
+ addItem(item: OrderItem): this;
184
+ setShipping(address: Address): this;
185
+ setPayment(method: PaymentMethod): this;
186
+ validate(): Result<void>;
187
+ build(): Order;
188
+ }
189
+ // Callers must know ordering. State machine hidden in method calls.
190
+ // Better: single method that takes a complete request.
191
+ ```
192
+
193
+ ## Decision Checklist
194
+
195
+ Before finalizing an interface:
196
+
197
+ - [ ] Run the deletion test — does complexity reappear across N callers?
198
+ - [ ] Check depth — is the interface at least 3x smaller than the implementation?
199
+ - [ ] Verify seam — are there at least two adapters?
200
+ - [ ] Encode invariants — are error modes, ordering, and constraints visible in types?
201
+ - [ ] Test surface — can you test all behaviour through the public interface?
202
+ - [ ] Hide details — does the interface leak SQL, HTTP, frameworks, or implementation?
203
+ - [ ] Common case — is the most frequent caller's experience trivial?
@@ -0,0 +1,252 @@
1
+ ---
2
+ name: oracle-doubt
3
+ description: >
4
+ Adversarial review of non-trivial decisions using fresh-context scrutiny.
5
+ Use when correctness matters more than speed, when stakes are high
6
+ (production, security-sensitive logic, irreversible operations), or before
7
+ committing significant architectural or implementation choices.
8
+ user-invocable: true
9
+ ---
10
+
11
+ # Doubt: Fresh-Context Adversarial Review
12
+
13
+ A confident answer is not a correct one. Long sessions accumulate context that quietly turns assumptions into "facts" without anyone noticing. Doubt-driven development is the discipline of materializing a fresh-context reviewer — biased to **disprove**, not approve — before any non-trivial output stands.
14
+
15
+ This is not `/review`. `/review` is a verdict on a finished artifact. This is an in-flight posture: non-trivial decisions get cross-examined while course-correction is still cheap.
16
+
17
+ ## When to Use
18
+
19
+ A decision is **non-trivial** when at least one of these is true:
20
+
21
+ - It introduces or modifies branching logic
22
+ - It crosses a module or service boundary
23
+ - It asserts a property the type system or compiler cannot verify (thread safety, idempotence, ordering, invariants)
24
+ - Its correctness depends on context the future reader cannot see
25
+ - Its blast radius is irreversible (production deploy, data migration, public API change)
26
+
27
+ Apply the skill when:
28
+
29
+ - About to make an architectural decision under uncertainty
30
+ - About to commit non-trivial code
31
+ - About to claim a non-obvious fact ("this is safe", "this scales", "this matches the spec")
32
+ - Working in code you don't fully understand
33
+
34
+ **When NOT to use:**
35
+
36
+ - Mechanical operations (renaming, formatting, file moves)
37
+ - Following a clear, unambiguous user instruction
38
+ - Reading or summarizing existing code
39
+ - One-line changes with obvious correctness
40
+ - Pure tooling operations (running tests, listing files)
41
+ - The user has explicitly asked for speed over verification
42
+
43
+ If you doubt every keystroke, you ship nothing. The skill applies only to non-trivial decisions as defined above.
44
+
45
+ ## Loading Constraints
46
+
47
+ This skill is designed for the **main-session orchestrator**, where Step 3 (DOUBT) can spawn fresh-context reviewers via the `task` tool.
48
+
49
+ - **Do NOT add this skill to a persona's `skills:` frontmatter.** A persona that follows Step 3 would spawn another persona — the orchestration anti-pattern explicitly forbidden by `references/orchestration-patterns.md` ("personas do not invoke other personas").
50
+ - **If you find yourself applying this skill from inside a subagent context** (where nested subagent spawn is prevented): the preferred path is to surface to the user that doubt-driven cannot run nested and let the main session handle it. As a last resort only, a degraded self-questioning fallback exists — rewrite ARTIFACT + CONTRACT as a fresh self-prompt with a hard mental separator from your prior reasoning, and walk Steps 1–5. This is **not fresh-context review** (you carry your own context with you), so flag the result as degraded and prefer escalation whenever the user is reachable.
51
+
52
+ ## The Process
53
+
54
+ Copy this checklist when applying the skill:
55
+
56
+ ```
57
+ Doubt cycle:
58
+ - [ ] Step 1: CLAIM — wrote the claim + why-it-matters
59
+ - [ ] Step 2: EXTRACT — isolated artifact + contract, stripped reasoning
60
+ - [ ] Step 3: DOUBT — invoked fresh-context reviewer with adversarial prompt
61
+ - [ ] Step 4: RECONCILE — classified every finding against the artifact text
62
+ - [ ] Step 5: STOP — met stop condition (trivial findings, 3 cycles, or user override)
63
+ ```
64
+
65
+ ### Step 1: CLAIM — Surface what stands
66
+
67
+ Name the decision in two or three lines:
68
+
69
+ ```
70
+ CLAIM: "The new caching layer is thread-safe under the
71
+ read-heavy workload described in the spec."
72
+ WHY THIS MATTERS: a race here corrupts user data and is
73
+ hard to detect in QA.
74
+ ```
75
+
76
+ If you can't write the claim that compactly, you have a vibe, not a decision. Surface it before scrutinizing it.
77
+
78
+ ### Step 2: EXTRACT — Smallest reviewable unit
79
+
80
+ A fresh-context reviewer needs the **artifact** and the **contract**, not the journey.
81
+
82
+ - **Code**: the diff or the function — not the whole file
83
+ - **Decision**: the proposal in 3–5 sentences plus the constraints it has to satisfy
84
+ - **Assertion**: the claim plus the evidence that supposedly supports it (kept distinct from the Step 1 CLAIM block, which is the orchestrator's hypothesis under scrutiny)
85
+
86
+ Strip your reasoning. If you hand over conclusions, you'll get back validation of your conclusions. The unit must be small enough that a reviewer can hold it in mind in one read — if it's a 500-line PR, decompose first.
87
+
88
+ ### Step 3: DOUBT — Invoke the fresh-context reviewer
89
+
90
+ The reviewer's prompt **must be adversarial**. Framing decides the answer.
91
+
92
+ Use the adversarial prompt template from [references/adversarial-prompt.md](references/adversarial-prompt.md). The template is pasted verbatim into the subagent invocation to override any persona's default balanced response shape.
93
+
94
+ **Pass ARTIFACT + CONTRACT only. Do NOT pass the CLAIM.** Handing the reviewer your conclusion biases it toward agreement. The reviewer must independently determine whether the artifact satisfies the contract.
95
+
96
+ #### Cross-model escalation
97
+
98
+ A single-model reviewer shares blind spots with the original author — a colder, different-architecture perspective catches them. Doubt-driven is already opt-in for non-trivial decisions, so within that scope offering cross-model is part of the skill's value, not optional friction.
99
+
100
+ **Interactive sessions: always offer. Never silently skip.**
101
+
102
+ **Step 1: Ask the user**
103
+
104
+ After the single-model review in Step 3 above, but before RECONCILE, pause and ask:
105
+
106
+ > *"Single-model review complete. Want a cross-model second opinion? Options: spawn parallel subagents with different types (oracle + architect), manual external review (you paste it elsewhere), or skip."*
107
+
108
+ This question is mandatory in every interactive doubt cycle — even on artifacts that feel low-stakes. The user — not the agent — decides whether the cost is worth it. The agent's job is to surface the choice.
109
+
110
+ **Step 2: If the user picks parallel subagents — dispatch**
111
+
112
+ Spawn two `task` subagents in parallel with the same adversarial prompt + ARTIFACT + CONTRACT:
113
+
114
+ ```
115
+ task tool:
116
+ subagent_type: oracle
117
+ task tool:
118
+ subagent_type: architect
119
+ ```
120
+
121
+ Each subagent starts with isolated context by design. Take both outputs into Step 4 (RECONCILE).
122
+
123
+ **Step 3: If the user skips**
124
+
125
+ Acknowledge the skip in the output (*"Proceeding with single-model findings only"*) and continue to RECONCILE. Skipping is fine; silent skipping is not.
126
+
127
+ **Non-interactive contexts** (CI, scheduled runs):
128
+
129
+ - Cross-model is **skipped**, and the skip must be **announced** in the output: *"Cross-model skipped: non-interactive context."*
130
+ - **Never invoke external subagents without explicit user authorization** — this is a load-bearing safety property.
131
+
132
+ Cross-model adds cost, latency, and tool fragility. The agent surfaces the choice every cycle; the user decides whether this artifact warrants it.
133
+
134
+ ### Step 4: RECONCILE — Fold findings back
135
+
136
+ The reviewer's output is data, not verdict. **You are still the orchestrator.** Re-read the artifact text against each finding before classifying — rubber-stamping the reviewer is the same failure mode as ignoring it.
137
+
138
+ For each finding, classify in this **precedence order** (first matching class wins):
139
+
140
+ 1. **Contract misread** — reviewer flagged something specifically because the CONTRACT you provided was unclear or incomplete. Fix the contract first, re-classify on the next cycle.
141
+ 2. **Valid + actionable** — real issue requiring a change to the artifact. Change it, re-loop.
142
+ 3. **Valid trade-off** — issue is real but cost of fixing exceeds cost of accepting. Document the trade-off explicitly so the user sees it.
143
+ 4. **Noise** — reviewer flagged something that's actually correct under context the reviewer didn't have. Note it, move on, and ask: would adding that context to the contract have prevented the false flag?
144
+
145
+ A fresh reviewer can be wrong because it lacks context. Don't defer just because it's "fresh."
146
+
147
+ ### Step 5: STOP — Bounded loop, not recursion
148
+
149
+ Stop when:
150
+
151
+ - Next iteration returns only trivial or already-considered findings, **or**
152
+ - 3 cycles completed (escalate to user, don't grind a fourth alone), **or**
153
+ - User explicitly says "ship it"
154
+
155
+ If after 3 cycles the reviewer still surfaces substantive issues, the artifact may not be ready. Surface this to the user — three unresolved cycles is information about the artifact, not a reason to keep looping.
156
+
157
+ If 3 cycles is "obviously insufficient" because the artifact is large: the artifact is too big — return to Step 2 and decompose. Do not lift the bound.
158
+
159
+ ## Common Rationalizations
160
+
161
+ | Rationalization | Reality |
162
+ |---|---|
163
+ | "I'm confident, skip the doubt step" | Confidence correlates poorly with correctness on novel problems. Moments of certainty are exactly when blind spots hide. |
164
+ | "Spawning a reviewer is expensive" | Debugging a wrong commit in production is more expensive. The check is bounded; the bug isn't. |
165
+ | "The reviewer will just nitpick" | Only if unscoped. Constrain the prompt to "issues that would make this fail under the contract." |
166
+ | "I'll do doubt at the end with `/review`" | `/review` is a final gate. Doubt-driven catches wrong directions early when course-correction is cheap. By PR time it's too late. |
167
+ | "If I doubt every step I'll never ship" | The skill applies to non-trivial decisions, not every keystroke. Re-read "When NOT to Use." |
168
+ | "Two opinions are always better than one" | Not when the second has less context and produces noise. Reconcile, don't defer. |
169
+ | "The reviewer disagreed so I was wrong" | The reviewer lacks your context — disagreement is information, not verdict. Re-read the artifact, classify, then decide. |
170
+ | "Cross-model is always better" | Cross-model catches blind spots a single model shares with itself, but it adds cost and tool fragility. Offer it every interactive doubt cycle — the user decides whether the artifact warrants it. The agent's job is to surface the choice, not to gate it. |
171
+ | "User said yes once, so I can keep invoking subagents" | Each invocation is its own authorization. The artifact, the prompt, and the context change between calls — re-confirm with the user before every run. |
172
+
173
+ ## Red Flags
174
+
175
+ - Spawning a fresh-context reviewer for a one-line rename or formatting change
176
+ - Treating reviewer output as authoritative without re-reading the artifact text
177
+ - Looping >3 cycles without escalating to the user
178
+ - Prompting the reviewer with "is this good?" instead of "find issues"
179
+ - Skipping doubt under time pressure on a high-stakes decision
180
+ - Re-spawning fresh-context on an unchanged artifact (you'll get the same findings; you're stalling)
181
+ - **Doubt theater (checkable signal)**: across 2 or more cycles where the reviewer surfaced substantive findings, zero findings were classified as actionable. You are validating, not doubting. Stop and escalate.
182
+ - Doubting only after committing — that's `/review`, not doubt-driven development
183
+ - Hardcoding a subagent invocation without confirming with the user that the approach is acceptable
184
+ - **Silently skipping cross-model in an interactive doubt cycle.** Even when not recommending it, the offer must be visible. Skipping is fine; silent skipping is not.
185
+ - Falling back silently when a subagent errors or is unavailable — surface the failure and let the user redirect
186
+ - Stripping the contract from the reviewer's input
187
+ - Passing the CLAIM to the reviewer (biases toward agreement)
188
+
189
+ ## Interaction with Other Skills
190
+
191
+ - **`code-review` / `/review`**: complementary. `/review` is post-hoc PR verdict; doubt-driven is in-flight per-decision. Use both.
192
+ - **`oracle-architect`** / **`spec-research`**: SDD verifies *facts about frameworks* against official docs. Doubt-driven verifies *your reasoning about the artifact*. SDD checks the API exists; doubt-driven checks you used it correctly under the contract.
193
+ - **`oracle-testing`**: TDD's RED step is doubt made concrete — a failing test is a disproof attempt. When TDD applies, that failing test *is* the doubt step for behavioral claims.
194
+ - **`code-debug`**: when the reviewer surfaces a real failure mode, drop into the debugging skill to localize and fix.
195
+
196
+ ## Verification
197
+
198
+ After applying doubt-driven development:
199
+
200
+ - Every non-trivial decision (per the definition above) was named explicitly as a CLAIM before standing
201
+ - At least one fresh-context review per non-trivial artifact (a failing test produced by TDD's RED step satisfies this for behavioral claims, per Interaction with Other Skills)
202
+ - The reviewer received ARTIFACT + CONTRACT — NOT the CLAIM, NOT your reasoning
203
+ - The reviewer's prompt was adversarial ("find issues"), not validating ("is it good")
204
+ - Findings were classified against the artifact text (not rubber-stamped) using the precedence: contract misread / actionable / trade-off / noise
205
+ - A stop condition was met (trivial findings, 3 cycles, or user override)
206
+ - In interactive mode, cross-model was **explicitly offered** to the user (regardless of artifact stakes) and the response was acknowledged in the output
207
+ - In non-interactive mode, cross-model was skipped and the skip was announced
208
+ - Any subagent invocation was preceded by user authorization and confirmation of the approach
209
+
210
+ ## Usage Examples
211
+
212
+ **Doubt an architectural decision:**
213
+ ```
214
+ /atelier-doubt
215
+ CLAIM: "I will use DynamoDB single-table design for the Order service."
216
+ WHY: "Single-table simplifies access patterns but may couple unrelated domains."
217
+ ARTIFACT: "Proposed key schema: PK=ORDER#<id>, SK=METADATA#<id>. All order data in one table."
218
+ CONTRACT: "Must support: 1) lookup by order ID, 2) list by customer, 3) list by status. No cross-domain queries."
219
+ ```
220
+
221
+ **Doubt a code change before commit:**
222
+ ```
223
+ /atelier-doubt
224
+ CLAIM: "The retry logic in PaymentService is safe under concurrent requests."
225
+ WHY: "Race here could double-charge customers."
226
+ ARTIFACT: "<paste diff or function>"
227
+ CONTRACT: "Must be idempotent: same paymentId processed twice produces same result, no duplicate charges."
228
+ ```
229
+
230
+ **Doubt a non-obvious assertion:**
231
+ ```
232
+ /atelier-doubt
233
+ CLAIM: "This migration is safe to run online without downtime."
234
+ WHY: "Downtime here blocks checkout for all users."
235
+ ARTIFACT: "ALTER TABLE orders ADD COLUMN tracking_id VARCHAR(255); CREATE INDEX idx_tracking ON orders(tracking_id);"
236
+ CONTRACT: "Must not lock table for more than 1 second. Must not fail on 10M row table. Must be backward-compatible with running application code."
237
+ ```
238
+
239
+ ## Relationship to Other Skills
240
+
241
+ | Skill | Use When |
242
+ |---|---|
243
+ | **oracle-doubt** | In-flight adversarial review before a decision stands. Catches wrong directions early. |
244
+ | **oracle-challenge** | Critically evaluating an existing approach or decision after it's been made. |
245
+ | **code-review** | Post-hoc PR verdict on a finished artifact. |
246
+ | **oracle-testing** | TDD RED step serves as the doubt mechanism for behavioral claims. |
247
+ | **oracle-thinkdeep** | Deep exploration and alternative discovery for complex decisions (use doubt after thinkdeep narrows to a specific choice). |
248
+
249
+ **Key distinction:**
250
+ - `oracle-doubt` = "Before I commit to this, prove me wrong" (pre-commit adversarial review)
251
+ - `oracle-challenge` = "Is this approach valid?" (critical evaluation of standing decisions)
252
+ - `code-review` = "Judge this finished artifact" (post-hoc verdict)