basquetWi + New ticket
movilba MOVILBA-247

Stale Server Action tras un deploy falla en silencio en todo el resto de la app

Done normal cmcoder03-mba-l-cc

Found while fixing the dominio-search silence on the ficha (coder03, v5.4.176): a browser tab loaded before a deploy holds Server Action ids the new server no longer has, so the next call rejects with 'Server action not found'. Any call site without a catch fails silently - the user clicks and nothing happens. coder03 fixed the one call site Elazar hit (page.tsx, reload on that error, showError otherwise); every other Server Action call site in the app has the same exposure. Proposed fix: one global window.addEventListener('unhandledrejection') that matches the stale-action error and reloads once, with a guard against reload loops (e.g. a sessionStorage flag cleared on successful load) so a genuinely broken action does not spin the page. Decide guard shape before coding. Note this is a dev-only nuisance today because dev redeploys ~20x a night; in prod it appears on every deploy for tabs left open. == HECHO 2026-09-05 (coder03, e6442d00, dev v5.4.201; medido por proxy en v5.4.202) == Guardia elegida: UNA recarga por VERSION del bundle (sessionStorage 'movilba.bundleDesactualizado.recargaPorVersion' = packageJson.version). Si el error vuelve con la misma version no se recarga mas y se muestra el modal propio 'Versión anterior' / 'La aplicación se actualizó y esta pestaña quedó con una versión anterior. Recargá la página para continuar.' Cada deploy sube la version, asi que el siguiente deploy rehabilita la recarga; no hay marca temporal ni 'limpiar en carga exitosa'. Cobertura: (1) rechazos sin catch -> window.onunhandledrejection en lib/client-logger.ts (sigue logueando a app_logs, ademas recarga/avisa por CustomEvent que escucha NotificationProvider); (2) call sites con catch que muestran error.message -> showError/showWarning interceptan el texto en contexts/ErrorContext.tsx, nunca sale el texto crudo de Next; (3) tres catch que solo hacian console.error alrededor de una Server Action (ramales/[id], instalaciones/agregar, ExpedienteForm) pasan por manejarBundleDesactualizado. Deteccion: /server action not found/i y ChunkLoadError. vehiculos/[id]/page.tsx usa el modulo y conserva solo el dominio pendiente. Controles positivos (proxy, dev01): A) rechazo sintetico 'Server action not found.' sin catch -> recarga (perf nav type reload), marca = '5.4.202'; B) mismo rechazo tras recargar -> sin recarga, modal 'Versión anterior' con el texto propio; C) rechazo no-stale -> ni recarga ni modal; D) busqueda por dominio AA040BD -> /vehiculos/3350 (regresion OK). NO EJERCITADO: un stale REAL (pestaña vieja + deploy + click sobre una action real) - el control uso Promise.reject sintetico; la rama ChunkLoadError; los tres call sites de consola; el camino (2) con un showError real conteniendo el texto. == AUDIT e6442d00 -> 9f5e02ec, dev v5.4.204 == H1 (la recarga tiraba un formulario a medio escribir): listener 'input' en captura sobre document marca la pestaña como editada si el target esta dentro de un <form>; 'submit' la limpia. Con la marca puesta NO se recarga: modal 'Versión anterior' con texto propio que pide copiar lo escrito y recargar. El buscador por dominio de la ficha no esta en un <form>, sigue recargando. H2: la garantia es UNA recarga POR VERSION (no 'una'): una action rota de verdad recarga una vez por deploy antes del modal, y dos veces si la primera recarga trae version nueva. Aceptado y escrito en el modulo. Controles (proxy, v5.4.206): E editar/colectivo con #interno tipeado + rechazo stale -> sin recarga, modal con texto con-edicion, valor conservado. F /vehiculos sin tipear -> recarga una vez, marca '5.4.206'. NO ejercitado: 'submit' limpiando la marca; showError con el texto estando editado. == AUDIT r2 9f5e02ec -> 2dfb91d6, dev v5.4.210 (dev01 sirve v5.4.211, mismo codigo) == H1: la marca de edicion iba por <form> ancestro y media app de carga no usa <form>. Ahora va sobre el CONTROL (input/select/textarea con evento 'input'), salvo dentro de [data-sin-guardar] (buscador por dominio de la ficha, selector de tamaño de pagina de DataTableLayout). Texto del modal con edicion neutral: 'Para no perder lo que escribiste, copialo antes de recargar la página.' H2: 'submit' ya no limpia la marca (un envio rechazado dejaba todo cargado sin proteccion); la limpia el cambio de pathname. Controles (proxy, v5.4.211): G agregar/colectivo #dominio tipeado + rechazo stale -> sin recarga, modal neutral, valor conservado. H navegacion client-side a /vehiculos + rechazo -> recarga una vez. I ficha, dominio tipeado en el buscador + rechazo -> recarga una vez (opt-out). NO ejercitado: pagina con inputs sin <form> (perfil, admin/users/[id]); opt-out de DataTableLayout; envio fallido seguido de click stale. Nota: /vehiculos/agregar redirige a /vehiculos/agregar/colectivo, que SI tiene <form>; la premisa de audit sobre esa ruta era del redirect.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 6w ago
  • wi-cli-venus note · 5w ago
    Related fix already shipped on the ficha search path by coder03: 74b7256a (v5.4.178) - dominio persisted in sessionStorage before the reload and re-run on mount so the user lands on the target vehicle; Next version pinned in a comment (16.2.10, message text observed on the dev01 build); reload capped at one per failure, key cleared only when a search reaches the server. Positive controls via proxy: stale tab + deploy -> reload -> automatic navigation to /vehiculos/3350; fresh tab -> direct push, no stale row in app_logs. NOT exercised: the loop guard's second failure (modal), the Enter key path, a non-stale rejection. The global handler in this item must reuse that guard shape, not invent a second one.
  • wi-cli-venus assigned · 5w ago
    unassigned
  • wi-cli-venus assigned · 5w ago
    coder03-mba-l-cc
  • wi-cli-venus statusChanged · 5w ago
  • wi-cli-venus descriptionChanged · 5w ago
    was: Found while fixing the dominio-search silence on the ficha (coder03, v5.4.176): a browser tab loaded before a deploy holds Server Action ids the new server no longer has, so the next call rejects with 'Server action not found'. Any call site without a catch fails silently - the user clicks and nothing happens. coder03 fixed the one call site Elazar hit (page.tsx, reload on that error, showError otherwise); every other Server Action call site in the app has the same exposure. Proposed fix: one global window.addEventListener('unhandledrejection') that matches the stale-action error and reloads once, with a guard against reload loops (e.g. a sessionStorage flag cleared on successful load) so a genuinely broken action does not spin the page. Decide guard shape before coding. Note this is a dev-only nuisance today because dev redeploys ~20x a night; in prod it appears on every deploy for tabs left open.
  • wi-cli-venus completed · 5w ago
    completed
  • wi-cli-venus descriptionChanged · 5w ago
    was: Found while fixing the dominio-search silence on the ficha (coder03, v5.4.176): a browser tab loaded before a deploy holds Server Action ids the new server no longer has, so the next call rejects with 'Server action not found'. Any call site without a catch fails silently - the user clicks and nothing happens. coder03 fixed the one call site Elazar hit (page.tsx, reload on that error, showError otherwise); every other Server Action call site in the app has the same exposure. Proposed fix: one global window.addEventListener('unhandledrejection') that matches the stale-action error and reloads once, with a guard against reload loops (e.g. a sessionStorage flag cleared on successful load) so a genuinely broken action does not spin the page. Decide guard shape before coding. Note this is a dev-only nuisance today because dev redeploys ~20x a night; in prod it appears on every deploy for tabs left open. == HECHO 2026-09-05 (coder03, e6442d00, dev v5.4.201; medido por proxy en v5.4.202) == Guardia elegida: UNA recarga por VERSION del bundle (sessionStorage 'movilba.bundleDesactualizado.recargaPorVersion' = packageJson.version). Si el error vuelve con la misma version no se recarga mas y se muestra el modal propio 'Versión anterior' / 'La aplicación se actualizó y esta pestaña quedó con una versión anterior. Recargá la página para continuar.' Cada deploy sube la version, asi que el siguiente deploy rehabilita la recarga; no hay marca temporal ni 'limpiar en carga exitosa'. Cobertura: (1) rechazos sin catch -> window.onunhandledrejection en lib/client-logger.ts (sigue logueando a app_logs, ademas recarga/avisa por CustomEvent que escucha NotificationProvider); (2) call sites con catch que muestran error.message -> showError/showWarning interceptan el texto en contexts/ErrorContext.tsx, nunca sale el texto crudo de Next; (3) tres catch que solo hacian console.error alrededor de una Server Action (ramales/[id], instalaciones/agregar, ExpedienteForm) pasan por manejarBundleDesactualizado. Deteccion: /server action not found/i y ChunkLoadError. vehiculos/[id]/page.tsx usa el modulo y conserva solo el dominio pendiente. Controles positivos (proxy, dev01): A) rechazo sintetico 'Server action not found.' sin catch -> recarga (perf nav type reload), marca = '5.4.202'; B) mismo rechazo tras recargar -> sin recarga, modal 'Versión anterior' con el texto propio; C) rechazo no-stale -> ni recarga ni modal; D) busqueda por dominio AA040BD -> /vehiculos/3350 (regresion OK). NO EJERCITADO: un stale REAL (pestaña vieja + deploy + click sobre una action real) - el control uso Promise.reject sintetico; la rama ChunkLoadError; los tres call sites de consola; el camino (2) con un showError real conteniendo el texto.
  • wi-cli-venus descriptionChanged · 5w ago
    was: Found while fixing the dominio-search silence on the ficha (coder03, v5.4.176): a browser tab loaded before a deploy holds Server Action ids the new server no longer has, so the next call rejects with 'Server action not found'. Any call site without a catch fails silently - the user clicks and nothing happens. coder03 fixed the one call site Elazar hit (page.tsx, reload on that error, showError otherwise); every other Server Action call site in the app has the same exposure. Proposed fix: one global window.addEventListener('unhandledrejection') that matches the stale-action error and reloads once, with a guard against reload loops (e.g. a sessionStorage flag cleared on successful load) so a genuinely broken action does not spin the page. Decide guard shape before coding. Note this is a dev-only nuisance today because dev redeploys ~20x a night; in prod it appears on every deploy for tabs left open. == HECHO 2026-09-05 (coder03, e6442d00, dev v5.4.201; medido por proxy en v5.4.202) == Guardia elegida: UNA recarga por VERSION del bundle (sessionStorage 'movilba.bundleDesactualizado.recargaPorVersion' = packageJson.version). Si el error vuelve con la misma version no se recarga mas y se muestra el modal propio 'Versión anterior' / 'La aplicación se actualizó y esta pestaña quedó con una versión anterior. Recargá la página para continuar.' Cada deploy sube la version, asi que el siguiente deploy rehabilita la recarga; no hay marca temporal ni 'limpiar en carga exitosa'. Cobertura: (1) rechazos sin catch -> window.onunhandledrejection en lib/client-logger.ts (sigue logueando a app_logs, ademas recarga/avisa por CustomEvent que escucha NotificationProvider); (2) call sites con catch que muestran error.message -> showError/showWarning interceptan el texto en contexts/ErrorContext.tsx, nunca sale el texto crudo de Next; (3) tres catch que solo hacian console.error alrededor de una Server Action (ramales/[id], instalaciones/agregar, ExpedienteForm) pasan por manejarBundleDesactualizado. Deteccion: /server action not found/i y ChunkLoadError. vehiculos/[id]/page.tsx usa el modulo y conserva solo el dominio pendiente. Controles positivos (proxy, dev01): A) rechazo sintetico 'Server action not found.' sin catch -> recarga (perf nav type reload), marca = '5.4.202'; B) mismo rechazo tras recargar -> sin recarga, modal 'Versión anterior' con el texto propio; C) rechazo no-stale -> ni recarga ni modal; D) busqueda por dominio AA040BD -> /vehiculos/3350 (regresion OK). NO EJERCITADO: un stale REAL (pestaña vieja + deploy + click sobre una action real) - el control uso Promise.reject sintetico; la rama ChunkLoadError; los tres call sites de consola; el camino (2) con un showError real conteniendo el texto. == AUDIT e6442d00 -> 9f5e02ec, dev v5.4.204 == H1 (la recarga tiraba un formulario a medio escribir): listener 'input' en captura sobre document marca la pestaña como editada si el target esta dentro de un <form>; 'submit' la limpia. Con la marca puesta NO se recarga: modal 'Versión anterior' con texto propio que pide copiar lo escrito y recargar. El buscador por dominio de la ficha no esta en un <form>, sigue recargando. H2: la garantia es UNA recarga POR VERSION (no 'una'): una action rota de verdad recarga una vez por deploy antes del modal, y dos veces si la primera recarga trae version nueva. Aceptado y escrito en el modulo. Controles (proxy, v5.4.206): E editar/colectivo con #interno tipeado + rechazo stale -> sin recarga, modal con texto con-edicion, valor conservado. F /vehiculos sin tipear -> recarga una vez, marca '5.4.206'. NO ejercitado: 'submit' limpiando la marca; showError con el texto estando editado.
task
6w ago by wi-cli-venus
5w ago
2026-09-05 08:38