git:20260801.8234b5f to git:20261029.276ae81

76 added, 78 removed. Audit A to A.

---
name: codebase-design
- description: "Design or improve a known module boundary, interface, seam, dependency, or test surface. Use for a selected structural change or new module. Not for broad architecture discovery, formatting, or speculative abstraction."
+ description: Design or improve a module interface, dependency seam, or test boundary for the requested change without speculative abstraction.
---
- # Codebase Design
+ Read [local host integration](../.shared/host-integration.md) before applying this imported workflow.
- Concentrate related complexity behind the smallest stable interface that fully serves real callers. Optimize for correctness, locality, leverage, testability, and consistency with the existing repository.
+ # Codebase Design
- Read `references/evidence.md` when a boundary or abstraction decision is consequential. If delegation is explicitly authorized, use `delegate-work` for non-overlapping read-only traces or an independent review, not for competing writers on the same interface.
+ Design **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. Use this language and these principles wherever code is being designed or restructured. The aim is leverage for callers, locality for maintainers, and testability for everyone.
- ## Use Repository Evidence First
+ ## Glossary
- - Read applicable instructions, architecture records, nearby code, tests, callers, and supported versions.
- - Preserve established domain language and architecture unless evidence justifies a change.
- - Identify the concrete behavior, callers, variation, failure modes, and change pressure before proposing a boundary.
- - Treat current pain and expected work as evidence. Do not design for hypothetical reuse.
+ Use this vocabulary to reason consistently, while preserving the repository's established domain language. The terms below are design concepts rather than mandatory renaming rules.
- ## Use a Precise Design Vocabulary
+ **Module**: anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. _Avoid_: unit, component, service.
- - **Module:** a cohesive unit with an interface and hidden implementation, at any scale.
- - **Interface:** everything a caller must know, including inputs, outputs, invariants, errors, ordering, configuration, and relevant cost.
- - **Seam:** a location where behavior can vary without changing its callers.
- - **Adapter:** an implementation that satisfies an interface at a seam.
- - **Depth:** the useful behavior and complexity hidden behind a small interface.
- - **Leverage:** the value many callers and tests gain from one implementation.
- - **Locality:** the degree to which related knowledge, changes, defects, and verification remain together.
+ **Interface**: everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. _Avoid_: API, signature (too narrow, they refer only to the type-level surface).
- Use repository terminology in user-facing work. Use this vocabulary internally when it makes a design decision more exact.
+ **Implementation**: what's inside a module, its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.
- ## Find the Natural Module
+ **Depth**: leverage at the interface. The amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface, **shallow** when the interface is nearly as complex as the implementation.
- Group behavior that shares:
+ **Seam** _(Michael Feathers)_: a place where you can alter behaviour without editing in that place; the *location* at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. _Avoid_: boundary (overloaded with DDD's bounded context).
- - the same domain responsibility;
- - the same invariants and failure policy;
- - the same data ownership or lifecycle;
- - the same reason to change;
- - the same verification surface.
+ **Adapter**: a concrete thing that satisfies an interface at a seam. Describes *role* (what slot it fills), not substance (what's inside).
- Do not group code merely because it uses the same technology or sits in the same layer. Do not split cohesive behavior to satisfy arbitrary line or file limits.
+ **Leverage**: what callers get from depth. More capability per unit of interface they learn. One implementation pays back across N call sites and M tests.
- Apply the deletion test: imagine removing the proposed module. If its complexity disappears, it may be a pass-through. If the complexity spreads across callers, the module is concentrating real knowledge.
+ **Locality**: what maintainers get from depth. Change, bugs, knowledge, and verification concentrate in one place rather than spreading across callers. Fix once, fixed everywhere.
- ## Design the Interface
+ ## Deep vs shallow
- Make callers provide only information they naturally own and return results they can use directly.
+ **Deep module** = small interface + lots of implementation:
- - Minimize methods, parameters, states, configuration, and ordering requirements.
- - Hide policy, orchestration, persistence details, retries, caching, and provider quirks when callers do not need to control them.
- - Make invalid states difficult to represent when the repository's type system supports it.
- - Define failure behavior and ownership explicitly.
- - Preserve compatibility unless the task authorizes a deliberate break.
- - Prefer one coherent operation over a sequence that forces callers to reconstruct internal policy.
+ ```
+ ┌─────────────────────┐
+ │ Small Interface │ ← Few methods, simple params
+ ├─────────────────────┤
+ │ │
+ │ Deep Implementation│ ← Complex logic hidden
+ │ │
+ └─────────────────────┘
+ ```
- Do not expose implementation structure merely to make internal code reachable by tests.
+ **Shallow module** = large interface + little implementation (avoid):
- ## Place Seams Only Where Evidence Supports Them
+ ```
+ ┌─────────────────────────────────┐
+ │ Large Interface │ ← Many methods, complex params
+ ├─────────────────────────────────┤
+ │ Thin Implementation │ ← Just passes through
+ └─────────────────────────────────┘
+ ```
- Introduce a seam when at least one real need exists:
+ When designing an interface, ask:
- - multiple current adapters or algorithms;
- - an external, nondeterministic, or expensive boundary;
- - independent lifecycle or ownership;
- - a compatibility boundary;
- - a stable test surface around important behavior.
+ - Can I reduce the number of methods?
+ - Can I simplify the parameters?
+ - Can I hide more complexity inside?
- One implementation does not automatically require an interface. Avoid factories, registries, plugin systems, generic repositories, and dependency injection layers created only for hypothetical future variation.
+ ## Principles
- ## Design for Verification
+ - **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts; they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface.
+ - **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.
+ - **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.
+ - **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it.
- Treat the public interface as the primary test surface.
+ ## Designing for testability
- - Verify observable behavior, invariants, transitions, and failures through the same seam callers use.
- - Keep internal seams private unless real consumers require them.
- - Accept dependencies at the boundary when construction would otherwise hide nondeterminism or external effects.
- - Separate decision logic from irreversible effects when doing so produces a clearer real seam.
- - Avoid tests that mirror internal call graphs.
+ Good interfaces make testing natural:
- If no stable test surface exists, reconsider the boundary before adding test-only access.
+ 1. **Accept dependencies, don't create them.**
- ## Compare Alternatives When the Choice Is Material
+ ```typescript
+ // Testable
+ function processOrder(order, paymentGateway) {}
- Generate two or three genuinely different interface shapes when placement or ownership is uncertain. Compare them against:
+ // Hard to test
+ function processOrder(order) {
+ const gateway = new StripeGateway();
+ }
+ ```
- - caller simplicity;
- - hidden complexity;
- - locality of invariants and failure handling;
- - number and reality of seams;
- - compatibility and migration cost;
- - verification quality;
- - operational and performance consequences.
+ 2. **Return results, don't produce side effects.**
- Choose the smallest complete design supported by evidence. Record rejected alternatives only when the trade-off is consequential or hard to reverse.
+ ```typescript
+ // Testable
+ function calculateDiscount(cart): Discount {}
- ## Keep the Change Focused
+ // Hard to test
+ function applyDiscount(cart): void {
+ cart.total -= discount;
+ }
+ ```
- - Prefer deepening or replacing a weak boundary over layering a new abstraction on top of it.
- - Avoid parallel implementations, broad rewrites, unrelated cleanup, and premature generalization.
- - Stage risky migrations through compatible intermediate states when necessary.
- - Measure performance-sensitive decisions rather than assuming indirection or consolidation is faster.
+ 3. **Small surface area.** Fewer methods = fewer tests needed. Fewer params = simpler test setup.
- ## Present the Design
+ ## Relationships
- State:
+ - A **Module** has exactly one **Interface** (the surface it presents to callers and tests).
+ - **Depth** is a property of a **Module**, measured against its **Interface**.
+ - A **Seam** is where a **Module**'s **Interface** lives.
+ - An **Adapter** sits at a **Seam** and satisfies the **Interface**.
+ - **Depth** produces **Leverage** for callers and **Locality** for maintainers.
- - the responsibility and callers;
- - the proposed interface and seam;
- - what complexity remains hidden;
- - ownership, invariants, failures, and compatibility;
- - verification strategy;
- - material alternatives and migration implications.
+ ## Rejected framings
- Use diagrams only when relationships cannot be explained clearly with concise prose.
+ - **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.
+ - **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow: interface here includes every fact a caller must know.
+ - **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**.
- ## Completion Standard
+ ## Going deeper
- Finish only when the boundary is justified by real behavior, its interface is smaller than the complexity it hides, callers and tests can use the same stable seam, and no speculative abstraction is required.
+ - **Deepening a cluster given its dependencies**, see [DEEPENING.md](DEEPENING.md): dependency categories, seam discipline, and replace-don't-layer testing.
+ - **Exploring alternative interfaces**, see [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md): evaluate substantially different interfaces directly, then compare depth, locality, and seam placement. Use separate agents only when explicitly authorized.