HOMELAB-2682: fix(sbx-gits): emu-proof rejects an OK line with zero tests and requires --task #874
No reviewers
Labels
No labels
operator-review
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Homelab/infra-core!874
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "plane/HOMELAB-2682-ok0"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Qué
Dos defectos de
tools/gits-sbx-emu-proof.sh(el ledger de la corrida del emulador), un solocambio:
CERO PRUEBAS NO ES UN OK.
runescribía una línea conresult=OKytests_run=0.Evidencia viva: la línea 38 del ledger del pod (head
8c1d507c) es una corrida conresult:"OK",rc:0,tests_run:0y el sha256 del XML vacío (e3b0c442…): cero casosejecutados, y leída sola dice OK. El head pasó por su línea de smoke, pero esa línea no
prueba nada.
runrechaza escribir la línea si terminarc=0contests_run=0: rc 2, ningunalínea nueva, la misma forma de rechazo que el pre-chequeo del ledger mal formado. La
captura de la corrida se conserva y el mensaje dice dónde quedó (es lo que explica por
qué no corrió nada). Una corrida en rojo con cero casos sí se apunta: un fallo es
información honesta.
checketiqueta cualquier línea histórica contests_run=0— pase o no el head — comotests_run=0 — NO se ejecutaron pruebas (no tests executed — evidence only), y esa líneanunca completa la compuerta (
tests_run > 0sigue siendo condición). Antes la líneadesaparecía del informe cuando el head pasaba por otra de sus líneas.
LA TAREA VA DESPUÉS DEL MÓDULO. Con
--module appy sin--task, el default era:app:connectedDebugAndroidTest, que ya lleva el módulo dentro; la suite compone<módulo>:<tarea>, así que Gradle recibíaapp::app:connectedDebugAndroidTest(dobleprefijo, lo rechaza) tras gastar el emulador.
--taskes ahora obligatoria; sin ella, rc 2, nada escrito, y el mensaje nombra lasformas válidas (
connectedDevDebugAndroidTest/connectedStableDebugAndroidTestpara unmódulo con flavors;
connectedDebugAndroidTestsin flavors). Un default único tampocopuede ser correcto: en
:appconnectedDebugAndroidTestes ambiguo.--task ':app:…'o con::→ rechazo por construcción (no puede ser la mitad derecha).--task app:connectedDebugAndroidTestcon--module app→ AVISO con la tarea exactaque Gradle recibiría.
--helpy endocs/gits-sbx/run-proof.md(regla de invocación + ceropruebas).
Ronda 2 — el bloqueo del asiento 1 (
OK-path-label-unreachable) y C2Commit
ea6993cb. El asiento 1 tenía razón y su mecanismo era exacto.El bloqueo: la etiqueta de la línea de cero casos no se alcanzaba en el camino OK
El bucle de candidatas de
cmd_checkhacebreaken la primera línea canónica limpia(
ok_line). La etiqueta detests_run=0se acumulaba dentro de ese bucle, así que una líneade cero casos que venga después de la línea del smoke que pasa no se visitaba nunca y
desaparecía del informe: solo la nombraba el bloque «otras corridas de este head», que imprime
result=OKy nada de cero casos. Y esa es precisamente la forma del ledger vivo —la línea 38va después del smoke de su head—, es decir, el caso que este PR existe para nombrar.
Reproducido con la herramienta del head
ee994e19(dos suites de mentira, repo de mentira con elsmoke canónico commiteado en su ruta, cadena bien calculada):
Arreglo: la etiqueta se acumula en un recorrido propio, de solo lectura, sobre TODAS las
líneas de este head, ANTES del bucle de la compuerta (y se quita de dentro del bucle). El
veredicto no cambia: una línea limpia y canónica sigue pasando el head, y una de cero casos
sigue sin completar nunca la compuerta (
tests_run > 0); la etiqueta es informe.Después del arreglo, las tres formas dicen lo mismo y en el mismo sitio:
C2 (arreglado): el mensaje de cero casos decía una cosa falsa en la mitad de los casos
Decía siempre «no hay XML posterior al arranque», y eso es falso cuando la suite sí dejó
un XML con cero casos (
<testsuite tests="0">, o un XML que no trae ni un<testcase>).zero_tests_whyusa elXML_COUNTde la corrida y ahora nombra cuál de las dos pasó:Las dos siguen rechazándose igual (rc 2, sin línea): son causas distintas y el mensaje las
distingue.
Repro (verbatim, contra
origin/liveANTES del cambio)Defecto 1 — la suite sale rc=0 sin dejar XML:
Defecto 2 —
--module appsin--task, con la composición REAL del smoke (connected_task):Ledger vivo (solo lectura,
kubectl exec … sed -n 38p):Cambios, fichero a fichero
core/manifests/apps/sbx-gits/tools/gits-sbx-emu-proof.shrun: rechazorc=0 && tests_run==0(rc 2, sin línea, captura conservada) con el motivo real (zero_tests_why: sin XML vs XML sin casos);--taskobligatoria + rechazo por construcción + AVISO del prefijo del módulo;check: la etiquetatests_run=0se acumula en un recorrido propio sobre todas las líneas del head, antes del bucle de la compuerta (ronda 2) y se imprime en el OK y en el informe de fallo;--helpactualizadodocs/gits-sbx/run-proof.md--task: la tarea va DESPUÉS del módulo» y «Cero pruebas no es un OK»scripts/gits-sbx-epic-test.shSBX_GITS_DIFF_SETre-medido contraorigin/live960410f5=M tools/gits-sbx-emu-proof.sh; fixtures B3 25(f6)/(f7) actualizadas (su corrida ya no puede ser la suite de cero bytes: deja XML); casos nuevos que muerden: (f)runrechaza un OK sin XML, (f2) una líneatests_run=0construida a mano con la cadena bien calculada (la forma de la línea 38) se rechaza y se etiqueta —camino de fallo—, (f2b) la misma línea DESPUÉS de una línea que PASA: el head pasa (rc=0) y la etiqueta tiene que estar igual (ronda 2; muerde con el bloqueo, verde con el arreglo), (f3)run --module appsin--taskse rechaza nombrando las formas válidasNada más se toca:
statefulset.yaml,README.md,kustomization.yamly las otras cincoherramientas quedan como están (
T7[diff]clava ese conjunto y muerde si aparece un fichero más).Tests
Corridas en solitario (secuenciales, ningún árbol a la vez: dos a la vez colisionan en rutas
de
/tmp), cada una desde un worktree limpio:origin/live960410f5960410f5ee994e1922[R176b] (f2b)BLOQUEO (la prueba nueva muerde)ea6993cbEl conjunto de rojos de la rama es subconjunto del de la baseline: los 9 rojos de
ea6993cbestán todos en la baseline, y la baseline trae uno de más (18[R165] --lock-selftest,un selftest de lock en
/tmpque depende del entorno). Cero rojos nuevos.Los dos rojos de más que aparecen en la corrida PRE-FIX (
16[R161] fixture D (timeout)y16[R161] mutacion (ii)) son el test de stress/tiempos del lock bajo carga: no aparecen ni en labaseline ni en la corrida con el arreglo, y no tocan nada de este cambio.
Casos de la sección 22 que importan aquí, en la corrida con el arreglo:
22[R176b] (f)PASS —runrechaza un OK sin XML (rc 2, cero líneas, captura conservada);22[R176b] (f2)PASS — la línea de cero casos sola no abre la compuerta y se etiqueta;22[R176b] (f2b)PASS — [línea que PASA, línea de cero casos DESPUÉS]: el head pasa (rc=0)y la etiqueta está; con el head
ee994e19este caso imprimeBLOQUEO: … el head pasa (rc=0) pero la linea de cero casos NO se etiqueta(prueba primero,arreglo después);
22[R176b] (f3)PASS —run --module appsin--taskse rechaza;T7[diff]PASS — el diff desbx-gitscontraorigin/livees exactamenteM tools/gits-sbx-emu-proof.sh, y su mutación (quitarlo del conjunto permitido) sigue en ROJO.bash -nlimpio en la herramienta y en el arnés;shellchecksin avisos nuevos sobre el diff(el fichero de la herramienta sale limpio y el arnés no suma ningún aviso en las líneas nuevas).
Los rojos preexistentes son de la baseline (pines de memoria/imagen del manifiesto y del seed en
este checkout), no de este cambio.
Seguimiento nombrado (C1 del asiento 1) — NO va en este PR
Ejemplos de invocación sin
--taskque quedan obsoletos desde que--taskes obligatoria, yque este PR no toca a propósito (el conjunto de diff clavado por
T7[diff]no los admite; searreglan en su propio cambio):
core/manifests/apps/sbx-gits/README.md§10.4, líneas 756 y 762(
run --epic <epica> --tree …sin--task);docs/gits-sbx/t7-emu-smoke.md, líneas 795 y 836 (ídem);tools/gits-sbx-emu-proof.sh(línea 19: el ejemplorecord --epic X --rc 0 --result OK …, que ya no existe) y el texto deldiederecord(«la unica forma … esrun --epic <E> --tree <checkout>», sin--task).Despliegue: este PR NO cambia nada en el pod (dicho claro)
El ConfigMap de herramientas lleva el pin de bloque literal (#870): sus claves son una copia
literal de los ficheros, así que editar
tools/gits-sbx-emu-proof.shen el repo no llega alpod por auto-sync. Hasta que la bump de pin (#872) — que va por su propia compuerta — no se
mergee, este cambio tiene cero efecto visible en
sbx-gits-0:/run/sbx-tools/gits-sbx-emu-proof.shsigue siendo el de antes, y el
checkde la compuerta se comporta exactamente igual.No se ha desplegado nada, no se ha tocado el ledger vivo (solo lectura) ni el volumen de trabajo.
Lo que no he podido verificar
etiqueta están probados con repos y suites de mentira (como el resto de la sección 22 del
arnés) y con la composición real de
connected_taskdel hermano smoke, no contra Gradle.checken el pod sobre el ledger vivo (38 líneas) imprima la etiqueta nueva: hace falta elpin-bump (#872) para que el pod tenga este fichero. La lógica de la etiqueta está probada
offline en
22[R176b] (f2)(camino de fallo) y22[R176b] (f2b)(camino OK, la forma delledger vivo).
Verdict of record — ld-reviewer — head
ee994e19d2: REQUEST_CHANGESmodel: deepseek-flash
session: ses-874-seat1-b3f7a2
Blockers
OK-path-label-unreachable: blocker — claim 3 is not delivered in the OK report. Incmd_checkthe candidate loopbreaks at the first clean canonical line (gits-sbx-emu-proof.sh, theok_line=$ln … breakin the anchor branch, ~L1876), so atests_run=0line that comes AFTER the head's passing smoke line is never appended to the newzero_tests[]array and is never labelled. It is then only reported by the pre-existing "otras corridas de este head en el ledger" loop, which printsresult=OK rc=0 via=run — … es OTRA suiteand says nothing about zero tests. That is precisely the live line-38 shape the PR sets out to fix (and the shape the code comment promises: "se acumula para TODA linea … se imprime tanto si el head pasa … como si no"), and the new harness case22[R176b] (f2)cannot see it: (f2) writes a ledger whose ONLY line is the zero-tests line, i.e. the failure path.Reproduced in my own worktrees with fake suites (no emulator, both orders, same head H, canonical fake smoke committed at the canonical relpath so the anchor resolves):
[passing 2-case canonical line, then line-38-shaped OK/tests_run=0 line]→check Hrc 0, report line:PROOF otras corridas de este head en el ledger (NO son el smoke canonico, NO lo prueban): linea 2 … result=OK rc=0 via=run — su sha256 NO es el ancla_blob, and nono tests executed/NO se ejecutaron pruebasanywhere in the output.PROOF evidencia (no suficiente): linea 1 … tests_run=0 — NO se ejecutaron pruebas (no tests executed — evidence only).tests_runblock.The fix is small (accumulate
zero_tests[]in a pass over every head-matching line independent of the anchorbreak, or carry the label into the "otras corridas" loop), and (f2) should gain a second ledger — passing line FIRST, zero line second — so the test bites for the OK path it claims.What I verified (executed, not read)
Both defects reproduce at origin/live
960410f5first, then the fixes at the head:exit 0+ no XML: line written with"result":"OK","rc":0,"tests_run":0,"xml_sha256":"e3b0c442…",rc=0, andtask=":app:connectedDebugAndroidTest"(defect 2 riding along in the same run). At the head: rc 2, ledger file not even created, capture kept and named (ledger.runs/<head>.<sha>.log), message names the cause. The condition is exactlyrc == 0 && TESTS_RUN == 0: anrc=1+ zero-case run is still recorded (result=FAIL,tests_run=0,rc=0overall, capture kept). Empty-XML-directory and a suite that writes<testsuite tests="0">are both refused — refusing there is right (nothing was proven), see C2 for the message.--taskrequired (claim 2) — verified. absent → rc 2, nothing written, message names both valid forms;--task ':app:…'and--task 'x::y'refused by construction;--task 'app:connectedDevDebugAndroidTest'with--module app→ AVISO namingapp:app:connectedDevDebugAndroidTest; a normal 2-case run still writes a clean OK line withtests_run=2. The composition model matches the smoke (task="$TEST_MODULE:$(connected_task)"+CONNECTED_TASKwins).checklabel (claim 3) — half; blocker above. Failure path works, OK path works only when the zero line precedes the passing line; tamper detection is not weakened (the label is a report-side accumulation; the chain/anchor/capture checks are untouched and the labelled line still went through chain verification, and the same line still fails the gate).22[R176b] (f),(f2),(f3).git diff --stat 960410f5..ee994e19is exactly 3 files with onlytools/gits-sbx-emu-proof.shunder sbx-gits, consistent with the re-measured T7 diff set. I could not independently certify the red-set equality (9 red/690vs9 red/693) — see C4.kustomization.yaml's literal copy still carries the old help (run --epic <E> --tree <dir> [--module <m>] [--task <t>]optional), which is what the pod keeps until the pin bump; nothing in this PR is pod-visible.Concerns
[--task <t>]as optional (L120), and therecordrefusal message still tells callers the only way is'$PROG run --epic <E> --tree <checkout>'— an invocation that now exits 2 (L~2049). Outside this file, the canonical examples incore/manifests/apps/sbx-gits/README.md(L756, L762) anddocs/gits-sbx/t7-emu-smoke.md(L795, L836) also lack--task. Those two files cannot be touched here without breaking the T7 diff pin, so they need a follow-up ticket; the two occurrences insidegits-sbx-emu-proof.shcan and should be fixed now.<testsuite tests="0">), the refusal still says "no hay XML posterior al arranque en …". That is false and points the reader at a missing file when the real case is a filter that matched nothing (--class). The message should distinguish "no XML" from "XML with zero cases".scripts/gits-sbx-epic-test.sh: nothing automated invokesrunwithout--task(the harness passes--task), so no GITS merge would start refusing. The only callers that now rc 2 are the doc examples in C1 and the tool's own message./tmppaths (e.g./tmp/h2v3-objects-sbx-sendrast-*.txt), which produced one spurious extra red on the head (H2v3[3] render … anadidos: ConfigMap/sbx-sendrast-models-json) that I do not treat as evidence against this PR — the two worktrees' sendrast directories are byte-identical and resolve the sameorigin/live. The landing worker should re-measure the red lists with sequential solo runs before merge.--taskis validated for shape but not against the module's real tasks (by design, the suite resolves it) — fine, just noting the AVISO is the only guard against a plausible-but-wrong task name.Verdict of record — ld-reviewer — head
ea6993cb14: APPROVEmodel: deepseek-flash
session: ses-874r2-seat1-4f18c07b
Blockers
None.
The round-1 blocker is genuinely fixed and I reproduced both sides of it myself: with the pre-fix head (
ee994e19) the[line that PASSES, then zero-test line]shape gives rc 0 and the label is absent (and the report prints only "el smoke CANONICO tambien corrio en este head, en la linea 2: result=OK rc=0", i.e. a second good run); with this head the same shape gives rc 0 and the label. The zero-test line never completes the gate, and the pre-pass changes no verdict: over six ledger shapes the pre-fix and this head print byte-identical output except the added label line.Concerns
origin/plane/HOMELAB-2682-pin-bumppinsgits-sbx-emu-proof.shto211be2b5…(1957 lines / 125320 B — the post-#871 tool), while this head'stools/gits-sbx-emu-proof.shhashes43e5f04e0a1d71ec931109268cc2e4a576ab4d235280813b0f75e57f7a84be1b(2090 lines / 136638 B). The narrow claim is true and I confirmed the mechanism (thesbx-gits-toolsConfigMap is aliterals:block with nofiles:, so editingtools/renders identically and reaches no pod until the block is re-cut): zero pod-visible change from this PR. But "hace falta el pin-bump (#872) para que el pod tenga este fichero" is false as things stand — merging #872 leavessbx-gits-0on the pre-#874 bytes, so the live ledger's zero-test lines stay unlabelled while the record implies #872 shipped the fix. Fix by correcting the body, or by re-cutting #872's literal block to43e5f04e…before #872 merges. No code change needed, which is why this is not a blocker.--task-less invocations remain exactly where round 1 found them:core/manifests/apps/sbx-gits/README.md§10.4 (~lines 756, 762, and the--classexample at ~766),docs/gits-sbx/t7-emu-smoke.md(~795, ~836), and the tool's own header (record --epic X --rc 0 --result OK …, now lines 19–21) plusrecord'sdietext, which still namesrun --epic <E> --tree <checkout>with no--task. Every one of those now exits rc 2. Declaring them out of scope is honest and the frozenT7[diff]set genuinely does not admit those files — what is missing is a named tracker: the PR names no ticket, and the identifier the branch uses (HOMELAB-2682) resolves in Plane to an unrelated LD intent ("ld-1: see my programs in Lab Director"), while the sbx-gits epicHOMELAB-2648resolves correctly. Please confirm the reference and file the follow-up, or README and the runbook keep documenting a command that now fails.PROOF aviso el smoke CANONICO tambien corrio en este head, en la linea 2: result=OK rc=0 via=run …and only thenPROOF evidencia (no suficiente): linea 2 … tests_run=0 …. The pair is now truthful, but that first line still says nothing abouttests_run, so a reader who stops there reads a second good run — the exact misreading round 1 named. Additive fix: saytests_run=$tests_runinside the (4d) "otras corridas" block (or drop that line whentests_run=0), or print the zero-test evidence before it.jstr/jrawfour more times per candidate instead of reusing the$h/$result/$rc/$tests_runthe chain loop had in hand. Cost on a pathological 38-line ledger whose 38 lines all belong to the checked head:check4.37 s → 5.55 s (median of 5; min 4.23 → 4.81). On the real ledger (38 lines, a handful of candidates for any one head) the cost is negligible, so this is a simplification note, not a defect.check's label still reads "no hay ni un caso en los XML", true by the definition oftests_run, but unlikerun's message it does not distinguish "the suite left no XML" from "XML present with no<testcase>". When the line carriesresults_sha256, the XML did exist and had no cases; that could be said. Not false in either case, so cosmetic.What I verified first-hand
All runs solo and sequential (never two trees at once), from clean detached worktrees.
1. Round-1 blocker, both sides. Fake repo with the canonical smoke committed at
core/manifests/apps/sbx-gits/tools/gits-sbx-emu-smoke.sh, fake suite, and a hand-built zero-test line chained with the tool's ownchain_text(tests_run=0,xml_sha256=e3b0c442…, its ownPROOF-RUNcapture,script_sha256= the anchor):ee994e19(pre-fix)ea6993cb(this head)2. Additive-only, proven by diff. Same ledger, both binaries, six shapes —
[pass, then zero],[zero, then pass],[only zero], red canonical + green canonical, another suite (evidence line), and a hand-edited line (broken chain). Output identical in all six except (a) the single newevidencia (no suficiente)line in the[pass, then zero]case and (b) nothing else — no refusal text, no verdict, no ordering changed. Round-1 test still holds: a clean canonical line passes the head; a zero-test line never completes it;rc=1with zero cases is still recorded (result":"FAIL","rc":1,"tests_run":0) with the "SI hay XML … pero NINGUNO trae un<testcase>" AVISO.3.
(f2b)bites. I extracted epic-test §22b (T176) into a standalone runner and drove it twice: real head tool → 40 checks, 1 FAIL (an extraction artifact, present in both runs),(f2b)PASS; then a surgical mutation of the head tool that removes only the pre-pass and puts the label back inside the gate loop (the round-1 shape) →(f2b)FAIL: "BLOQUEO: … el head pasa (rc=0) pero la linea de cero casos NO se etiqueta", while(f2),(f),(f3)stay PASS. The case fails for exactly the reason it claims.4. Harness honesty, solo and sequential.
bash scripts/gits-sbx-epic-test.sh:origin/live960410f5: FAIL 10 of 690 (8 skipped);ea6993cb: FAIL 9 of 694 (6 skipped);16[R161] mutacion (ii)(the lock-under-load self-test flake). The skip delta is the branch exercising two checks the baseline skips:T7[diff]and17[R159] (d)PASS here, with the diff ofsbx-gitsvsorigin/liveexactlyM tools/gits-sbx-emu-proof.sh, and the mutation ("remove that line from the allowed set") still red.git diff --name-status 960410f5..ea6993cbis three files: the tool,docs/gits-sbx/run-proof.md,scripts/gits-sbx-epic-test.sh— no new files.5.
run's refusals, re-checked at this head. no--task→ rc 2, nothing executed, no line, valid forms named;--task ':app:…'→ rc 2;--task 'app::…'→ rc 2; guard is exactlyrc==0 && TESTS_RUN==0. C2: both new strings reachable and true in the case that produces them — XML present with zero<testcase>(<testsuite tests="0">, and theFAKE_TESTS=0suite) gives "SI hay XML posterior al arranque … pero NINGUNO trae un<testcase>";FAKE_NOWRITE=1gives "no hay ni un XML posterior al arranque". The pre-scan keeps "posterior al arranque" honest (a stale untouched XML is excluded).6. Chain/anchor/integrity. The round-2 delta touches no hash, chain, anchor, artifact-binding or
results_sha256logic; the pre-pass is read-only overcand/candn(this head's lines only) and its locals cannot leak into the verdict. The gate'stests_run > 0,via=run,tree_clean/tree_clean_after,smoke@commitanchor and capture binding are unchanged, and the harness's attack cases ((b),(c1)–(c3),(d)–(d4),(i),(i2),(o)) all still PASS.Verdict of record — ld-reviewer — head
ea6993cb14: APPROVEmodel: deepseek-flash
session: ses-874r2-seat2-54a5f625
Blockers
None.
The round-1 blocker is closed, and I reproduced it first-hand before accepting the fix.
What I verified myself (no prior verdict used as evidence)
Independent fixtures: fake repo with the canonical smoke committed at its real path (identical bytes to the
suite
runexecutes), a fake suite that leaves 3 cases, and the hand-builttests_run=0line chained withthe tool's own
chain_text(the live ledger line-38 shape). Tools taken straight out of the objects:ee994e19(pre-fix),ea6993cb(head),960410f5(origin/live).1. The blocker: label reachable on the OK path — REPRODUCED, then GONE
ee994e19ea6993cbAt the pre-fix head the OK path prints nothing about the second line's zero cases — it says only
aviso el smoke CANONICO tambien corrio en este head, en la linea 2: result=OK rc=0 … SI es el smoke canonico, NO otra suite, i.e. it reads as a second good run. That is exactly the live ledger shape (line 38 after thesmoke line) and exactly the seat-1 mechanism. At
ea6993cbthe same fixture adds:Gate semantics did not move: a clean canonical line still returns rc=0 (shapes 1 and 2), the zero-test line
never completes the head (shape 3 stays rc=1, and its own
tests_run>0refusal is still there), andok_linecan never be a zero-test line.2. The new pre-pass is additive-only
I diffed the full
checkreport of the same fixture atee994e19vsea6993cb(fake head sha normalised):shape 1 gains exactly one line (the label); shapes 2 and 3 are byte-identical. No refusal text changed, no
verdict flipped, no new reason appears. In code the pass only reads
cand/candninto a newzero_tests[]array; its locals (
zi zln zc zh zres zrc zrun) are declared and do not shadow the gate loop's.Perf: a 41-line ledger for one head with 40 zero lines costs 5.2 s vs 3.7 s for the same size with no zero
lines (~37 ms per candidate line). Real ledgers are 38 lines total with 1-3 lines for a given head, so the
added cost is tens of milliseconds. No issue.
3.
runrefusal is exactlyrc==0 && tests_run==0(
…queda en '<art>'); I read<art>back — it is the run's own log.result=FAIL, and the AVISO saystests_run=0 (…) : result=FAIL sin casos ejecutados — check <head> NO la acepta como prueba.<testsuite tests="0">) → refused too, with the other cause named(see C2 below).
The guard sits after the run and before chaining, so a refusal cannot leave a partial append.
4.
--task--task '') → rc 2, nothing written, nothing executed, message names both valid forms(
connectedDevDebugAndroidTest/connectedStableDebugAndroidTestfor a flavoured module,connectedDebugAndroidTestwithout flavours).--task ':app:connectedDebugAndroidTest'and--task 'a::b'→ rc 2, nothing written, refused byconstruction.
--task 'app:connectedDebugAndroidTest'with--module app→ AVISO naming the exact task Gradle wouldreceive (
app:app:connectedDebugAndroidTest) and the corrected invocation; the run proceeds.The check is at step 0b, i.e. before the emulator is spent.
5. C2 messages are reachable and true
At
ee994e19the zero-case suite printedtests_run=0 (no hay XML posterior al arranque …)while the runhad left one XML (
<testsuite tests="0">) — the false sentence. Atea6993cbthe same fixture printstests_run=0 (SI hay XML posterior al arranque en … (1 fichero(s)) pero NINGUNO trae un <testcase>: cero casos en los XML …), and the no-XML case printsno hay ni un XML posterior al arranque en … (la suite no dejo resultados). Both branches observed; both refusals still rc 2 with no line.6. Harness — SOLO, SEQUENTIAL (clean worktrees, never two at once)
960410f5ea6993cbThe FAIL sets (after normalising tmp paths and shas) are identical: branch ⊆ baseline with zero new reds
(the nine are the known environment/pin reds:
manifest[2]/[3]/[3b],T7 emulador,T7+R99[10b],11[H11]x3, theprobe --dircase). My baseline came out 9, not the 10 the PR table reports — the18[R165] --lock-selftestred did not reproduce on this box; that only makes the subset relation cleaner,it does not weaken the claim.
T7[diff]PASS with the pinned set exactlyM tools/gits-sbx-emu-proof.sh, and its mutation(removing that entry from the allowed set) is RED — the set bites.
git diff --name-status 960410f5..ea6993cb=M tools/gits-sbx-emu-proof.sh,M docs/gits-sbx/run-proof.md,M scripts/gits-sbx-epic-test.sh. No new files; the two round-1 files sit outsidecore/manifests/apps/sbx-gits/so the pinned set is correct.
22[R176b] (f2),(f2b),(f3)— all PASS at the head; the rewritten(f)PASSes too.(f2b)bites: its assertion ischeck rc=0 AND the label present; on the pre-fix tool the same fixturegives rc=0 with the label absent, which is precisely the case's BLOQUEO branch. Test first, fix after —
that is what the object graph actually does, not just what the PR body says.
7. Chain / anchor / integrity — nothing weakened
chain_textis untouched (the tamper cases(b),(d),(d2),(n),(o2),(q2)all still PASS), theanchor is still the committed blob, and both new behaviours fail closed (refuse to write) rather than
loosen anything. The only verdict-shaped risk in this diff is the label, and the label is provably report-only.
8. Deployment note intact
The
sbx-gits-toolsConfigMap is still a literal pin (kustomization recordsgits-sbx-emu-proof.shshaac29a440…= the tool ata848b717), and that is neitherorigin/live's211be2b5…nor this head's43e5f04e…. The pod's/run/sbx-tools/gits-sbx-emu-proof.shis unchanged by this PR; #872 is open and isthe only route to the pod. The claim "zero pod-visible change until the pin bump" is true.
Concerns
Non-blocking. None of these changes the verdict.
two causes and the PR argues at length that conflating them is misleading — but the new
docs/gits-sbx/run-proof.mdsection and the tool's--helpstill describe zero-tests as one cause only("ningún XML posterior al arranque en
<árbol>/<módulo>/build/outputs/androidTest-results"). A run thatleaves
<testsuite tests="0">or an XML without<testcase>is refused with the other message. Onesentence in each place ("o XML sin ningún
<testcase>") closes it.core/manifests/apps/sbx-gits/README.mdlines 755/762 anddocs/gits-sbx/t7-emu-smoke.mdlines 795/836 allshow
run --epic … --tree …with no--taskand would now be refused (rc 2), and so does the liverecorddie text (La unica forma de anadir una linea es EJECUTAR la suite: '<prog> run --epic <E> --tree <checkout>') — a user-facing instruction that now always fails. Please make sure the follow-up carries aPlane id; the PR text names files but no ticket. Minor: the header's
record --epic X --rc 0 --result OK …example is historical framing ("why record is gone"), not a stale instruction — only the
dietext is.(f2)'s message still reads "no hay ni un caso en los XML" for a line that mayhave carried no XML at all; harmless (the line is refused either way) and out of scope, but the same
distinction C2 makes in
runcould be made here too.Limits of this review
Read-only: I ran the tool and the harness against throwaway fixtures/worktrees, I did not edit, commit, push or
merge, and this comment is my only write. I did not see any other round-2 verdict, and no emulator, Gradle or
cluster was involved — the two refusals and the label are proven against fake suites and a fake repo, the same
way section 22 of the harness proves them.
The blocker raised in review 22723 is resolved on head
ea6993cb14.The blocker raised in review 22768 is resolved on head
ea6993cb14.The blocker raised in review 22789 is resolved on head
ea6993cb14.