import InfoBox from '../components/InfoBox.astro';
import PullQuote from '../components/PullQuote.astro';

Two days of committing straight to main had been [living on borrowed time](/posts/surviving-the-first-deploy#where-this-leaves-things), and today it ran out. Every one of today's eight merges landed as a reviewed pull request instead, and by evening the project had a CI workflow gating every future one, a licensing problem fixed before it could become a legal one, a WCAG audit's findings closed, and a design refactor that reopened a question about what this game is actually testing.

## A borrowed word list becomes a liability

The dictionary had been running on SOWPODS, the Collins Scrabble word list, since day one, and Collins' license is not one a commercial game can rely on. The fix was a straight swap to `dwyl/english-words`, Unlicense and already sitting in the codebase as an emergency fallback, now promoted to the primary source. Coverage held, 370,079 English words and 162 antonym pairs, the same shape as before. The lesson is not the swap itself but where the safety net came from: the fallback path built for a different reason turned out to be the exit when the primary source became untenable.

## What an accessibility audit actually finds

A WCAG 2.0 AA pass against Norway's own test procedures turned up three Level A failures, on top of a codebase that was already carrying comprehensive ARIA, live regions, and reduced-motion support, which says something about how narrow a specific structural gap can be even inside broad coverage.

<InfoBox title="Three Level A gaps, one shape">
  The page's declared language never updated on switching to Norwegian. Five dialogs had no focus
  trap, so Tab could escape them into the page behind. And the game board declared itself an ARIA
  grid while marking every cell `aria-hidden`, offering an empty interactive grid to anyone not
  looking at it, when the live regions were already narrating every game event correctly.
</InfoBox>

## Every change gets a gate

The CI workflow is the one change here that reshapes everything after it: four jobs, type-check, unit tests, production build, and a Playwright end-to-end run in a real browser, on every push to main and every pull request against it. Wiring the four job names as required checks in the repository settings is the one small step still manual, but the direction is set regardless.

<InfoBox title="What the four jobs actually gate">
  Type-check and lint via svelte-check; unit tests via Vitest; a production build via Vite, so a
  bundler regression fails here and not on deploy; and the Playwright run, so "the game works" is
  checked in a real browser instead of only asserted by unit tests.
</InfoBox>

## Is this a skill test or a toy?

The same day's casual-gameplay refactor is a smaller change with a bigger question inside it. The modifier system, speed and score multipliers layered onto word submission, is gone entirely, engine, store, API, database column, language strings, all of it; the grid shrank to a fixed 15 by 10; the word counter became a progress bar that warns as words run low; the leaderboard came out of the play view. None of it makes the game harder. It makes the game calmer, closer to something played for the words than against the clock, and that tension is not resolved by this PR, only stated for the first time.

<PullQuote>Is this a skill test or a toy?</PullQuote>

## Where this leaves things

Two smaller fixes closed the day: the PR preview infrastructure moved to Render's native preview generation instead of a broken custom API, and a preview deployment crash traced to a startup validation check rejecting a daily-challenge secret that did not meet it. Small, but of a piece with everything else today. The project now has a gate in front of it, and today was mostly spent finding out what the gate should check for.