Parent: #713.
Updated 2026-08-07 against main at 47e26cc. Every file the original body named has since
been split. The policy breach did not go away with them — the M19 tranche (#706) regrew the same
seams under new names, so the file list below is current and the old one is preserved at the
bottom as the before-half of the record this issue's acceptance criteria ask for.
Problem
Root AGENTS.md sets an approximately 800–1,000-line limit and docs/coding-standards.md calls
1000+ a hard smell to break up before adding more code. Twelve production source files exceed
1,000 lines, counting code only — a file's own #[cfg(test)] mod tests { … } block is excluded,
and files whose tests live in a sibling tests.rs are counted in full.
| File |
Code lines |
crates/sage-engine/src/ability/effect.rs |
1,936 |
crates/sage-server/src/rules_text/effects.rs |
1,625 |
crates/sage-engine/src/state/zone.rs |
1,236 |
crates/sage-engine/src/apply/cast/targeted.rs |
1,232 |
crates/sage-engine/src/triggers.rs |
1,225 (of 1,631 total) |
crates/sage-engine/src/apply/cast/effects.rs |
1,195 |
crates/sage-engine/src/choice/mod.rs |
1,163 |
crates/sage-server/src/rules_text.rs |
1,152 |
crates/sage-engine/src/state/types.rs |
1,119 |
clients/web/src/interaction.ts |
1,108 |
crates/sage-engine/src/resolve.rs |
1,039 |
clients/web/src/protocol.ts |
1,002 |
Six more sit in the 800–1,000 soft-ceiling band and are worth watching rather than splitting now:
clients/prototype/src/App.tsx (963), crates/sage-engine/src/actions/generation.rs (863),
crates/sage-engine/src/catalog/effects.rs (858), clients/web/src/ui/game/Board.tsx (857),
crates/sage-protocol/src/card.rs (831), crates/sage-engine/src/actions/definition.rs (801).
clients/prototype/src/styles.css (3,228) is out of scope: the prototype is a throwaway
sandbox and the repository's design and structure doctrine does not govern it.
These are again exactly the seams the next rules or protocol work will land in — ability/effect.rs
and rules_text/effects.rs are the two halves of the same vocabulary, and every card added widens
both.
Scope
Perform behavior-preserving splits along cohesive existing domains with root re-exports. Sequence
the work in small PRs rather than one repository-wide rewrite.
Suggested waves, in payoff order:
- The effect vocabulary —
ability/effect.rs and its rules-text mirror
sage-server/src/rules_text/effects.rs, split along the same domain seams so the two stay
readable against each other.
- Engine state —
state/zone.rs and state/types.rs.
- Cast application —
apply/cast/targeted.rs and apply/cast/effects.rs, which were
themselves produced by the previous wave and have since regrown.
- Triggers, choices, and resolution —
triggers.rs, choice/mod.rs, resolve.rs.
- Client —
interaction.ts and protocol.ts.
Acceptance criteria
Non-goals
- Broad renaming or formatting churn.
- New abstractions without an existing domain seam.
- Combining rules expansion with structural refactoring.
Original list (2026-08-04) — all of these are now split
Sixteen non-test production files exceeded 1,000 lines; the largest and most central were:
crates/sage-engine/src/apply/cast.rs — ~2,696
crates/sage-engine/src/apply/combat.rs — ~2,104
crates/sage-engine/src/ability.rs — ~1,849
crates/sage-server/src/lobby/commands.rs — ~1,521
crates/sage-engine/src/characteristics.rs — ~1,398
crates/sage-server/src/lobby.rs — ~1,332
crates/sage-server/src/view/requirements.rs — ~1,262
crates/sage-protocol/src/lobby.rs — ~1,215
crates/sage-server/src/rules_text.rs — ~1,190
- seven additional production files between ~1,017 and ~1,168 lines
Not one of them is over the limit today: cast.rs became apply/cast/, combat.rs became
apply/combat/, ability.rs became ability/, characteristics.rs became characteristics/
with a module per CR 613 layer, and the server's lobby, view, and protocol files split the same
way. rules_text.rs is the one that came back — it is 1,152 lines again, with a
rules_text/effects.rs of 1,625 beside it.
Parent: #713.
Problem
Root
AGENTS.mdsets an approximately 800–1,000-line limit anddocs/coding-standards.mdcalls1000+ a hard smell to break up before adding more code. Twelve production source files exceed
1,000 lines, counting code only — a file's own
#[cfg(test)] mod tests { … }block is excluded,and files whose tests live in a sibling
tests.rsare counted in full.crates/sage-engine/src/ability/effect.rscrates/sage-server/src/rules_text/effects.rscrates/sage-engine/src/state/zone.rscrates/sage-engine/src/apply/cast/targeted.rscrates/sage-engine/src/triggers.rscrates/sage-engine/src/apply/cast/effects.rscrates/sage-engine/src/choice/mod.rscrates/sage-server/src/rules_text.rscrates/sage-engine/src/state/types.rsclients/web/src/interaction.tscrates/sage-engine/src/resolve.rsclients/web/src/protocol.tsSix more sit in the 800–1,000 soft-ceiling band and are worth watching rather than splitting now:
clients/prototype/src/App.tsx(963),crates/sage-engine/src/actions/generation.rs(863),crates/sage-engine/src/catalog/effects.rs(858),clients/web/src/ui/game/Board.tsx(857),crates/sage-protocol/src/card.rs(831),crates/sage-engine/src/actions/definition.rs(801).clients/prototype/src/styles.css(3,228) is out of scope: the prototype is a throwawaysandbox and the repository's design and structure doctrine does not govern it.
These are again exactly the seams the next rules or protocol work will land in —
ability/effect.rsand
rules_text/effects.rsare the two halves of the same vocabulary, and every card added widensboth.
Scope
Perform behavior-preserving splits along cohesive existing domains with root re-exports. Sequence
the work in small PRs rather than one repository-wide rewrite.
Suggested waves, in payoff order:
ability/effect.rsand its rules-text mirrorsage-server/src/rules_text/effects.rs, split along the same domain seams so the two stayreadable against each other.
state/zone.rsandstate/types.rs.apply/cast/targeted.rsandapply/cast/effects.rs, which werethemselves produced by the previous wave and have since regrown.
triggers.rs,choice/mod.rs,resolve.rs.interaction.tsandprotocol.ts.Acceptance criteria
Non-goals
Original list (2026-08-04) — all of these are now split
Sixteen non-test production files exceeded 1,000 lines; the largest and most central were:
crates/sage-engine/src/apply/cast.rs— ~2,696crates/sage-engine/src/apply/combat.rs— ~2,104crates/sage-engine/src/ability.rs— ~1,849crates/sage-server/src/lobby/commands.rs— ~1,521crates/sage-engine/src/characteristics.rs— ~1,398crates/sage-server/src/lobby.rs— ~1,332crates/sage-server/src/view/requirements.rs— ~1,262crates/sage-protocol/src/lobby.rs— ~1,215crates/sage-server/src/rules_text.rs— ~1,190Not one of them is over the limit today:
cast.rsbecameapply/cast/,combat.rsbecameapply/combat/,ability.rsbecameability/,characteristics.rsbecamecharacteristics/with a module per CR 613 layer, and the server's lobby, view, and protocol files split the same
way.
rules_text.rsis the one that came back — it is 1,152 lines again, with arules_text/effects.rsof 1,625 beside it.