
Refactoring Review Router
- 1 installs
- 1 repo stars
- Updated June 15, 2026
- tome-kota/agent-skill-catalog
Routes a refactoring request to one primary diagnostic lens and produces a single staged, safe refactoring plan.
About
Selects the smallest useful refactoring lens for state-space complexity, responsibility boundaries, or dependency risk, loading only that reference. A developer uses it to make a structural refactoring decision or a staged safety plan before moving code.
- Picks one primary lens plus at most one secondary
- Returns one integrated plan, not separate mini-reviews
Refactoring Review Router by the numbers
- 1 all-time installs (skills.sh)
- Ranked #982 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Jul 8, 2026 (Skillselion catalog sync)
npx skills add https://github.com/tome-kota/agent-skill-catalog --skill refactoring-review-routerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 1 |
| Last updated | June 15, 2026 |
| Repository | tome-kota/agent-skill-catalog ↗ |
What it does
Routes a refactoring request to one primary diagnostic lens and produces a single staged, safe refactoring plan.
Files
Refactoring Review Router
Route a refactoring request to the smallest useful diagnostic lens, then synthesize one practical refactoring plan.
This is the single entry skill for practical refactoring review. The detailed methods live in references/ and should be loaded only after selecting the relevant lens.
Default behavior:
1. Pick exactly one primary lens. 2. Add at most one secondary lens when it materially changes the plan. 3. Read only the selected reference files. 4. Return one integrated refactoring plan, not separate mini-reviews.
When To Use
Use this skill when the user wants to:
- make a structural refactoring decision before moving code
- produce a safe staged refactoring plan for a risky code area
- make code safer to change before adding a feature that would otherwise force structural movement
- understand why a code area is hard to modify when the answer affects how refactoring should proceed
- untangle modes, flags, transitions, or derived state
- separate mixed responsibilities or clarify where logic belongs
- reduce blast radius, dependency coupling, or migration risk
- review an AI-generated refactoring plan or code change from a refactoring-design perspective
When Not To Use
Do not use this skill when the task is primarily:
- formatting, linting, mechanical rename, or style-only cleanup
- implementing a clearly scoped feature with no refactoring decision
- fixing a syntax or type error
- answering a framework or library how-to question
- debugging one isolated defect with no structural concern
- broad architecture critique that is not about a refactoring move
If the task is small enough that ordinary implementation is clearly safe, do not make it heavy.
If the user is only asking for routine implementation help and no structural refactoring judgment is needed, do not trigger this skill just because the code is imperfect.
Lens Selection
Choose one dominant concern.
State-Space Complexity
Read references/state-space-refactoring.md when the hard part is:
- modes, flags, statuses, transitions, selected entities, permissions, or feature flags
- async loading/error/success/retry/optimistic state
- validation, dirty state, submit state, or operation-specific validity
- duplicated or derived state
- invalid, impossible, or ambiguous combinations
- screens/forms/workflows where visibility, editability, action availability, and validation drift apart
Short version:
state, modes, transitions, invalid combinations, derived stateResponsibility-Boundary Confusion
Read references/responsibility-boundary-refactoring.md when the hard part is:
- code changes for too many unrelated reasons
- logic has no obvious home
- rendering, validation, authorization, policy, orchestration, formatting, persistence, mapping, or integrations are mixed together
- helpers, hooks, controllers, services, managers, composables, or shared modules became dumping grounds
- visual similarity or framework placement is hiding the real reason for change
- decision logic, operation validation, action availability, workflow orchestration, or display concerns need clearer ownership
Short version:
change reasons, semantic ownership, responsibility placementDependency-Impact Risk
Read references/dependency-impact-refactoring.md when the hard part is:
- changing one shared type, schema, API, DTO, module, event, helper, or contract may break many consumers
- hidden consumers or indirect dependencies are unclear
- migration must be staged
- old and new behavior must coexist
- domain logic depends directly on transport, persistence, framework, vendor APIs, or shared implementation details
- compile success is not enough to prove safety
Short version:
dependency direction, consumers, blast radius, staged migrationSecondary Lens Rules
Add a secondary lens only when it changes the sequencing or risk controls.
- State-space primary + responsibility secondary: use when modes and transitions are clear enough, but rule ownership or display/workflow boundaries decide the safe extraction order.
- Responsibility primary + state-space secondary: use when mixed responsibilities are driven by tangled mode, permission, or validation combinations.
- Dependency primary + responsibility secondary: use when reducing blast radius requires moving logic to a clearer owner.
- Responsibility primary + dependency secondary: use when moving a responsibility would affect many consumers or shared contracts.
- State-space primary + dependency secondary: use rarely, when the state model is serialized, shared, persisted, or consumed externally.
Do not include all three lenses by default. If all three seem relevant, choose the one that makes the first safe step possible and mention the others as follow-up checks.
When the primary lens is not obvious, break ties with these questions:
1. Which lens most changes the first safe move? 2. If we guess wrong, which axis creates the largest damage: behavioral confusion, ownership drift, or migration blast radius? 3. Is the user mainly asking how to model behavior or state transitions, how to place logic, or how to change shared contracts safely?
Use those answers to pick the primary lens. Keep the others as supporting notes unless they materially change sequence or verification.
Workflow
1. Frame the refactoring problem. Identify the code area, intended change, pain symptoms, observable behavior, and current risk. If the target is unclear, inspect enough code to name the likely target.
2. Select the primary lens. Use the lens selection rules above. State the dominant concern in one sentence.
3. Load the selected reference. Read only the primary reference first. Read one secondary reference only if it materially changes the plan.
4. Inspect before proposing movement. When code is available, search and read the implementation, nearby tests, callers, related helpers, routes, schemas, and contracts as required by the selected reference. If code is unavailable or partial, do not invent evidence; produce assumptions, missing evidence, and a provisional plan instead.
5. Produce one integrated plan. Use the output contract from the primary reference. Add only the secondary concerns that affect sequence, safety checks, or risks.
6. Keep implementation incremental. Prefer behavior-preserving slices, characterization checks, and narrow first moves. Do not turn a refactoring diagnosis into a big rewrite.
7. Respect user intent about planning versus implementation. If the user asked for a review, diagnosis, or plan, stop at the plan. If the user asked for implementation, use the selected lens to shape the first safe move, then implement in small behavior-preserving steps.
If implementation also includes a requested behavior change, first isolate behavior-preserving refactoring from the requested behavior change, and do not expand refactoring beyond what that change needs.
Output Contract
Use the output contract from the primary reference.
Also include, near the top:
Selected Lens
Why This Lens
Secondary Lens, if anyScale the output to the request size:
- small request or partial context: use at most
Selected Lens,Why This Lens,Key Risk, andNext Safe Steps - medium request: use a shortened form of the primary reference with only the sections that drive the first safe move
- high-risk or high-blast-radius request: use the full output contract from the primary reference
If evidence is partial, explicitly label the output as provisional and include Assumptions or Needed Evidence.
If the request is not a good fit, return:
Not a Fit
Suggested FallbackSafety Checks
- Do not start by splitting files, extracting layers, or changing shared contracts.
- Preserve current behavior unless the user explicitly asks to change it.
- Prefer characterization tests or manual matrices before invasive movement.
- Keep public APIs, persisted data, events, routes, and external contracts stable unless compatibility is explicitly addressed.
- Treat missing information as an assumption, not as proof.
- After each planned step, name the smallest meaningful verification.
Common Traps
- Applying all three lenses and producing a generic architecture essay.
- Choosing by file type instead of by dominant risk.
- Triggering on vague words like "cleanup", "messy", or "hard to change" when no structural refactoring decision is actually needed.
- Treating UI refactoring as automatically state-space work; many UI problems are responsibility-boundary problems.
- Treating service refactoring as automatically responsibility work; shared service changes may be dependency-impact problems.
- Moving code before identifying the behavior or contract being preserved.
- Creating abstractions that hide the same complexity under more impressive names.
Example Routing
- "This form has edit/view/history modes, permissions, async save, and weird disabled buttons." Use state-space primary; maybe responsibility secondary if ownership of action rules matters.
- "This service validates, authorizes, maps DTOs, calls a vendor, writes persistence, and decides policy." Use responsibility-boundary primary.
- "Changing this shared DTO breaks admin, billing, API clients, and vendor sync." Use dependency-impact primary.
Self-Check
Before responding, verify:
- one primary lens is explicit
- no more than one secondary lens was used
- selected reference files were actually needed
- the plan preserves behavior before restructuring
- the output is a practical refactoring plan, not a broad design review
interface:
display_name: "Refactoring Review Router"
short_description: "Route refactoring work to the right diagnostic lens"
default_prompt: "Use $refactoring-review-router to pick the right lens for this structural refactoring decision and return a safe plan or first implementation steps."
refactoring-review-router
このスキルは何か
リファクタリングの悩みを、状態の複雑さ、責務の混線、依存影響の広がりといった主要な論点に振り分け、最初の安全な進め方を決めるためのスキルです。ここでいう診断レンズは、「どの見方で問題を切り分けるか」という意味です。
作った意図
「このコードはつらいから整理したい」という相談は多い一方で、難しさの原因が何なのかが曖昧なまま動くと、ただコードを動かしただけで終わりがちです。このスキルは、リファクタリングを一般論ではなく、どの種類の難しさを扱っているのかに分けて考えられるようにするために作っています。
また、大きく作り直す前に、最初にどこまで安全に触れるかを決めるための入口としても意図しています。
どういう人・場面に向いているか
- 状態管理、責務分離、依存整理のどれが本丸か見極めたい人
- 実装前に、壊しにくいリファクタリングの進め方を考えたい人
- AI が出したリファクタリング案が大きすぎて、そのまま進めるのが不安な人
使いどころの例
- フラグやモードが増えて画面やフォームの振る舞いが追いにくい
- service や hook が何でも屋になっていて、どこに何を置くべきか悩む
- 共通 DTO や shared module を触る変更で、影響範囲が広そうに見える
依頼イメージ
入力例: 「このリファクタリング相談は、状態整理と責務分離のどちらを主軸に考えるべきか見て。そのうえで最初の安全な一歩もほしい」
返ってくるもの: 主にどの観点で切り分けるべきか、なぜその見方が効くか、どこから触ると壊しにくいかをまとめた実行前の診断
関連するスキル
- software-design-review-router: リファクタリングではなく、設計判断全体を評価したいときに向いています
- delivery-slice-planner: 進め方を delivery slice(作業単位)や PR 順に落としたいときに向いています
Dependency-Impact Refactoring
Use this lens when a change is dangerous because dependency direction, consumers, contracts, and blast radius are unclear. The goal is to reduce change propagation with a staged strategy, not merely draw a dependency graph.
This lens is technology-independent. It applies to frontend shared modules, backend services, schemas, DTOs, APIs, persistence models, jobs, libraries, framework integrations, vendor clients, and tests.
Use When
Use this lens when:
- changing one type, schema, API, shared module, DTO, event, or helper affects many consumers
- shared code has hidden or poorly understood consumers
- upper layers depend on lower-level implementation details
- domain logic depends directly on transport, persistence, framework, or vendor APIs
- old and new behavior must coexist temporarily
- migration must be staged safely
- tests are tightly coupled to implementation details
- a team wants to reduce blast radius before adding a feature
- compile success is not enough to prove behavioral safety
The signal is change propagation risk: a local edit may break unrelated areas or external consumers.
Do Not Use When
Do not use this as the primary lens when:
- the change is local and all consumers are obvious
- the main issue is complex states, modes, or transitions
- the main issue is mixed responsibilities or unclear ownership
- the task is purely formatting, renaming, or deleting unused code with no consumers
- the user wants only a conceptual explanation, not a migration or refactoring strategy
Core Principle
Ask:
Who depends on this?
Why do they depend on it?
Which dependencies are semantic, and which are accidental?
Where can an adapter, compatibility layer, or boundary reduce blast radius?A safe refactor changes dependency pressure before changing the risky shared thing.
Workflow
If code is unavailable or partial, treat this lens as a provisional diagnostic checklist; ask for or name the evidence needed instead of filling the sections as facts.
1. Identify the change target. Name the type, module, schema, endpoint, DTO, event, helper, service, table, job, or behavior being changed. Clarify whether the change is behavioral, structural, naming, data-shape, contract, or dependency-direction related.
2. Trace direct consumers. Use search, static references, tests, route declarations, schema references, import graphs, API clients, job configuration, generated code, documentation, and known runtime entry points. Include non-code consumers when visible.
3. Trace indirect consumers. Follow wrappers, re-exports, mappers, inheritance, callbacks, events, serialized data, persisted records, queues, caches, feature flags, and test fixtures. Record uncertainty instead of pretending the graph is complete.
4. Classify dependency types. For each consumer, classify the dependency:
- semantic dependency: relies on business meaning or behavior
- data shape dependency: relies on fields, schema, payload, or serialization
- control-flow dependency: relies on call timing, ordering, callbacks, retries, or side effects
- framework dependency: relies on framework lifecycle, annotations, hooks, middleware, or configuration
- persistence dependency: relies on tables, queries, migrations, indexes, storage format, or transactions
- API/transport dependency: relies on endpoint shape, HTTP behavior, events, queues, messages, or vendor protocol
- test dependency: relies on fixtures, mocks, snapshots, factories, or implementation details
5. Assess blast radius. Identify which consumers are internal, external, high-value, hard to test, operationally sensitive, versioned, generated, or owned elsewhere. Separate compile-time breakage from behavioral breakage.
6. Identify semantic versus accidental dependencies. Preserve semantic dependencies that express real domain needs. Reduce accidental dependencies on field names, transport details, persistence structures, vendor payloads, framework lifecycle, or incidental helper behavior.
7. Find safe boundary points. Look for places where an adapter, facade, mapper, compatibility layer, feature flag, versioned endpoint, anti-corruption boundary, wrapper, or temporary bridge can isolate consumers. Add such boundaries only when they support a concrete migration.
8. Design a staged plan. Prefer this sequence: characterize current behavior, add compatibility boundary, migrate one consumer group, verify, repeat, then remove obsolete paths after confidence and ownership are clear.
9. Preserve compatibility where needed. Keep old and new behavior coexisting when external consumers, persisted data, async jobs, rolling deploys, or cross-service calls require it. State when compatibility can be dropped.
10. Define rollback and verification. Include contract tests, characterization tests, migration checks, telemetry, feature flags, canary paths, or manual verification appropriate to the change. Identify the rollback point before the risky edit.
Output Contract
Change Target
Dependency Map
Consumer Classification
Blast Radius Assessment
Semantic vs Accidental Dependencies
Safe Boundaries / Adapters / Compatibility Points
Staged Refactoring Plan
Rollback and Verification StrategyMark unknown consumers and assumptions explicitly.
Safety Checks
- Do not change shared contracts before mapping consumers.
- Preserve compatibility for external callers, persisted data, queued messages, generated clients, and rolling deployments unless explicitly allowed to break them.
- Add contract or characterization checks before risky shared changes.
- Verify both compile-time and runtime behavior where dependency type demands it.
- Confirm that adapters have a migration purpose and an intended removal or stabilization path.
- Keep useful characterization tests until the migration risk has passed.
- Review test fixture changes carefully; they can hide consumer assumptions.
Common Traps
- Changing shared types before mapping consumers.
- Assuming compile success means behavioral safety.
- Introducing adapters everywhere without a migration purpose.
- Flattening all dependencies into generic interfaces.
- Breaking compatibility before identifying external consumers.
- Refactoring tests in a way that removes useful characterization coverage.
- Treating all dependencies as bad instead of distinguishing semantic from accidental dependencies.
- Migrating every consumer at once when staged coexistence would be safer.
Example
A shared CustomerDto is used by an API response, an admin screen, a billing job, and a vendor sync. A requested change renames status and changes how suspended customers are represented.
Map consumers: API clients depend on data shape and compatibility, admin screen depends on display meaning, billing job depends on semantic eligibility, vendor sync depends on transport mapping, and tests depend on fixtures and snapshots. A safe plan might introduce a new internal customer status model, keep the public DTO stable, update the billing job against the semantic model, adapt the vendor payload through a mapper, add contract tests for the public API, then version or migrate the DTO only after external consumers are accounted for.
Responsibility-Boundary Refactoring
Use this lens when complexity comes from unclear ownership of logic. The goal is not to make layers look tidy. The goal is to identify change reasons and move logic so each unit has a coherent reason to change.
This lens is technology-independent. It applies to frontend components, backend services, controllers, API layers, jobs, validators, helpers, domain logic, and integration code.
Use When
Use this lens when code shows symptoms such as:
- a UI unit contains rendering, validation, authorization, formatting, API calls, and business decisions
- a service contains persistence details, external API concerns, policy decisions, DTO mapping, and orchestration
- utility, common, shared, helper, hook, composable, or manager modules become context-dependent dumping grounds
- one file or function changes for many unrelated feature requests
- new logic has no obvious home
- policy rules are mixed with transport, persistence, framework, or formatting concerns
- orchestration code makes domain decisions inline
- generic abstractions contain domain-specific exceptions
- screens, forms, controllers, or jobs mix authorization, validation, action availability, workflow transitions, display formatting, and side effects
- future variants such as history, audit, comparison, snapshot, privileged view, embedded mode, or alternate read model would amplify existing boundary confusion
The signal is mixed reasons to change, not just size, duplication, or naming.
Do Not Use When
Do not use this as the primary lens when:
- the main issue is complex modes, transitions, derived state, or invalid state combinations
- the main issue is hidden consumers, contract migration, or blast radius
- the task is a mechanical rename, formatting pass, or style-only extraction
- responsibilities are already clear and the user only needs a local implementation
- the code is duplicated but the duplication protects separate change reasons
Core Principle
Ask:
What kind of change should cause this code to change?
Are multiple change reasons mixed together?
Is the current boundary semantic, accidental, or framework-driven?Refactoring succeeds when future changes have a natural home and do not force unrelated concerns to move together.
Workflow
If code is unavailable or partial, treat this lens as a provisional diagnostic checklist; ask for or name the evidence needed instead of filling the sections as facts.
1. Identify current units. List the functions, classes, components, modules, jobs, handlers, validators, helpers, and shared abstractions involved. Include adjacent tests and callers when they reveal intended ownership.
2. Map current responsibilities. For each unit, list what it does in concrete terms: render, validate, authorize, format, decide policy, orchestrate workflow, map data, persist data, call external systems, handle retries, translate errors, emit events, or coordinate side effects.
For screen-like or workflow-like units, separate these responsibilities when present:
- screen or flow purpose
- data loading and saving
- workflow transitions
- authorization and privileged controls
- action availability
- operation-specific validation
- field or section visibility
- field editability
- display formatting
- layout, route, or application chrome
- navigation, notifications, telemetry, auditability, or explanation behavior
3. List change reasons by unit. Ask which future requests would require this unit to change. Separate product rule changes, policy changes, data-shape changes, framework changes, vendor changes, presentation changes, persistence changes, and operational changes.
4. Separate semantic responsibilities from technical mechanisms. A route, hook, controller, job, or service name may reflect framework placement rather than real ownership. Identify the business or operational concept that should own each decision.
5. Detect responsibility leaks. Look for domain policy in generic utilities, authorization in rendering, persistence details in domain logic, vendor payloads in core rules, formatting in services, validation duplicated across layers, and orchestration code making hidden policy decisions.
In UI or workflow code, also look for role/status/action checks embedded directly in rendering, validation tied only to a visual form, action buttons whose visibility and handler guards disagree, duplicated field visibility/editability conditions, and shared components that know too much about screen purpose, permissions, workflow, or layout.
6. Decide move, extract, inline, or leave. Move logic when ownership is clear. Extract only when the extracted unit has a coherent reason to change. Inline when an abstraction only hides mixed concerns. Leave duplication when separate change reasons are more important than reuse.
7. Propose target boundaries. Name the target owner for each important responsibility. Prefer local patterns already present in the codebase: policy objects, validators, presenters, selectors, use cases, services, mappers, repositories, adapters, modules, or plain functions.
Common target boundaries include:
- decision-logic boundary: inspectable authorization, visibility, editability, and action availability rules
- validation boundary: validation attached to operations and workflow transitions, not just forms
- workflow/action boundary: transition preconditions, execution, API calls, optimistic updates, navigation, and notifications
- display boundary: stable readonly display sections, labels, formatters, and simple field renderers
- layout/context boundary: normal app chrome, embedded, print, chrome-free, audit, snapshot, or alternate read-model contexts
Match the codebase. These boundaries can be implemented as selectors, policies, presenters, view models, configuration, validators, use cases, controllers, domain services, modules, or plain functions.
8. Plan incremental movement. Preserve behavior while moving one responsibility at a time. Start with pure or easily tested logic when possible, then adjust orchestration and callers. Prefer moving decision logic, validation profiles, or action availability before moving large rendering blocks.
9. Verify ownership and behavior. Add or preserve tests that prove the moved responsibility still behaves the same. Check that the new boundary reduces future change friction rather than just moving lines.
Output Contract
Current Responsibility Map
Change Reasons by Unit
Boundary Smells
Target Responsibility Boundaries
Move / Extract / Inline Decisions
Safe Refactoring Sequence
Risks and Verification PointsEach boundary recommendation should name the reason for change it protects.
Safety Checks
- Preserve behavior before and after each move with tests or characterization checks.
- Keep public API, route, schema, event, and persistence contracts stable unless explicitly changing them.
- Verify that extracted logic no longer depends on the old mixed context.
- Check that authorization, validation, and policy decisions remain enforceable outside presentation code.
- Avoid moving code across ownership or team boundaries without identifying the new owner.
- Verify that visible actions, disabled reasons, handler guards, and validation rules still agree after extraction.
- Prefer sharing low-level stable display primitives over sharing page-level abstractions when screen purpose differs.
Common Traps
- Creating layers only because architecture diagrams look cleaner.
- Extracting functions that preserve the same mixed responsibility.
- Moving logic based only on file size.
- Treating all duplication as bad.
- Putting domain-specific logic into generic utilities.
- Creating
manager,handler,helper, orserviceobjects without a clear responsibility boundary. - Mistaking framework boundaries for semantic boundaries.
- Centralizing unrelated rules into a single "rules" object that changes for every reason.
- Hiding business rules inside generic UI components.
- Moving all complexity into one huge hook, store, controller, presenter, use case, or service.
- Extracting components only because markup looks duplicated.
- Treating visual similarity as proof that two use cases share the same boundary.
Example
An API handler validates input, checks whether a user may approve an order, formats a vendor payload, calls the vendor, updates local persistence, and chooses the response DTO.
Map change reasons: approval policy changes with business rules, vendor payload changes with the provider, persistence changes with storage, response DTO changes with API consumers, and orchestration changes with workflow. A safe plan might extract approval policy into a focused rule owner, extract vendor payload mapping into an adapter, leave orchestration in the handler or use-case layer, and preserve the response contract.
State-Space Refactoring
Use this lens when behavior is hard to change because too many states, modes, flags, transitions, and derived values interact. The goal is to observe the state model before changing structure, reduce invalid or duplicated state, and plan safe behavior-preserving refactoring.
This lens is technology-independent. It applies to UI screens, backend workflows, API handlers, batch jobs, stateful services, and ordinary business code.
Use When
Use this lens when behavior depends on several of these:
- create, edit, view, detail, history, review, or workflow modes
- selected entities, active tabs, filters, route/query state, or persisted settings
- loading, error, success, retry, stale, or optimistic-update state
- validation state, dirty state, submit state, or operation-specific validity
- user role, permission, tenant, account status, or feature flags
- field visibility, field editability, action availability, layout variant, or data perspective
- derived values computed in multiple places
- event handlers that mutate several state values at once
- conditionals that imply unsupported, illegal, or impossible state combinations
- side effects triggered by state changes
The signal is not file size. The signal is that understanding "what can happen" requires reasoning across combinations of state.
Do Not Use When
Do not use this as the primary lens when:
- the change is a simple presentational extraction, rename, formatting change, or local bug fix
- the main issue is unclear semantic ownership or mixed responsibilities
- the main issue is consumer impact, shared contracts, or migration risk
- the state model is already explicit and the task is only implementation
- the user explicitly asks for a framework tutorial or library-specific state-machine implementation
Core Principle
Do not start by splitting files mechanically. First model the state space.
A smaller file with the same hidden state combinations is not simpler. Refactoring is useful only if it makes source state, derived state, valid modes, transitions, ownership, rendering, and side effects easier to inspect.
Workflow
If code is unavailable or partial, treat this lens as a provisional diagnostic checklist; ask for or name the evidence needed instead of filling the sections as facts.
1. Inspect the current behavior surface. Read the main implementation, nearby handlers, selectors/computed values, validators, tests, routes, persistence points, and side-effect code. Identify user-visible behavior or externally observable behavior before proposing changes.
2. Inventory observable source states. List the state values that are stored, received, persisted, read from the URL, loaded from the server, supplied by permissions, or controlled by the environment. Include implicit states such as "no selection", "stale data", "validation not yet run", or "operation in progress".
For screens, forms, and workflow UIs, commonly inspect:
- screen purpose: create, edit, detail, review, alternate read model, snapshot, comparison
- entity status: draft, submitted, approved, rejected, archived, locked
- user role or permission: owner, reviewer, admin, privileged viewer
- operation or action: save draft, submit, approve, reject, cancel, reopen
- validation profile: draft save, submit, approve, reject, import, publish
- field or section visibility, field editability, layout variant, and data perspective
Express the state space compactly when useful:
screen purpose x entity status x user role x action x validation profile x visibility x editability x layout variant3. Separate source state from derived state. Mark values that can be computed from other values. Look for duplicated booleans, cached derivations, and fields synchronized by handlers or effects. Do not delete duplicated state until you understand why it exists.
4. Identify modes and mutually exclusive states. Find states that represent modes: create/edit/view, draft/submitted/approved, loading/error/ready, manual/automatic, or similar. Check whether multiple booleans are really one exclusive mode.
5. Map transitions and triggers. For each state change, identify the trigger: user action, route change, server response, timer, job step, permission update, validation result, retry, or side effect. Note handlers that change multiple state values together.
6. Identify invalid or impossible combinations. Record combinations that should never happen, are ambiguous, are unsupported, or currently rely on scattered guards. Distinguish true illegal states from rare but valid states.
7. Map state to behavior. Connect state combinations to rendering branches, enabled actions, validation rules, API calls, persistence writes, emitted events, retries, notifications, navigation, and cleanup behavior. For UI-heavy cases, compare visibility, disabled state, handler guards, validation profile, and post-action effects.
8. Propose a smaller state model. Suggest removing duplicated derived state, replacing related booleans with an explicit mode where justified, tightening ownership, making transition functions explicit, or isolating side effects. Use a state machine only when the transition model is central and the added machinery pays for itself.
9. Refactor incrementally. Start with characterization tests, a state matrix, or focused assertions for important combinations. Then make one behavior-preserving change at a time.
10. Preserve semantics. Do not change UX, API behavior, retry behavior, validation timing, or persistence semantics unless the user explicitly requested it.
Output Contract
State Inventory
Derived State / Duplicated State
Mode and Transition Map
Invalid or Impossible States
Refactoring Strategy
Safe Step-by-Step Plan
Risks and Characterization ChecksKeep each section grounded in evidence from the code. If evidence is incomplete, state the assumption and confidence level.
Safety Checks
- Verify current behavior before refactoring with tests, snapshots, logs, a manual matrix, or existing fixtures.
- Preserve externally visible behavior unless explicitly changing it.
- Check whether duplicated state exists for latency, optimistic updates, undo/history, persistence, or compatibility reasons.
- Confirm transition ordering when async responses, retries, or cancellation can race.
- Check that invalid states are prevented at the source, not merely hidden at rendering time.
- For workflow screens, verify important role/status/action combinations with a small matrix before moving UI code.
- Treat future variants such as history, audit, comparison, snapshot, embedded, or print views as design pressure, not automatic scope for new mode flags.
Common Traps
- Replacing state complexity with premature abstraction.
- Hiding transitions inside generic helpers that make behavior harder to inspect.
- Introducing a state machine without proving the state model needs one.
- Splitting components, services, or handlers before understanding state ownership.
- Assuming all boolean flags are bad.
- Deleting duplicated state without checking synchronization semantics.
- Treating derived display convenience as source state.
- Collapsing rare but valid states into "impossible" states.
- Adding another
mode,variant, or equivalent flag to an already complex flow without proving it is the right model. - Treating history, audit, snapshot, comparison, or alternate read models as merely readonly versions of edit/detail mode.
Example
A workflow has isEditing, isReadonly, isSubmitting, hasError, selectedId, draftValue, and serverValue. Several handlers set three or four values together.
First inventory source state: selected record, server value, local draft, submit request status, and permission. Then mark derived state, such as readonly from permission, submit status, and selected record status. A safe plan might characterize edit, cancel, submit success, submit failure, and selection change while dirty before extracting derived readonly logic or replacing related booleans with an explicit mode.