From 80890dd715ad481135430cdd14c6b6c3aabea291 Mon Sep 17 00:00:00 2001 From: KodeStar Date: Fri, 16 Oct 2026 12:59:14 +0100 Subject: [PATCH] Bridge 1b: the ASR worker wait in the console, quiet like the other self-resuming parks - asr_worker_waiting (no ASR worker connected and the Bridge's fallback is wait, or no ASR of its own) joins transientParks: it resumes by itself, and a sleeping laptop worker would otherwise park, and announce, each book that reaches its transcription. - The console words it (KNOWN_PARKS, bridge.park.asr_worker_waiting), and library_not_writable, which had no sentence; the Workers card's empty state points at the Bridge's Workers tab instead of a later version. - es/fr/it/pt: the Bridge's gender and the job's word as elsewhere. --- admin-ui/src/features/bridge/bridge-topic.tsx | 2 +- admin-ui/src/features/bridge/generate-model.ts | 2 ++ admin-ui/src/i18n/locales/de.json | 4 +++- admin-ui/src/i18n/locales/en.json | 4 +++- admin-ui/src/i18n/locales/es.json | 4 +++- admin-ui/src/i18n/locales/fr.json | 4 +++- admin-ui/src/i18n/locales/it.json | 4 +++- admin-ui/src/i18n/locales/pt.json | 4 +++- internal/bridge/jobs.go | 15 ++++++++------- internal/bridge/sidecars_test.go | 4 ++++ 10 files changed, 33 insertions(+), 14 deletions(-) diff --git a/admin-ui/src/features/bridge/bridge-topic.tsx b/admin-ui/src/features/bridge/bridge-topic.tsx index 000017ee..e61384c0 100644 --- a/admin-ui/src/features/bridge/bridge-topic.tsx +++ b/admin-ui/src/features/bridge/bridge-topic.tsx @@ -469,7 +469,7 @@ function LibraryRow({ ); } -/** The ASR workers the Bridge reports (Phase 1b), or that they come later. */ +/** The ASR workers the Bridge reports (Phase 1b), or that none has connected yet. */ function WorkersCard({ status }: { status: BridgeStatus }) { const { t, i18n } = useTranslation(); const lang = i18n.resolvedLanguage ?? 'en'; diff --git a/admin-ui/src/features/bridge/generate-model.ts b/admin-ui/src/features/bridge/generate-model.ts index 594bdce1..9218aaf8 100644 --- a/admin-ui/src/features/bridge/generate-model.ts +++ b/admin-ui/src/features/bridge/generate-model.ts @@ -127,6 +127,7 @@ export const KNOWN_PARKS = [ 'manifest_changed', 'fix_loop_exhausted', 'asr_decode_timeout', + 'asr_worker_waiting', 'contrib_unavailable', 'core_needed', 'core_pending', @@ -137,6 +138,7 @@ export const KNOWN_PARKS = [ 'supervisor_escalated', 'supervisor_budget', 'book_not_writable', + 'library_not_writable', 'agent_credential_refused', ] as const; diff --git a/admin-ui/src/i18n/locales/de.json b/admin-ui/src/i18n/locales/de.json index 23f66d0e..35d4c3b0 100644 --- a/admin-ui/src/i18n/locales/de.json +++ b/admin-ui/src/i18n/locales/de.json @@ -2659,7 +2659,7 @@ "bridge.result.took": "dauerte {{time}}", "bridge.workers.title": "Worker", "bridge.workers.none": "Keine Worker", - "bridge.workers.noneBody": "Worker, die Audio auf einem anderen Computer transkribieren, kommen in einer späteren Version.", + "bridge.workers.noneBody": "Noch kein ASR-Worker hat sich verbunden. Füge auf der Seite der Bridge (Workers) einen hinzu, um auf einem schnelleren Computer zu transkribieren, etwa einem Mac mit Apple Silicon.", "bridge.unpair.title": "Bridge entkoppeln", "bridge.unpair.body": "Die Bridge hört bei ihrem nächsten Aufruf auf zu arbeiten. Ihre Aufgaben bleiben.", "bridge.unpair.action": "Entkoppeln...", @@ -2705,6 +2705,7 @@ "bridge.park.manifest_changed": "Die Dateien des Buchs haben sich während der Aufgabe geändert.", "bridge.park.fix_loop_exhausted": "Die Prüfungen fanden auch nach mehreren Korrekturen noch Fehler.", "bridge.park.asr_decode_timeout": "Ein Kapitel hat zu lange zum Transkribieren gebraucht.", + "bridge.park.asr_worker_waiting": "Wartet auf einen ASR-Worker. Die Aufgabe läuft weiter, sobald sich einer verbindet.", "bridge.park.contrib_unavailable": "Zum Beitragen braucht die Bridge ein GitHub-Token.", "bridge.park.core_needed": "Die Community hat noch keinen Eintrag für dieses Buch. Lege auf der Bridge einen an, um beizutragen.", "bridge.park.core_pending": "Wartet darauf, dass der Community-Eintrag des Buchs angenommen wird.", @@ -2715,6 +2716,7 @@ "bridge.park.supervisor_escalated": "Die Bridge hat die Aufgabe angehalten, damit jemand sie sich ansieht.", "bridge.park.supervisor_budget": "Die Aufsicht der Bridge hat ihr Ausgabenlimit erreicht.", "bridge.park.book_not_writable": "Die Bridge kann nicht in den Ordner dieses Buchs schreiben.", + "bridge.park.library_not_writable": "Die Bridge kann nicht mehr in die Bibliothek dieses Buchs schreiben. Die Aufgabe läuft weiter, sobald sie es kann.", "bridge.park.agent_credential_refused": "Die Anmeldedaten des Agenten wurden abgelehnt. Ersetze sie im Agent-Container.", "bridge.park.unknown": "Die Aufgabe wartet auf dich ({{code}}).", "bridge.generate.title": "Figuren und Zusammenfassungen", diff --git a/admin-ui/src/i18n/locales/en.json b/admin-ui/src/i18n/locales/en.json index 8c8719fc..087c2345 100644 --- a/admin-ui/src/i18n/locales/en.json +++ b/admin-ui/src/i18n/locales/en.json @@ -2659,7 +2659,7 @@ "bridge.result.took": "took {{time}}", "bridge.workers.title": "Workers", "bridge.workers.none": "No workers", - "bridge.workers.noneBody": "Workers that transcribe audio on another computer come in a later version.", + "bridge.workers.noneBody": "No ASR worker has connected. Add one on the Bridge's page (Workers) to transcribe on a faster computer, such as a Mac with Apple Silicon.", "bridge.unpair.title": "Unpair the bridge", "bridge.unpair.body": "The Bridge stops working at its next call. Its jobs stay.", "bridge.unpair.action": "Unpair...", @@ -2705,6 +2705,7 @@ "bridge.park.manifest_changed": "The book's files changed while the job was running.", "bridge.park.fix_loop_exhausted": "The checks kept finding mistakes after several fixes.", "bridge.park.asr_decode_timeout": "A chapter took too long to transcribe.", + "bridge.park.asr_worker_waiting": "Waiting for an ASR worker. The job carries on once one connects.", "bridge.park.contrib_unavailable": "Contributing needs a GitHub token on the Bridge.", "bridge.park.core_needed": "The community has no entry for this book yet. Add one on the Bridge to contribute.", "bridge.park.core_pending": "Waiting for the book's community entry to be accepted.", @@ -2715,6 +2716,7 @@ "bridge.park.supervisor_escalated": "The Bridge stopped the job for a person to look at.", "bridge.park.supervisor_budget": "The Bridge's supervisor reached its spending limit.", "bridge.park.book_not_writable": "The Bridge can't write to this book's folder.", + "bridge.park.library_not_writable": "The Bridge can't write to this book's library any more. The job carries on once it can.", "bridge.park.agent_credential_refused": "The agent's credential was refused. Replace it in the agent container.", "bridge.park.unknown": "The job is waiting for you ({{code}}).", "bridge.generate.title": "Characters and recaps", diff --git a/admin-ui/src/i18n/locales/es.json b/admin-ui/src/i18n/locales/es.json index c118b7a7..6038447a 100644 --- a/admin-ui/src/i18n/locales/es.json +++ b/admin-ui/src/i18n/locales/es.json @@ -2804,7 +2804,7 @@ "bridge.result.took": "tardó {{time}}", "bridge.workers.title": "Workers", "bridge.workers.none": "No hay workers", - "bridge.workers.noneBody": "Los workers que transcriben audio en otro ordenador llegan en una versión posterior.", + "bridge.workers.noneBody": "Ningún worker de ASR se ha conectado. Añade uno en la página de la Bridge (Workers) para transcribir en un ordenador más rápido, como un Mac con Apple Silicon.", "bridge.unpair.title": "Desvincular la bridge", "bridge.unpair.body": "La Bridge deja de funcionar en su próxima llamada. Sus trabajos se quedan.", "bridge.unpair.action": "Desvincular...", @@ -2850,6 +2850,7 @@ "bridge.park.manifest_changed": "Los archivos del libro cambiaron mientras se hacía el trabajo.", "bridge.park.fix_loop_exhausted": "Las comprobaciones siguieron encontrando errores tras varias correcciones.", "bridge.park.asr_decode_timeout": "Un capítulo tardó demasiado en transcribirse.", + "bridge.park.asr_worker_waiting": "Esperando a un worker de ASR. El trabajo sigue en cuanto se conecte uno.", "bridge.park.contrib_unavailable": "Para contribuir, la Bridge necesita un token de GitHub.", "bridge.park.core_needed": "La comunidad aún no tiene una entrada para este libro. Añade una en la Bridge para contribuir.", "bridge.park.core_pending": "Esperando a que se acepte la entrada del libro en la comunidad.", @@ -2860,6 +2861,7 @@ "bridge.park.supervisor_escalated": "La Bridge detuvo el trabajo para que lo revise una persona.", "bridge.park.supervisor_budget": "El supervisor de la Bridge llegó a su límite de gasto.", "bridge.park.book_not_writable": "La Bridge no puede escribir en la carpeta de este libro.", + "bridge.park.library_not_writable": "La Bridge ya no puede escribir en la biblioteca de este libro. El trabajo sigue en cuanto pueda.", "bridge.park.agent_credential_refused": "Se rechazó la credencial del agente. Sustitúyela en el contenedor del agente.", "bridge.park.unknown": "El trabajo te está esperando ({{code}}).", "bridge.generate.title": "Personajes y resúmenes", diff --git a/admin-ui/src/i18n/locales/fr.json b/admin-ui/src/i18n/locales/fr.json index 7b08b62a..6aa2c660 100644 --- a/admin-ui/src/i18n/locales/fr.json +++ b/admin-ui/src/i18n/locales/fr.json @@ -2804,7 +2804,7 @@ "bridge.result.took": "en {{time}}", "bridge.workers.title": "Workers", "bridge.workers.none": "Aucun worker", - "bridge.workers.noneBody": "Les workers qui transcrivent l'audio sur un autre ordinateur arrivent dans une version ultérieure.", + "bridge.workers.noneBody": "Aucun worker ASR ne s'est connecté. Ajoutez-en un sur la page de la Bridge (Workers) pour transcrire sur un ordinateur plus rapide, comme un Mac avec Apple Silicon.", "bridge.unpair.title": "Dissocier la bridge", "bridge.unpair.body": "La Bridge cesse de fonctionner à son prochain appel. Ses tâches restent.", "bridge.unpair.action": "Dissocier...", @@ -2850,6 +2850,7 @@ "bridge.park.manifest_changed": "Les fichiers du livre ont changé pendant la tâche.", "bridge.park.fix_loop_exhausted": "Les vérifications trouvaient encore des erreurs après plusieurs corrections.", "bridge.park.asr_decode_timeout": "Un chapitre a mis trop de temps à être transcrit.", + "bridge.park.asr_worker_waiting": "En attente d'un worker ASR. La tâche reprend dès qu'il s'en connecte un.", "bridge.park.contrib_unavailable": "Pour contribuer, la Bridge a besoin d'un jeton GitHub.", "bridge.park.core_needed": "La communauté n'a pas encore d'entrée pour ce livre. Ajoutez-en une sur la Bridge pour contribuer.", "bridge.park.core_pending": "En attente de l'acceptation de l'entrée communautaire du livre.", @@ -2860,6 +2861,7 @@ "bridge.park.supervisor_escalated": "La Bridge a arrêté la tâche pour qu'une personne l'examine.", "bridge.park.supervisor_budget": "Le superviseur de la Bridge a atteint sa limite de dépenses.", "bridge.park.book_not_writable": "La Bridge ne peut pas écrire dans le dossier de ce livre.", + "bridge.park.library_not_writable": "La Bridge ne peut plus écrire dans la bibliothèque de ce livre. La tâche reprend dès qu'elle le peut.", "bridge.park.agent_credential_refused": "L'identifiant de l'agent a été refusé. Remplacez-le dans le conteneur de l'agent.", "bridge.park.unknown": "La tâche vous attend ({{code}}).", "bridge.generate.title": "Personnages et résumés", diff --git a/admin-ui/src/i18n/locales/it.json b/admin-ui/src/i18n/locales/it.json index 4eed4e29..a8ac5b8e 100644 --- a/admin-ui/src/i18n/locales/it.json +++ b/admin-ui/src/i18n/locales/it.json @@ -2804,7 +2804,7 @@ "bridge.result.took": "in {{time}}", "bridge.workers.title": "Worker", "bridge.workers.none": "Nessun worker", - "bridge.workers.noneBody": "I worker che trascrivono l'audio su un altro computer arrivano in una versione successiva.", + "bridge.workers.noneBody": "Nessun worker ASR si è collegato. Aggiungine uno nella pagina della Bridge (Workers) per trascrivere su un computer più veloce, come un Mac con Apple Silicon.", "bridge.unpair.title": "Scollega la bridge", "bridge.unpair.body": "La Bridge smette di funzionare alla sua prossima chiamata. I suoi lavori restano.", "bridge.unpair.action": "Scollega...", @@ -2850,6 +2850,7 @@ "bridge.park.manifest_changed": "I file del libro sono cambiati durante il lavoro.", "bridge.park.fix_loop_exhausted": "I controlli trovavano ancora errori dopo diverse correzioni.", "bridge.park.asr_decode_timeout": "Un capitolo ha richiesto troppo tempo per la trascrizione.", + "bridge.park.asr_worker_waiting": "In attesa di un worker ASR. Il lavoro riprende appena se ne collega uno.", "bridge.park.contrib_unavailable": "Per contribuire, la Bridge ha bisogno di un token GitHub.", "bridge.park.core_needed": "La community non ha ancora una voce per questo libro. Aggiungine una sulla Bridge per contribuire.", "bridge.park.core_pending": "In attesa che la voce del libro nella community venga accettata.", @@ -2860,6 +2861,7 @@ "bridge.park.supervisor_escalated": "La Bridge ha fermato il lavoro perché lo veda una persona.", "bridge.park.supervisor_budget": "Il supervisore della Bridge ha raggiunto il suo limite di spesa.", "bridge.park.book_not_writable": "La Bridge non può scrivere nella cartella di questo libro.", + "bridge.park.library_not_writable": "La Bridge non può più scrivere nella libreria di questo libro. Il lavoro riprende appena può.", "bridge.park.agent_credential_refused": "La credenziale dell'agente è stata rifiutata. Sostituiscila nel container dell'agente.", "bridge.park.unknown": "Il lavoro ti aspetta ({{code}}).", "bridge.generate.title": "Personaggi e riassunti", diff --git a/admin-ui/src/i18n/locales/pt.json b/admin-ui/src/i18n/locales/pt.json index c735e9ab..6ac4509b 100644 --- a/admin-ui/src/i18n/locales/pt.json +++ b/admin-ui/src/i18n/locales/pt.json @@ -2804,7 +2804,7 @@ "bridge.result.took": "demorou {{time}}", "bridge.workers.title": "Workers", "bridge.workers.none": "Sem workers", - "bridge.workers.noneBody": "Os workers que transcrevem áudio noutro computador chegam numa versão posterior.", + "bridge.workers.noneBody": "Nenhum worker de ASR se ligou. Adicione um na página da Bridge (Workers) para transcrever num computador mais rápido, como um Mac com Apple Silicon.", "bridge.unpair.title": "Desemparelhar a bridge", "bridge.unpair.body": "A Bridge deixa de funcionar na próxima chamada. Os trabalhos dela ficam.", "bridge.unpair.action": "Desemparelhar...", @@ -2850,6 +2850,7 @@ "bridge.park.manifest_changed": "Os ficheiros do livro mudaram durante o trabalho.", "bridge.park.fix_loop_exhausted": "As verificações continuaram a encontrar erros após várias correções.", "bridge.park.asr_decode_timeout": "Um capítulo demorou demasiado a transcrever.", + "bridge.park.asr_worker_waiting": "À espera de um worker de ASR. O trabalho continua assim que um se ligar.", "bridge.park.contrib_unavailable": "Para contribuir, a Bridge precisa de um token do GitHub.", "bridge.park.core_needed": "A comunidade ainda não tem uma entrada para este livro. Adicione uma na Bridge para contribuir.", "bridge.park.core_pending": "À espera de que a entrada do livro na comunidade seja aceite.", @@ -2860,6 +2861,7 @@ "bridge.park.supervisor_escalated": "A Bridge parou o trabalho para uma pessoa o ver.", "bridge.park.supervisor_budget": "O supervisor da Bridge atingiu o limite de gastos.", "bridge.park.book_not_writable": "A Bridge não consegue escrever na pasta deste livro.", + "bridge.park.library_not_writable": "A Bridge já não consegue escrever na biblioteca deste livro. O trabalho continua assim que conseguir.", "bridge.park.agent_credential_refused": "A credencial do agente foi recusada. Substitua-a no contentor do agente.", "bridge.park.unknown": "O trabalho está à sua espera ({{code}}).", "bridge.generate.title": "Personagens e resumos", diff --git a/internal/bridge/jobs.go b/internal/bridge/jobs.go index 6f712cb7..839bac03 100644 --- a/internal/bridge/jobs.go +++ b/internal/bridge/jobs.go @@ -873,13 +873,14 @@ func (s *Service) UpdateHeld(ctx context.Context, id int64, u Update) (*Job, err return job, nil } -// transientParks are the park codes that are not news: the agent's rate limit -// and a short outage of the agent container, which the Bridge resumes by itself -// once they pass (telling an admin about every one would flood a phone). Any -// other park waits on something a person sees to, or is long enough to hear -// about (a monthly budget spent until the month turns, a credential refused), -// whatever its retry_at says. -var transientParks = []string{"agent_rate_limited", "agent_unavailable"} +// transientParks are the park codes that are not news: the agent's rate limit, +// a short outage of the agent container, and a wait for an ASR worker (a +// laptop worker asleep: each book that reaches its transcription would park in +// turn), which the Bridge resumes by itself once they pass (telling an admin +// about every one would flood a phone). Any other park waits on something a +// person sees to, or is long enough to hear about (a monthly budget spent until +// the month turns, a credential refused), whatever its retry_at says. +var transientParks = []string{"agent_rate_limited", "agent_unavailable", "asr_worker_waiting"} // Notable reports whether a job's move from the state `from` (fromCode: the // park code it named there, "" for none) is one the server tells admins about diff --git a/internal/bridge/sidecars_test.go b/internal/bridge/sidecars_test.go index 29a126b2..9f30ee4f 100644 --- a/internal/bridge/sidecars_test.go +++ b/internal/bridge/sidecars_test.go @@ -199,6 +199,10 @@ func TestUpdateHeldReportsTheMove(t *testing.T) { {StateNeedsAttention, `{"step":"waiting","park":{"code":"agent_unavailable"}}`}, {StateRunning, `{"step":"fact_pass"}`}, {StateNeedsAttention, `{"step":"waiting","park":{"code":"agent_rate_limited",` + later + `}}`}, + {StateRunning, `{"step":"asr"}`}, + {StateNeedsAttention, `{"step":"asr","park":{"code":"asr_worker_waiting"}}`}, + {StateRunning, `{"step":"asr"}`}, + {StateNeedsAttention, `{"step":"waiting","park":{"code":"agent_rate_limited",` + later + `}}`}, // ...until, still parked, one turns into a park that isn't (its retry ran // into the book's budget), once. {StateNeedsAttention, `{"step":"waiting","park":{"code":"budget_exceeded"}}`},