The bot now answers only its predefined commands and stays silent on
anything else, logging ignored commands at debug level.
Tests no longer assert exact reply/reminder wording (which broke on
copy tweaks like 37a81a2) — they check behavior instead: message
counts, the names/handles substituted in, and that /sync persists its
fetch and doesn't leak internal errors.
Migrate Sheets auth from an API key to a service-account credential
(GOOGLE_CREDENTIALS_FILE) with the read+write spreadsheets scope, add a
WriteSheet primitive, and use it to actively manage empty duty weeks in
the weekly reminder.
Each fire now handles a fixed this-week/next-week model (replacing the
DUTY_AHEAD_DAYS announce):
- this week empty -> pick the two people with the fewest duties (random
tie-break), write their names into cols B/C, and announce
- this week filled -> announce who is on duty
- next week empty -> ask people to volunteer before it is auto-assigned
Col G ("Liczba dyżurów") is a live formula, so names-only writes keep the
fewest-duties selection fair across weeks. Selection, row tracking, range
building, and every fire() branch are unit-tested; live tests for sheet
read/write are env-gated.
Read each member's Telegram handle from the new sheet column F (duty
count moves to G) and mention on-duty people as @handle in the weekly
reminder, so they get a real notification. Names without a handle, or
not found in the people list, fall back to plain text.
- sheet.go: add colHandle, Person.Handle; parse handle column
- scheduler.go: resolve names to @mentions via handlesByName/mention
- service.go: widen default SHEET_RANGE to column G
These were never committed (hidden by status.showUntrackedFiles=no): without
go.mod/go.sum a fresh clone would not build, and the source files committed in
abb38e3 were missing their accompanying tests.