@garethdaine/agentops 0.9.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 (148) hide show
  1. package/.claude-plugin/plugin.json +10 -0
  2. package/LICENSE +21 -0
  3. package/README.md +410 -0
  4. package/agents/architecture-researcher.md +115 -0
  5. package/agents/code-critic.md +190 -0
  6. package/agents/delegation-router.md +40 -0
  7. package/agents/feature-researcher.md +117 -0
  8. package/agents/interrogator.md +11 -0
  9. package/agents/pitfalls-researcher.md +112 -0
  10. package/agents/plan-validator.md +173 -0
  11. package/agents/proposer.md +61 -0
  12. package/agents/security-reviewer.md +189 -0
  13. package/agents/skill-builder.md +43 -0
  14. package/agents/spec-compliance-reviewer.md +154 -0
  15. package/agents/stack-researcher.md +89 -0
  16. package/commands/build.md +766 -0
  17. package/commands/code-analysis.md +39 -0
  18. package/commands/code-field.md +22 -0
  19. package/commands/compliance-check.md +34 -0
  20. package/commands/configure.md +178 -0
  21. package/commands/cost-report.md +17 -0
  22. package/commands/enterprise/adr.md +78 -0
  23. package/commands/enterprise/brainstorm.md +461 -0
  24. package/commands/enterprise/design.md +203 -0
  25. package/commands/enterprise/dev-setup.md +136 -0
  26. package/commands/enterprise/docker-dev.md +229 -0
  27. package/commands/enterprise/e2e.md +233 -0
  28. package/commands/enterprise/feature.md +218 -0
  29. package/commands/enterprise/gap-analysis.md +204 -0
  30. package/commands/enterprise/handover.md +195 -0
  31. package/commands/enterprise/herd.md +152 -0
  32. package/commands/enterprise/knowledge.md +173 -0
  33. package/commands/enterprise/onboard.md +86 -0
  34. package/commands/enterprise/qa-check.md +80 -0
  35. package/commands/enterprise/reason.md +196 -0
  36. package/commands/enterprise/review.md +177 -0
  37. package/commands/enterprise/scaffold.md +153 -0
  38. package/commands/enterprise/status-report.md +101 -0
  39. package/commands/enterprise/tech-catalog.md +170 -0
  40. package/commands/enterprise/test-gen.md +138 -0
  41. package/commands/evolve.md +39 -0
  42. package/commands/flags.md +44 -0
  43. package/commands/interrogate.md +263 -0
  44. package/commands/lesson.md +15 -0
  45. package/commands/lessons.md +10 -0
  46. package/commands/plan.md +44 -0
  47. package/commands/prune.md +27 -0
  48. package/commands/star.md +17 -0
  49. package/commands/supply-chain-scan.md +44 -0
  50. package/commands/unicode-scan.md +63 -0
  51. package/commands/verify.md +41 -0
  52. package/commands/workflow.md +436 -0
  53. package/hooks/ai-guardrails.sh +114 -0
  54. package/hooks/audit-log.sh +26 -0
  55. package/hooks/auto-delegate.sh +45 -0
  56. package/hooks/auto-evolve.sh +22 -0
  57. package/hooks/auto-lesson.sh +26 -0
  58. package/hooks/auto-plan.sh +59 -0
  59. package/hooks/auto-test.sh +46 -0
  60. package/hooks/auto-verify.sh +30 -0
  61. package/hooks/budget-check.sh +24 -0
  62. package/hooks/code-field-preamble.sh +30 -0
  63. package/hooks/compliance-gate.sh +50 -0
  64. package/hooks/content-trust.sh +22 -0
  65. package/hooks/credential-redact.sh +23 -0
  66. package/hooks/delegation-trust.sh +15 -0
  67. package/hooks/detect-test-run.sh +19 -0
  68. package/hooks/enforcement-lib.sh +60 -0
  69. package/hooks/evolve-gate.sh +32 -0
  70. package/hooks/evolve-lib.sh +32 -0
  71. package/hooks/exfiltration-check.sh +67 -0
  72. package/hooks/failure-collector.sh +27 -0
  73. package/hooks/feature-flags.sh +67 -0
  74. package/hooks/file-provenance.sh +31 -0
  75. package/hooks/flag-utils.sh +36 -0
  76. package/hooks/hooks.json +145 -0
  77. package/hooks/injection-scan.sh +58 -0
  78. package/hooks/integrity-verify.sh +91 -0
  79. package/hooks/lessons-check.sh +17 -0
  80. package/hooks/lockfile-audit.sh +109 -0
  81. package/hooks/patterns-lib.sh +22 -0
  82. package/hooks/plan-gate.sh +18 -0
  83. package/hooks/redact-lib.sh +15 -0
  84. package/hooks/runtime-mode.sh +56 -0
  85. package/hooks/session-cleanup.sh +74 -0
  86. package/hooks/skill-validator.sh +28 -0
  87. package/hooks/standards-enforce.sh +106 -0
  88. package/hooks/star-gate.sh +93 -0
  89. package/hooks/star-preamble.sh +10 -0
  90. package/hooks/telemetry.sh +33 -0
  91. package/hooks/todo-prune.sh +84 -0
  92. package/hooks/unicode-firewall.sh +122 -0
  93. package/hooks/unicode-lib.sh +66 -0
  94. package/hooks/unicode-scan-session.sh +96 -0
  95. package/hooks/validate-command.sh +103 -0
  96. package/hooks/validate-env.sh +51 -0
  97. package/hooks/validate-path.sh +81 -0
  98. package/package.json +40 -0
  99. package/settings.json +6 -0
  100. package/templates/ai-config/tool-standards.md +56 -0
  101. package/templates/architecture/api-first.md +192 -0
  102. package/templates/architecture/auth-patterns.md +302 -0
  103. package/templates/architecture/caching-strategy.md +359 -0
  104. package/templates/architecture/database-patterns.md +347 -0
  105. package/templates/architecture/event-driven.md +252 -0
  106. package/templates/architecture/integration-patterns.md +185 -0
  107. package/templates/architecture/multi-tenancy.md +104 -0
  108. package/templates/architecture/service-boundaries.md +200 -0
  109. package/templates/build/brief-template.md +86 -0
  110. package/templates/build/summary-template.md +100 -0
  111. package/templates/build/task-plan-template.md +133 -0
  112. package/templates/communication/effort-estimate.md +54 -0
  113. package/templates/communication/incident-response.md +59 -0
  114. package/templates/communication/post-mortem.md +109 -0
  115. package/templates/communication/risk-register.md +43 -0
  116. package/templates/communication/sprint-demo-checklist.md +64 -0
  117. package/templates/communication/stakeholder-presentation-outline.md +84 -0
  118. package/templates/communication/technical-proposal.md +77 -0
  119. package/templates/delivery/deployment/deployment-checklist.md +49 -0
  120. package/templates/delivery/design/solution-design-checklist.md +37 -0
  121. package/templates/delivery/discovery/stakeholder-questions.md +33 -0
  122. package/templates/delivery/handover/knowledge-transfer-checklist.md +75 -0
  123. package/templates/delivery/handover/operational-runbook.md +117 -0
  124. package/templates/delivery/handover/support-escalation-matrix.md +56 -0
  125. package/templates/delivery/implementation/blocker-escalation-template.md +55 -0
  126. package/templates/delivery/implementation/sprint-planning-template.md +49 -0
  127. package/templates/delivery/implementation/task-decomposition-guide.md +59 -0
  128. package/templates/delivery/qa/test-plan-template.md +76 -0
  129. package/templates/delivery/qa/test-results-template.md +55 -0
  130. package/templates/delivery/qa/uat-signoff-template.md +44 -0
  131. package/templates/governance/codeowners.md +60 -0
  132. package/templates/integration/adapter-pattern.md +160 -0
  133. package/templates/scaffolds/env-validation.md +85 -0
  134. package/templates/scaffolds/error-handling.md +171 -0
  135. package/templates/scaffolds/graceful-shutdown.md +139 -0
  136. package/templates/scaffolds/health-check.md +109 -0
  137. package/templates/scaffolds/structured-logging.md +134 -0
  138. package/templates/standards/engineering-standards.md +413 -0
  139. package/templates/standards/standards-checklist.md +125 -0
  140. package/templates/tech-catalog.json +663 -0
  141. package/templates/utilities/project-detection.md +75 -0
  142. package/templates/utilities/requirements-collection.md +68 -0
  143. package/templates/utilities/template-rendering.md +81 -0
  144. package/templates/workflows/architecture-decision.md +90 -0
  145. package/templates/workflows/bug-investigation.md +83 -0
  146. package/templates/workflows/feature-implementation.md +80 -0
  147. package/templates/workflows/refactoring.md +83 -0
  148. package/templates/workflows/spike-exploration.md +82 -0
@@ -0,0 +1,413 @@
1
+ # Engineering Standards
2
+
3
+ This document is injected into every execution subagent during a build. All code produced MUST comply with these standards. Deviations are flagged by the spec-compliance reviewer in Phase 6.
4
+
5
+ ---
6
+
7
+ ## SOLID Principles
8
+
9
+ ### Single Responsibility Principle (SRP)
10
+
11
+ Every class, module, and function should have exactly one reason to change.
12
+
13
+ **Heuristics:**
14
+ - Functions: ≤30 lines. If you exceed this, split into smaller named functions.
15
+ - Classes: ≤200 lines. If you exceed this, extract a collaborator.
16
+ - Files: one primary export per file. Do not combine unrelated classes or functions in a single file.
17
+ - If you find yourself saying "and" when describing what a function does, it has two responsibilities.
18
+
19
+ ```typescript
20
+ // BAD: Two responsibilities — fetching AND formatting
21
+ async function getUserReport(userId: string): Promise<string> {
22
+ const user = await db.users.findById(userId);
23
+ const orders = await db.orders.findByUser(userId);
24
+ return `${user.name}: ${orders.length} orders, total: ${orders.reduce(...)}`;
25
+ }
26
+
27
+ // GOOD: Separate concerns
28
+ async function getUserWithOrders(userId: string): Promise<UserWithOrders> {
29
+ const user = await userRepository.findById(userId);
30
+ const orders = await orderRepository.findByUserId(userId);
31
+ return { user, orders };
32
+ }
33
+
34
+ function formatUserReport(data: UserWithOrders): string {
35
+ return `${data.user.name}: ${data.orders.length} orders, total: ${calculateTotal(data.orders)}`;
36
+ }
37
+ ```
38
+
39
+ ### Open/Closed Principle (OCP)
40
+
41
+ Code should be open for extension, closed for modification.
42
+
43
+ **Heuristics:**
44
+ - Use the Strategy pattern or dependency injection instead of `switch` chains on type.
45
+ - Adding new behaviour means adding a new class/function — not modifying existing ones.
46
+ - When you find yourself adding `else if` to an existing block, consider whether a new strategy/handler is the right move.
47
+
48
+ ```typescript
49
+ // BAD: Every new payment type requires modifying this function
50
+ function processPayment(type: string, amount: number) {
51
+ if (type === 'stripe') { ... }
52
+ else if (type === 'paypal') { ... }
53
+ else if (type === 'crypto') { ... } // New type = modify existing code
54
+ }
55
+
56
+ // GOOD: New payment type = new class, zero changes to existing code
57
+ interface PaymentProcessor {
58
+ process(amount: number): Promise<PaymentResult>;
59
+ }
60
+
61
+ class StripeProcessor implements PaymentProcessor { ... }
62
+ class PayPalProcessor implements PaymentProcessor { ... }
63
+ class CryptoProcessor implements PaymentProcessor { ... }
64
+
65
+ function processPayment(processor: PaymentProcessor, amount: number) {
66
+ return processor.process(amount);
67
+ }
68
+ ```
69
+
70
+ ### Liskov Substitution Principle (LSP)
71
+
72
+ Subtypes must be substitutable for their base types without altering program correctness.
73
+
74
+ **Heuristics:**
75
+ - Do NOT strengthen preconditions in a subclass (e.g., adding null checks the base doesn't require).
76
+ - Do NOT weaken postconditions (e.g., returning a narrower type or throwing where the base doesn't).
77
+ - If a subclass overrides a method and throws `UnsupportedOperationException`, it violates LSP — extract a separate interface instead.
78
+ - Test by asking: "If I swap this subtype for its base type, do all existing tests still pass?"
79
+
80
+ ### Interface Segregation Principle (ISP)
81
+
82
+ Clients should not be forced to depend on interfaces they do not use.
83
+
84
+ **Heuristics:**
85
+ - Small, focused interfaces over one fat interface.
86
+ - Multiple specific interfaces are better than one generic interface with optional methods.
87
+ - If a class implementing an interface must provide a stub/no-op for any method, split the interface.
88
+
89
+ ```typescript
90
+ // BAD: Everything in one interface
91
+ interface Repository<T> {
92
+ findById(id: string): Promise<T>;
93
+ findAll(): Promise<T[]>;
94
+ save(entity: T): Promise<T>;
95
+ delete(id: string): Promise<void>;
96
+ search(query: string): Promise<T[]>; // Not all repos need this
97
+ exportToCsv(): string; // Definitely not all repos
98
+ }
99
+
100
+ // GOOD: Segregated interfaces composed as needed
101
+ interface Readable<T> {
102
+ findById(id: string): Promise<T>;
103
+ findAll(): Promise<T[]>;
104
+ }
105
+ interface Writable<T> {
106
+ save(entity: T): Promise<T>;
107
+ delete(id: string): Promise<void>;
108
+ }
109
+ interface Searchable<T> {
110
+ search(query: string): Promise<T[]>;
111
+ }
112
+ ```
113
+
114
+ ### Dependency Inversion Principle (DIP)
115
+
116
+ High-level modules should not depend on low-level modules. Both should depend on abstractions.
117
+
118
+ **Heuristics:**
119
+ - Use constructor injection. Do NOT instantiate concrete dependencies inside a class.
120
+ - No `new ConcreteClass()` in business logic — dependencies are injected.
121
+ - Depend on interfaces/abstract types, not concrete implementations.
122
+ - Repositories, services, and external clients are always injected.
123
+
124
+ ```typescript
125
+ // BAD: Hard-coupled to Stripe
126
+ class OrderService {
127
+ private stripe = new StripeClient(process.env.STRIPE_KEY); // Concrete dep, untestable
128
+ }
129
+
130
+ // GOOD: Depends on abstraction, injected
131
+ class OrderService {
132
+ constructor(private readonly paymentProcessor: PaymentProcessor) {}
133
+ }
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Clean Code
139
+
140
+ ### Naming
141
+
142
+ - **Reveal intent.** Names should explain WHY, not HOW.
143
+ - **Functions:** verb phrases (`calculateTotal`, `sendWelcomeEmail`, `validateUserInput`)
144
+ - **Booleans:** question form (`isActive`, `hasPermission`, `canAccessResource`, `shouldRetry`)
145
+ - **Classes:** noun phrases, no "Manager", "Handler", "Processor" suffixes unless genuinely appropriate (`UserRepository`, not `UserManager`)
146
+ - **Constants:** SCREAMING_SNAKE_CASE for module-level constants (`MAX_RETRY_ATTEMPTS`)
147
+ - Avoid single-letter variables outside of math-heavy code or trivially-scoped loops.
148
+ - Avoid abbreviations unless universally understood (`url`, `id`, `db` are fine; `usrMgr` is not).
149
+
150
+ ### Functions
151
+
152
+ - **One abstraction level per function.** A function should either orchestrate OR compute, not both.
153
+ - **Command-query separation:** Functions either DO something (commands) or RETURN something (queries) — not both. Functions that both mutate state and return a value are confusing.
154
+ - **Stepdown rule:** Functions call only functions one level below them in abstraction.
155
+ - **Max 3 parameters.** More than 3: introduce a parameter object.
156
+ - **No flag parameters.** A boolean argument is a sign the function should be split in two.
157
+
158
+ ```typescript
159
+ // BAD: Does and returns, flag parameter, mixed abstraction
160
+ async function processUser(userId: string, sendEmail: boolean): Promise<User> {
161
+ const raw = await db.query(`SELECT * FROM users WHERE id = ?`, [userId]);
162
+ const user = { id: raw.id, name: raw.name, email: raw.email };
163
+ await db.query(`UPDATE users SET last_seen = NOW() WHERE id = ?`, [userId]);
164
+ if (sendEmail) await mailer.send(user.email, 'Welcome back');
165
+ return user;
166
+ }
167
+
168
+ // GOOD: Single responsibility, no flag parameter
169
+ async function findUser(userId: string): Promise<User> {
170
+ return userRepository.findById(userId);
171
+ }
172
+
173
+ async function recordUserLogin(userId: string): Promise<void> {
174
+ await userRepository.updateLastSeen(userId, new Date());
175
+ }
176
+
177
+ async function sendLoginEmail(user: User): Promise<void> {
178
+ await emailService.send(user.email, 'Welcome back');
179
+ }
180
+ ```
181
+
182
+ ### Error Handling
183
+
184
+ - **Typed error hierarchy.** Define domain-specific error classes. Never throw raw `Error` with a string message from business logic.
185
+ - **Never swallow errors.** Empty `catch` blocks are forbidden. Log at minimum.
186
+ - **Correlation IDs.** Every request should have a correlation ID propagated through all log entries and error objects.
187
+ - **Fail fast at boundaries.** Validate all external input at the point of entry. Do not let invalid data propagate into the domain.
188
+
189
+ ```typescript
190
+ // BAD
191
+ try {
192
+ await processOrder(order);
193
+ } catch (e) {} // Swallowed
194
+
195
+ // GOOD
196
+ class OrderProcessingError extends AppError {
197
+ constructor(message: string, public readonly orderId: string, cause?: Error) {
198
+ super(message, 'ORDER_PROCESSING_FAILED', { orderId }, cause);
199
+ }
200
+ }
201
+
202
+ try {
203
+ await processOrder(order);
204
+ } catch (error) {
205
+ logger.error('Order processing failed', { orderId: order.id, correlationId, error });
206
+ throw new OrderProcessingError('Failed to process order', order.id, error as Error);
207
+ }
208
+ ```
209
+
210
+ ---
211
+
212
+ ## DRY — Don't Repeat Yourself
213
+
214
+ - **2+ locations = extract.** If the same logic appears in two places, extract it. Three is a certainty.
215
+ - **Knowledge duplication = single source of truth.** The same business rule should live in exactly one place. If you update it, you should only need to update it in one file.
216
+ - **DRY applies to knowledge, not syntax.** Two `for` loops that happen to look similar are not a DRY violation if they represent different concepts.
217
+
218
+ ---
219
+
220
+ ## KISS / YAGNI
221
+
222
+ - **Simplest correct solution first.** Before adding abstraction, ask: does the simpler version solve the problem?
223
+ - **YAGNI (You Aren't Gonna Need It).** Do not implement features or abstractions "in case we need them later." Implement what is required now.
224
+ - **No speculative generality.** Hooks, extension points, and plugin systems not required by current features must not be added.
225
+ - **Three similar lines are better than a premature abstraction.** Only extract when the pattern is stable and has 3+ concrete uses.
226
+
227
+ ---
228
+
229
+ ## Design Patterns
230
+
231
+ Apply patterns when NOT applying them creates a named problem. Do not apply patterns speculatively.
232
+
233
+ Reference: [refactoring.guru](https://refactoring.guru/design-patterns)
234
+
235
+ ### Creational
236
+
237
+ | Pattern | Use when |
238
+ |---------|----------|
239
+ | **Factory Method** | Object creation logic is complex or varies by subtype; callers shouldn't know the concrete class |
240
+ | **Builder** | Object requires many optional parameters or a multi-step construction process |
241
+ | **Singleton** | Prefer Dependency Injection. Use Singleton only for stateless utilities (loggers, config readers) where a single instance is provably correct |
242
+
243
+ ### Structural
244
+
245
+ | Pattern | Use when |
246
+ |---------|----------|
247
+ | **Adapter** | Integrating a third-party library whose interface doesn't match your domain's needs |
248
+ | **Decorator** | Adding cross-cutting behaviour (logging, caching, validation) to an existing object without subclassing |
249
+ | **Facade** | Simplifying a complex subsystem behind a clean, high-level interface for callers |
250
+ | **Proxy** | Controlling access to a resource — lazy loading, access control, logging |
251
+
252
+ ### Behavioral
253
+
254
+ | Pattern | Use when |
255
+ |---------|----------|
256
+ | **Strategy** | Interchangeable algorithms or behaviours; replaces switch chains on type |
257
+ | **Observer** | One-to-many event propagation; decouples producers from consumers |
258
+ | **Command** | Encapsulating a request as an object — enables undo, queuing, logging |
259
+ | **Template Method** | Invariant algorithm structure with variable steps; base class defines the skeleton |
260
+ | **Chain of Responsibility** | A request passes through a chain of handlers; each decides to handle or pass on |
261
+
262
+ **Selection heuristic:** Before applying a pattern, name the problem it solves. If you can't name the problem, you don't need the pattern.
263
+
264
+ ---
265
+
266
+ ## Action-Based Architecture
267
+
268
+ For business logic: use single-purpose action classes.
269
+
270
+ - **One public method** (`execute` or `handle`).
271
+ - **One responsibility** — the class name describes exactly what it does.
272
+ - **Fully injectable** — all dependencies injected via constructor.
273
+ - **No side effects beyond the stated purpose.**
274
+
275
+ ```typescript
276
+ // GOOD: Action class
277
+ class CreateOrderAction {
278
+ constructor(
279
+ private readonly orderRepository: OrderRepository,
280
+ private readonly inventoryService: InventoryService,
281
+ private readonly eventBus: EventBus,
282
+ ) {}
283
+
284
+ async execute(input: CreateOrderInput): Promise<Order> {
285
+ await this.inventoryService.reserve(input.items);
286
+ const order = Order.create(input);
287
+ await this.orderRepository.save(order);
288
+ await this.eventBus.publish(new OrderCreatedEvent(order));
289
+ return order;
290
+ }
291
+ }
292
+ ```
293
+
294
+ Use action classes for:
295
+ - Every user-initiated state change (create, update, delete, transition)
296
+ - Complex business operations with multiple steps
297
+ - Operations that publish domain events
298
+
299
+ ---
300
+
301
+ ## Domain-Driven Design (DDD)
302
+
303
+ Apply DDD where domain complexity warrants it. For simple CRUD, DDD adds unnecessary ceremony.
304
+
305
+ | Concept | Rule |
306
+ |---------|------|
307
+ | **Aggregate** | Cluster of related objects with a single entry point (Aggregate Root). Only the root is referenced from outside. Enforce invariants at the aggregate root. |
308
+ | **Entity** | Has identity (`id`). Two entities are equal if their IDs match, regardless of other field values. |
309
+ | **Value Object** | No identity. Immutable. Two value objects are equal if all their fields match. |
310
+ | **Domain Service** | Stateless logic that doesn't naturally belong to any entity or value object. |
311
+ | **Application Service / Action** | Orchestrates use cases. Has no domain logic itself — calls domain objects and infrastructure. |
312
+ | **Repository** | Interface defined in the domain layer. Implementation in the infrastructure layer. |
313
+ | **Ubiquitous Language** | Use the business's language in code. Class names, method names, and variable names should match how domain experts talk about the problem. |
314
+
315
+ ---
316
+
317
+ ## Layered Architecture
318
+
319
+ **Layer order (no skipping):**
320
+
321
+ ```
322
+ Controller (HTTP/GraphQL/CLI)
323
+ └── Application Service / Action
324
+ └── Domain (Entities, Aggregates, Domain Services)
325
+ └── Repository Interface
326
+ └── Repository Implementation (Infrastructure)
327
+ └── Database / External Services
328
+ ```
329
+
330
+ - A controller must not contain business logic — it delegates to an application service or action.
331
+ - An application service must not contain SQL or ORM calls — it uses repository interfaces.
332
+ - Domain objects must not depend on infrastructure (no `import prisma from '...'` in domain code).
333
+ - Violation of layering is a CRITICAL finding in code review.
334
+
335
+ ---
336
+
337
+ ## Modular Structure
338
+
339
+ - **Feature-based modules.** Group by business capability, not technical layer.
340
+ - **Co-located tests.** Test files live next to the code they test (`foo.service.ts` → `foo.service.test.ts`).
341
+ - **Barrel exports.** Each module exposes a deliberate public API via `index.ts`. Internal implementation details are not exported.
342
+ - **Shared kernel.** Cross-cutting concerns (errors, logging, HTTP utilities, config) live in `shared/` or `lib/`. This directory must NOT contain domain logic.
343
+ - **No circular dependencies.** Module A may not import from Module B if Module B imports from Module A.
344
+
345
+ ---
346
+
347
+ ## Testing Standards
348
+
349
+ - **Tests document behaviour, not implementation.** Test descriptions use the form: "should {do something} when {condition}".
350
+ - **Arrange-Act-Assert.** Structure every test with a clear setup, a single action, and explicit assertions.
351
+ - **One assertion concept per test.** Multiple `expect` calls are fine if they all verify the same behaviour.
352
+ - **No magic numbers in assertions.** Use named constants or setup variables.
353
+ - **Test the contract, not the internals.** Do not test private methods directly.
354
+ - **Red first.** In TDD, the test MUST fail before implementation. A test that passes without implementation is a broken test.
355
+
356
+ ---
357
+
358
+ ## Security Standards
359
+
360
+ Any violation of these rules is a **CRITICAL** finding in code review. No exceptions.
361
+
362
+ ### Injection Prevention
363
+
364
+ - **No raw SQL string concatenation.** Always use parameterised queries or the ORM's query builder. Never interpolate user input into SQL strings.
365
+ - **No raw HTML rendering of user input.** All user-controlled values rendered in HTML must be sanitised or escaped. Use the framework's built-in escaping (e.g., React's JSX auto-escaping, Django's template auto-escaping).
366
+ - **No `eval()`, `Function()`, or equivalent dynamic code execution** with user-controlled input.
367
+
368
+ ```typescript
369
+ // BAD: SQL injection via string interpolation
370
+ const users = await db.query(`SELECT * FROM users WHERE name = '${name}'`);
371
+
372
+ // GOOD: Parameterised query
373
+ const users = await db.query('SELECT * FROM users WHERE name = $1', [name]);
374
+ ```
375
+
376
+ ### Secrets and Credentials
377
+
378
+ - **No hardcoded secrets.** API keys, passwords, tokens, and connection strings must come from environment variables or a secrets manager. Never commit them to source code.
379
+ - **No secrets in URL query parameters.** Tokens and keys go in headers (`Authorization`, `X-API-Key`), never in URLs (they appear in logs, browser history, and referrer headers).
380
+ - **No secrets in client-side code.** Frontend bundles are public. Server-side secrets must stay server-side.
381
+
382
+ ### Authentication and Authorisation
383
+
384
+ - **Auth middleware on every route handling user data.** No route that reads or writes user-specific data should be accessible without authentication.
385
+ - **Authorisation checks at the resource level.** Verifying that a user is logged in is not enough — verify they have access to the specific resource they're requesting (prevents IDOR vulnerabilities).
386
+ - **Session tokens must be httpOnly, secure, sameSite.** Never store session tokens in localStorage (XSS-accessible). Use httpOnly cookies.
387
+
388
+ ### Input Validation
389
+
390
+ - **Validate all external input at system boundaries.** Every API endpoint that accepts POST/PUT/PATCH must have an input validation schema (zod, joi, yup, pydantic, or equivalent).
391
+ - **Fail closed.** If validation fails, reject the request. Never proceed with partially-valid data.
392
+ - **Validate types, ranges, and formats.** Not just presence — check that email fields contain emails, IDs are valid formats, numbers are within expected ranges.
393
+
394
+ ```typescript
395
+ // GOOD: Schema validation at the boundary
396
+ const CreateUserSchema = z.object({
397
+ email: z.string().email(),
398
+ name: z.string().min(1).max(200),
399
+ role: z.enum(['user', 'admin']),
400
+ });
401
+
402
+ app.post('/users', async (req, res) => {
403
+ const input = CreateUserSchema.parse(req.body); // Throws on invalid input
404
+ const user = await createUserAction.execute(input);
405
+ res.json(user);
406
+ });
407
+ ```
408
+
409
+ ### Data Protection
410
+
411
+ - **Never log sensitive data.** Passwords, tokens, credit card numbers, and PII must be redacted from log output.
412
+ - **Encrypt sensitive data at rest** when regulatory requirements demand it (GDPR, HIPAA, PCI-DSS).
413
+ - **Use constant-time comparison for secrets.** When comparing tokens, hashes, or API keys, use `crypto.timingSafeEqual` or equivalent to prevent timing attacks.
@@ -0,0 +1,125 @@
1
+ # Engineering Standards — Quick-Reference Checklist
2
+
3
+ Use this checklist during Phase 6 spec-compliance review. One rule per line. Every item is checkable.
4
+
5
+ ---
6
+
7
+ ## SOLID
8
+
9
+ ### Single Responsibility Principle
10
+ - [ ] No function exceeds 30 lines
11
+ - [ ] No class exceeds 200 lines
12
+ - [ ] Every file has exactly one primary export
13
+ - [ ] No function name contains "and" or "or" indicating dual responsibility
14
+
15
+ ### Open/Closed Principle
16
+ - [ ] No `switch` or long `if/else if` chains on type — use Strategy/polymorphism
17
+ - [ ] Adding new behaviour does not require modifying existing classes
18
+ - [ ] Extension points use interfaces, not concrete base classes
19
+
20
+ ### Liskov Substitution Principle
21
+ - [ ] Subclasses do not strengthen preconditions
22
+ - [ ] Subclasses do not weaken postconditions
23
+ - [ ] No subclass method throws `UnsupportedOperationException` / equivalent
24
+
25
+ ### Interface Segregation Principle
26
+ - [ ] No interface has methods that implementors must stub or no-op
27
+ - [ ] Interfaces are small and focused on a single concern
28
+ - [ ] Multiple specific interfaces preferred over one fat interface
29
+
30
+ ### Dependency Inversion Principle
31
+ - [ ] No `new ConcreteClass()` instantiation inside business logic
32
+ - [ ] All external dependencies injected via constructor
33
+ - [ ] Business logic depends on interfaces, not concrete implementations
34
+
35
+ ---
36
+
37
+ ## Clean Code
38
+
39
+ ### Naming
40
+ - [ ] All function names are verb phrases
41
+ - [ ] All boolean variables/props use question form (`is`, `has`, `can`, `should`)
42
+ - [ ] No single-letter variable names outside trivial loops
43
+ - [ ] No unexplained abbreviations
44
+
45
+ ### Functions
46
+ - [ ] Each function operates at a single level of abstraction
47
+ - [ ] No function has more than 3 parameters (or uses a parameter object)
48
+ - [ ] No boolean flag parameters
49
+ - [ ] Functions either do something OR return something (command-query separation)
50
+
51
+ ### Error Handling
52
+ - [ ] No empty `catch` blocks
53
+ - [ ] All errors are typed (domain-specific error classes)
54
+ - [ ] Correlation IDs propagated in all log entries
55
+ - [ ] Input validated at system boundaries (HTTP handlers, CLI args, webhook payloads)
56
+
57
+ ---
58
+
59
+ ## DRY / KISS / YAGNI
60
+ - [ ] No logic duplicated in 2+ locations
61
+ - [ ] No speculative features or extension points not required by current scope
62
+ - [ ] No abstractions with fewer than 3 concrete uses
63
+ - [ ] No "Manager", "Helper", or "Util" classes without a clear bounded purpose
64
+
65
+ ---
66
+
67
+ ## Design Patterns
68
+ - [ ] Patterns applied only where the problem they solve exists
69
+ - [ ] No strategy pattern applied speculatively
70
+ - [ ] Factory/Builder used where construction complexity warrants it
71
+ - [ ] Adapter used when integrating third-party interfaces with mismatched contracts
72
+
73
+ ---
74
+
75
+ ## Action-Based Architecture
76
+ - [ ] Every user-initiated state change is an Action class
77
+ - [ ] Action classes have exactly one public method
78
+ - [ ] Action classes are fully injectable (no `new` inside)
79
+ - [ ] Actions do not contain repository SQL — they call repository interfaces
80
+
81
+ ---
82
+
83
+ ## Layered Architecture
84
+ - [ ] Controllers contain no business logic
85
+ - [ ] Application services / actions contain no SQL or ORM calls
86
+ - [ ] Domain objects do not import from infrastructure layer
87
+ - [ ] No layer is skipped (controller → service → domain → repository)
88
+ - [ ] No circular imports between layers
89
+
90
+ ---
91
+
92
+ ## Modular Structure
93
+ - [ ] Code is organised by feature/domain, not technical layer
94
+ - [ ] Each module has a barrel `index.ts` exporting its public API only
95
+ - [ ] Test files co-located with source files
96
+ - [ ] `shared/` contains only cross-cutting utilities, no domain logic
97
+ - [ ] No circular imports between modules
98
+
99
+ ---
100
+
101
+ ## Testing
102
+ - [ ] All test descriptions use "should {behaviour} when {condition}" form
103
+ - [ ] Every test follows Arrange-Act-Assert structure
104
+ - [ ] No tests pass before the implementation is written (TDD RED phase confirmed)
105
+ - [ ] No test uses `toBeDefined()` or `toBeTruthy()` as the only assertion
106
+ - [ ] All mocked dependencies are verified with `.toHaveBeenCalledWith(...)`
107
+ - [ ] No `it.skip` or `describe.skip` on critical paths
108
+
109
+ ---
110
+
111
+ ## Security (Critical — any violation is CRITICAL severity)
112
+ - [ ] No raw SQL string concatenation
113
+ - [ ] No hardcoded secrets (API keys, passwords, tokens)
114
+ - [ ] All API POST/PUT/PATCH handlers have input validation schemas (zod/joi/yup)
115
+ - [ ] Auth middleware applied to all routes handling user data
116
+ - [ ] No user-controlled values rendered in HTML without sanitisation
117
+ - [ ] No sensitive data in URL query parameters
118
+
119
+ ---
120
+
121
+ ## Performance
122
+ - [ ] No database calls inside loops (N+1 pattern)
123
+ - [ ] No `findMany()` / `SELECT *` without `limit`/`take`
124
+ - [ ] All list endpoints have pagination
125
+ - [ ] No synchronous file I/O in request handlers