Skip to content

Break leaderboard ties by entry time and highlight the leader - #27

Merged
arilivigni merged 4 commits into
mainfrom
arilivigni-leaderboard-leader-highlight
Oct 29, 2026
Merged

arilivigni merged 4 commits into
mainfrom
arilivigni-leaderboard-leader-highlight

Conversation

@arilivigni

Copy link
Copy Markdown
Contributor

What

  • Tie-break (f5a75a1): drinks with the same score are now ranked by who reached the board first (createdAt), then by drink ID, so every drink gets its own rank. The live board currently has four drinks tied at 4,600.
  • Leader highlight (26c7c14): first place on the public board gets a Leader badge, an accent bar, and the time it was entered ("Entered 3:48 AM", or "Entered Oct 28, 3:48 AM" if it wasn't today).
  • GET /api/board gains a top-level leaderEnteredAt field (null on an empty board). Rows still carry no timestamps, so only the leader's time is published.

Compatibility and data

  • The booths read only boardId, captured, rebuilding, and total, and name-score.mjs is unchanged, so booths need no update.
  • Every stored entry already has a validated createdAt, so the existing board re-ranks on deploy without a reset.
  • A code-only zip deploy leaves /home/data untouched.

Accessibility

  • Every text colour in the leader row stays above 4.5:1. Tests check this.
  • When the leader is also the attendee's own drink, the attendee's own highlight takes precedence.
  • All text is set with textContent, so the CSP is unchanged.

Tests

npm test: 333/333 pass. New tests cover:

  • the API field
  • the page rendering, run in a VM with a fake DOM (badge on the leader only, time formats, invalid or missing time)
  • CSS contrast and rule order

A mutation check showed the tests catch a badge applied beyond first place.

Checked visually at desktop and phone widths against a local service seeded with a four-way tie.

arilivigni and others added 2 commits October 28, 2026 14:17
Equal scores used to share a rank, and the live board has a three-way
tie for first at 3,250. leaderboard() now gives every drink its own
place: score first, then the earliest createdAt (admission time on the
service, serve time at a booth), then drink ID for a same-millisecond
tie. Every stored entry already has createdAt, so the live board settles
on redeploy with no reset or rescore. Booths only check a receipt's rank
is a positive integer, so they keep working against the new service.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A tied top score goes to the drink that reached the board first, so the
public page now marks first place with a Leader badge and shows when that
drink was entered. GET /api/board adds a top-level leaderEnteredAt (null
on an empty board); rows still carry no timestamps, so no other drink's
time is published. Booths read only boardId, captured, rebuilding, and
total, so they need no update.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 29, 2026 13:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A critical concurrency issue allows timestamps assigned before serialized admission to misorder drink rankings across service instances, requiring timestamp assignment under the shared lock and a regression test.

1 open issue
What changed in this PR

This PR replaces shared ranks with entry-time tie-breaking in the shared leaderboard logic and highlights first place on the public board.

Changes:

  • Rank drinks by score, then entry time and drink ID, assigning each a unique place.
  • Publish only the leader’s entry time and add a Leader badge with accessible styling.
  • Update attendee guidance and tests for ranking, API output, rendering, and contrast.
File Description
tests/​leaderboard-service.test.mjs Tests tie-breaking, leader timestamps, rendering, and contrast.
tests/​booth-menu.test.mjs Tests unique ranks and deterministic tie-breaking.
leaderboard-service/​public/​board.js Displays the leader badge, entry time, and updated caption.
leaderboard-service/​public/​board.css Styles the leader while preserving personal-row highlighting.
leaderboard-service/​app.mjs Adds leaderEnteredAt to the public board response.
docs/​learner-guide.md Explains entry-time tie-breaking to attendees.
docs/​leaderboard-service.md Documents ranking, rebuild behavior, and the API field.
docs/​integration-contract.md Defines booth and service tie-breaking semantics.
booth/​RUNBOOK.md Updates staff guidance on local and event ranks.
.github/​steps/​1-name-a-drink.md Updates learner instructions for tied scores.
.github/​skills/​order-up/​SKILL.md Aligns booth-session guidance with the new ranking rule.
.github/​extensions/​commit-and-sip/​services/​booth-menu.mjs Implements score, timestamp, and ID ordering with unique ranks.

Review effort: Balanced

arilivigni and others added 2 commits October 29, 2026 07:02
The service stamped createdAt before FileStore.admit took the write lock,
so a request that waited for another instance's write could be admitted
second but carry the earlier time and win the tie. The store now stamps
the time inside admit, under the lock, never earlier than the latest
drink already on the board, so entry order matches admission order even
when instance clocks disagree.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the leaderboard ranking and leader-display changes.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@arilivigni
arilivigni merged commit b1c930f into main Oct 29, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants