Skip to main content

code-standards

Consult shared code standards for a relevant design decision or an explicit standards reference request, not for every code change.

Source facts

Repository
davesnx/setup
Last source activity
September 24, 2026 at 10:29
Detected SKILL.md language
English
Stars
11
Forks
1

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
code-standards
description
Consult shared code standards for a relevant design decision or an explicit standards reference request, not for every code change.
# Code standards Consult the sections relevant to the design decision or reference request. Apply them within the task's scope. Keep unrelated old code unchanged. ## Decision order 1. Preserve correctness, safety, and the ability to diagnose failures. 2. Meet the requested behavior and public contract. 3. Follow compatible repository architecture and conventions. 4. Contain incompatible old patterns at the nearest boundary. 5. Prefer the solution with less owned complexity. ## Complexity - Keep architecture proportional to the real problem. Start with the smallest honest implementation of the use case, often a direct script or one vertical slice. - Judge an abstraction by total system cost: lines, interfaces, files, call hops, configuration, tests, and the concepts a reader must learn. Ten obvious lines spread over five files is negative value. - Make code usable before reusable. Extract a helper, port, service, or module only after real examples expose the shared shape, or when it owns a real invariant, hides real complexity, or has several real implementations. - Duplication is cheaper than the wrong abstraction (Sandi Metz). Constrain first, generalize later. - After correctness, intention, and duplication, prefer the fewest classes, functions, and names. - A pattern name is vocabulary for a design that emerged, not a requirement to manufacture that design. - Keep behavior local. A reader learns what a unit does by reading it, not by searching distant files. - Prefer one obvious path and one source of truth. - Justify guards, fallbacks, retries, and race handling with documented contracts, reachable failure paths, or observed failures. An incident is not required to protect a known boundary or invariant. Use the smallest safeguard at its owner. - Weigh the failure's likelihood and impact against the safeguard's cost. Speculation alone does not justify a general defense system. - Change internal call sites rather than preserve a bad interface. - Prefer less code, fewer names, fewer branches, and net-negative diffs when behavior permits. Remove a branch, helper, mode, or layer rather than rearrange it. ## Cyclomatic complexity - Use the project's configured limit. Without one: 1-5 low, 6-10 moderate, 11-15 high, 16+ very high. Compare scores only under the same counting convention. - These are review prompts, not quality ratings. Judge branch meaning, interactions, state, and failure behavior alongside the count. ## Boundaries and safety - Don't lie to the type system. When the compiler can't prove a fact, prove it: validate, narrow, or refine the model. A cast that remains needs a `SAFETY` comment that states what was checked and who guarantees it. - Turn unknown or weakly structured input into trusted application values at the earliest useful boundary. Keep what parsing learned instead of validating and discarding it. - Keep framework, protocol, database, runtime, and vendor values inside the boundary that owns them. Pass application or domain values inward. - Inbound boundaries verify credentials and produce a parsed identity. Pure permission decisions live with the domain values. Application code enforces them while it runs the operation. Boundaries project denials into protocol outcomes and never define permission policy. - Catch and classify unknown dependency failures at the owning boundary. Map internal outcomes to valid responses, exit codes, retry decisions, or startup errors at the outer boundary. - Preserve existing logs, traces, metrics, and error reporting. Record safe structured context such as operation names, identifiers, dependency names, state, retries, and error categories. - Keep secrets and raw credentials out of errors, logs, traces, and snapshots. Expose a sensitive raw value only where the external call needs it. - Treat invalid configuration as a clear startup failure. - Read configuration once at startup and pass typed values inward. ## Functions - Show the happy path first. Guards leave early, the valid path stays flat and linear, and the common case gets most of the code a reader sees. - A function should tell one story at one level of abstraction - `let` bindings are sentences. Order them like you'd narrate them. - The caller reads the headline; the callee owns the paragraph. - Comments explain why; names explain what; the body should rarely need to explain how. - Good code is boring to read — surprise is a code smell. - Push side effects to the edges; keep the core pure - Composition beats inheritance; functions compose better than objects. - What you can't express as a value, you can't test. - Make failure outcomes explicit using the repository's error model (see Failures). ## Modules and dependencies - Things that change together, should stay together. - Things that change at different rates should be separated. - Classify code by what would make it change: a business rule, an application policy or effect order, a technology translation, or wiring. Split a unit when it owns more than one reason, never to satisfy a taxonomy. - A good interface makes the wrong call look wrong. - Modules exist to hide decisions, not code. - Use composition over inheritance. - Build cohesive modules that hide meaningful behavior, policy, sequencing, or translation behind a small caller burden. - Apply the deletion test. If deleting a module makes complexity disappear, it was pass-through waste. If deleting it spreads complexity across callers, it earned its keep. - Keep interfaces narrow and expressed in the caller's terms. - Reuse an existing integration first. Extend it when the new work belongs to the same capability. Create a new one only when reuse would mix ownership. - Remove modules that only forward calls, rename another API, or mirror storage without hiding useful complexity. - Reuse the codebase's canonical helper instead of writing a near-duplicate. - Parallelize independent work only when it also makes the orchestration clearer, not by default. - Keep deterministic rules independent of I/O, frameworks, mutable global state, ambient time, and randomness. Pass required capabilities explicitly. - Export the supported public surface and keep implementation details private. ## State and data - Make illegal states unrepresentable - Use dedicated domain values when raw identifiers, units, or parsed strings can be confused. - Model meaningful lifecycle states explicitly instead of combining flags and optional fields that permit impossible states. - Prefer named options or domain values over boolean arguments that change behavior. - Use explicit operation inputs instead of generic partial records unless partiality is the domain concept. - Resolve absence before calling code that requires a value. Keep mutable state local, intentional, and hidden behind a precise interface. Avoid mutable global state. - Question unnecessary `any`, `unknown`, casts, and optional fields that hide the real invariant. - Make related state updates atomic when a partial update would leave an unsafe or confusing state. ## Failures - Match the repository's established error model. Do not introduce a result framework into an exception-based codebase only to satisfy this skill. - Make expected failures clear in the public contract through return values, declared errors, documented outcomes, or the repository's equivalent. - Keep failure categories precise at module boundaries. Include useful context and an underlying cause without leaking sensitive data. - Reserve panic-style failures for broken internal invariants and impossible states when that distinction matches the language and repository. - Do not silence failures with casts, ignored errors, broad catches, or fallback values that change meaning. ## Domain modeling with types - The type signature is the domain document. If the domain expert can't read it, the model is wrong. - Use the ubiquitous language in code — OrderId, not int; ValidatedOrder, not Order with a flag. - Use domain wrappers when they prevent a concrete mix-up or enforce an invariant; keep ordinary primitives when a wrapper adds no safety or clarity. - Model choices as sum types, not as booleans or nullable fields. - States that differ in shape deserve different types, not one type with optional fields. - Constraints are types: EmailAddress, NonEmptyString, Quantity between 1 and 1000 — enforced at construction, trusted after. - Constructors enforce constraints and report invalid input through the repository's error model. A refined type records that the check happened. - Name construction by what it does: `parse` turns untrusted input into a result, `make` builds from already-typed pieces, `is` is a plain predicate. A function that returns a refined value parsed something, so do not call it `validate`. - Design the types with the domain expert first, then write functions. Code that compiles against wrong types is still wrong. ## Tests - Prefer confidence in this order when practical: tests through real public entrypoints, integration tests through real seams, property tests for pure rules, then focused unit tests. - Do not add logic in tests. - Test observable behavior such as returned outcomes, stored state, emitted messages, rendered responses, or recorded external actions. - Prefer real seams, local substitutes, or explicit fake integrations over module mocks and tests driven mainly by spies. - Use a real local database when schema, query, or transaction behavior matters. - Construct test data through the same valid paths used by production code. - Follow the repository's test tools and conventions. Add the smallest test set that proves the changed behavior and important edge cases. ## Operations - Retry a technical failure only when the operation is safely repeatable and the retry preserves its meaning. - The boundary that owns the external call retries short technical failures. Application code decides whether to attempt the operation again. Durable workflows own retries that must survive a crash, a delay, or redelivery. - Give retryable external mutations an explicit idempotency method, such as a unique key, deduplication record, guarded state transition, or transactional message pattern. - Do not keep a database transaction open across network calls or long-running work. - Use durable workflow machinery only when progress must survive process loss, redelivery, long delays, compensation, human approval, or several transaction boundaries. - Avoid load-time I/O outside true bootstrap code. Make resource creation and cleanup explicit.
View on GitHub