basquetWi + New ticket

Una radiografia sacada con el telefono no se puede guardar: el limite de 1 MB del cuerpo de la server action la rechaza con un 413 del framework

Done high ctcoder03-terra-cc

UNA FOTO DE TELEFONO NO ENTRA. La superficie de Radiografias esta desplegada desde 0.31.50 y nunca fue ejercida - cero practicas tienen imagen - asi que esto no produjo todavia ningun incidente y va a producirlo el 1/10, cuando empiece el uso real. EL LIMITE ES DE 1 MB PARA TODO EL CUERPO DE LA SERVER ACTION, campos del formulario mas todas las radiografias juntas. next.config.ts no define serverActions.bodySizeLimit, asi que rige el default de Next 16. Pasado ese tamaño el framework responde HTTP 413 'Body exceeded 1mb limit' ANTES de que corra una sola linea de codigo nuestro: ninguna validacion, ningun ActionError, ningun mensaje en castellano. Verificado en node_modules/next/dist/server/app-render/action-handler.js:576-585, leido y no recordado. POR QUE EL CASO DOMINANTE ES EL QUE FALLA. practica-form.tsx:1372 declara accept='image/*' multiple. En un telefono eso abre la camara. Una foto de telefono pesa entre 3 y 6 MB, o sea entre 3 y 6 veces el limite, con un solo archivo. El alumno llena toda la practica, aprieta guardar y recibe un error generico despues de haber cargado todo. NO HAY TOPE NI DE TAMAÑO NI DE CANTIDAD EN NINGUNA CAPA NUESTRA. El input no limita nada y la unica validacion del servidor es file.type.startsWith('image/') en practica-actions.ts:376. Se pueden adjuntar veinte archivos de cualquier peso; el unico que dice que no es el framework, en un idioma que no es el nuestro y con un codigo que el formulario no distingue de una caida. TRES ARREGLOS POSIBLES Y NO SON EXCLUYENTES. (a) GUARDA EN EL CLIENTE, sin decision de por medio: rechazar el archivo al elegirlo, con un mensaje en castellano que diga el peso y el tope, en vez de un 413 despues de llenar el formulario. Mejora bajo CUALQUIER limite que se elija despues, asi que no depende de (b). (b) SUBIR EL LIMITE con serverActions.bodySizeLimit. Es una decision, no un arreglo obvio: Vercel impone su propio techo al cuerpo de una funcion serverless (4.5 MB), asi que subirlo no es gratis ni ilimitado y hay que elegir un numero. (c) SACAR LA SUBIDA DEL CUERPO DE LA SERVER ACTION - que el navegador hable con api-images y que la action reciba solamente el id. Es el unico camino que escala a varias radiografias por practica y el unico que no pelea contra el limite en vez de evitarlo. Es tambien el cambio mas grande y toca el contrato con api-images. BLOQUEA A TERRA-208: su brazo de 'ejercicio autenticado con imagen real' (TERRA-213) no puede pasar hoy con una foto de telefono, que es exactamente lo que se va a usar para ejercerlo.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 5w ago
    parent=#3143
  • wi-cli-venus verified · 5w ago
    DOS AFIRMACIONES DE ESTA FILA VERIFICADAS EN FUENTE, no dejadas de memoria. Marker: T218-verif-mtwxs8. 1. EL TECHO DE VERCEL ES 4.5 MB Y ES DURO. Confirmado en la documentacion de Vercel (docs/functions/limitations, last_updated 2026-08-24), citado textual: 'The maximum payload size for the request body or the response body of a Vercel Function is 4.5 MB. If a Vercel Function receives a payload in excess of the limit it will return an error 413: FUNCTION_PAYLOAD_TOO_LARGE'. Aplica al cuerpo de la peticion Y al de la respuesta, no distingue por plan y no lo cambia fluid compute. ESO ACOTA LA OPCION (b): subir serverActions.bodySizeLimit no puede pasar de 4.5 MB, asi que aun con (b) al maximo posible UNA foto de telefono de 5 MB sigue fallando, y dos de 3 MB tambien. (b) sola no es un arreglo, es mas aire. 2. EL USUARIO VE UN ERROR GENERICO, no un mensaje sobre el tamaño. Leido, no supuesto. El 413 lo emite el framework antes de que corra la action, asi que la llamada del cliente TIRA en vez de devolver {ok:false}. Cae en el catch de src/hooks/use-action-form.ts:72, cuyo propio comentario dice 'A server action that throws past the wrapper (should not happen)', y muestra el toast 'Ocurrio un error inesperado. Por favor, intenta de nuevo mas tarde.' Es literalmente el mismo texto que veria si el servidor se cayera: el alumno no tiene forma de saber que el problema es el peso de la foto ni que sacando una foto mas chica funcionaria. Y el formulario ya esta lleno cuando lo ve. CONSECUENCIA PARA EL ORDEN DE LOS ARREGLOS: (a) deja de ser cosmetica. No es 'un mensaje mas lindo' - es la diferencia entre un usuario que puede corregir y un usuario que cree que el sistema esta caido. Pero el numero contra el que guarda depende del camino elegido, asi que hacerla hoy es hacerla dos veces. NO DECIDO TODAVIA ENTRE (a)/(b)/(c). Es la pregunta que Elazar retuvo el 2026-09-05 - el tamaño de las imagenes - y la estimacion que pmmaster pidio en eq 93 es justamente el documento donde se decide. Sale antes del 1/10.
  • wi-cli-venus assigned · 5w ago
    coder03-terra-cc
  • wi-cli-venus spec · 5w ago
    ESPECIFICACION PARA IMPLEMENTAR. Decidida por coder-terra-cc como PM de terra (Elazar 2026-09-11 09:27), camino resuelto por pmmaster-evolutiva-cc con GO delegado. Marker: T218-spec-mtwxw4. CAMINO ELEGIDO: reducir la imagen en el NAVEGADOR antes de que entre al cuerpo de la server action. Subir serverActions.bodySizeLimit NO es el arreglo y no se presenta como tal - el techo duro de Vercel es 4.5 MB, asi que al maximo posible una foto de 5 MB sigue fallando. Se sube igual, como ACOMPANANTE, para que entren varias imagenes. Sacar la subida del cuerpo de la action queda para despues, detras de un plan de huerfanos escrito: mars ya midio 256 archivos huerfanos / 37.1 MB por esa forma exacta. EL PISO: 2000 PX EN EL LADO MAS LARGO, JPEG CALIDAD 0.85. Justificado contra lo que la pantalla realmente dibuja, no por intuicion. - El contenedor es max-w-5xl (1024 px) menos padding, o sea ~976 px de ancho util. - La grilla es sm:grid-cols-2 con gap-3, asi que cada celda mide ~482 px CSS. - La imagen esta limitada por max-h-96 (384 px CSS) con object-contain. - En una pantalla de densidad 3x - el peor caso realista, un telefono moderno - eso son ~1446 px de dispositivo en el lado mas largo. 2000 px cubre ese peor caso con margen y deja aire para que en el futuro la imagen se pueda ver mas grande sin volver a decidir esto. Una foto 4:3 a 2000 px pesa aproximadamente 400-800 KB, o sea entra con el formulario debajo de 1 MB. TRES REGLAS QUE HACEN QUE EL PISO NO DEGRADE LO QUE NO HACE FALTA DEGRADAR: 1. NUNCA AGRANDAR. Si la imagen ya mide menos que el piso, se manda tal cual, sin reencodear. Una periapical digital tipica es 1200x1600, o sea que pasa INTACTA: el arreglo no la toca. 2. NUNCA REENCODEAR UN ARCHIVO QUE YA ENTRA. Si el archivo pesa menos que el presupuesto, va como esta. Reencodear por reencodear es perdida de calidad gratis. 3. SI EL NAVEGADOR NO PUEDE DECODIFICAR EL ARCHIVO (HEIC en algunos navegadores, un formato raro), NO SE ROMPE: se manda el original y que dispare el aviso de tamano del punto siguiente. Un arreglo que convierte un archivo no soportado en una pantalla en blanco es peor que el problema. POR QUE REDUCIR EN EL NAVEGADOR TAMBIEN ARREGLA UN PROBLEMA DE PRIVACIDAD, y esto no estaba en la pregunta original. coder-apiimages-cc confirmo hoy que api-images NO reduce ni reconvierte - guarda los bytes como llegan - y que lo unico que modifica es borrar los metadatos EXIF del JPEG, BEST-EFFORT: si ese borrado falla, la imagen se guarda IGUAL con los metadatos intactos, y el aviso de que fallo existe en el codigo pero no esta desplegado, asi que hoy falla en silencio. Una foto de telefono lleva la UBICACION GPS de donde se saco. Reducir en el navegador reescribe la imagen entera y elimina los metadatos como efecto secundario, ANTES de que salgan del telefono, sin depender de que el borrado del otro lado funcione. SEGUNDO ARREGLO, INDEPENDIENTE Y CASI GRATIS: EL 413 NO PUEDE SEGUIR DICIENDO 'Ocurrio un error inesperado'. Hoy el rechazo por tamano cae en el catch generico de src/hooks/use-action-form.ts:72 y muestra un texto identico al de un servidor caido, despues de que el usuario lleno todo el formulario. Hay que distinguir el caso de cuerpo demasiado grande y decir que la imagen es muy pesada. SE HACE AUNQUE EL PRIMER ARREGLO ENTRE EL MISMO DIA: el catch generico se va a tragar el proximo fallo distinto exactamente igual. Es la misma clase de defecto que db-mars-cc acaba de resolver en mars - atrapar el caso puntual para el que se escribio el handler, nunca un WHEN OTHERS. CONTEXTO QUE NO ES RESTRICCION, para que nadie lo trate como una: api-images acepta hasta 10 MiB, mas del doble de nuestro techo, asi que NO esta en el camino que ata y ningun cambio de su lado nos ayuda. Y hay lugar de sobra: 2.22 GB usados contra un piso de 25 GB, y ese consumo es de los 13 dominios de la cuenta, no nuestro. VERIFICACION QUE TIENE QUE ACOMPANAR AL CODIGO: un test que falle si el piso desaparece o si alguna de las tres reglas de arriba se rompe. Y el brazo de imagen de TERRA-213 sigue sin poder ejercerse con una foto de telefono hasta que esto este pusheado. DEFINICION DE TERMINADO, palabras de Elazar: codigo pusheado y funcionando.
  • wi-cli-venus assigned · 5w ago
    coder03-terra-cc / coder
  • wi-cli-venus note · 5w ago
    ENTREGABLE ESCRITO: /data-venus/evolutiva/terra/pm/2026-09-11-radiografias-estimacion.md. Marker: T143-entregable-mtwxx7. Es la estimacion que Elazar pidio el 2026-09-05 al retener el grupo 5 y que pmmaster-evolutiva-cc convirtio en condicion de la decision A en eq 93. En castellano, para el cliente, no para el carril. Separa explicitamente tres cosas que se confunden: lo MEDIDO (limites del framework y de Vercel leidos en fuente, comportamiento del formulario, contenido real de la base y del servicio de imagenes), lo ESTIMADO (cuanto pesa una radiografia segun como se capture - marcado como estimacion porque no se midieron archivos de la catedra), y lo que NO SE PUEDE CALCULAR TODAVIA (la proyeccion por ciclo, porque no hay denominador). EL DOCUMENTO NO ENTIERRA EL HALLAZGO EN EL FINAL. Empieza diciendo que hoy una radiografia sacada con el telefono no se puede guardar, porque esa es la respuesta util a la pregunta que se hizo: preguntó cuanto ibamos a almacenar y la respuesta es que todavia no se almacena nada porque el archivo no sale del navegador. TAMBIEN DEJA DICHO QUE FALTA UN SOLO DATO Y QUE ES SUYO: matricula de la catedra y practicas esperadas por alumno por ciclo. Con esos dos numeros la proyeccion sale en una linea. Sin ellos cualquier tasa por alumno seria una sesion de prueba de una sola persona disfrazada de proyeccion - 6 practicas, todas de agosto, cero de alumnos, y dos creadores que son la misma persona con dos direcciones. Y CORRIGE UNA AFIRMACION MIA: 'terra nunca escribio en el servicio de imagenes' es falso. Cero archivos VIVOS es cierto, pero la papelera de api-images tiene 16 archivos de terra de 160 bytes cada uno, artefactos de prueba subidos con nuestra clave y despues borrados. Lo pedi confirmado en vez de suponerlo y por eso aparecio.
  • wi-cli-venus spec · 5w ago
    DOS ACLARACIONES A LA ESPECIFICACION, porque como estaba escrita se contradecia en un caso y pedia algo que puede no ser implementable. Marker: T218-spec2-mtwxy9. 1. CUAL REGLA GANA CUANDO UN JPEG YA ENTRA PERO TIENE METADATOS. La regla 2 dice 'nunca reencodear un archivo que ya entra' y el parrafo de privacidad dice que reencodear es lo que borra el EXIF. Para un JPEG chico con GPS adentro las dos se contradicen y quien implemente iba a elegir una en silencio. GANA LA REGLA DE TAMANO: un archivo que ya entra NO se reencoda, porque reencodear es perdida de calidad sin ganancia de tamano y estamos hablando de documentacion clinica. PERO NO SE MANDA CON LOS METADATOS. Cuando se saltea el reencodeo, se hace un borrado SIN PERDIDA del segmento EXIF (APP1) sobre los bytes del JPEG - es cortar un bloque de metadatos, no tocar la imagen. Si ese corte falla por cualquier motivo, ENTONCES SI se reencoda, aceptando la perdida, porque mandar la ubicacion GPS del consultorio adentro de una radiografia no es una opcion. Orden final: si no entra -> reducir y reencodear (borra metadatos de paso). Si entra -> cortar EXIF sin perdida. Si el corte falla -> reencodear. No dependemos de que api-images borre nada: su borrado es best-effort, falla en silencio y su aviso no esta desplegado. Endurecerlo es de su carril; que no salga del telefono es del nuestro. 2. EL ARREGLO 2 PUEDE NO SER IMPLEMENTABLE COMO ESTA ESCRITO - VERIFICAR PRIMERO. Pedi distinguir el 413 dentro del catch de use-action-form.ts. Un cliente de server action de Next, ante una respuesta que no es 2xx, puede tirar un error generico SIN el codigo de estado adentro; si es asi, adentro del catch el 413 es indistinguible de cualquier otra caida y la distincion no se puede hacer ahi. ANTES DE ESCRIBIR CODIGO: comprobar que recibe realmente el cliente ante un 413. Si trae el estado, hacer la distincion en el catch como estaba especificado. SI NO LO TRAE, EL ARREGLO 2 CAMBIA DE LUGAR Y NO DE OBJETIVO: se hace ANTES de enviar, sumando file.size de todas las imagenes YA REDUCIDAS mas un margen para los campos del formulario, y comparando contra el limite configurado. Mismo mensaje en castellano, disparado antes de que el usuario pierda el formulario lleno. El objetivo es que nunca vea 'Ocurrio un error inesperado' por un problema de tamano; donde se logra es secundario. La objecion anterior de que la guarda previa habria que hacerla dos veces ya no aplica: el camino esta decidido, asi que el numero contra el que guarda es uno solo.
  • wi-cli-venus note · 5w ago
    PROVENANCE NOTE - THIS ROW'S CODE CHANGE IS INSIDE A COMMIT THAT DOES NOT NAME IT. Marker: T-prov-mtwz10. The local commit def2e64, whose message reads "db(TERRA-199): declarar NO TAG razonado en las 13 migraciones que la compuerta de citas rechaza", carries the work of THREE agents, not one. Its file list: - db-terra-cc's TERRA-199 migration headers (13 files) - what the message describes. - coder-terra-cc's TERRA-214 comment corrections: src/lib/email/recipients.ts, src/lib/support-queue.ts. - coder03-terra-cc's TERRA-218 implementation: src/lib/downscale-image.ts, downscale-image-core.ts, downscale-image-core.test.ts, src/components/practica-form.tsx, src/hooks/use-action-form.ts, src/lib/friction-codes.ts, friction-toast-coverage.test.ts, next.config.ts. HOW: gitpush.sh v4.14 stages the --only paths BEFORE running .gitpush-pre.sh, so the hook sees a real index. When the hook FAILS, the paths stay staged and the tree is left dirty-in-index. My run failed on "Another next build process is already running" - a concurrent agent's build - and left my two files staged. The next agent's gitpush.sh then ran `git add -- <its own paths>` and `git commit`, and git commits THE WHOLE INDEX, not just the paths just added. Three agents' work, one message, one author line. NOTHING IS LOST AND NOTHING IS WRONG IN THE CONTENT. Verified: def2e64:src/lib/email/recipients.ts contains "THE RULE IS NOW DECIDED" and def2e64:src/lib/support-queue.ts contains "TERRA-214 then". The working tree is identical to HEAD. The defect is in ATTRIBUTION, not in the code. NOT SPLITTING IT. def2e64 is unpushed (0 ahead of origin/main by the left-right count at the time of writing, i.e. origin has not seen it). Rewriting it would mean rebasing a commit another agent authored and is about to push, to fix a message - worse than the problem. It gets pushed as is, and this note is how the three rows stay findable from their own side. REPORTED as a gitpush.sh defect rather than a local accident, because the failure mode is fleet-wide: any hook failure on a strict repo silently loads the next agent's commit with the previous agent's files.
  • wi-cli-venus verified · 5w ago
    PUSHED AND DEPLOYED. c0c0aab (EXIF-strip amendment, T218-spec2-mtwxy9) landed in the 5-lane range 1ad80b8..116e809; live /api/health confirms version 0.31.64 == package.json, deploymentId dpl_4yLaW8Cm1cbf79MTeHhrCVwjZoUg, dbOk/mailOk true. All three original rules (never upscale, never re-encode a file that already fits, never break on undecodable input) plus the spec2 EXIF-strip refinement are implemented and covered by node --test (12 tests in downscale-image-core.test.ts): floor constants, rule 1 at/under/over the 2000px floor, rule 2 byte-budget skip, and EXIF-strip success/no-op/non-Exif-APP1-preserved/malformed-input-fails-closed. Fix 2 (use-action-form.ts 413 distinction) verified against the actual client-received error shape before writing (Next's action-handler.js message 'Body exceeded X limit.' survives to the catch), per T218-spec2-mtwxy9's implementability check. Full suite 543/543 + tsc clean at commit time.
  • wi-cli-venus completed · 5w ago
    completed
bug
5w ago by wi-cli-venus
5w ago
2026-09-11 14:24