Build the smallest correct version first. Name every case, implement only what has a real consumer, return typed errors for the rest. Use when designing new systems, extracting shared packages, or deciding how much to build before shipping.
Build the smallest thing that is correct, tested, and fail-closed. Do not build the smallest thing that compiles.
The decision logic should be exhaustive from day one. If there are three resize strategies, define all three variants now. The decision tree should be complete even when execution is partial.
This is not speculative design. It is documenting the problem space so the code tells the truth about what it handles and what it does not.
A named variant with no execution path returns a typed error:
match action {
ResizeAction::Hotplug => hotplug(spec),
ResizeAction::LiveMigration => Err(ResizeError::NotImplemented),
ResizeAction::ColdMigration => Err(ResizeError::NotImplemented),
}That is not incomplete. That is the correct first version. The variant exists so the compiler and tests can prove the decision logic is exhaustive. The execution exists only when someone needs it.
Never return Ok(()) for a path you have not built. Never log a warning and continue. Return a typed error that the caller can match on. This is the intersection with fail-closed case matching: if a resize request routes to LiveMigration and that path is not wired, the user gets a clear rejection, not a silent no-op.
Do not add:
until there is a real second consumer that would benefit. The first consumer should use concrete types, free functions, and direct calls. If a pattern emerges after the second consumer, extract it then.
A shared package (packages/go/...) is justified only when:
If only one app uses it, keep it local. Extract when the boundary proves itself, not when you hope it will.
Even when execution is partial, the decision logic should be fully tested. Table-driven tests with one row per named case prove that:
This is how you ship a partial implementation without shipping partial correctness.
The alternative is building the full system up front, which means:
Minimal-first avoids all of that by making the first version honest about what it does and what it does not do. The decision tree is complete. The execution is partial. The errors are explicit. The tests are real.
resize_strategy.go: three named strategies (hotplug, live migration, cold migration), exhaustive resolver, tested with table-driven cases.workspace-schema/resize.rs: three named ResizeAction variants with serde round-trip tests. No execution logic in the schema crate.packages/go/capacity: started as a pure planning kernel. Only extracted to a shared package after the API stabilized and compaction became a second consumer.packages/go/compaction: started as a feasibility kernel. Kept the packing heuristic simple (scalar best-fit-decreasing) because vector demand is not a real need yet.packages/go/resize module before the controlplane resize path has a real second consumerColdMigration execution before any primary path has failed in productionAssignedHost on sleep convergenceThese former standalone skills are bundled here as references to keep the runtime list compact. Load only the reference that matches the user's exact product, framework, or failure mode.
| Former skill | Reference | Description |
|---|---|---|
dedalus-minimal-first-implementation | references/skills/dedalus-minimal-first-implementation/SKILL.md | Build the smallest correct version first. Name every case, implement only what has a real consumer, return typed errors for the rest. Use when designing new systems, extracting shared packages, or deciding how much to build before shipping. |