Skip to content

Dashboard: clear the shared public leaderboard after the event - #17

Merged
arilivigni merged 5 commits into
mainfrom
arilivigni-cautious-goggles
Oct 2, 2026
Merged

arilivigni merged 5 commits into
mainfrom
arilivigni-cautious-goggles

Conversation

@arilivigni

@arilivigni arilivigni commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Problem: End the event (archive and reset) clears only the booth's own records. The public leaderboard is shared by every booth, so after a reset it still showed every drink name.

Fix: a staff-confirmed Clear the public leaderboard step on the dashboard, after End the event.

Service (leaderboard-service/)

  • Adds POST /api/board/clear, which needs the staff key. The body must be exactly { boardId }, naming the board staff checked.
  • The board is emptied: entries, takedown reservations and the captured count all go, it stays open, and it gets a new board ID. The old board file is copied, before anything changes and while the board is locked, to <EVENT_ID>.cleared-<time>.json.
  • Any other board ID gets 409 board_changed, so a repeated or stale request can't erase a newer board.
  • GET /api/board now reads the entries, board ID and counts in a single read of the store (store.view()). A checked board ID therefore always matches the contents shown.

Booth dashboard

  • A new section appears only on machines with the staff key. Staff press Check the public leaderboard to see "N drink name(s) on it, M captured in all", then give their name and type clear board.
  • The clear is refused while this booth holds any event record (event_not_ended). An archived and reset booth may clear, and so may a staff machine that has served no one.
  • The check, the records and the request all run under this booth's ledger lock, so no attendee can be served mid-clear.
  • Records: board-clear-requested-… is written before the request, so a machine that can't write it clears nothing. Then comes either board-cleared-… with the service's receipt, or board-clear-refused-… if the service refused. A request record with neither after it means the answer never arrived.
  • Outcomes:
    • A 4xx refusal is reported as "not cleared".
    • A timeout, a 5xx or an unreadable answer is reported as "could not be confirmed: check the board".
    • A confirmed clear is always reported as done, even if a later local write or read fails.

Docs

  • RUNBOOK: Ending an event step 6, the new-event row, the operations paragraph and the status banner.
  • docs/leaderboard-service.md: the API list, retention and the status banner.
  • docs/architecture.md and the README.

Verification

  • New tests cover the route, the file store, the dashboard flow, record-before-clear, the lock, refused vs. unconfirmed outcomes, a late commit failure, single-read views, and a failed read after the clear. Every guard was mutation-tested, and every mutation was caught.
  • npm test: 321 pass, three runs in a row. npm run check passes.
  • Real Chromium: the section is hidden without the staff key; the check shows counts; clearing before the reset is refused; the clear succeeds after the reset; the board then reads 0/0.

Live: this branch's service code is deployed (board and key backed up first). The live board was not cleared by me.

Resetting a booth never touched the public board, so it kept every drink
after an event was wiped. Add a staff-key POST /api/board/clear that
empties the board (entries, reservations, captured count) under a new
board ID, keeps the old file as <EVENT_ID>.cleared-<time>.json, and only
clears the board staff checked (409 board_changed otherwise). The staff
dashboard gets a Check, then name + 'clear board', step that is refused
until this booth has been archived and reset, and records who cleared
which board in its saved files.

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

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.

Copilot review overview

🟡 Changes recommended

The irreversible remote clear can succeed before its required local audit record is persisted.

Review effort: Balanced
Findings: 1 Medium severity · 1 Low severity

Open (2)
What changed in this PR

Adds a staff-controlled workflow to safely clear the shared leaderboard after an event.

Changes:

  • Adds authenticated board clearing with archival and board-ID rotation.
  • Adds dashboard confirmation, audit records, schemas, and UI.
  • Updates tests and operational documentation.
File Description
tests/​leaderboard-service.test.mjs Tests API, persistence, and dashboard clearing.
README.md Documents the staff operation.
leaderboard-service/​store.mjs Archives and resets board state.
leaderboard-service/​app.mjs Adds the clear endpoint.
docs/​leaderboard-service.md Documents API and retention.
docs/​architecture.md Explains lifecycle safeguards.
booth/​RUNBOOK.md Adds operating procedures.
.github/​extensions/​commit-and-sip/​services/​leaderboard-client.mjs Adds board inspection and clearing.
.github/​extensions/​commit-and-sip/​services/​event-archive.mjs Defines clear confirmation text.
.github/​extensions/​commit-and-sip/​renderer/​admin.js Implements dashboard interactions.
.github/​extensions/​commit-and-sip/​renderer/​admin.html Adds the clearing form.
.github/​extensions/​commit-and-sip/​booth-engine.mjs Validates and executes clearing.
.github/​extensions/​commit-and-sip/​admin-panel.mjs Dispatches new staff actions.
.github/​extensions/​commit-and-sip/​admin-canvas.mjs Declares action schemas.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .github/extensions/commit-and-sip/booth-engine.mjs Outdated
Comment thread docs/leaderboard-service.md Outdated
The clear cannot be undone, so the dashboard now writes a
board-clear-requested record first (no record, no clear) and the
board-cleared record after; a failure writing the second no longer
reports a clear that happened as failed. Keep the retractions
continuation lines under their endpoint.

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.

Copilot review overview

🟡 Changes recommended

Concurrency gaps can clear a board that staff did not inspect or erase a newly published local drink.

Review effort: Balanced
Findings: 2 High severity · 1 Low severity

Open (3)
Resolved since last review (2)

Comment thread .github/extensions/commit-and-sip/booth-engine.mjs Outdated
Comment thread leaderboard-service/app.mjs
Comment thread .github/extensions/commit-and-sip/booth-engine.mjs Outdated
The empty-booth check and the clear now run in one ledger transaction,
so nothing can be served between them. GET /api/board reads entries and
board ID from a single store snapshot, so a checked ID always matches
the contents shown. A refusal (4xx) says the board was not cleared; a
timeout, 5xx or unreadable answer says the clear could not be confirmed
and to check the board.

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.

Copilot review overview

🟡 Changes recommended

Post-clear persistence failures can incorrectly report failure, and audit records currently misclassify definitive refusals.

Review effort: Balanced
Findings: 3 Medium severity

Open (3)
Resolved since last review (3)

Comment thread .github/extensions/commit-and-sip/booth-engine.mjs Outdated
Comment thread .github/extensions/commit-and-sip/booth-engine.mjs Outdated
Comment thread leaderboard-service/store.mjs Outdated
A ledger write failing after a confirmed clear no longer turns it into
a reported failure. A refusal (board_changed or another 4xx) writes a
board-clear-refused record, so an unmatched request always means no
answer came. MemoryStore.view reads the board synchronously.

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.

Copilot review overview

🟡 Changes recommended

Successful clears can still be reported as failures, and the archive prerequisite is not durably enforced.

Review effort: Balanced
Findings: 1 High severity · 1 Medium severity

Open (2)
Resolved since last review (3)
Previously missed (1)

In code that hasn't changed since last review

Low severity Align deployment status with the route's actual availability

docs/​leaderboard-service.md:114

The status banner at the top of this document says everything described here is already deployed, but this PR explicitly says the live service still needs a code deployment before this route exists. Listing the endpoint without qualifying that status gives operators contradictory deployment guidance. Mark this route as pending, or update the live-status banner only after deployment.

Comment thread .github/extensions/commit-and-sip/booth-engine.mjs Outdated
Comment thread .github/extensions/commit-and-sip/admin-panel.mjs Outdated
…test

The dashboard reads its state before the irreversible clear and falls
back to it if the read afterwards fails. The empty-ledger guard is
described as what it is: this booth holds no event records (archived
and reset, or a staff machine that served no one). Status banners say
the clear route is live. The outcome test used one timestamp for
several clears and collided on fast CI; each attempt now has its own.

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.

Copilot review overview

🟢 Approval recommended

The destructive workflow is authenticated, archived, concurrency-protected, failure-aware, documented, and thoroughly tested.

Review effort: Balanced
Findings: None

Resolved since last review (2)

@arilivigni
arilivigni merged commit 6398332 into main Oct 2, 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