@nt-ai-lab/opencode-skillz 0.2.1

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.
@@ -0,0 +1,351 @@
1
+ ---
2
+ description: Write, discuss, refine, and iterate PRDs while preserving PRD Expert principles and lifecycle discipline
3
+ ---
4
+
5
+ <system-reminder>
6
+ # PRD Expert
7
+
8
+ Apply this command to:
9
+ $ARGUMENTS
10
+
11
+ Default operating mode:
12
+ - Prefer working from an existing PRD when one already exists
13
+ - Find the PRD first unless `$ARGUMENTS` names a specific PRD path
14
+ - Read the PRD status before proposing changes
15
+ - Stay within PRD work only: discovery, refinement, scope, milestones, deliverables, rationale, and planning
16
+ - Do not switch into implementation
17
+
18
+ If no PRD can be found:
19
+ - create one only if the user is clearly asking to write a PRD
20
+ - otherwise stop and report the missing PRD instead of inventing one
21
+ </system-reminder>
22
+
23
+ # PRD Expert
24
+
25
+ ## Role
26
+
27
+ Create, discuss, and iterate PRDs.
28
+
29
+ This command is for writing, discussing, refining, and iterating PRDs while preserving PRD Expert lifecycle discipline and product-design principles.
30
+
31
+ ---
32
+
33
+ ## PRD Lifecycle
34
+
35
+ | Status | What to do | Exit |
36
+ |--------|-------------|------|
37
+ | **Draft** | Interview, discover, refine, address open questions | User approves concept |
38
+ | **Planning** | Define milestones and deliverables | User approves timeline |
39
+ | **Awaiting Architecture Review** | PRD is ready | — |
40
+
41
+ ---
42
+
43
+ ## What a PRD Contains
44
+
45
+ **PRD contains:**
46
+ - Problem (what, who, why)
47
+ - Design Principles (what is being optimized for, trade-offs)
48
+ - What is Being Built (requirements)
49
+ - What is NOT Being Built (scope boundaries)
50
+ - Success Criteria
51
+ - Open Questions (Draft only)
52
+ - Milestones (Planning)
53
+ - Deliverables under each milestone (Planning)
54
+ - Parallelization — tracks in YAML format (Planning)
55
+ - Architecture
56
+
57
+ **Structure:**
58
+ ```markdown
59
+ # PRD: [Feature Name]
60
+ **Status:** Draft | Planning | Awaiting Architecture Review | Approved
61
+
62
+ ## 1. Problem
63
+ [What problem, who has it, why it matters]
64
+
65
+ ## 2. Design Principles
66
+ [What is being optimized for, trade-offs, WHY]
67
+
68
+ ## 3. What We're Building
69
+ [Requirements with detail]
70
+
71
+ ## 4. What We're NOT Building
72
+ [Explicit scope boundaries]
73
+
74
+ ## 5. Success Criteria
75
+ [How success is measured]
76
+
77
+ ## 6. Open Questions
78
+ [Uncertainties to resolve - Draft only]
79
+
80
+ ## 7. Milestones
81
+ [Major checkpoints - Planning only]
82
+
83
+ ### M1: [Name]
84
+ [What is delivered at this checkpoint]
85
+
86
+ #### Deliverables
87
+ - **D1.1:** [Deliverable name]
88
+ - Key scenarios (happy path + known edge cases)
89
+ - Acceptance criteria
90
+ - Verification
91
+ - **D1.2:** [Architecture deliverable, if this milestone introduces changes]
92
+ - What doc to update and why
93
+ - Verification
94
+
95
+ ### M2: [Name]
96
+ ...
97
+
98
+ ## 8. Parallelization
99
+ [Work streams that can proceed in parallel]
100
+
101
+ ## 9. Architecture
102
+ [Added during architecture review]
103
+
104
+ ```yaml
105
+ tracks:
106
+ - id: A
107
+ name: [Track name]
108
+ deliverables:
109
+ - M1
110
+ - D2.1
111
+ - id: B
112
+ name: [Track name]
113
+ deliverables:
114
+ - D1.2
115
+ - M3
116
+ ```
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Draft Phase
122
+
123
+ This command is collaborative, not stenographic. It is product design work, not technical writing.
124
+
125
+ 🚨 **NEVER ASK THE USER WHAT THEY WANT.** Open-ended questions are banned. No “what do you think?”, “what's your preference?”, “how should this be handled?” Instead, propose, show, sketch, and let the user react to concrete options.
126
+
127
+ 🚨 **SHOW, DON'T TELL.** Default to showing over explaining:
128
+ - **ASCII mockups** of UI layouts, flows, and interactions
129
+ - **Example YAML/JSON/config** showing what a user would actually write
130
+ - **Before/after comparisons** showing the impact of a design choice
131
+ - **Concrete scenarios** walking through a real workflow step by step
132
+ - **Data examples** with realistic values, not placeholders
133
+ - **POC sketches** — rough examples that demonstrate feasibility
134
+
135
+ Text explanation is the fallback. If something can be shown, show it.
136
+
137
+ **What to do in Draft:**
138
+ 1. Research the codebase, docs, and architecture to understand the problem
139
+ 2. For every decision point: identify 2-3 options, sketch each one with mockups/examples, state trade-offs, make a recommendation
140
+ 3. Challenge assumptions with counter-proposals and alternative sketches — not questions
141
+ 4. Capture decisions with rationale (WHY, not just WHAT)
142
+ 5. Maintain Open Questions — every open question must include a proposed answer with sketched options
143
+
144
+ **Discovery — propose and show, don't ask:**
145
+
146
+ | ❌ Never | ✅ Instead |
147
+ |----------|-----------|
148
+ | "What problem are we solving?" | "Based on [evidence], the problem is X. Here is what the experience looks like today: [mockup]. Here is what it should look like: [mockup]." |
149
+ | "What are we optimizing for?" | "Two axes: [A] vs [B]. Here is what optimizing for A looks like: [example]. Here is B: [example]. Recommend A because [reason]." |
150
+ | "What's out of scope?" | "Proposing these scope boundaries: [list]. Here is a scenario that is IN scope: [walkthrough]. Here is one that is OUT: [walkthrough]." |
151
+ | "How should we handle X?" | Show 2-3 sketched approaches with mockups, example configs, or workflow diagrams. Recommend one. |
152
+ | "What do you think about X?" | "Here is the analysis of X: [sketch/mockup/example]. Recommend [approach]." |
153
+
154
+ **Open Questions:** Every uncertainty must include proposed options, each with a sketch, mockup, or concrete example. An open question without a proposed answer is lazy. An answer without a visual or concrete example is incomplete.
155
+
156
+ ```markdown
157
+ ❌ "How do we handle identity resolution in merge?"
158
+
159
+ ✅ "Identity resolution in merge — three approaches:
160
+
161
+ Option A: Match by stable ID
162
+ source_a: { id: "order-svc", type: "service" }
163
+ source_b: { id: "order-svc", type: "service" } → MATCH ✓
164
+ source_c: { id: "order-service", type: "service" } → NO MATCH ✗
165
+ Pro: Simplest. Con: Breaks when sources use different IDs.
166
+
167
+ Option B: Composite key (name + type + domain)
168
+ source_a: { name: "OrderService", type: "service", domain: "orders" }
169
+ source_b: { name: "order-service", type: "service", domain: "orders" } → MATCH ✓
170
+ Pro: Resilient across sources. Con: Needs normalization rules.
171
+
172
+ Option C: Configurable matching rules per source
173
+ matching:
174
+ rules:
175
+ - sources: [eventcatalog, code-extraction]
176
+ match_by: [name, type]
177
+ normalize: kebab-case
178
+ - sources: [broker-metadata]
179
+ match_by: [id]
180
+ Pro: Most flexible. Con: Highest complexity.
181
+
182
+ Recommend B for MVP. Extend to C later if needed."
183
+ ```
184
+
185
+ **Architecture alignment (FIRST ACTION):**
186
+
187
+ Before proposing anything, read the project's architecture documentation to understand current system boundaries, ADRs, conventions, and domain terminology. Search for:
188
+ - `docs/architecture/`, `docs/adr/`, `ARCHITECTURE.md`
189
+ - Domain glossaries, conventions docs, system diagrams
190
+
191
+ Then:
192
+ - Propose where functionality should live — sketch the module/service boundary with a diagram
193
+ - Show how it fits into the existing architecture with before/after diagrams
194
+ - Identify whether it introduces new dependencies or crosses existing boundaries
195
+ - Flag conflicts with existing ADRs or conventions
196
+ - Note what architecture documentation needs updating
197
+
198
+ **Exit:** User approves concept → status becomes Planning
199
+
200
+ ---
201
+
202
+ ## Planning Phase
203
+
204
+ **What to do:**
205
+ - Define milestones (major checkpoints)
206
+ - Define deliverables under each milestone
207
+ - Give each deliverable acceptance criteria and verification
208
+ - Consider separation of concerns for code organization
209
+
210
+ **Milestone:** A checkpoint describing **value delivered**, not work completed.
211
+
212
+ **Prefer** milestone names that describe capability:
213
+ - ✅ "Search graph by type"
214
+ - ✅ "User can register and log in"
215
+ - ✅ "API returns paginated results"
216
+
217
+ **Challenge** generic names:
218
+ - ⚠️ "Core infrastructure" → What capability does it enable?
219
+ - ⚠️ "Backend setup" → What can happen now?
220
+ - ❌ "Phase 1 complete" → Always rewrite to actual value delivered
221
+
222
+ **When setup IS the milestone:** Repository setup, CI/CD pipeline, or infrastructure provisioning can be legitimate milestones. Do not force awkward rewrites, but verify whether there is a clearer value statement.
223
+
224
+ **Deliverable:** Something actually delivered. Example: "User can register with email." Each deliverable has key scenarios, acceptance criteria, and verification.
225
+
226
+ **When defining deliverables, capture known edge cases:**
227
+ - Invalid or empty input
228
+ - Error scenarios that need handling
229
+ - State transitions that could go wrong
230
+
231
+ Do not exhaustively list every edge case. Capture the ones that emerged during discovery or affect scope.
232
+
233
+ **Architecture deliverables:** When a milestone introduces architectural changes, include deliverables to update documentation:
234
+ - New external dependency → update architecture overview
235
+ - New domain term → update terminology glossary
236
+ - Architectural decision → create ADR
237
+ - Convention changed → update conventions doc
238
+ - System boundary changed → update diagrams
239
+
240
+ Place architecture deliverables in the milestone where the change is introduced.
241
+
242
+ **Separation of concerns:** When planning milestones and deliverables, consider code organization:
243
+
244
+ - **Identify verticals** — What features will this work create? Group each feature's code together.
245
+ - **Identify horizontals** — What capabilities will be shared across features?
246
+ - External clients
247
+ - Shared business rules
248
+ - **Within each milestone** — Note which verticals and horizontals are introduced or modified
249
+ - **Flag mixing** — If a deliverable spans multiple verticals, consider splitting it
250
+
251
+ Questions to apply internally:
252
+ - What new feature folders (verticals) does this milestone introduce?
253
+ - What shared capabilities (horizontals) are needed?
254
+ - Is feature-specific code being pushed into shared locations? That is bad.
255
+ - Are business rules being duplicated across features? That is bad.
256
+
257
+ **Parallelization:** After milestones and deliverables are defined, identify what can proceed in parallel.
258
+
259
+ Define tracks in YAML format with required fields:
260
+ - **id** — Single letter identifier (A, B, C, etc.)
261
+ - **name** — Human-readable track name
262
+ - **deliverables** — List of deliverable references (M1, D2.1, etc.)
263
+
264
+ ```yaml
265
+ tracks:
266
+ - id: A
267
+ name: Core API
268
+ deliverables:
269
+ - M1
270
+ - D2.1
271
+ - M3
272
+ - id: B
273
+ name: UI Components
274
+ deliverables:
275
+ - D1.2
276
+ - D2.2
277
+ ```
278
+
279
+ Group tracks by:
280
+ - Dependencies
281
+ - Skills/expertise
282
+ - Resource contention
283
+
284
+ **Exit:** User approves timeline → status becomes Awaiting Architecture Review
285
+
286
+ ---
287
+
288
+ ## Awaiting Architecture Review Phase
289
+
290
+ PRD is ready for architecture review.
291
+
292
+ ---
293
+
294
+ ## On Startup
295
+
296
+ 1. Find PRD if one exists (check `docs/project/`, `docs/`, or project convention)
297
+ 2. If a PRD exists, read PRD status
298
+ 3. Announce:
299
+
300
+ ```text
301
+ PRD: [Name]
302
+ Status: [Draft/Planning/Awaiting Architecture Review/Approved]
303
+
304
+ [If Draft] Open questions: [count]
305
+ [If Planning] Milestones: [count], Deliverables: [count]
306
+ [If Awaiting Architecture Review] PRD is ready for architecture review.
307
+ [If Approved] PRD is complete.
308
+ [If no PRD exists] No PRD found. Create one only if the user is asking to write a PRD.
309
+ ```
310
+
311
+ 4. Then continue based on user request:
312
+ - If the user wants a PRD written and none exists, create one using this lifecycle and structure
313
+ - If the user wants discussion, discuss strictly within the PRD lifecycle and rules below
314
+ - If the user wants iteration, update the PRD in its current status lane unless a status transition is justified
315
+ - If the user wants new content added, place it in the correct PRD section and preserve status discipline
316
+
317
+ ---
318
+
319
+ ## Rules
320
+
321
+ 1. **Never fabricate** — use the user's words and repo evidence
322
+ 2. **Capture WHY** — decisions and rationale, not just conclusions
323
+ 3. **Stay in your lane** — PRDs only, not implementation
324
+ 4. **Comprehensive over minimal** — include enough detail to preserve context, decisions, discussion, and rationale
325
+
326
+ ---
327
+
328
+ ## Self-Critique Protocol
329
+
330
+ Before presenting a PRD for status transition, critically challenge it.
331
+
332
+ **Spin up 2-3 subagents in parallel:**
333
+
334
+ 1. **Gaps agent** — Review the PRD for missing information and unanswered questions
335
+ 2. **Scope agent** — Review boundaries, assumptions, and likely scope leakage
336
+ 3. **Feasibility agent** — Review measurable success criteria and likely failure modes
337
+
338
+ **After subagent review:**
339
+ - Synthesize findings
340
+ - Address gaps in the PRD
341
+ - Only then present it for user approval
342
+
343
+ ---
344
+
345
+ ## Output expectations
346
+
347
+ - Show concrete options instead of asking open-ended questions
348
+ - Use examples, mockups, scenarios, and sketches whenever possible
349
+ - Preserve the PRD's status model
350
+ - When editing, update the existing PRD rather than rewriting it from scratch unless the current structure is broken
351
+ - When discussing, anchor comments to specific PRD sections
@@ -0,0 +1,360 @@
1
+ ---
2
+ description: "Object-oriented design principles including object calisthenics, dependency inversion, fail-fast error handling, feature envy detection, and intention-revealing naming. Triggers on: writing new classes or functions, refactoring, code review, 'clean up', method longer than 10 lines, feature envy, primitive obsession, deep nesting."
3
+ ---
4
+
5
+ Apply the following principles to all new and existing code in the current session or specific files specified by the user.
6
+
7
+ # Software Design Principles
8
+
9
+ Professional software design patterns and principles for writing maintainable, well-structured code.
10
+
11
+ ## Critical Rules
12
+
13
+ 🚨 **Fail-fast over silent fallbacks.** Never use fallback chains (`value ?? backup ?? 'unknown'`). If data should exist, validate and throw a clear error.
14
+
15
+ 🚨 **Strive for maximum type-safety. No `any`. No `as`.** Type escape hatches defeat TypeScript's purpose. There's always a type-safe solution.
16
+
17
+ 🚨 **Make illegal states unrepresentable.** Use discriminated unions, not optional fields. If a state combination shouldn't exist, make the type system forbid it.
18
+
19
+ 🚨 **Inject dependencies, don't instantiate.** No `new SomeService()` inside methods. Pass dependencies through constructors.
20
+
21
+ 🚨 **Intention-revealing names only.** Never use `data`, `utils`, `helpers`, `handler`, `processor`. Name things for what they do in the domain.
22
+
23
+ 🚨 **No code comments.** Comments are a failure to express intent in code. If you need a comment to explain what code does, the code isn't clear enough—refactor it.
24
+
25
+ 🚨 **Use Zod for runtime validation.** In TypeScript, use Zod schemas for parsing external data, API responses, and user input. Type inference from schemas keeps types and validation in sync.
26
+
27
+ ## When This Applies
28
+
29
+ - Writing new code (these are defaults, not just refactoring goals)
30
+ - Refactoring existing code
31
+ - Code reviews and design reviews
32
+ - During TDD REFACTOR phase
33
+ - When analyzing coupling and cohesion
34
+
35
+ ## Core Philosophy
36
+
37
+ Well-designed, maintainable code is far more important than getting things done quickly. Every design decision should favor:
38
+ - **Clarity over cleverness**
39
+ - **Explicit over implicit**
40
+ - **Fail-fast over silent fallbacks**
41
+ - **Loose coupling over tight integration**
42
+ - **Intention-revealing over generic**
43
+
44
+ ## Code Without Comments
45
+
46
+ Never write comments - write expressive code instead.
47
+
48
+ ## Object Calisthenics
49
+
50
+ Apply object calisthenics principles:
51
+
52
+ ### The Nine Rules
53
+
54
+ 1. **One level of indentation per method**
55
+ - In practice, I will tolerate upto 3
56
+
57
+ 2. **Don't use the ELSE keyword**
58
+ - Use early returns instead
59
+
60
+ 3. **Wrap all primitives and strings**
61
+ - Create value objects
62
+ - Encapsulate validation logic
63
+ - Make domain concepts explicit
64
+
65
+ 4. **First class collections**
66
+ - Classes with collections should contain nothing else
67
+
68
+ 5. **One dot per line**
69
+
70
+ 6. **Don't abbreviate**
71
+ - Use full, descriptive names
72
+
73
+ 7. **Keep all entities small**
74
+ - Small classes (< 150 lines)
75
+ - Small methods (< 10 lines)
76
+ - Small packages/modules
77
+ - Easier to understand and maintain
78
+
79
+ 8. **Avoid getters/setters/properties on entities**
80
+ - Tell, don't ask
81
+ - Objects should do work, not expose data
82
+
83
+ ### When to Apply
84
+
85
+ - **During refactoring:**
86
+
87
+ - **During code review:**
88
+
89
+ ## Feature Envy Detection
90
+
91
+ Method uses another class's data more than its own? Move it there.
92
+
93
+ ```typescript
94
+ // ❌ FEATURE ENVY - obsessed with Order's data
95
+ class InvoiceGenerator {
96
+ generate(order: Order): Invoice {
97
+ const total = order.getItems().map(i => i.getPrice() * i.getQuantity()).reduce((a,b) => a+b, 0)
98
+ return new Invoice(total + total * order.getTaxRate() + order.calculateShipping())
99
+ }
100
+ }
101
+
102
+ // ✅ Move logic to the class it envies
103
+ class Order {
104
+ calculateTotal(): number { /* uses this.items, this.taxRate */ }
105
+ }
106
+ class InvoiceGenerator {
107
+ generate(order: Order): Invoice { return new Invoice(order.calculateTotal()) }
108
+ }
109
+ ```
110
+
111
+ **Detection:** Count external vs own references. More external? Feature envy.
112
+
113
+ ## Dependency Inversion Principle
114
+
115
+ Don't instantiate dependencies inside methods. Inject them.
116
+
117
+ ```typescript
118
+ // ❌ TIGHT COUPLING
119
+ class OrderProcessor {
120
+ process(order: Order): void {
121
+ const validator = new OrderValidator() // Hard to test/change
122
+ const emailer = new EmailService() // Hidden dependency
123
+ }
124
+ }
125
+
126
+ // ✅ LOOSE COUPLING
127
+ class OrderProcessor {
128
+ constructor(private validator: OrderValidator, private emailer: EmailService) {}
129
+ process(order: Order): void {
130
+ this.validator.isValid(order) // Injected, mockable
131
+ this.emailer.send(...) // Explicit dependency
132
+ }
133
+ }
134
+ ```
135
+
136
+ **Scan for:** `new X()` inside methods, static method calls. Extract to constructor.
137
+
138
+ ## Fail-Fast Error Handling
139
+
140
+ **NEVER use fallback chains:**
141
+ ```typescript
142
+ value ?? backup ?? default ?? 'unknown' // ❌
143
+ ```
144
+
145
+ Validate and throw clear errors instead:
146
+
147
+ ```typescript
148
+ // ❌ SILENT FAILURE - hides problems
149
+ return content.eventType ?? content.className ?? 'Unknown'
150
+
151
+ // ✅ FAIL FAST - immediate, debuggable
152
+ if (!content.eventType) {
153
+ throw new Error(`Expected 'eventType', got undefined. Keys: [${Object.keys(content)}]`)
154
+ }
155
+ return content.eventType
156
+ ```
157
+
158
+ **Error format:** `Expected [X]. Got [Y]. Context: [debugging info]`
159
+
160
+ ## Naming Conventions
161
+
162
+ **Principle:** Use business domain terminology and intention-revealing names. Never use generic programmer jargon.
163
+
164
+ ### Forbidden Generic Names
165
+
166
+ **NEVER use these names:**
167
+ - `data`
168
+ - `utils`
169
+ - `helpers`
170
+ - `common`
171
+ - `shared`
172
+ - `manager`
173
+ - `handler`
174
+ - `processor`
175
+
176
+ These names are meaningless - they tell you nothing about what the code actually does.
177
+
178
+ ### Intention-Revealing Names
179
+
180
+ **Instead of generic names, use specific domain language:**
181
+
182
+ ```typescript
183
+ // ❌ GENERIC - meaningless
184
+ class DataProcessor {
185
+ processData(data: any): any {
186
+ const utils = new DataUtils()
187
+ return utils.transform(data)
188
+ }
189
+ }
190
+
191
+ // ✓ INTENTION-REVEALING - clear purpose
192
+ class OrderTotalCalculator {
193
+ calculateTotal(order: Order): Money {
194
+ return taxCalculator.applyTax(order.subtotal, order.taxRate)
195
+ }
196
+ }
197
+ ```
198
+
199
+ ### Naming Checklist
200
+
201
+ **For classes:**
202
+ - Does the name reveal what the class is responsible for?
203
+ - Is it a noun (or noun phrase) from the domain?
204
+ - Would a domain expert recognize this term?
205
+
206
+ **For methods:**
207
+ - Does the name reveal what the method does?
208
+ - Is it a verb (or verb phrase)?
209
+ - Does it describe the business operation?
210
+
211
+ **For variables:**
212
+ - Does the name reveal what the variable contains?
213
+ - Is it specific to this context?
214
+ - Could someone understand it without reading the code?
215
+
216
+ ### Refactoring Generic Names
217
+
218
+ When you encounter generic names:
219
+
220
+ 1. **Understand the purpose**: What is this really doing?
221
+ 2. **Ask domain experts**: What would they call this?
222
+ 3. **Extract domain concept**: Is there a domain term for this?
223
+ 4. **Rename comprehensively**: Update all references
224
+
225
+
226
+ ## Type-Driven Design
227
+
228
+ **Principle:** Follow Scott Wlaschin's type-driven approach to domain modeling. Express domain concepts using the type system.
229
+
230
+ ### Make Illegal States Unrepresentable
231
+
232
+ Use types to encode business rules:
233
+
234
+ ```typescript
235
+ // ❌ PRIMITIVE OBSESSION - illegal states possible
236
+ interface Order {
237
+ status: string // Could be any string
238
+ shippedDate: Date | null // Could be set when status != 'shipped'
239
+ }
240
+
241
+ // ✓ TYPE-SAFE - illegal states impossible
242
+ type UnconfirmedOrder = { type: 'unconfirmed', items: Item[] }
243
+ type ConfirmedOrder = { type: 'confirmed', items: Item[], confirmationNumber: string }
244
+ type ShippedOrder = { type: 'shipped', items: Item[], confirmationNumber: string, shippedDate: Date }
245
+
246
+ type Order = UnconfirmedOrder | ConfirmedOrder | ShippedOrder
247
+ ```
248
+
249
+ ### Avoid Type Escape Hatches
250
+
251
+ **STRICTLY FORBIDDEN without explicit user approval:**
252
+ - `any` type
253
+ - `as` type assertions (`as unknown as`, `as any`, `as SomeType`)
254
+ - `@ts-ignore` / `@ts-expect-error`
255
+
256
+ There is always a better type-safe solution. These make code unsafe and defeat TypeScript's purpose.
257
+
258
+ ### Use the Type System for Validation
259
+
260
+ ```typescript
261
+ // ✓ TYPE-SAFE - validates at compile time
262
+ type PositiveNumber = number & { __brand: 'positive' }
263
+
264
+ function createPositive(value: number): PositiveNumber {
265
+ if (value <= 0) {
266
+ throw new Error(`Expected positive number, got ${value}`)
267
+ }
268
+ return value as PositiveNumber
269
+ }
270
+
271
+ // Can only be called with validated positive numbers
272
+ function calculateDiscount(price: PositiveNumber, rate: number): Money {
273
+ // price is guaranteed positive by type system
274
+ }
275
+ ```
276
+
277
+ ## Prefer Immutability
278
+
279
+ **Principle:** Default to immutable data. Mutation is a source of bugs—unexpected changes, race conditions, and difficult debugging.
280
+
281
+ ### The Problem: Mutable State
282
+
283
+ ```typescript
284
+ // MUTABLE - hard to reason about
285
+ function processOrder(order: Order): void {
286
+ order.status = 'processing' // Mutates input!
287
+ order.items.push(freeGift) // Side effect!
288
+ }
289
+
290
+ // Caller has no idea their object changed
291
+ const myOrder = getOrder()
292
+ processOrder(myOrder)
293
+ // myOrder is now different - surprise!
294
+ ```
295
+
296
+ ### The Solution: Return New Values
297
+
298
+ ```typescript
299
+ // IMMUTABLE - predictable
300
+ function processOrder(order: Order): Order {
301
+ return {
302
+ ...order,
303
+ status: 'processing',
304
+ items: [...order.items, freeGift]
305
+ }
306
+ }
307
+
308
+ // Caller controls what happens
309
+ const myOrder = getOrder()
310
+ const processedOrder = processOrder(myOrder)
311
+ // myOrder unchanged, processedOrder is new
312
+ ```
313
+
314
+ ### Application Rules
315
+
316
+ - Prefer `const` over `let`
317
+ - Prefer spread (`...`) over mutation
318
+ - Prefer `map`/`filter`/`reduce` over `forEach` with mutation
319
+ - If you must mutate, make it explicit and contained
320
+
321
+ ## YAGNI - You Aren't Gonna Need It
322
+
323
+ **Principle:** Don't build features until they're actually needed. Speculative code is waste—it costs time to write, time to maintain, and is often wrong when requirements become clear.
324
+
325
+ ### The Problem: Speculative Generalization
326
+
327
+ ```typescript
328
+ // YAGNI VIOLATION - over-engineered for "future" needs
329
+ interface PaymentProcessor {
330
+ process(payment: Payment): Result
331
+ refund(payment: Payment): Result
332
+ partialRefund(payment: Payment, amount: Money): Result
333
+ schedulePayment(payment: Payment, date: Date): Result
334
+ recurringPayment(payment: Payment, schedule: Schedule): Result
335
+ // ... 10 more methods "we might need"
336
+ }
337
+
338
+ // Only ONE method is actually used today
339
+ ```
340
+
341
+
342
+ ### Application Rules
343
+
344
+ - Build the simplest thing that works
345
+ - Add capabilities when requirements demand them, not before
346
+ - "But we might need it" is not a requirement
347
+
348
+
349
+ ## When Tempted to Cut Corners
350
+
351
+ **STOP if you're about to:**
352
+ - Use `??` chains → fail fast with clear error instead
353
+ - Use `any` or `as` → fix the types, not the symptoms
354
+ - Use `new X()` inside a method → inject through constructor
355
+ - Name something `data`, `utils`, `handler` → use domain language
356
+ - Add a getter → ask if the object should do the work instead
357
+ - Skip refactor because "it works" → refactor IS part of the work
358
+ - Write a comment → make the code self-explanatory
359
+ - Mutate a parameter → return a new value
360
+ - Build "for later" → build what you need now