Spec — Court Control from Control Center¶
Status: not started — outline only. Written 2026-10-05 against
sage-tools-api2.8.0,tools/control-center.htmland the three workbook generators as of that date. It records what is known and the shape agreed so far, not an implementation guide: §5 lists the owner's open decisions, and the detail is written once those are settled.Builds on Score entry from Control Center, and should wait for its real-Google checks (§11.2, C1–C8), since it reuses the same write path.
Let a signed-in operator put a match on a court, change it or clear it from Control Center, without opening the facility workbook.
1. Why¶
Since score entry, Court Control is the one job that still keeps the operator in the Google Sheet all day. It is also the field that decides what counts as live: Control Center's Live Matches, the schedule board and the Tournament Hub all read it. With it in the console, the console can run the whole day, not just show it.
2. What we know¶
- One input cell per court, the same in every workbook type. Court Control
has one 3-row block per court from row 5 (
5 + 3·(k − 1)): column B is the court label (merged over the 3 rows), column C the match number, typed by hand. D and E are formulas that read the match. This holds for the dual-meet generator (dual-meet-generator.gs, B is the court number), the standard generator (standard-tournament-generator.gs, B is=Variables!R<k+1>) and the hand-built PickleDrive team workbook. - The snapshot's
courtvalue is column B.CSV'scourtcolumn isFILTER('Court Control'!B:B, 'Court Control'!C:C = matchNumber), so the label the console shows is exactly the value to look the block up by. - An API write fires no
onEdit. As with score entry (its D4 and §10), the API has to publish throughsyncService.syncDayin the same request, or nothing reaches the pages until the next edit by hand. - C is not always a plain number. After the 3 October event, the team
workbook's typed match numbers in
Court Control!Cread#REF!(Team workbook recalculation §2). The write has to refuse a cell holding a formula or an error, as score entry refuses a formula in a score cell. - Typing in the sheet stays.
sheets-sync.gswatches Court Control by its pinned GID and is unchanged: hand edits and console edits write the same cell and can be mixed. - The pieces to reuse exist: the service account and
SheetsClient(writes guarded by a per-feature allowlist), operator tokens,scheduleGridto check that a match number exists inSCHEDULE, and the optimisticexpectedcheck with a 409 carrying the sheet's current value.
3. Proposed shape¶
API (sage-tools-api, a minor version):
PUT /v1/days/{day}/facilities/{facility}/courts/{court}/match
{ "matchNumber": 57 | null, "expected": { "matchNumber": 42 | null } }
- Read
Court Control!B5:Cand find the block whose B equals{court}. - Refuse when C holds a formula or an error, when the match is not in
SCHEDULE, or when it is already on another court. - 409 with the current value when C no longer equals
expected. - Write C (
values:batchUpdate, RAW) or clear it (values:batchClear) fornull.SheetsClientgains a third allowlist: that one cell. - Publish via
syncService.syncDayfor that facility; log one audit line.
Control Center. In Live Matches, which already shows one row per court, a signed-in operator gets Set match on each court. A dialog suggests the next match (the earliest scheduled one that is neither played nor on a court, preferring matches assigned to that court) and offers Clear. Warnings, never refusals: the match is already scored; one of its players is live on another court; it is scheduled for a different court. A court action, not a match action, so score entry's "matches are clickable only in Match Finder" rule (its D8) still holds.
Phase 2, the payoff. After saving the score of a match that is live on a
court, the score dialog offers "Court 3 is free: put #57 on it?". That is the
event-day rhythm ("score it, call the next one") in one step. It changes the
shared SCORE CLIENT block and so the scorer page too.
4. Not changing¶
sheets-sync.gs and every .gs file, the generators, the snapshot format,
the live Worker, score entry's routes and attendance.
5. Decisions for the owner¶
| # | Question | Leaning |
|---|---|---|
| Q1 | May scorers set courts from the scorer page, or only operators? | Operators only, at first |
| Q2 | Gate it on the event's existing scoreEntry setting, or a new courtControl one? |
Reuse scoreEntry: one fewer switch |
| Q3 | Build the "save score, then next match" prompt with it, or after? | After, as phase 2 |
6. Blocked on¶
Score entry's real-Google checks (C1–C8). Not before or during an event.
Related: Score entry from Control Center · Run the day · Control Center technical