Review code for quality, simplicity, and common mistakes before declaring work complete.
日本語の概要は準備中です。原文の説明を表示しています。
Evaluate architecture and module boundaries for volatility-based decomposition using Juval Lowy's framework (from "Righting Software", building on Parnas 1972). Use when reviewing module splits, service boundaries, new abstractions, or any decomposition decision. Trigger on phrases like "where should this boundary be", "how to split this", "module boundaries", "encapsulate change", "volatility", or references to Lowy, Parnas, or "Righting Software". Complements /hickey (interleaved concerns) with a different lens (change encapsulation).
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Evaluate module boundaries and decomposition decisions using Juval Lowy's volatility-based decomposition framework. The core question: do your boundaries encapsulate axes of change, or do they just group related functionality?
Source: Juval Lowy, Righting Software (2019), building on David Parnas, "On the Criteria to Be Used in Decomposing Systems into Modules" (1972). See also: Volatility-Based Decomposition (book excerpt).
Functional decomposition groups code by what it does (UserService, PaymentController, AuthModule). Volatility-based decomposition groups code by what is likely to change — and encapsulates each axis of change behind a stable interface.
"This principle governs the design of all practical systems, from houses, to laptops, to jumbo planes, to your own body. To survive and thrive they all encapsulate the volatility of their constituent components." — Lowy
Lowy's electricity analogy: a house's power supply has enormous volatility (AC/DC, 110v/220v, 50/60Hz, solar/grid/generator, wire gauges). All of it is encapsulated behind a receptacle. Without that encapsulation, you'd need an oscilloscope every time you plugged something in. The receptacle is the stable interface; the volatility behind it can change without affecting consumers.
Functional decomposition maximizes the blast radius of change. When boundaries track functionality rather than volatility, a single change cuts across multiple modules. "Functional decomposition is as diverse as the required functionality across all customers and points in time. The resulting huge diversity in the architecture leads directly to out-of-control complexity." Volatility-based decomposition contains the grenade in the vault.
Lowy identifies two independent axes within any workflow:
Sequence volatility — the order of steps in a workflow can change independently of what those steps do. Different customers or use cases may require different orchestrations of the same activities. This volatility belongs in orchestrators (Lowy's "Managers").
Activity volatility — how a specific activity is performed can change independently of the sequence it appears in. There may be an unknown number of ways to do the same activity (different algorithms, providers, strategies). This volatility belongs in strategy components (Lowy's "Engines").
Conflating these two — putting orchestration logic and activity logic in the same module — means a change to either axis ripples into the other.
Not everything that varies is volatile. Lowy makes a critical distinction: adding an attribute to a data model is variable but not volatile — the architecture won't suffer. "If you cannot clearly state what the volatility is, why it is volatile, and what risk the volatility poses in terms of likelihood and effect, then you need to look further." Decomposing around things that merely vary (rather than things that are genuinely volatile) produces over-engineered boundaries that add cost without containing real change.
The trigger — "review this boundary", "should we split X", "look at module Y", a /do diff inside one component — is a starting point, not a frame. Volatility-based decomposition is most legible at module boundaries; reviewing only the lines the user (or upstream issue) pointed at is how a missing volatility seam in the surrounding module gets missed.
Default to whole-module scope. When the trigger lives inside a single file or component, read the whole file — not just the cited region. When invoked on a multi-file diff, each touched file is in scope, and cross-file boundary questions (does this volatility actually live in one place, or is it sprayed across modules?) are in scope too. Sibling modules are fair game when the same boundary question recurs there.
Don't let the user's framing define the scope. A trigger that says "extract this into a new component" implies the boundary is the right shape and only the placement is wrong; if the surrounding module shows the volatility axis is actually elsewhere — the data model, the consumer pattern, a sequence/activity split — name that, even when the implied fix lands at a different layer than the trigger suggests. The reviewer's job is to surface what the evidence says about volatility, not to confirm the trigger's framing.
Push back when the evidence contradicts the trigger. If the prompt narrows the question to one boundary but the surrounding code shows the volatility doesn't track that boundary at all, the redirected finding is the headline, not a footnote. "Issue #N described a UI extraction; the volatility actually splits the data model into two kinds" is a valid first finding, not an out-of-scope tangent.
For every module boundary, service split, or new abstraction in the code under review:
What is likely to change behind this boundary? Be specific — not "requirements might change" but "the payment provider, the auth protocol, the notification channel." If you can't name concrete axes of change, the boundary may be arbitrary.
Consider project-declared areas of volatility. If the project has enumerated its own areas of volatility — the term of art Lowy uses throughout Righting Software — read .agency/lowy.md if it exists. Its content is project-specific (inline rows or a pointer to another file). The schema, loosely modeled on Lowy's TradeMe enumeration (Righting Software, Ch. 5), is:
| Area of volatility | What changes | Why volatile (likelihood × effect) | Expected encapsulation |
|---|
Rows in that table are surviving candidates after the project's own variable-vs-volatile screen (see §"Variable vs. Volatile" above). They are not findings, and they are not above review. Do two things with each row: (a) re-apply Lowy's bar — "state what the volatility is, why it is volatile, and what risk the volatility poses in terms of likelihood and effect" — and challenge any row that fails it (Lowy: "It is important to discuss the volatility candidates this way and even challenge them"); (b) audit whether the boundaries under review actually encapsulate the surviving volatilities in a single component, rather than spraying or leaking them across modules.
Speculative volatility is not volatility. A change scenario counts only if it has happened before, is on a roadmap, or is a near-certain consequence of the domain (e.g. "payment providers change" in e-commerce). "What if we swap color spaces" in an app that has never swapped color spaces is speculation, not an axis of change. Lowy's framework is about observed or plausible volatility — designing for hypothetical change is over-engineering, not encapsulation.
Weak volatility may not deserve its own boundary. Some volatilities are real but too minor to justify a separate component. Lowy's example: notification delivery might be volatile, but if the system already has a message bus utility, a dedicated NotificationManager adds complexity without containing meaningful additional change. Ask: does this volatility justify the cost of an additional boundary, or can it be folded into an existing one?
Is the volatility about sequence (the order/orchestration of a workflow) or activity (how a specific step is performed)? These are independent axes and should be encapsulated separately. A module that mixes both will be modified for two unrelated reasons.
Also check for domain decomposition — boundaries drawn around domain entities (ProjectService, TradesmanModule, AccountsManager) rather than around axes of change. Domain decomposition is functional decomposition wearing a domain hat. Lowy warns: it creates ambiguity about who does what and when, duplicates functionality across domain lines, and is nearly impossible to validate against use cases.
Does this boundary exist because the code does something different (functional), or because what's behind it changes independently (volatility)? Functional boundaries look clean on day one but fracture under change. A UserService that groups all user operations is functional decomposition — the volatility of auth, profile data, and notification preferences are unrelated axes of change jammed behind one boundary.
The naming test. Lowy uses naming conventions as a diagnostic. Orchestrator names should be nouns associated with the encapsulated volatility (AccountManager, MarketManager — good; BillingManager — bad, the gerund "billing" signals functional grouping around an activity). Strategy/engine names should indicate the volatile activity (SearchEngine, TransformationEngine — good; AccountEngine — bad, no indication of what activity varies). If you struggle to name the component after a volatility axis, it may not encapsulate one.
For a plausible change scenario (new provider, new format, new rule), trace how many modules would need to be modified. If the change leaks across boundaries, the decomposition is functional, not volatility-based.
Volatility should decrease downward. In a layered system, higher layers (clients, UI) should be the most volatile, and lower layers (data access, infrastructure) should be the least volatile. "The components in the lower layers have more items that depend on them. If the components you depend upon the most are also the most volatile, your system will implode." If high volatility lives deep in the stack, the blast radius of change is maximized.
Check symmetry. All good architectures are symmetric — you should see the same calling patterns across similar modules. If three of four workflows publish events but the fourth doesn't, or only one module has a particular coupling pattern, that asymmetry is a red flag for functional decomposition or a missed volatility axis. Symmetry can also be broken by the presence of something, not just its absence.
Is the interface between modules stable under the changes the module encapsulates? The receptacle doesn't change when you switch from grid to solar. If the interface must change when the encapsulated volatility changes, the abstraction is leaking.
Expose atomic business verbs, not implementation operations. Lowy's key interface design principle: interfaces should expose indivisible business-level operations (credit, debit, transfer) rather than CRUD or implementation details. "Atomic business verbs are practically immutable because they relate strongly to the nature of the business which hardly ever changes." An interface that exposes OpenPort(), ClosePort(), AdjustBeam() alongside ReadCode() is mixing communication volatility with reading volatility — two axes jammed behind one interface.
Good interfaces are reusable; implementations never are. Lowy's "tool-hand" analogy: a stone axe and a computer mouse have nothing in common internally, but both reuse the same hand interface. If an interface can only be used by one consumer, it may be shaped around the implementation (functional) rather than around a stable contract (volatility-based). Well-designed contracts are logically consistent (operations form a coherent unit), cohesive (all aspects required, no more, no less), and independent (each stands alone).
Volatility-based building blocks are reusable because they encapsulate one axis of change. If a module can only be used in one context, it may be encapsulating functionality rather than volatility.
Lowy observes that reuse increases downward through layers: infrastructure and data-access components should be highly reusable across contexts, business-logic orchestrators are reusable across multiple clients, and clients/UI are rarely reusable. If a lower-layer component is locked to a single consumer, the boundary likely tracks functionality rather than a genuine axis of change.
Lowy's litmus test for correct decomposition: when a change request arrives, the response should be contemplative — you think through how to adapt. If a module is expensive to change, it's too big (functional decomposition has coupled unrelated concerns). If a module is expendable (trivially thrown away), it's an unnecessary boundary. If a module is almost expendable — it encapsulates just enough to contain one axis of change, and replacing it is straightforward but not trivial — the decomposition is correct.
After completing all steps, invoke /fact-check on your own output. The fact-check catches:
Flag these phrase shapes — they mean you stopped one step early:
If fact-check finds issues, revise before presenting to the user.
Boundaries examined — List each module boundary or decomposition decision reviewed.
Volatility map — For each boundary: what volatility it encapsulates (or fails to), classified as sequence or activity volatility where applicable.
Findings — Boundaries that track functionality rather than volatility, with blast-radius analysis. Include symmetry violations and layering inversions.
Simplifications — Concrete restructuring to align boundaries with axes of change.
Fact-check result — Output of /fact-check on this evaluation, including the phrase-shape check.
Actions — One entry per finding, formatted so a downstream step (e.g. /do's PR comment composer) can lift each entry into a table row. Each entry starts with a short bolded finding label (≤8 words) naming what is wrong, then dispositions it as exactly one of:
There is no Defer disposition. "Out of scope", "pre-existing", "follow-up refactor", "should be its own PR" are not dispositions — they are process judgments dressed up as volatility analysis. Every finding must appear here — including those labeled "pre-existing" or "orthogonal" — and every finding either gets fixed in this PR or is a No-op. A finding that never reaches this section has been dismissed.
Example: **useViewport encapsulates ghost concern** — Fix in this PR: delete the hook, let FitAddon measure per-tile.
No findings → "No actions." Findings without actions = incomplete review.
This skill and /hickey are complementary lenses. Hickey asks "are independent concerns interleaved?" Lowy asks "do boundaries encapsulate axes of change?" Run both on architectural decisions for full coverage.
The two lenses can produce conflicting recommendations. Lowy may say "merge these — shared volatility is duplicated across both" while Hickey says "keep them separate — a mode flag would complect configuration with implementation." Neither lens is wrong; they're optimizing for different things.
The resolution pattern: unify the volatile axis without complecting the strategies. Typically this means a wrapper or shared module that encapsulates the volatile part (satisfying Lowy) while the distinct strategies remain private and uncomplected (satisfying Hickey). If merging for blast-radius reduction requires a mode flag, conditional branching, or type-switching — that's complecting. Find the layer where unification is mechanical (a shared function, a common interface, a single config source) rather than conditional.
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Review code for quality, simplicity, and common mistakes before declaring work complete.
日本語の概要は準備中です。原文の説明を表示しています。
Do a task end-to-end — implement, PR, CI loop, ship. ONLY invoke when the user explicitly types `/do` or `$do`; never auto-select from a natural-language request, even one that sounds like an end-to-end task.
日本語の概要は準備中です。原文の説明を表示しています。
Iteratively study and apply elegant coding patterns. Each iteration - understand the code, research what simple and elegant code looks like, apply learnings, verify with CI. Use as a standalone refactoring pass or when the user asks to make code more elegant, simple, or idiomatic.
日本語の概要は準備中です。原文の説明を表示しています。
Audit code for correctness and rigor — logic errors, silent error swallowing, wishful thinking, and unjustified fallbacks. This is not a style review; it's a logic review. Use when you want a focused correctness audit separate from the full code-police pass.
日本語の概要は準備中です。原文の説明を表示しています。
Write engaging PR titles and descriptions for any forge (GitHub today; Bitbucket planned). Use when creating or updating PRs. Leads with narrative paragraphs and reaches for lists, tables, and diagrams when content is genuinely structured.
日本語の概要は準備中です。原文の説明を表示しています。
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
日本語の概要は準備中です。原文の説明を表示しています。