fix(roadtrip): say which filter emptied the list, and stop typing a limit racing itself

Four small things, and one that was not this branch's fault but is now its
neighbour.

The driving limits saved on every keystroke. Typing "180" sent three settings
writes carrying 1, 18 and 180, unordered and concurrent over HTTP/2, so
whichever the server committed last won: the number that decides every
over-budget warning could quietly end up a tenth of what was typed, and only
show it after the next reload. Typed locally now, committed on blur or Enter,
and a value that did not actually change writes nothing.

The empty-result message always blamed the name box. Four controls narrow that
list and only one of them is the name, so picking a section with no hits
produced `Nothing on the way matches ""` — empty quotes naming a filter the
reader never set. The count line above it was gated the same way, so the section
case lost its "x of y" as well. Both follow whatever actually narrowed the list.

The check-out dropdown printed a bare ISO date, the only place in the planner
that did; it goes through the same helper as the rail beside it.

Switching an addon off left open MCP sessions holding its write tools. A `when:`
gate runs once per session, at attach time, so the tools stay registered and
callable while the REST half answers 404 for the same user in the same moment —
and the list that decides whether to tear those sessions down had drifted:
airtrail and collections gate tools and were missing from it, which this addon
would have inherited. The list now sits beside ADDON_IDS and a parity test reads
the gates out of the source and holds it there. Read out of the source rather
than out of a runtime registry on purpose: a runtime set only holds the gates
whose modules the caller happened to import, so it would pass in a suite that
imports none — which is the shape of test that hid this in the first place.

RoadtripLimitsCard gets the test it never had, including the one case that
matters: three keystrokes are not three writes.
This commit is contained in:
Maurice
2026-09-07 17:23:55 +02:00
committed by Maurice
parent 44d52ab215
commit b2d9b25bb6
30 changed files with 318 additions and 20 deletions
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'ضمن',
'roadtrip.poi.filter': 'تصفية حسب الاسم',
'roadtrip.poi.noMatch': 'لا يوجد على الطريق ما يطابق «{name}».',
'roadtrip.poi.noneMatchFilters': 'لا يوجد شيء على الطريق يطابق عوامل التصفية هذه.',
'roadtrip.poi.foundFiltered': '{count} من {total} على الطريق',
'roadtrip.poi.truncated': 'في {count} من المقاطع كان هناك أكثر مما تتسع له استجابة واحدة — قلّص الممر لرؤية البقية.',
'roadtrip.poi.search': 'بحث',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Num raio de',
'roadtrip.poi.filter': 'Filtrar por nome',
'roadtrip.poi.noMatch': 'Nada no trajeto corresponde a “{name}”.',
'roadtrip.poi.noneMatchFilters': 'Nada no caminho corresponde a esses filtros.',
'roadtrip.poi.foundFiltered': '{count} de {total} no trajeto',
'roadtrip.poi.truncated': 'Em {count} trechos havia mais do que cabe em uma resposta — estreite o corredor para ver o restante.',
'roadtrip.poi.search': 'Buscar',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'En un radi de',
'roadtrip.poi.filter': 'Filtra per nom',
'roadtrip.poi.noMatch': 'Res del trajecte no coincideix amb «{name}».',
'roadtrip.poi.noneMatchFilters': 'Res del camí no coincideix amb aquests filtres.',
'roadtrip.poi.foundFiltered': '{count} de {total} al trajecte',
'roadtrip.poi.truncated': 'En {count} trams hi havia més del que cap en una resposta: estreny el corredor per veure la resta.',
'roadtrip.poi.search': 'Cerca',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Do',
'roadtrip.poi.filter': 'Filtrovat podle názvu',
'roadtrip.poi.noMatch': 'Na trase nic neodpovídá „{name}“.',
'roadtrip.poi.noneMatchFilters': 'Nic na trase neodpovídá těmto filtrům.',
'roadtrip.poi.foundFiltered': '{count} z {total} na trase',
'roadtrip.poi.truncated': 'Na {count} úsecích jich bylo více, než se vejde do jedné odpovědi — zužte koridor, abyste viděli zbytek.',
'roadtrip.poi.search': 'Hledat',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Im Umkreis',
'roadtrip.poi.filter': 'Nach Name filtern',
'roadtrip.poi.noMatch': 'Unterwegs passt nichts zu „{name}“.',
'roadtrip.poi.noneMatchFilters': 'Nichts auf dem Weg passt zu diesen Filtern.',
'roadtrip.poi.foundFiltered': '{count} von {total} unterwegs',
'roadtrip.poi.truncated': 'Auf {count} Abschnitten gab es mehr, als in eine Antwort passt — den Korridor schmaler machen, um den Rest zu sehen.',
'roadtrip.poi.search': 'Suchen',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Within',
'roadtrip.poi.filter': 'Filter by name',
'roadtrip.poi.noMatch': 'Nothing on the way matches “{name}”.',
'roadtrip.poi.noneMatchFilters': 'Nothing on the way matches these filters.',
'roadtrip.poi.foundFiltered': '{count} of {total} on the way',
'roadtrip.poi.truncated': '{count} stretches had more than fits in one answer — narrow the corridor to see the rest.',
'roadtrip.poi.search': 'Search',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'En un radio de',
'roadtrip.poi.filter': 'Filtrar por nombre',
'roadtrip.poi.noMatch': 'Nada en la ruta coincide con «{name}».',
'roadtrip.poi.noneMatchFilters': 'Nada en el camino coincide con estos filtros.',
'roadtrip.poi.foundFiltered': '{count} de {total} en la ruta',
'roadtrip.poi.truncated': 'En {count} tramos había más de lo que cabe en una respuesta: reduce el corredor para ver el resto.',
'roadtrip.poi.search': 'Buscar',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Dans un rayon de',
'roadtrip.poi.filter': 'Filtrer par nom',
'roadtrip.poi.noMatch': 'Rien sur le trajet ne correspond à « {name} ».',
'roadtrip.poi.noneMatchFilters': 'Rien sur le trajet ne correspond à ces filtres.',
'roadtrip.poi.foundFiltered': '{count} sur {total} sur le trajet',
'roadtrip.poi.truncated': 'Sur {count} tronçons, il y en avait plus que ce qu’une réponse peut contenir : réduisez le corridor pour voir le reste.',
'roadtrip.poi.search': 'Rechercher',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Εντός',
'roadtrip.poi.filter': 'Φιλτράρισμα κατά όνομα',
'roadtrip.poi.noMatch': 'Τίποτα στη διαδρομή δεν ταιριάζει με «{name}».',
'roadtrip.poi.noneMatchFilters': 'Τίποτα στη διαδρομή δεν ταιριάζει με αυτά τα φίλτρα.',
'roadtrip.poi.foundFiltered': '{count} από {total} στη διαδρομή',
'roadtrip.poi.truncated': 'Σε {count} τμήματα υπήρχαν περισσότερα από όσα χωρούν σε μία απάντηση — στενέψτε τον διάδρομο για να δείτε τα υπόλοιπα.',
'roadtrip.poi.search': 'Αναζήτηση',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Ezen belül',
'roadtrip.poi.filter': 'Szűrés név szerint',
'roadtrip.poi.noMatch': 'Az útvonalon semmi sem egyezik ezzel: „{name}”.',
'roadtrip.poi.noneMatchFilters': 'Az útvonalon semmi sem felel meg ezeknek a szűrőknek.',
'roadtrip.poi.foundFiltered': '{count} / {total} az útvonalon',
'roadtrip.poi.truncated': '{count} szakaszon több volt, mint amennyi egy válaszba fér — szűkítse a folyosót a többi megtekintéséhez.',
'roadtrip.poi.search': 'Keresés',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Dalam',
'roadtrip.poi.filter': 'Saring menurut nama',
'roadtrip.poi.noMatch': 'Tidak ada di rute yang cocok dengan “{name}”.',
'roadtrip.poi.noneMatchFilters': 'Tidak ada di sepanjang rute yang cocok dengan filter ini.',
'roadtrip.poi.foundFiltered': '{count} dari {total} di rute',
'roadtrip.poi.truncated': 'Di {count} ruas ada lebih banyak daripada yang muat dalam satu jawaban — persempit koridor untuk melihat sisanya.',
'roadtrip.poi.search': 'Cari',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Entro',
'roadtrip.poi.filter': 'Filtra per nome',
'roadtrip.poi.noMatch': 'Lungo il percorso non c’è nulla che corrisponda a “{name}”.',
'roadtrip.poi.noneMatchFilters': 'Niente lungo il percorso corrisponde a questi filtri.',
'roadtrip.poi.foundFiltered': '{count} di {total} lungo il percorso',
'roadtrip.poi.truncated': 'Su {count} tratti ce n’erano più di quanti ne stiano in una risposta: restringi il corridoio per vedere il resto.',
'roadtrip.poi.search': 'Cerca',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': '範囲',
'roadtrip.poi.filter': '名前で絞り込む',
'roadtrip.poi.noMatch': 'ルート沿いに「{name}」に一致するものはありません。',
'roadtrip.poi.noneMatchFilters': 'この条件に合うものは道中にありません。',
'roadtrip.poi.foundFiltered': 'ルート沿いの {total} 件中 {count} 件',
'roadtrip.poi.truncated': '{count} 区間で一度に返せる件数を超えました。回廊を狭めると残りを確認できます。',
'roadtrip.poi.search': '検索',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': '반경',
'roadtrip.poi.filter': '이름으로 필터',
'roadtrip.poi.noMatch': '경로상에 “{name}”와(과) 일치하는 곳이 없습니다.',
'roadtrip.poi.noneMatchFilters': '이 필터에 맞는 곳이 경로에 없습니다.',
'roadtrip.poi.foundFiltered': '경로상 {total}곳 중 {count}곳',
'roadtrip.poi.truncated': '{count}개 구간에서 한 번에 반환할 수 있는 수를 넘었습니다. 회랑을 좁히면 나머지를 볼 수 있습니다.',
'roadtrip.poi.search': '검색',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Binnen',
'roadtrip.poi.filter': 'Filteren op naam',
'roadtrip.poi.noMatch': 'Niets onderweg komt overeen met “{name}”.',
'roadtrip.poi.noneMatchFilters': 'Niets onderweg voldoet aan deze filters.',
'roadtrip.poi.foundFiltered': '{count} van {total} onderweg',
'roadtrip.poi.truncated': 'Op {count} stukken waren er meer dan in één antwoord passen — maak de corridor smaller om de rest te zien.',
'roadtrip.poi.search': 'Zoeken',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'W promieniu',
'roadtrip.poi.filter': 'Filtruj wedug nazwy',
'roadtrip.poi.noMatch': 'Nic po drodze nie pasuje do „{name}”.',
'roadtrip.poi.noneMatchFilters': 'Nic po drodze nie pasuje do tych filtrów.',
'roadtrip.poi.foundFiltered': '{count} z {total} po drodze',
'roadtrip.poi.truncated': 'Na {count} odcinkach było więcej, niż mieści się w jednej odpowiedzi — zawęź korytarz, aby zobaczyć resztę.',
'roadtrip.poi.search': 'Szukaj',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'В радиусе',
'roadtrip.poi.filter': 'Фильтр по названию',
'roadtrip.poi.noMatch': 'По пути ничего не соответствует «{name}».',
'roadtrip.poi.noneMatchFilters': 'На маршруте нет ничего, что подходит под эти фильтры.',
'roadtrip.poi.foundFiltered': '{count} из {total} по пути',
'roadtrip.poi.truncated': 'На {count} участках нашлось больше, чем помещается в один ответ — сузьте коридор, чтобы увидеть остальное.',
'roadtrip.poi.search': 'Искать',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Inom',
'roadtrip.poi.filter': 'Filtrera på namn',
'roadtrip.poi.noMatch': 'Inget längs vägen matchar ”{name}”.',
'roadtrip.poi.noneMatchFilters': 'Inget längs vägen matchar de här filtren.',
'roadtrip.poi.foundFiltered': '{count} av {total} längs vägen',
'roadtrip.poi.truncated': 'På {count} sträckor fanns fler än vad som får plats i ett svar – gör korridoren smalare för att se resten.',
'roadtrip.poi.search': 'Sök',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Mesafe',
'roadtrip.poi.filter': 'Ada göre süz',
'roadtrip.poi.noMatch': 'Yol boyunca “{name}” ile eşleşen bir şey yok.',
'roadtrip.poi.noneMatchFilters': 'Yol boyunca bu filtrelere uyan bir yer yok.',
'roadtrip.poi.foundFiltered': 'yol üzerinde {total} içinden {count}',
'roadtrip.poi.truncated': '{count} bölümde bir yanıta sığandan fazlası vardı — geri kalanı görmek için koridoru daraltın.',
'roadtrip.poi.search': 'Ara',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'У радіусі',
'roadtrip.poi.filter': 'Фільтр за назвою',
'roadtrip.poi.noMatch': 'Дорогою ніщо не відповідає «{name}».',
'roadtrip.poi.noneMatchFilters': 'На маршруті немає нічого, що відповідає цим фільтрам.',
'roadtrip.poi.foundFiltered': '{count} з {total} дорогою',
'roadtrip.poi.truncated': 'На {count} відрізках знайшлося більше, ніж уміщується в одну відповідь — звузьте коридор, щоб побачити решту.',
'roadtrip.poi.search': 'Шукати',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': 'Trong vòng',
'roadtrip.poi.filter': 'Lọc theo tên',
'roadtrip.poi.noMatch': 'Không có gì trên đường khớp với “{name}”.',
'roadtrip.poi.noneMatchFilters': 'Không có gì trên đường phù hợp với các bộ lọc này.',
'roadtrip.poi.foundFiltered': '{count} trong {total} trên đường',
'roadtrip.poi.truncated': 'Có {count} đoạn nhiều hơn mức một phản hồi chứa được — thu hẹp hành lang để xem phần còn lại.',
'roadtrip.poi.search': 'Tìm kiếm',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': '範圍內',
'roadtrip.poi.filter': '依名稱篩選',
'roadtrip.poi.noMatch': '沿途沒有與「{name}」相符的地點。',
'roadtrip.poi.noneMatchFilters': '沿途沒有符合這些篩選條件的地點。',
'roadtrip.poi.foundFiltered': '沿途 {total} 個中的 {count} 個',
'roadtrip.poi.truncated': '有 {count} 段的結果超出單次回應上限,縮小走廊寬度可查看其餘部分。',
'roadtrip.poi.search': '搜尋',
+1
View File
@@ -72,6 +72,7 @@ const roadtrip: TranslationStrings = {
'roadtrip.poi.within': '范围内',
'roadtrip.poi.filter': '按名称筛选',
'roadtrip.poi.noMatch': '沿途没有与“{name}”匹配的地点。',
'roadtrip.poi.noneMatchFilters': '沿途没有符合这些筛选条件的地点。',
'roadtrip.poi.foundFiltered': '沿途 {total} 个中的 {count} 个',
'roadtrip.poi.truncated': '有 {count} 段的结果超出单次响应上限,缩小走廊宽度可查看其余部分。',
'roadtrip.poi.search': '搜索',