fragment = "cli"
[aliases]
lib = "uri ~ '**/dir:crates/dir:cli/dir:src/module:lib/**'"
[[rust.enum.where]]
id = "command-variants-have-command-modules"
severity = "error"
expr = """
uri ~ '**/dir:crates/dir:cli/dir:src/module:args/enum:Command' => all(enum_constant,
require("**/dir:crates/dir:cli/dir:src/module:{name.snake}")
)
"""
message = "CLI command variant `{name}` must have an owning module at `crates/cli/src/{name.snake}/mod.rs`."
rationale = """
`args::Command` is the command registry. Each variant declares a user-facing command and
must resolve to the command module that owns its runtime.
"""
[[rust.shape.type.where]]
id = "public-type-needs-external-consumer"
severity = "error"
expr = """
$crate_cli
AND NOT uri ~ '**/dir:crates/dir:cli/dir:src/module:lib/*'
AND visibility = 'public'
AND count(in_refs) > 0
=> require("**/dir:crates/dir:cli/dir:src/module:lib/path:{name}")
OR count(in_refs, NOT source ~ '**/dir:crates/dir:cli/dir:src/**') > 0
"""
message = "`{name}` is `pub` but it is neither exposed by the crate root nor consumed outside `crates/cli/src`; narrow it to `pub(crate)` (or `pub(in …)`)."
rationale = """
`cli` is a leaf binary crate: public types are legitimate when they are part of the crate root
boundary (`lib.rs` reexport) or when a consumer outside `cli/src` uses them. A `pub` type that has
only local incoming references and is not exposed at the crate root overstates the real boundary,
which makes the module graph read as fully connected when consumption is actually local. The
`require(...)` clause is intentional because check rules evaluate one extracted file graph at a
time; the crate-root reexport lives in `lib.rs`, not in the defining file.
"""
[[refs.where]]
id = "production-macros-must-not-hide-domain-calls"
severity = "error"
expr = """
$crate_cli
AND kind = 'calls'
AND source.kind != 'test'
=> NOT target ~ '**/external_pkg:std/path:macros/macro:/^(assert|assert_eq|assert_ne|debug_assert|debug_assert_eq|debug_assert_ne)$/'
"""
message = "Macro `{target}` outside tests can hide domain calls from the Rust extractor; bind the value first or use explicit control flow."
rationale = """
Architecture rules depend on a graph-readable production surface. Rust macros can hide calls
inside token arguments, so a rule based on references may under-count real dependencies. Tests
are excluded: test assertions are a normal testing idiom and should not drive production
modularization rules. In production code, bind the domain value before the macro or use explicit
control flow when the call matters structurally.
"""
[[rust.shape.callable.where]]
id = "lib-only-dispatches-commands"
severity = "error"
expr = "$lib => name =~ ^(run|from)$"
message = "`lib.rs` callable `{name}` is not part of the CLI dispatch surface. Keep command runtime in the owning command module's `run`."
rationale = """
`lib.rs` is the crate surface that routes `Command::*` to command modules. Allowing extra
helpers or command runtime there turns the crate root back into a hidden command
implementation.
"""
[[rust.shape.callable.where]]
id = "lib-has-no-inline-tests"
severity = "error"
expr = "$lib => kind != 'test'"
message = "`lib.rs` must not host inline test `{name}`; test command behavior through command modules or integration tests."
rationale = """
The crate root is a dispatch surface. Inline tests there tend to lock helper functions and
make command relocation harder.
"""
[[rust.shape.callable.where]]
id = "lib-run-has-no-local-state"
severity = "error"
expr = "$lib AND name = 'run' => count(shape:value) = 3"
message = "`lib::run` must not introduce local state; delegate each `Command::*` branch directly to the owning command module."
rationale = """
`lib::run` owns the command dispatch boundary only. Its stable symbol shape is the three
dispatcher parameters; additional local values are a strong signal that command logic is
being added inline instead of staying in the command module.
"""