mirror of
https://github.com/kuhyx/signal-bot.git
synced 2026-11-10 19:27:20 +01:00
One row per command attempt, not two aggregates written only on success. command_uses holds last-use only and daily_uses counts successes; both are rate-limiter state and both are written by store.record_use, which the dispatcher calls only when a handler returns cleanly. A gate refusal and a crash returned before it, so a command that failed every time looked exactly like one nobody ran, and nothing knew which command a counted message was. command_events now takes every attempt with its outcome, its duration and the item it served; upstream_calls takes every outbound request made while serving one. The two writes stay separate on purpose -- recording a refusal as a use is what slid the cooldown window forward every time somebody was told to wait -- and test_dispatcher_outcomes asserts last_used does not move. Backfilled from journald joined against message_events, with daily_uses filling the residual so the two sources cannot double-count. Two things were wrong on the first attempt and both were found by measuring rather than by reasoning: the window has to be symmetric, because sent_at_ms comes from the sender's phone and the journal stamp from this host (194 of 299 lines landed *before* their own message, by up to 3.2 s); and matching has to be a global closest-pair assignment, because per-row greedy cannot separate two commands seconds apart. Together those took the dropped rows from 137 to zero, and recovered 418 invocations back to 29 August. Also: !analityka in the group, twelve Polish lines, naming at most three people and only ones whose display name has been seen; an Analytics tab with Nivo charts; and continuous latency measurement, which answers the open question in DOCS-latency.md -- a text send is 235 ms and an image send about 2.2 s, so the upload really is where the time goes. EPHEMERAL_TABLES was doing two unrelated jobs and is now two tuples: what a schema bump rebuilds, and what leaving a group clears. daily_uses left the first (it is a backfill source now) and stayed in the second, and _drop_reshaped took over the repair a bump used to do for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4QTp3h5Q3MvfrwGV8xqPf
240 lines
11 KiB
Markdown
240 lines
11 KiB
Markdown
# Changelog
|
|
|
|
Releases are named after the popes, in order: release *n* is pope *n*. The
|
|
version number is a pure function of that ordinal — see `signal_bot/versioning.py`
|
|
for the two constants and why they are what they are. The short version is that
|
|
Jan Paweł II has to land on 2.13.7, and everything else follows.
|
|
|
|
**The name is Latin, and it is derived, not typed.** `latin_name()` in
|
|
`signal_bot/versioning.py` builds it from `popes.json`: the Latin stem plus the
|
|
Roman numeral off the Polish name. So 0.0.3 is «Clemens I», not «Klemens I» and
|
|
not the raw `latin` field's «Clemens Romanus»; 3.0.4 will be «Leo XIV», not «Leo
|
|
Decimus Quartus». Ask the code rather than guessing:
|
|
|
|
```
|
|
python -c 'from signal_bot.versioning import *; print(latin_name(pope_for(14)))'
|
|
```
|
|
|
|
The same string goes in the release commit subject, in `/healthz`, and in the
|
|
heading below.
|
|
|
|
The bot reads this file. The heading format is load-bearing:
|
|
|
|
```
|
|
## <version> — <pope name>
|
|
- <one change, in Polish, as the group will read it>
|
|
```
|
|
|
|
Add the new section at the top when you bump `RELEASE_ORDINAL`. Anything that
|
|
is not a `##` heading or a `-` bullet under one is ignored, so prose between
|
|
releases is free. The heading *name* is checked rather than trusted —
|
|
`tests/test_changelog.py` asserts it equals `latin_name()` for that version —
|
|
and the announcement reads `popes.json` regardless, so a typo here fails the
|
|
suite instead of reaching a group.
|
|
|
|
**Preview the announcement before you bump.** Because a bump is a publish,
|
|
the announcement was the one feature that could never be exercised first.
|
|
`tool/preview_release.py testbot` posts exactly what the next release would
|
|
say, into one test group, touching neither `RELEASE_ORDINAL` nor any
|
|
`announced_version` row; `--print-only` renders it without sending. It is
|
|
fail-closed on `SELFTEST_GROUPS`, so it cannot post a release that does not
|
|
exist into the group that would believe it. Write the `##` section below
|
|
first -- the preview reads it, so what you see is what ships.
|
|
|
|
**A release announcement is a photo now.** It carries the pope's portrait, his
|
|
Latin name and his pl.wikipedia article, the same three things `!papież` posts.
|
|
Only for the pope in the header: a backlog announcement lists up to ten
|
|
releases, and ten attachments is the wall the cap exists to avoid. If Commons
|
|
will not serve the portrait the announcement still goes out, as text — the
|
|
`announced_version` marker is written before the send, so a failure there would
|
|
otherwise cost that group its release notes permanently.
|
|
|
|
**Every release takes the next pope, however small.** A one-line fix consumes
|
|
an ordinal exactly like a feature does; the ladder tracks releases, not
|
|
importance. 0.0.4 and 0.0.5 were both bug fixes. Do not try to squeeze a fix
|
|
out at the current version to "save" a pope -- there are 267 of them.
|
|
|
|
**A version bump is a publish, not a checkpoint.** Restarting the service after
|
|
one posts these bullets into every watched group, including the real one. So
|
|
exercise the feature in a test group — `testbot`, `catbot`, `finaltestbot`,
|
|
each just you and the bot — *before* bumping `RELEASE_ORDINAL`, tagging or
|
|
restarting. To try something at the current version without announcing, leave
|
|
`RELEASE_ORDINAL` alone and restart. Green unit tests and a green
|
|
`scripts/e2e.sh` are **not** sufficient evidence: `e2e.sh` runs against the
|
|
local fake, so it proves the wiring and nothing about how Signal renders the
|
|
result or how the real upstream API behaves. 0.0.3 shipped a `!gekon` that
|
|
passed every gate and posted the same photo every time, because the one thing
|
|
nobody had done was call the real endpoint twice.
|
|
|
|
**Write bullets the group can notice.** The audience is people in a chat, not
|
|
this repo: describe what changes for them. 0.0.1 shipped a bullet about
|
|
`/healthz`, an endpoint bound to 127.0.0.1 that nobody in a Signal group can
|
|
reach, and it was rightly called out.
|
|
|
|
## 0.2.6 — Stephanus I
|
|
|
|
papież nr 23 z 267, pontyfikat 254-257
|
|
|
|
- nowa komenda `!analityka` — kto ile używa bota, o której godzinie i które komendy nikomu się nie przydają
|
|
- bot pamięta teraz każde użycie komendy, także to nieudane; wcześniej komenda, która zawsze się psuła, wyglądała jak taka, której nikt nie używa
|
|
- historia sprzed tej wersji została odtworzona z dziennika systemowego, więc statystyki zaczynają się od 29 sierpnia, a nie od dzisiaj
|
|
- strona zarządzania ma nową zakładkę z wykresami
|
|
|
|
## 0.2.5 — Lucius I
|
|
|
|
papież nr 22 z 267, pontyfikat 253-254
|
|
|
|
- dodano !sztuka — losowe dzieło sztuki, częściej polskie niż nie
|
|
- dodano !wiersz — losowy krótki wiersz, w całości, z domeny publicznej
|
|
|
|
## 0.2.4 — Cornelius
|
|
|
|
papież nr 21 z 267, pontyfikat 251-253
|
|
|
|
- dodano !traps
|
|
|
|
## 0.2.3 — Fabianus
|
|
|
|
papież nr 20 z 267, pontyfikat 236-250
|
|
|
|
- jak wpiszecie komendę z literówką, bot podpowie tę właściwą: `!cta`
|
|
dostaje odpowiedź „chodziło o `!kot`?”. Wcześniej milczał, więc pomyłka
|
|
wyglądała dokładnie tak samo jak bot, który nie działa
|
|
- komenda, której bot nie zna i do której nic nie pasuje, dostaje
|
|
odpowiedź z podpowiedzią, co z tym zrobić
|
|
- nowa komenda `!zaproponuj` — zapisuje pomysł na komendę, której jeszcze
|
|
nie ma, np. `!zaproponuj !pogoda pokaż pogodę na jutro`. Pomysły trafiają
|
|
na listę, którą czytam
|
|
- każde `!słowo`, którego bot nie zna, jest zapisywane. To jest lista
|
|
komend, które warto dopisać — więc wpisywanie ich ma sens nawet wtedy,
|
|
kiedy jeszcze nie działają
|
|
- bez zmian: zwykłe pisanie, samo `!!` i `!kot` z dopiskiem dalej nie
|
|
wywołują żadnej odpowiedzi
|
|
|
|
## 0.2.2 — Anterus
|
|
|
|
papież nr 19 z 267, pontyfikat 235-236
|
|
|
|
- album urósł do 180 zdjęć — każda komenda ma ich teraz więcej, a jedna
|
|
zaczęła w ogóle działać: nie miała dotąd ani jednego zdjęcia, więc nie
|
|
odpowiadała nikomu, kto ją wpisał
|
|
- `!dodaj` przyjmuje wreszcie filmy. Do tej pory odrzucał **każdy** film:
|
|
bot sprawdzał, czy z pliku zniknęły daty, a narzędzie, którym je usuwał,
|
|
wcale ich nie usuwało — więc film nigdy nie przechodził tej kontroli
|
|
- z filmów wycinana jest teraz też ścieżka, którą iPhone dopisuje obok
|
|
obrazu: ramka po ramce, gdzie na nagraniu są twarze i który to numer
|
|
twarzy. Nie da się jej usunąć jak zwykłych metadanych, bo to nie jest
|
|
opis pliku tylko osobny strumień — więc film jest przepakowywany i
|
|
zostaje w nim wyłącznie obraz i dźwięk
|
|
- zdjęcia wrzucane hurtem z folderu przechodzą teraz dokładnie tę samą
|
|
kontrolę metadanych co te z czatu — wcześniej były wgrywane jak leci
|
|
- to samo zdjęcie wysłane dwa razy, pod dwiema nazwami albo raz z czatu
|
|
i raz z folderu, trafia do albumu jeden raz
|
|
- to samo co wcześniej: te komendy istnieją tylko w tej grupie
|
|
|
|
## 0.2.1 — Pontianus
|
|
|
|
papież nr 18 z 267, pontyfikat 230-235
|
|
|
|
- zdjęcia można teraz dorzucać z czatu: podpisz wysyłane zdjęcie
|
|
`!dodaj <imię>` i od razu wychodzi na `!<imię>`, bez restartu bota
|
|
- można podać kilka etykiet naraz (`!dodaj ktos ktos2`) — zdjęcie dostaje
|
|
wszystkie; można też wysłać kilka zdjęć w jednej wiadomości
|
|
- etykieta, która nie pasuje do nikogo, zakłada nową — bot mówi wtedy, że
|
|
powstała, i sięga się po nią przez `!losowe <etykieta>`
|
|
- `!losowe` bez niczego to losowe zdjęcie z całego albumu
|
|
- z każdego dodanego zdjęcia bot wycina metadane — w tym miejsce, w którym
|
|
zostało zrobione, i model telefonu — po czym sprawdza, czy naprawdę
|
|
zniknęły; jak nie potrafi tego zrobić, nie zapisuje zdjęcia w ogóle
|
|
- kasuje też swoją kopię odebranego załącznika, żeby nie została poza albumem
|
|
- w odpowiedzi są tylko liczby i skróty (`dodano · p1: 4`) — to, co
|
|
wpisaliście, nie trafia ani do odpowiedzi, ani do logów
|
|
- to samo co wcześniej: te komendy istnieją tylko w tej grupie
|
|
|
|
## 0.2.0 — Urbanus I
|
|
|
|
papież nr 17 z 267, pontyfikat 222-230
|
|
|
|
- nowe komendy ze zdjęciami: każda osoba ma swoją, a kilka naraz
|
|
(`!ktos !ktos2`) daje zdjęcie, na którym są wszyscy naraz
|
|
- jak takiego zdjęcia nie ma, bot mówi to jednym zdaniem zamiast milczeć
|
|
- filmiki też działają — lecą jako filmiki, a nie jako plik, którego nie da
|
|
się odtworzyć
|
|
- te komendy istnieją tylko w tej jednej grupie: w każdej innej nie ma ich
|
|
wcale, `!pomoc` ich tam nie pokazuje i bot na nie nie odpowiada
|
|
- zdjęcia i imiona nie są w kodzie bota ani nigdzie w internecie — leżą w
|
|
jednym katalogu na komputerze i nigdy go nie opuszczają
|
|
|
|
## 0.1.7 — Callistus I
|
|
|
|
papież nr 16 z 267, pontyfikat 217-222
|
|
|
|
- każda wersja mówi teraz, którym z kolei papieżem jest jej patron i w jakich
|
|
latach panował — w ogłoszeniu nowej wersji, w changelogu i przy `!papież`
|
|
- `!papież` pisze to samo zdaniem, którym opisuje każdego innego papieża, więc
|
|
nie trzeba już zgadywać, czy «Callistus I» to ten piętnasty, czy szesnasty
|
|
|
|
## 0.1.6 — Zephyrinus
|
|
|
|
papież nr 15 z 267, pontyfikat 199-217
|
|
|
|
- statystyki o 21:37 są od teraz o **dzisiejszym** dniu, a nie o wczorajszym —
|
|
wieczorny post pokazuje wreszcie ten dzień, który właśnie mijał
|
|
- licznik zamyka się o 21:37, więc to, co napiszecie później, wpada do jutra;
|
|
post sam to mówi, żeby liczba nie udawała całej doby
|
|
- **jedna wiadomość, nie kilka**: dzień, tydzień, miesiąc i to, co bot
|
|
przegapił, są blokami w jednym poście, a nie osobnymi powiadomieniami
|
|
- dzień, którego bot przegapił (bo go nie było o 21:37), nadal zostanie
|
|
wysłany później — nic nie ginie
|
|
|
|
## 0.1.5 — Victor I
|
|
|
|
papież nr 14 z 267, pontyfikat 189-199
|
|
|
|
- ogłoszenie nowej wersji przychodzi teraz ze zdjęciem papieża, po którym ta
|
|
wersja się nazywa, i z linkiem do jego strony na polskiej Wikipedii —
|
|
dokładnie tak, jak robi to `!papież`
|
|
- wersje nazywają się od teraz po łacinie: ta jest «Victor I», a nie
|
|
«Wiktor I», a poprzednia była «Eleutherius», nie «Eleuteriusz»
|
|
|
|
## 0.1.4 — Eleutherius
|
|
|
|
papież nr 13 z 267, pontyfikat 175-189
|
|
|
|
- `!pomoc` (albo `!help`) wypisuje wszystkie komendy i mówi jednym zdaniem,
|
|
co każda robi — do tej pory nigdzie na czacie nie było ich listy
|
|
|
|
## 0.1.3 — Soterius
|
|
|
|
papież nr 12 z 267, pontyfikat 166-175
|
|
|
|
- "POCZEKAJ 1 SEKUND" odmienia się wreszcie po polsku — teraz jest
|
|
1 SEKUNDĘ, 2 SEKUNDY, 5 SEKUND
|
|
- odczekanie tego, co bot każe, wreszcie działa: dotąd każda nieudana próba
|
|
po cichu przedłużała blokadę, więc kto grzecznie czekał, ten dostawał
|
|
odmowę w kółko
|
|
|
|
## 0.1.2 — Anicetus
|
|
|
|
papież nr 11 z 267, pontyfikat 155-166
|
|
|
|
- `!ja` pokazywał wszystkim tę samą godzinę (12:00) — to był artefakt
|
|
danych sprzed przebudowy licznika, a nie wasze zwyczaje. Teraz pokazuje
|
|
prawdziwe godziny, a komu ich nie znamy, temu nie zmyśla
|
|
|
|
## 0.1.1 — Pius I
|
|
|
|
papież nr 10 z 267, pontyfikat 140-155
|
|
|
|
- komendy mówią teraz, co pokazują — `!korona` na pustych danych tłumaczy,
|
|
co się w niej pojawi, zamiast samego "za mało danych"
|
|
- `!ja` pisze "między 12:00 a 13:00" zamiast "o 12:00" — bo to godzina, a
|
|
nie moment
|
|
|
|
Releases older than the ten most recent live in **`DOCS-changelog-archive.md`**.
|
|
Nothing reads them: `announce` caps a backlog at ten releases, and `since()`
|
|
resolves the floor from the version ladder rather than from this file, so a
|
|
group that has been quiet for twenty releases still gets the ten newest that
|
|
are here. Moved when this file crossed the shared 250-line cap; keep doing
|
|
that rather than letting it grow.
|