Older posts

  1. 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.

  2. 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.

  3. Fast, but not zero

    Speeding up the e2e suite by cranking animation speed risked breaking the one test that watches an animation happen. Reduced motion turned out to be the wrong kind of fast.

  4. The apple that shouldn't have been there

    A test asserting that hearts are growth-neutral failed on CI, intermittently, on a PR that never touched the file it failed in.

  5. 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.

  6. 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.

  7. 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?

  8. A date too coarse to sort by

    Two posts about the blog machine itself both ended their narrated git ranges on the same calendar day. The frontmatter date field had no way to say which came first.

  9. 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.

  10. 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.