@martinffx/atelier 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +22 -24
  3. package/agents/architect.md +1 -1
  4. package/agents/oracle.md +1 -1
  5. package/dist/atelier.js +12 -14
  6. package/package.json +1 -1
  7. package/skills/code-commit/SKILL.md +5 -13
  8. package/skills/code-pull-request/SKILL.md +36 -0
  9. package/skills/code-pull-request/references/common.md +76 -0
  10. package/skills/code-pull-request/references/create-pr.md +122 -0
  11. package/skills/code-pull-request/references/default-template.md +25 -0
  12. package/skills/code-pull-request/references/leave-comment.md +53 -0
  13. package/skills/code-pull-request/references/merge-pr.md +94 -0
  14. package/skills/code-pull-request/references/read-comments.md +61 -0
  15. package/skills/code-pull-request/references/respond-to-comment.md +66 -0
  16. package/skills/code-review/SKILL.md +21 -12
  17. package/skills/code-review/references/reviewers.md +142 -41
  18. package/skills/code-review/references/rq.md +48 -32
  19. package/skills/oracle-debug/SKILL.md +218 -0
  20. package/skills/{code-debug → oracle-debug}/references/bug-patterns.md +3 -3
  21. package/skills/oracle-domain-modelling/SKILL.md +84 -0
  22. package/skills/oracle-grill-me/SKILL.md +20 -0
  23. package/skills/spec-brainstorm/SKILL.md +91 -71
  24. package/skills/spec-finish/SKILL.md +20 -14
  25. package/skills/spec-implement/SKILL.md +3 -2
  26. package/skills/spec-orchestrator/SKILL.md +4 -15
  27. package/skills/spec-plan/SKILL.md +1 -1
  28. package/agents/scout.md +0 -40
  29. package/skills/code-commit/references/pr-workflow.md +0 -145
  30. package/skills/code-debug/SKILL.md +0 -199
  31. package/skills/code-docs/SKILL.md +0 -171
  32. package/skills/code-docs/references/api-docs.md +0 -116
  33. package/skills/code-docs/references/changelog.md +0 -64
  34. package/skills/code-docs/references/readme-structure.md +0 -94
  35. package/skills/oracle-architect/SKILL.md +0 -327
  36. package/skills/oracle-architect/references/api-design.md +0 -345
  37. package/skills/oracle-architect/references/data-modeling.md +0 -318
  38. package/skills/oracle-architect/references/ddd-patterns.md +0 -348
  39. package/skills/oracle-architect/references/interface-design.md +0 -203
  40. package/skills/oracle-challenge/SKILL.md +0 -126
  41. package/skills/oracle-doubt/SKILL.md +0 -252
  42. package/skills/oracle-doubt/references/adversarial-prompt.md +0 -47
  43. package/skills/oracle-grillme/SKILL.md +0 -160
  44. package/skills/oracle-security/SKILL.md +0 -225
  45. package/skills/oracle-security/references/security-patterns.md +0 -236
  46. package/skills/oracle-security/references/threat-modeling-guide.md +0 -137
  47. package/skills/oracle-testing/SKILL.md +0 -237
  48. package/skills/oracle-testing/references/anti-patterns.md +0 -618
  49. package/skills/oracle-testing/references/boundaries.md +0 -579
  50. package/skills/oracle-testing/references/core-testing.md +0 -691
  51. package/skills/oracle-testing/references/edge-testing.md +0 -794
  52. package/skills/oracle-testing/references/stub-driven-tdd.md +0 -322
  53. package/skills/oracle-thinkdeep/SKILL.md +0 -164
  54. /package/skills/{code-debug → oracle-debug}/references/language-tools.md +0 -0
  55. /package/skills/{code-debug → oracle-debug}/references/techniques.md +0 -0
  56. /package/skills/{oracle-grillme → oracle-domain-modelling}/references/ADR-FORMAT.md +0 -0
  57. /package/skills/{oracle-grillme → oracle-domain-modelling}/references/CONTEXT-FORMAT.md +0 -0
@@ -1,618 +0,0 @@
1
- # Testing Anti-Patterns
2
-
3
- What NOT to test and why. Common testing mistakes with examples.
4
-
5
- ## Testing Implementation Details
6
-
7
- Testing internal implementation forces refactors to update tests, even when behavior doesn't change.
8
-
9
- ### Anti-Pattern: Testing Private Methods
10
-
11
- ```typescript
12
- // ❌ DON'T: Test private methods
13
- class OrderService {
14
- private calculateTotal(items: OrderItem[]): number {
15
- return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
16
- }
17
-
18
- async createOrder(request: CreateOrderRequest): Promise<Result<Order>> {
19
- const total = this.calculateTotal(request.items);
20
- // ...
21
- }
22
- }
23
-
24
- // Test tries to call private method - won't compile
25
- describe('OrderService', () => {
26
- it('calculates total correctly', () => {
27
- const service = new OrderService();
28
- // Can't call private calculateTotal!
29
- const total = service['calculateTotal']([...]);
30
- expect(total).toBe(35);
31
- });
32
- });
33
- ```
34
-
35
- **Problem:**
36
- - Can't directly test private methods
37
- - Forced to use `service['calculateTotal']()` hack
38
- - Breaking refactors: rename or move the method, test breaks
39
-
40
- **Solution:** Test through public method
41
-
42
- ```typescript
43
- // ✓ DO: Test behavior through public method
44
- describe('OrderService.createOrder', () => {
45
- it('creates order with correct total', async () => {
46
- const mockRepo = { save: vi.fn().mockResolvedValue({ id: '123' }) };
47
- const service = new OrderService(mockRepo);
48
-
49
- const result = await service.createOrder({
50
- customerId: 'C1',
51
- items: [
52
- { productId: 'P1', quantity: 2, price: 10 },
53
- { productId: 'P2', quantity: 1, price: 15 }
54
- ]
55
- });
56
-
57
- expect(mockRepo.save).toHaveBeenCalledWith(
58
- expect.objectContaining({ total: 35 })
59
- );
60
- });
61
- });
62
- ```
63
-
64
- ## Testing Trivial Code
65
-
66
- Getters, setters, and simple assignments add test maintenance burden with zero value.
67
-
68
- ### Anti-Pattern: Testing Getters/Setters
69
-
70
- ```typescript
71
- // ❌ DON'T: Test trivial getters/setters
72
- class Order {
73
- constructor(private _id: string, private _customerId: string) {}
74
-
75
- get id(): string {
76
- return this._id;
77
- }
78
-
79
- get customerId(): string {
80
- return this._customerId;
81
- }
82
- }
83
-
84
- describe('Order', () => {
85
- it('returns id', () => {
86
- const order = new Order('123', 'C1');
87
- expect(order.id).toBe('123');
88
- });
89
-
90
- it('returns customerId', () => {
91
- const order = new Order('123', 'C1');
92
- expect(order.customerId).toBe('C1');
93
- });
94
- });
95
- ```
96
-
97
- **Problem:**
98
- - Tests trivial property access
99
- - Maintenance burden: change property, update test
100
- - Compiler already validates property access
101
-
102
- **Solution:** Only test getters with logic
103
-
104
- ```typescript
105
- // ✓ DO: Test getters with computed values
106
- class Order {
107
- constructor(
108
- private _id: string,
109
- private _customerId: string,
110
- private _items: OrderItem[]
111
- ) {}
112
-
113
- get id(): string {
114
- return this._id;
115
- }
116
-
117
- get total(): number {
118
- return this._items.reduce((sum, item) => sum + item.price * item.quantity, 0);
119
- }
120
- }
121
-
122
- describe('Order', () => {
123
- it('calculates total from items', () => {
124
- const order = new Order('123', 'C1', [
125
- { productId: 'P1', quantity: 2, price: 10 },
126
- { productId: 'P2', quantity: 1, price: 15 }
127
- ]);
128
-
129
- // Only test computed properties with logic
130
- expect(order.total).toBe(35);
131
- });
132
- });
133
- ```
134
-
135
- ## Testing Framework Behavior
136
-
137
- Framework libraries are already tested. Don't test Express, Jest, or database driver behavior.
138
-
139
- ### Anti-Pattern: Testing Framework Features
140
-
141
- ```typescript
142
- // ❌ DON'T: Test Express parses JSON
143
- import request from 'supertest';
144
- import { Express } from 'express';
145
-
146
- describe('Express integration', () => {
147
- it('parses JSON request body', async () => {
148
- const app: Express = express();
149
- app.use(express.json());
150
-
151
- app.post('/test', (req, res) => {
152
- res.json(req.body);
153
- });
154
-
155
- const response = await request(app)
156
- .post('/test')
157
- .send({ name: 'John' });
158
-
159
- // Framework already does this!
160
- expect(typeof response.body).toBe('object');
161
- expect(response.body.name).toBe('John');
162
- });
163
- });
164
-
165
- // ❌ DON'T: Test database driver functionality
166
- describe('Database driver', () => {
167
- it('returns results as array', async () => {
168
- const result = await db.query('SELECT * FROM orders');
169
-
170
- // Driver already does this
171
- expect(Array.isArray(result)).toBe(true);
172
- });
173
- });
174
- ```
175
-
176
- **Problem:**
177
- - Framework/library already tested by maintainers
178
- - Wastes test execution time
179
- - No value - not testing your code
180
-
181
- **Solution:** Test your code's integration with frameworks
182
-
183
- ```typescript
184
- // ✓ DO: Test your integration with framework
185
- describe('POST /orders', () => {
186
- it('parses request and calls service', async () => {
187
- const mockService = {
188
- createOrder: vi.fn().mockResolvedValue(Ok({ id: '123' }))
189
- };
190
-
191
- const app = createApp(mockService);
192
-
193
- const response = await request(app)
194
- .post('/orders')
195
- .send({ customerId: 'C1', items: [] });
196
-
197
- // Test your code, not Express behavior
198
- expect(mockService.createOrder).toHaveBeenCalledWith(
199
- expect.objectContaining({ customerId: 'C1' })
200
- );
201
- });
202
- });
203
- ```
204
-
205
- ## Testing Trivial Mappings
206
-
207
- Simple property-to-property mappings without logic add maintenance burden.
208
-
209
- ### Anti-Pattern: Testing Simple Mappings
210
-
211
- ```typescript
212
- // ❌ DON'T: Test trivial mappings
213
- class OrderMapper {
214
- toResponse(order: Order): OrderResponse {
215
- return {
216
- id: order.id,
217
- customerId: order.customerId,
218
- status: order.status,
219
- total: order.total
220
- };
221
- }
222
- }
223
-
224
- describe('OrderMapper', () => {
225
- it('maps order to response', () => {
226
- const order = new Order('123', 'C1', [], 'pending', 0);
227
- const response = OrderMapper.toResponse(order);
228
-
229
- expect(response.id).toBe('123');
230
- expect(response.customerId).toBe('C1');
231
- expect(response.status).toBe('pending');
232
- expect(response.total).toBe(0);
233
- });
234
- });
235
- ```
236
-
237
- **Problem:**
238
- - No logic to test - pure property copy
239
- - Compiler validates mapping at type-check time
240
- - Maintenance: change property, update test
241
-
242
- **Solution:** Test mappings with logic or transformation
243
-
244
- ```typescript
245
- // ✓ DO: Test mappings with transformations
246
- class OrderMapper {
247
- // Includes logic: calculation, conditional, transformation
248
- toResponse(order: Order): OrderResponse {
249
- return {
250
- id: order.id,
251
- customerId: order.customerId,
252
- status: order.status,
253
- total: order.total,
254
- displayTotal: `$${order.total.toFixed(2)}`,
255
- // Only include recent orders
256
- isRecent: order.createdAt > Date.now() - 7 * 24 * 60 * 60 * 1000
257
- };
258
- }
259
- }
260
-
261
- describe('OrderMapper', () => {
262
- it('formats total with currency', () => {
263
- const order = new Order('123', 'C1', [], 'pending', 35.5);
264
- const response = OrderMapper.toResponse(order);
265
-
266
- expect(response.displayTotal).toBe('$35.50');
267
- });
268
-
269
- it('marks recent orders', () => {
270
- const order = new Order('123', 'C1', [], 'pending', 0, new Date());
271
- const response = OrderMapper.toResponse(order);
272
-
273
- expect(response.isRecent).toBe(true);
274
- });
275
- });
276
- ```
277
-
278
- ## Testing Third-Party Libraries
279
-
280
- Libraries have their own test suites. Test your integration, not their behavior.
281
-
282
- ### Anti-Pattern: Testing Library Behavior
283
-
284
- ```typescript
285
- // ❌ DON'T: Test third-party library
286
- import _ from 'lodash';
287
-
288
- describe('lodash', () => {
289
- it('groups array elements', () => {
290
- const result = _.groupBy([1, 2, 3, 4], x => x % 2);
291
- expect(result[0]).toEqual([2, 4]);
292
- expect(result[1]).toEqual([1, 3]);
293
- });
294
- });
295
-
296
- // ❌ DON'T: Test validation library
297
- import Joi from 'joi';
298
-
299
- describe('Joi validation', () => {
300
- it('validates required field', () => {
301
- const schema = Joi.object({
302
- name: Joi.string().required()
303
- });
304
-
305
- const result = schema.validate({ name: 'John' });
306
- expect(result.error).toBeUndefined();
307
- });
308
- });
309
- ```
310
-
311
- **Problem:**
312
- - Library already tested by maintainers
313
- - No test coverage value - not testing your code
314
- - Wasted execution time
315
-
316
- **Solution:** Test your code that uses libraries
317
-
318
- ```typescript
319
- // ✓ DO: Test how you use the library
320
- describe('OrderValidator', () => {
321
- it('rejects order with missing customerId', () => {
322
- const result = OrderValidator.validate({
323
- // customerId missing
324
- items: [{ productId: 'P1', quantity: 1 }]
325
- });
326
-
327
- expect(result.ok).toBe(false);
328
- expect(result.error).toContain('customerId');
329
- });
330
-
331
- it('accepts valid order', () => {
332
- const result = OrderValidator.validate({
333
- customerId: 'C1',
334
- items: [{ productId: 'P1', quantity: 1 }]
335
- });
336
-
337
- expect(result.ok).toBe(true);
338
- });
339
- });
340
-
341
- // ✓ DO: Test grouping logic (not lodash)
342
- describe('OrderAnalytics', () => {
343
- it('groups orders by customer', () => {
344
- const orders = [
345
- { id: '1', customerId: 'C1' },
346
- { id: '2', customerId: 'C2' },
347
- { id: '3', customerId: 'C1' }
348
- ];
349
-
350
- const grouped = OrderAnalytics.groupByCustomer(orders);
351
-
352
- expect(grouped['C1']).toHaveLength(2);
353
- expect(grouped['C2']).toHaveLength(1);
354
- });
355
- });
356
- ```
357
-
358
- ## Over-Testing (Too Many Tests)
359
-
360
- Test everything eventually fails: changes break dozens of tests, even when behavior unchanged.
361
-
362
- ### Anti-Pattern: Testing Every Line
363
-
364
- ```typescript
365
- // ❌ DON'T: Test every internal detail
366
- class OrderService {
367
- async createOrder(request: CreateOrderRequest): Promise<Result<Order>> {
368
- // Test 1: validating format
369
- if (!request.customerId) return Err('Missing customerId');
370
-
371
- // Test 2: validating items
372
- if (!request.items || request.items.length === 0) return Err('Empty items');
373
-
374
- // Test 3: validating prices
375
- for (const item of request.items) {
376
- if (item.price < 0) return Err('Negative price');
377
- }
378
-
379
- // Test 4: validation result
380
- const order = Order.fromRequest(request);
381
- const validation = order.validate();
382
- if (!validation.ok) return validation;
383
-
384
- // Test 5: repo call
385
- const record = order.toRecord();
386
-
387
- // Test 6: repo result
388
- const saved = await this.repo.save(record);
389
-
390
- // Test 7: transformation
391
- return Ok(Order.fromRecord(saved));
392
- }
393
- }
394
-
395
- describe('OrderService.createOrder', () => {
396
- it('returns error for missing customerId', async () => { /* ... */ });
397
- it('returns error for empty items', async () => { /* ... */ });
398
- it('returns error for negative price', async () => { /* ... */ });
399
- it('validates order entity', async () => { /* ... */ });
400
- it('calls repo save', async () => { /* ... */ });
401
- it('transforms record to entity', async () => { /* ... */ });
402
- it('returns Ok result', async () => { /* ... */ });
403
- // 7 tests for 1 method - high maintenance
404
- });
405
- ```
406
-
407
- **Problem:**
408
- - Every refactor breaks multiple tests
409
- - Tests test implementation, not behavior
410
- - Slow feedback loop
411
- - Hard to see what actually matters
412
-
413
- **Solution:** Test behavior, not implementation
414
-
415
- ```typescript
416
- // ✓ DO: Test high-level behavior
417
- describe('OrderService.createOrder', () => {
418
- it('creates order for valid request', async () => {
419
- const mockRepo = {
420
- save: vi.fn().mockResolvedValue({ id: '123' })
421
- };
422
- const service = new OrderService(mockRepo);
423
-
424
- const result = await service.createOrder({
425
- customerId: 'C1',
426
- items: [{ productId: 'P1', quantity: 1, price: 10 }]
427
- });
428
-
429
- expect(result.ok).toBe(true);
430
- });
431
-
432
- it('rejects invalid order', async () => {
433
- const mockRepo = { save: vi.fn() };
434
- const service = new OrderService(mockRepo);
435
-
436
- const result = await service.createOrder({
437
- customerId: 'C1',
438
- items: [] // Invalid
439
- });
440
-
441
- expect(result.ok).toBe(false);
442
- expect(mockRepo.save).not.toHaveBeenCalled();
443
- });
444
-
445
- // 2 tests covering all code paths
446
- });
447
- ```
448
-
449
- ## Under-Testing (Too Few Tests)
450
-
451
- Only testing happy path leaves bugs in error handling and edge cases.
452
-
453
- ### Anti-Pattern: Only Testing Happy Path
454
-
455
- ```typescript
456
- // ❌ DON'T: Only test success case
457
- describe('OrderService.createOrder', () => {
458
- it('creates order', async () => {
459
- const mockRepo = {
460
- save: vi.fn().mockResolvedValue({ id: '123' })
461
- };
462
- const service = new OrderService(mockRepo);
463
-
464
- const result = await service.createOrder({
465
- customerId: 'C1',
466
- items: [{ productId: 'P1', quantity: 1, price: 10 }]
467
- });
468
-
469
- // Only tests success
470
- expect(result.ok).toBe(true);
471
- });
472
- });
473
- ```
474
-
475
- **Problem:**
476
- - Error handling untested
477
- - Edge cases not covered
478
- - Production bugs from unhandled errors
479
-
480
- **Solution:** Test both success and failure paths
481
-
482
- ```typescript
483
- // ✓ DO: Test success and error paths
484
- describe('OrderService.createOrder', () => {
485
- it('creates order for valid request', async () => {
486
- const mockRepo = {
487
- save: vi.fn().mockResolvedValue({ id: '123' })
488
- };
489
- const service = new OrderService(mockRepo);
490
-
491
- const result = await service.createOrder({
492
- customerId: 'C1',
493
- items: [{ productId: 'P1', quantity: 1, price: 10 }]
494
- });
495
-
496
- expect(result.ok).toBe(true);
497
- });
498
-
499
- it('returns error for empty items', async () => {
500
- const service = new OrderService(mockRepo);
501
-
502
- const result = await service.createOrder({
503
- customerId: 'C1',
504
- items: []
505
- });
506
-
507
- expect(result.ok).toBe(false);
508
- });
509
-
510
- it('returns error for missing customerId', async () => {
511
- const service = new OrderService(mockRepo);
512
-
513
- const result = await service.createOrder({
514
- customerId: '',
515
- items: [{ productId: 'P1', quantity: 1, price: 10 }]
516
- });
517
-
518
- expect(result.ok).toBe(false);
519
- });
520
-
521
- it('handles repository errors gracefully', async () => {
522
- const mockRepo = {
523
- save: vi.fn().mockRejectedValue(new Error('DB error'))
524
- };
525
- const service = new OrderService(mockRepo);
526
-
527
- const result = await service.createOrder({
528
- customerId: 'C1',
529
- items: [{ productId: 'P1', quantity: 1, price: 10 }]
530
- });
531
-
532
- expect(result.ok).toBe(false);
533
- });
534
- });
535
- ```
536
-
537
- ## Testing with Unstable Mocks
538
-
539
- Mocks that change behavior make tests brittle and unreliable.
540
-
541
- ### Anti-Pattern: Using Complex, Unstable Mocks
542
-
543
- ```typescript
544
- // ❌ DON'T: Create complex, coupled mocks
545
- class OrderServiceTest {
546
- createMockService() {
547
- return {
548
- createOrder: vi.fn(async (req) => {
549
- // Mock coupled to implementation
550
- if (!req.customerId) return Err('Missing');
551
- if (!req.items || req.items.length === 0) return Err('Empty');
552
-
553
- // Duplicates validation logic from real service
554
- return Ok(new Order('123', req.customerId, req.items, 'pending', 35));
555
- })
556
- };
557
- }
558
- }
559
-
560
- // Test breaks if validation changes in real service
561
- describe('OrderController', () => {
562
- it('handles service error', async () => {
563
- const mockService = createMockService();
564
- const controller = new OrderController(mockService);
565
-
566
- const result = await controller.createOrder({ customerId: '', items: [] });
567
-
568
- // Brittle - depends on mock implementation
569
- expect(result.status).toBe(400);
570
- });
571
- });
572
- ```
573
-
574
- **Problem:**
575
- - Mock duplicates validation logic
576
- - Test breaks if validation logic changes
577
- - Mock and real code diverge over time
578
-
579
- **Solution:** Use simple, declarative mocks
580
-
581
- ```typescript
582
- // ✓ DO: Use simple mocks with vi.fn()
583
- describe('OrderController', () => {
584
- it('handles service error', async () => {
585
- const mockService = {
586
- createOrder: vi.fn().mockResolvedValue(Err('Invalid order'))
587
- };
588
- const controller = new OrderController(mockService);
589
-
590
- const result = await controller.createOrder({
591
- customerId: 'C1',
592
- items: [{ productId: 'P1', quantity: 1, price: 10 }]
593
- });
594
-
595
- expect(result.status).toBe(400);
596
- expect(result.body.error).toBe('Invalid order');
597
- });
598
- });
599
- ```
600
-
601
- ## Summary: When to Skip Tests
602
-
603
- Save effort by NOT testing:
604
-
605
- | What | Why | Exception |
606
- |------|-----|-----------|
607
- | Getters/setters | No logic | Computed properties |
608
- | Framework behavior | Already tested | Your integration with framework |
609
- | Library behavior | Already tested | Your usage of library |
610
- | Trivial mappings | No logic, type-safe | Mappings with transformation |
611
- | Private methods | Access through public API | Can't isolate the logic |
612
- | Internal details | Break on refactor | Public behavior only |
613
-
614
- Focus testing effort on:
615
- - Business logic and rules
616
- - Validation and error handling
617
- - Integration points and boundaries
618
- - Public APIs and contracts