architecture-refactor
Load-bearing in one mode
Both duel pages held their own copy of the same reveal-timing math. One input to the shared version looks redundant for AI duel and is anything but for PvP.
The comment that confessed
A second architecture review found duplication a module's own doc comment had already admitted to, describing itself as a mirror of logic living somewhere else.
The plan had three slots
screenshot.ts had grown to 626 untested lines drawing both share images and the board underneath them. The obvious three-way split needed a fourth module once someone actually drew the boundary.
Verbatim, not cleaned up
GameEngine.ts held two unrelated engines in one 621-line file. The split needed no design round at all, just a careful move and one very literal constraint.
The deletion test
GameRecap and DuelRecap still carried the same state machine twice. Four candidate shells, judged by one question: does deleting it reduplicate the machine back into both callers?
Descriptors, not strings
The PvP lives-teaching hints get their own pure reducer. Four candidate designs, decided on two separate axes, one of them a rule the sync-engine round had already settled.
The design with no second copy
Four candidate shapes for pulling PvP sync logic out of an 898-line Svelte store. Two of them carried a duplicate copy of the game state; the winner needed none.
Illegal states, unrepresentable
An architecture review found both duel pages still carrying the same ninety-line derivation chain by hand. The fix collapses sixteen flat props into one discriminated model.
One parser for every mode
Three near-identical physical-keyboard parsers, one bug that only showed up in duel modes, and a wayfinder map that carried its own execution instead of stopping at a spec.
One recap, two modes
A blocking modal in PvE and an inline overlay in PvP get replaced by one shared recap component, ported wholesale from the Daily Challenge pattern.