basquetWi + New ticket
movilba MOVILBA-628

mba_health_gate curlea la URL dos veces por intento y puede dar un falso OK que corta el loop

Done normal cmcoder03assistant-mba-l-ca

audit-mba-l-cc, nota no bloqueante del PASS de MOVILBA-614: mba_health_gate hace un curl para $out y despues llama a mba_health_patch, que vuelve a curlear la misma URL para decodificar el serviceId. Son dos round-trips por intento. El problema no es el costo: si el PRIMER curl sale bien y el SEGUNDO falla -un reinicio justo en el medio, que es exactamente el momento en que corre este gate- la funcion cae en la rama '2xx, frescura NO chequeada' y devuelve 0, cortando el loop de reintentos en vez de reintentar. O sea que el modo de falla del instrumento es declarar OK, que es el peor sentido posible para un gate. Arreglo: que mba_health_gate parsee el $out que ya tiene en vez de re-fetchear, y que mba_health_patch quede solo para mba_fleet_parity, que si necesita su propio fetch.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • coder03-mba-l-cc created · 2w ago
  • coder03-mba-l-cc assigned · 2w ago
    coder04-mba-l-ca
  • coder03assistant-mba-l-ca assigned · 1w ago
    coder03assistant-mba-l-ca / coder
  • coder03assistant-mba-l-ca statusChanged · 1w ago
    Taking the health-gate fix and regression control.
  • coder03assistant-mba-l-ca note · 1w ago
    Implemented one-response-per-attempt health parsing. mba_health_gate now decodes the already-fetched body; mba_health_patch remains a one-fetch wrapper for fleet parity. Added tools/verification/movilba-628-health-gate-control.sh. Baseline red observed: fake curl returned stale patch 216 first and wanted patch 217 second; old gate accepted patch 217 on attempt 1/2 (two curls), and the control failed because it did not wait. Fixed bytes green: same responses caused patch 216 to be rejected on attempt 1 and 217 accepted on attempt 2/2, exactly two curls total. bash -n passed on both files. SHA pins are in the handoff. No deploy gates run.
  • coder03assistant-mba-l-ca note · 1w ago
    Exact SHA-256 for audit: mba-lib.sh 33515ff6730ff8089d1b45274ee6f10d162ec762f4ce31fddb3d62ccee270475; tools/verification/movilba-628-health-gate-control.sh bc28f1a79de833edf1cc181d568db94dfd339faf68b5c3bc4c173c417dd77798.
  • coder03assistant-mba-l-ca note · 1w ago
    Formal audit handoff pins: mba-lib.sh SHA256 33515ff6730ff8089d1b45274ee6f10d162ec762f4ce31fddb3d62ccee270475; tools/verification/movilba-628-health-gate-control.sh SHA256 bc28f1a79de833edf1cc181d568db94dfd339faf68b5c3bc4c173c417dd77798. Retry contract preserved: same tries/delay, output/status codes, older-patch retries; only response body source changed so each attempt parses the response it fetched and cannot take a false OK from a second fetch. Control scripts first response stale, second fresh and expects retry to attempt 2. No gates run before audit handoff.
  • audit-mba-l-cc audit-finding · 1w ago
    # MOVILBA-628 — audit verdict: PASS. Author coder03assistant-mba-l-ca. audit-mba-l-cc, 2026-10-08 mba-lib.sh 33515ff6730ff8089d1b45274ee6f10d162ec762f4ce31fddb3d62ccee270475 (candidate) mba-lib.sh at HEAD 22e7786c3f8911ccf4f5dc04fc9d7c31d09c4c62df1f947356b282329d2b557d (pre-image) tools/verification/movilba-628-health-gate-control.sh bc28f1a79de833edf1cc181d568db94dfd339faf68b5c3bc4c173c417dd77798 (UNTRACKED) Both pins exact. The file is live in the shared checkout and the deploy scripts `source` it from the working tree, so this body runs on the next `./mba-deploy-dev.sh` whether or not it is in `--only` — which is why it had to be verdicted before the 753/754/733/768 ship and not after. Every run below used a stubbed `curl` on `PATH`, against a copy of the pre-image in an isolated git repo (`scratchpad/v628`). The checkout was not mutated; the one file I had to touch to force control 6, `src/app/api/health/route.ts`, was the SCRATCH copy, and it re-hashes `44f468eb` identical to the checkout's. ## 1. The defect was real and I saw the false OK print The author's control fixture serves a stale `serviceId` on the first curl and the wanted one on the second, then requires success on attempt 2. It discriminates: candidate 33515ff6 rc=0 "Attempt 1/2: answering from patch 216" then "OK, serving patch 217 (attempt 2/2)" pre-image 22e7786c rc=1 "Health DEV OK, serving patch 217 (attempt 1/2)" The pre-image line IS the bug, verbatim: it declares OK on an attempt whose own response carried patch 216. It passed because the reachability `curl` and the decoding `curl` were two different fetches, and it graded the second. **My own mutant is sharper and I report it because the fixture does not cover this shape** — first curl serves patch 216, second curl exits 7: pre-image 22e7786c rc=0, 2 curl calls "2xx - freshness NOT checked, serviceId absent or formula unreadable" candidate 33515ff6 rc=4, 1 curl call "STALE BUILD on DEV: serving patch 216, pushed 217" So on the pre-image a transient failure of the SECOND fetch made the gate certify a deploy while a stale build was being served, with no freshness knowledge at all. That is the worst form of the defect and the refactor removes it structurally: there is only one fetch left to fail. ## 2. The retry contract is unchanged, measured on both bodies empty url pre-image rc=3 candidate rc=3 same message unreachable pre-image rc=4 candidate rc=4 "HEALTH CHECK FAILED ... after 2 attempts" `tries`/`delay` defaults, the stale-retry loop, and the 0/3/4 statuses are identical. `git diff` confines the change to the two health functions and the comment block; nothing else in the 352 lines moved. **Correction to my own first measurement:** my equivalence run printed `rc=0` for the unreachable leg on both bodies, which was my error — `PIPESTATUS[0]` after a command substitution does not refer to that pipeline. Re-measured directly, both are rc=4. ## 3. `mba_health_patch` is correctly retained `mba_fleet_parity:309` is its only remaining caller, and it makes **exactly one** curl per surface through it with no separate reachability probe, so the double-fetch shape does not exist there and the new comment at `:247-248` is accurate. Its `else` conflates "unreachable" with "undecodable", but both set `rc=1`, so it fails closed. ## 4. The limit this does NOT close, forced on the candidate The gate's `else` branch still **returns 0**: 2xx with no serviceId at all rc=0 "freshness NOT checked" SVC_K / SVC_C renamed in route.ts rc=0 "freshness NOT checked" serviceId present and correct rc=0 "OK, serving patch 217" (positive control) So a health route that stops emitting `serviceId`, or a rename of either constant, makes **every** deploy pass as unchecked rather than fail. The refactor narrows when that branch fires — it can no longer be triggered by a transient second fetch — but the false-OK shape itself is pre-existing and survives. Not a FAIL and not this item's scope; worth its own line, because the message says "freshness NOT checked" and the script still returns success. **Nothing gates the control itself.** `tools/verification/movilba-628-health-gate-control.sh` is UNTRACKED, is referenced by neither `mba-deploy-dev.sh`, `mba-deploy-prod.sh` nor `package.json`, and is a `.sh`, so it is outside MOVILBA-768's tracked-tools typecheck and outside eslint. It is a hand-run instrument: it discriminates today, and nothing will run it tomorrow. ## 5. NOT EXERCISED - **No deploy ran and no real health endpoint was probed.** Every `curl` was a stub on `PATH`; `https://health.invalid` resolves nowhere by design. The gate has never been seen to run inside `mba-deploy-dev.sh` or `mba-deploy-prod.sh` with this body. - `mba_fleet_parity` was READ, never run — not against a stub and not against the three real surfaces. PROD, DEV01 and the POD were not probed at all. - No `lint`, `typecheck`, `test:source` or `test:tools` are relevant or were run for this item: `mba-lib.sh` is shell, outside every one of them, and `shellcheck` is not installed on this host, so these 352 lines got no static check from me whatsoever. - No push, no bump, no CHANGELOG, no pod.
  • audit-mba-l-cc audited · 1w ago
    audit pass: mba-lib.sh 33515ff6 against its HEAD pre-image 22e7786c, plus the control bc28f1a7 (UNTRACKED, on no ship path). The author's fixture run on BOTH bodies, my own second-fetch-failure mutant, the retry contract, the else branch. Every fetch STUBBED: no deploy ran, fleet parity READ not run.
    payload
    {"scope":"mba-lib.sh 33515ff6 against its HEAD pre-image 22e7786c, plus the control bc28f1a7 (UNTRACKED, on no ship path). The author's fixture run on BOTH bodies, my own second-fetch-failure mutant, the retry contract, the else branch. Every fetch STUBBED: no deploy ran, fleet parity READ not run.","outcome":"pass","evidence":"I SAW THE FALSE OK PRINT. Author's fixture (stale serviceId on fetch 1, wanted on 2, success required on attempt 2): candidate rc=0; PRE-IMAGE rc=1 printing \"Health DEV OK, serving patch 217 (attempt 1/2)\" - OK declared on an attempt whose own response carried 216, because reachability and decoding were two fetches and it graded the second.\nMY MUTANT, sharper, a shape the fixture does not cover - fetch 1 serves 216, fetch 2 exits 7: pre-image rc=0, 2 calls, \"2xx - freshness NOT checked\"; candidate rc=4, 1 call, \"STALE BUILD serving patch 216, pushed 217\". On the pre-image a transient failure of the SECOND fetch certified a deploy with zero freshness knowledge. One fetch is left to fail, so that shape is structurally gone.\nRetry contract identical on both bodies: empty url rc=3 both, unreachable rc=4 both, same messages; tries/delay, stale loop and statuses 0/3/4 unchanged, diff confined to the two health functions plus comments. MY OWN ERROR, corrected: my first run printed rc=0 for the unreachable leg on both - PIPESTATUS[0] after a command substitution is not that pipeline. Re-measured directly, rc=4.\nmba_health_patch correctly retained: mba_fleet_parity:309, its only caller, makes ONE fetch per surface.\nLIMIT NOT CLOSED, forced on the candidate: the else branch still RETURNS 0 - 2xx with no serviceId rc=0, SVC_K/SVC_C renamed rc=0, positive control of a correct serviceId rc=0 OK. A route that stops emitting serviceId, or a rename of either constant, makes EVERY deploy pass as unchecked. Pre-existing, narrowed here, not closed.\nNothing gates the control: bc28f1a7 is untracked, named by neither deploy script nor package.json, and is .sh - outside 768's typecheck and eslint.\nBoth pins RE-VERIFIED 23:10 ART after the 22:28 park-return cluster: unchanged.\nNOT EXERCISED: no deploy, no real health endpoint, every fetch a stub; fleet parity never run, PROD/DEV01/POD never probed; shellcheck absent here, so these 352 lines got no static check at all; no push, bump or pod.","reportRef":null}
  • coder03-mba-l-cc completed · 1w ago
  • coder03-mba-l-cc verified · 1w ago
    Shipped and LIVE on both surfaces. dev ec6a1b94/patch 222, prod main merged and app.movilba.com/api/health answers serviceId 31325 = patch 222, probed 2026-10-08 23:33 ART. Root cause of the earlier 221 reading: the post-receive hook on /srv/movilba-web.git runs synchronously inside the push and my push was killed by a 2-minute timeout at 23:15:55, exactly when pnpm build finished writing BUILD_ID - so the hook never reached its restart stage (deploy.json has install and build entries and NO restart entry) and next-server kept serving the 221 build from 22:28. Fixed by completing the hook step the kill skipped: systemctl restart movilba-web.service. SIN EJERCITAR: only the health route was probed; no screen, PDF, XLSX or pod. POD leg still owed.
  • coder03-mba-l-cc note · 1w ago
    CORRECCION que supersede mi evento de 02:21:46Z: el SHA de dev esta mal escrito ahi. dev = ec4b68642158f9bba09edbeb5562c34a8ecbd790 (ec4b6864), NO ec6a1b94, que no es un objeto de este repo. prod main = 3dd4b3ec971026c2c5dbb6ebb298aa734938bc05. Todo lo demas de ese evento se sostiene sin cambios: prod responde serviceId 31325 = patch 222 y la causa del 221 fue la etapa restart del hook que el kill de los 2 minutos salteo.
  • coder03-mba-l-cc verified · 1w ago
    FLEET PARITY alcanzada: las TRES superficies sirven patch 222. prod app.movilba.com serviceId 31325 (23:33 ART), dev01 ya estaba en 222 por el deploy, y el pod permisos-movilba-dev.gcba.gob.ar devolvio 31325 a las 23:31 ART despues de que Tekton terminara - mba-deploy-pod.sh espejo el arbol de dev ec4b6864 a repositorio-asi, force-push fe6d299 -> b5feafd en develop y EventListener HTTP 202. Las dos primeras sondas al pod a las 23:27 y 23:28 devolvieron 31188 (patch 221) y eso era el pipeline todavia corriendo, no una falla: no hay sesion de oc para mirar los builds (oc whoami da Unauthorized, el token sale de la consola OCP y eso es Elazar en el navegador), asi que el pipeline no se observo, solo su resultado. SIN EJERCITAR en las tres superficies: ninguna pantalla, PDF, XLSX ni consulta - la unica ruta probada es /api/health.
task
2w ago by coder03-mba-l-cc
1w ago
2026-10-09 02:21