Public: anyone can read this; the crew can change it.

forked from trevato/cs

A result says which map it was played on, so the leaderboard is comparing like with like #240

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`parseResult` now takes a `map` field and validates it through `src/mapname.ts`: `de_forge` or `gen_<base36>`, anything else refused with the 422 the route already answers. A body with no map is still a result and records `de_forge`, so a client from before this keeps working — `src/server.test.ts`'s own fixture still posts none, which is that path under test end to end. `generated` is refused alo…

shipped production is serving it deploy ae07c2d

opened this

parseResult now takes a map field and validates it through src/mapname.ts: de_forge or gen_<base36>, anything else refused with the 422 the route already answers. A body with no map is still a result and records de_forge, so a client from before this keeps working — src/server.test.ts's own fixture still posts none, which is that path under test end to end. generated is refused along with the junk: it is a wish for a new map, not a map anybody played on, which is why playedOn is mapFrom's stricter twin rather than the same function — a control full of junk is a person mistyping and gets de_forge, a stored record full of junk is a claim nobody can check later and gets refused.

src/db.ts gains the column with a migration in the shape of the identity one beside it: additive, NOT NULL DEFAULT 'de_forge', so yesterday's database opens today with every row it had and calls them de_forge. The recent-matches feed on / names the map as a link to that layout — text escaped, href built from this app's own string via mapFrom and never the stored bytes — and the terminal's match list gains a 12-wide map column before when (worst case, a live match on a generated map, runs to 84 columns; no existing column moved), with the line under the cursor naming the map to paste into Map name when it was a generated one, because the id alone does not fetch that layout. The standings query is untouched: this records the fact, it does not split the board.

The map is the browser's word like every number beside it — resultOf posts the name of the level the world is actually standing on, and the server checks its shape and nothing more; a client can lie about which map it played exactly as it can about its kills. What to look at in the preview: the Recent matches list after playing one match on de_forge and one with gen_14u5j6g in Map name, and the same two rows in the terminal (FORGE_APP_SSH). bun test is 1078 green, and bun run scripts/mutate-result.ts kills all 27 mutants including the two new map rules — its two stale matchId mutants (they still looked for the regex that moved into src/matchid.ts) are replaced by one that breaks the isMatchId call. One thing found rather than changed: static/ held two app.*.js bundles, which made bun test red on main before this branch; the rebuild here sweeps the stale one.

🤖 Generated with Claude Code

Closes #150

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs