Change Shape

Change boundaries: what belongs together, what should split, and how much work one review should carry.

68 items in this guidance cluster.

Tagged guidance

Guide items

Agent Workflow rules

Change Shape rules

Avoid Speculative Public APICHANGE-AVOID-SPECULATIVE-PUBLIC-APIAdd public surfaces only when current or accepted callers need them. Waiting for concrete pressure keeps compatibility commitments smaller and easier to validate.Avoid Unnecessary Dependency ChurnCHANGE-AVOID-UNNECESSARY-DEPENDENCY-CHURNKeep package, manifest, and lockfile movement out of unrelated work. Separate dependency changes make build, compatibility, and downstream risk reviewable on their own.Identify Owning Module Before EditingCHANGE-IDENTIFY-OWNING-MODULE-BEFORE-EDITINGFind the component that owns the concept before adding or moving logic. That keeps invariants, tests, and future maintenance close to the responsible code.Isolate Controversial ChangesCHANGE-ISOLATE-CONTROVERSIAL-CHANGESPut risky or contentious moves in their own review unit when they can stand alone. This lets reviewers approve, reject, or revise the decision without incidental cleanup attached.Minimal but CompleteCHANGE-MINIMAL-BUT-COMPLETEKeep the diff as small as the purpose allows while including the evidence that purpose needs. Reviewers should see one coherent unit they can understand, validate, and revert.Pin Behavior With Early TestsCHANGE-PIN-BEHAVIOR-WITH-EARLY-TESTSAdd characterization tests before changing messy behavior when the existing contract is unclear. The baseline separates intentional behavior changes from accidental drift.Prefer Small Follow-UpsCHANGE-PREFER-SMALL-FOLLOW-UPSMove adjacent cleanup or broader improvements into focused follow-up changes when the current diff can stand alone. This preserves review focus while still capturing useful work.Preserve Unowned WorkCHANGE-PRESERVE-UNOWNED-WORKTreat nearby edits from users, agents, generators, or earlier changes as outside your ownership unless the task says otherwise. Adapting around them protects parallel work and context.Respect Generated Artifact OwnershipCHANGE-RESPECT-GENERATED-ARTIFACT-OWNERSHIPFix generated outputs through their source inputs, templates, metadata, or generator configuration whenever those own the result. Hand edits are durable only when the tool workflow explicitly supports curation.Separate Structure From BehaviorCHANGE-SEPARATE-STRUCTURE-FROM-BEHAVIORSplit refactoring or layout changes from behavior changes when the combined diff obscures intent. Separate review units make meaning preservation and new behavior easier to check.Sync Generated ArtifactsCHANGE-SYNC-GENERATED-ARTIFACTSUpdate checked-in generated outputs when their source inputs change and they are part of review. Keeping them aligned prevents consumers from seeing stale artifacts.Treat And as Scope WarningCHANGE-TREAT-AND-AS-SCOPE-WARNINGUse compound change descriptions as a prompt to inspect whether the work has more than one purpose. The word is not a rule, but it catches scope creep while splitting is still cheap.Use One Purpose per ChangeCHANGE-USE-ONE-PURPOSE-PER-CHANGEShape each change around one review question and one reason for existing. Related tests, docs, and generated files can travel with it when they support that same purpose.

Performance rules

Refactoring rules

Align Seams with Real VariationREFACTORING-ALIGN-SEAMS-WITH-REAL-VARIATIONPut abstraction seams where code already varies across backends, policies, protocols, tests, or ownership boundaries. Avoid adding names and jumps for hypothetical futures unless the next change or risk clearly justifies them.Do Not Over-apply DRYREFACTORING-DO-NOT-OVER-APPLY-DRYKeep similar-looking code separate until it has the same meaning and changes together. Premature sharing can couple unrelated policies and make later edits harder.Extract Concept HelpersREFACTORING-EXTRACT-CONCEPT-HELPERSExtract helpers when the new function names a real concept boundary with a stable purpose. Hiding a few lines behind a weak name adds a jump without reducing the readers burden.Keep Linear Story VisibleREFACTORING-KEEP-LINEAR-STORY-VISIBLEKeep simple ordered workflows inline when the sequence is the clearest explanation. Extract only the substeps that carry their own concept, policy, reuse, or test surface.Keep Weak Abstractions CloseREFACTORING-KEEP-WEAK-ABSTRACTIONS-CLOSE-TO-THEIR-USEKeep tentative helpers, types, or traits near their first use until the boundary proves itself. Local placement makes weak abstractions easier to revise, inline, or delete before other modules depend on them.Prefer Local ReasoningREFACTORING-PREFER-LOCAL-REASONINGShape code so relevant state, invariants, and effects are visible near the change. Centralize only when it reduces total reasoning, because distant reconstruction raises cognitive load and error risk.Prefer Loops for Side EffectsREFACTORING-PREFER-LOOPS-FOR-SIDE-EFFECTSUse ordinary loops when the main purpose is mutation, I/O, logging, or other side effects. Iterator chains are better for value transformation; using them for effects can hide order, early exits, and error handling.Use Whitespace as Function ParagraphsREFACTORING-USE-WHITESPACE-AS-FUNCTION-PARAGRAPHSUse blank lines to group related statements inside a function before extracting more names. Paragraph-like spacing can reveal the local story while avoiding unnecessary helper jumps.

Review rules

Rust rules

Avoid Empty Wrapper TypesRUST-AVOID-EMPTY-WRAPPER-TYPESAdd a wrapper type only when it carries an invariant, behavior, or ownership boundary. Otherwise it adds conversions and concepts without improving correctness.Consider Downstream API ImpactRUST-CONSIDER-DOWNSTREAM-API-IMPACTCheck public API changes against downstream imports, traits, inference, and examples before reshaping them. Additive paths and deprecations often avoid unnecessary breakage.Keep Crate Boundaries NarrowRUST-KEEP-CRATE-BOUNDARIES-NARROWPut behavior and tests in the crate or module that owns them before extracting shared helpers. Narrow boundaries reduce dependency fan-out, feature pressure, and hidden coupling.Keep Dependency Updates IntentionalRUST-KEEP-DEPENDENCY-UPDATES-INTENTIONALSeparate maintenance-only dependency refreshes from updates that change behavior, features, MSRV, or integration. Reviewable grouping lowers noise without hiding downstream risk.Keep Edits Scoped to Owning ConceptRUST-KEEP-EDITS-SCOPED-TO-OWNING-CONCEPTChange the module, crate, feature, or facade that owns the behavior being fixed. Scoped edits keep reviews atomic and prevent nearby files from pulling in unrelated concepts.Keep Pre-Release Compatibility IntentionalRUST-KEEP-PRE-RELEASE-COMPATIBILITY-INTENTIONALPreserve pre-release compatibility only when it reflects a chosen contract. Early cleanup is often cheaper than freezing accidental names, re-exports, features, or variants.Keep Public API Shape IntentionalRUST-KEEP-PUBLIC-API-SHAPE-INTENTIONALMake public visibility, aliases, features, re-exports, bounds, and variants reflect intended commitments. Published surface area becomes something downstream users can depend on.Use Functions For Incidental TypesRUST-USE-FUNCTIONS-FOR-INCIDENTAL-TYPESPrefer free or module functions when a type does not own the operation or invariant. Move behavior onto a type when the method relationship clarifies state, policy, or trait design.

Testing rules

VCS rules

Pattern items

Cap Change Radiuscap-change-radiusBroad diffs increase review cost and make unrelated regressions harder to isolate. Keep the change radius aligned with the requested behavior, using separate chunks for cleanup or adjacent improvements.Chunk Statementschunk-statementsDense prose asks readers to hold too many claims at once and hides which idea needs review. Split statements into coherent chunks so each paragraph, bullet, or sentence carries one inspectable purpose.Follow Local Conventionsfollow-local-conventionsInconsistent style and structure make each change feel like a new design decision. Start from nearby patterns and only diverge when the local convention cannot support the current need.Keep Public Dependencies Intentionalkeep-public-dependencies-intentionalPublic dependencies shape downstream compatibility, API expectations, and maintenance cost. Add or raise them only when the public behavior needs that requirement, using lockfile updates for ordinary compatible refreshes.Keep Structure Reversiblekeep-structure-reversibleEarly structure can harden into unnecessary abstraction before the design is proven. Prefer arrangements that are easy to inline, split, merge, or rename until the underlying concept earns permanence.Make The Change Easy Firstmake-the-change-easy-firstSome changes are risky because the path to make or verify them is unnecessarily hard. First add the smallest harness, boundary, helper, tool, or runbook that makes the real change cheaper to understand and review.Move Declaration And Initialization Togethermove-declaration-and-initialization-togetherA value declared before it is valid makes readers track an empty slot and its future assignment. Declare values where they become meaningful, using immutable locals and narrow scopes unless evaluation order requires more care.Name Couplingname-couplingRelationships between pieces are hard to judge when the reason they change together is unnamed. Describe the change pressure first, then decide whether the coupling belongs directly, behind a clearer owner, or across an explicit boundary.Optimize For Long Term Coherenceoptimize-for-long-term-coherenceAgent-produced work can satisfy a prompt while weakening the systems future concepts, names, boundaries, and tests. Choose the smallest change that preserves long-term direction without using coherence as an excuse for speculative architecture.Preserve Unowned Workpreserve-unowned-workShared working copies may contain edits from another person or an earlier task. Check state before editing, work around unrelated changes, and stop for direction when unowned work blocks the current change.Reader Localityreader-localityA change can reduce code size while increasing the number of jumps needed to understand one workflow. Keep related concepts near their meaning, extracting only when the new name and location reduce live context.Separate Discovery From Editingseparate-discovery-from-editingEditing while still discovering the system can bake early misunderstandings into the diff. Read enough to find the ownership, constraints, and likely change shape before making scoped edits.Separate Structure From Behaviorseparate-structure-from-behaviorDiffs that mix moves, renames, formatting, and behavior make review and rollback harder. Separate behavior-preserving structure from rule changes when each can be checked on its own.Small Reviewable Chunkssmall-reviewable-chunksLarge mixed changes blur structure, wording, behavior, and workflow decisions until review becomes slow or shallow. Choose one coherent purpose per chunk, validate it, and ask for direction before expanding into preference-sensitive follow-up work.Strengthen Cohesionstrengthen-cohesionA concept becomes harder to understand when its data, rules, and behavior are scattered or bundled with unrelated concerns. Move elements that change for the same reason toward one named owner, while separating nearby code that belongs to another concept.Untangle Before Changinguntangle-before-changingBehavior changes become risky when policy, formatting, validation, persistence, and side effects are braided together. Untangle only enough structure to give the new behavior a clear owner, then keep the behavior change reviewable.Use Explaining Variableuse-explaining-variableImportant decisions disappear when nested expressions or repeated conditions expose syntax before domain meaning. Introduce a local name when it makes the next branch, call, or return read in terms of the fact the reader needs.Use Guard Clauseuse-guard-clauseThe normal path is harder to see when the rest of a routine is indented under a precondition or failure case. Exit early for boring gates so the ordinary behavior stays flat, visible, and ordered by what readers must rule out.

Principle items