--- name: minimal-change description: "Chooses and implements the smallest correct change by checking YAGNI, existing code, the standard library, native platform features, and installed dependencies before adding abstractions or packages. Use when implementing features, fixes, or refactors, especially when a proposal adds wrappers, factories, configuration, dependencies, boilerplate, or speculative flexibility." license: MIT metadata: author: lammanhhoang version: "1.0.0" --- # Minimal Change ## Iron Law **UNDERSTAND THE REAL FLOW, THEN STOP AT THE EARLIEST SAFE SOLUTION.** Minimize the solution, never the understanding. Do not propose a one-liner before reading the code it changes, its callers, tests, constraints, and existing helpers. ## Workflow ### 1. Restate the required behavior - Separate the explicit requirement from imagined future requirements. - Name the observable behavior that must change and the behavior that must remain. - Ask only when an unresolved choice would materially change the result. ### 2. Trace the real path - Read the target code and its direct callers. - Search for existing helpers, components, conventions, and dependencies. - Read relevant tests and configuration. - Identify trust boundaries and failure paths before simplifying anything. Do not use this skill as permission to skip investigation. ### 3. Freeze the safety floor Write down the invariants the change MUST preserve: - authentication and authorization; - trust-boundary validation and sanitization; - data integrity, transactions, and data-loss protection; - accessibility and required compatibility; - required error handling, auditability, and observability; - acceptance criteria and tests explicitly required by the task. These are requirements, not optional complexity. ### 4. Walk the stop ladder in order Stop at the first rung that fully satisfies the requirement and safety floor: 1. **Does this need to exist?** If the requested artifact or flexibility has no current consumer, do not add it. 2. **Does the codebase already do it?** Reuse or extend the existing path. 3. **Does the standard library do it?** Prefer the maintained built-in. 4. **Does the platform do it natively?** Use browser, database, framework, or operating-system behavior already available. 5. **Does an installed dependency do it?** Reuse it only after confirming its contract and current project convention. 6. **Is the correct change local and direct?** Make the direct expression or small function change without a new layer. 7. **Only then add code.** Add the minimum new implementation that is complete, testable, and consistent with the surrounding design. Do not skip to a preferred abstraction. Each skipped rung needs concrete evidence. When the choice remains ambiguous or a proposal adds a dependency, wrapper, factory, adapter, configuration surface, compatibility layer, or extension point, read references/DECISION-LADDER.md before editing. ### 5. Keep the diff narrow - Change the owner of the behavior, not every caller, when one shared fix is correct. - Avoid parallel implementations of the same rule. - Add no option without a current caller and no interface with only one speculative implementation. - Follow existing conventions when their cost is small; do not redesign the repository to save a few local lines. - Prefer clarity over fewest characters. A named three-line function can be more minimal than a dense one-liner. ### 6. Verify the smallest correct result - Run the narrowest relevant test first, then the required broader suite. - Check the diff for new dependencies, files, flags, wrappers, and configuration. - For every added surface, identify its current consumer. Remove it if none exists. - Recheck every safety-floor invariant. - Report what was reused and what complexity was deliberately avoided. ## Scope boundaries - Use `prd-writing` first when the goal or acceptance criteria are unsettled. - Use `planning-before-code` first for work touching more than 2–3 files; apply this skill while choosing each planned implementation. - Use `systematic-debugging` first for an unexplained failure. Find the cause before attempting to shrink the fix. - Use `clean-code` for named code smells and behavior-preserving refactors. This skill decides how much solution to add, not how to rewrite an entire module. - Use `code-review` for severity-ranked findings on an existing diff. This skill may inform a fix after the review, but does not replace review protocol. ## Rationalization table | Rationalization | Response | |---|---| | "We may need another provider later." | Add the extension point when a second real provider establishes the variation. | | "A package is safer than a built-in." | Compare the actual requirement and support matrix; do not outsource a native feature by reflex. | | "The wrapper keeps things consistent." | Reuse an existing wrapper or keep the direct call; a new one-off wrapper adds another contract. | | "Config makes it flexible." | An unused option is an untested branch and a permanent support promise. | | "The architecture will be cleaner." | A diagram with more boxes is not cleaner when the runtime has one path. | | "Fewer lines means minimal." | Minimal means least total system complexity while remaining clear and correct. | | "Those guards look verbose." | Security, validation, accessibility, and data-loss protection are part of correctness. | ## Red flags — stop and walk the ladder again - Adding a dependency for one capability already available natively. - Creating an interface, factory, registry, adapter, or plugin point with one implementation and no explicit near-term consumer. - Adding configuration without a caller that needs to vary it. - Copying logic before searching the repository. - Changing unrelated files to make the local design feel more elegant. - Removing guards, error handling, tests, labels, logging, or rollback behavior solely to reduce line count. - Describing future scenarios without evidence in the approved requirement.