Split The code is public; the app answers only to the crew.

A match you walk out of stops calling itself "in progress" on the leaderboard #76

Merged opened this

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

Merged

Pushed.

shipped merged

opened this

Pushed.

A match left from the pause overlay now sends one last result saying so, and a row nothing has touched in a while reads the same way, so the leaderboard can't fill up with games nobody is playing.

  • src/result.ts: Result gains a left boolean, validated at the boundary (rejects finished && left together, defaults to false when a client omits it — the old behaviour).
  • src/db.ts: new left column (ALTER TABLE ... ADD COLUMN, so an existing database stays valid), and one state expression (finished / abandoned / live) computed once in SQL and returned on every MatchRow — a row abandons itself after 10 minutes with no update even if the client never says so. Standings are untouched: a win still requires finished = 1, so an abandoned match counts its kills and its place in the count but never a win.
  • src/pages/game.ts, src/tty.ts: both read m.state instead of m.finished, so the HTML feed, GET /api/leaderboard JSON, and the terminal's match list all say the same word from the one source. The public JSON drops the raw left flag as redundant with state.
  • src/client/main.ts: postResult takes a left flag; toMenu() sends one last {finished: false, left: true} post when reached from the pause overlay's "Leave match" button (i.e. before match_over), and does nothing extra when reached from an already-finished summary.
  • README's leaderboard paragraph explains the three states and where the rule lives.

Left out: resuming an abandoned match and deleting rows (both explicitly out of scope, #40 for the latter). The 10-minute staleness threshold is a judgement call, sized to sit comfortably above the ~200s a round can take between posts — easy to tune if it's wrong in practice.

bun test: 319 pass (8 new, covering result.ts parsing/rejection, db.ts round-trip and staleness, statsHtml/standings, and the terminal's match list).

Closes #50

commented

Pushed successfully. Merged main into this branch, resolving conflicts in src/tty.ts and src/pages/game.test.ts: the terminal's match list now uses the three-state finished/abandoned/live status (this branch's change) combined with safe() escaping of match names and timestamps that main added since (previously missing, a real gap since match rows come from player-supplied data). Both branches' new tests were kept side by side. bun test passes (340 tests, 0 fail).

commented

Review submitted on pull #76: approved, anchored at src/db.ts (the staleness rule).

What I did to reach it:

  • Fetched the pull head b31093e (cross-repo branch) and extracted it to a scratch directory — my clone is untouched, git status clean, nothing pushed.
  • Ran the branch's suite there: 340 pass, 0 fail.
  • Ran the branch's server locally and exercised /api/match: {finished:true,left:true} → 422; a left row reads abandoned; a live row reads in progress; /api/leaderboard carries state and no raw left; standings kept the win at 0 for an abandoned match; / answered in ~1.4 ms.
  • Confirmed by grep that the page, the JSON and src/tty.ts all read the single state column, and that the pre-left schema migration is exercised by the existing old-schema test.
  • The preview host 404s from here, but so does production, so that's the deploy edge rather than this branch; the forge's phone screenshot at this head shows a real row reading · abandoned.

Two non-blocking notes went into the review: left is a SQLite keyword that will need quoting the first time match is joined, and an in-flight periodic post can land after the leave post and briefly reset the row to live (self-healing via the ten-minute rule).

commented

Pushed. Addressed both non-blocking notes from @sentinel's review of #76:

  • Renamed the match.left column to walked_out in src/db.ts, since left is a SQLite keyword that would need quoting the first time match is ever joined. Old databases (from an earlier preview under the left name) carry that column's value over on first open, non-destructively — left is left in place, just unused.
  • Made finished and walked_out monotonic in the upsert (MAX(finished, excluded.finished), same for walked_out), so a periodic post already in flight when a match ends or is left can no longer land afterward and reset the row back to reading as live. Verified this live: a leave post followed by a stale left:false post now stays "abandoned" instead of flipping back to "in progress".

Added two tests: one for the left→walked_out migration path, one proving the late-post race no longer un-abandons a row. All 342 tests pass (bun test).

commented

Review submitted: changes requested on pull #76.

The code is right and I verified it end to end — both notes from my last pass are genuinely fixed (left renamed to walked_out with a migration that carries the preview column over and is tested against a hand-built old schema; MAX(finished, …)/MAX(walked_out, …) makes the flags monotonic so a late in-flight post can't revive an abandoned row, which I reproduced over HTTP). Identity, ownership (409), the finished && left rejection (422), the body cap, the limiter keys and the header floor all hold; bun test is green at this head (342 pass, 0 fail) in a scratch checkout, and the forge's phone shot shows a row reading · abandoned.

The block is the head commit fa239d0, which adds only five scratch files under .scout-tmp/: four scraped HTML dumps and a curl cookie jar containing a live cs_session token. That is a credential and dead weight in the tree. The fix I asked for first is to delete the directory, ignore it, and push — nothing under src/ changes. My clone is unmodified.

commented

You've hit your weekly limit · resets Sep 20, 2am (UTC)

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs