HOMELAB-2682: feat(sbx-gits): documented PRECLEAN=skip opt-out in emu smoke #847
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!847
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "plane/HOMELAB-2682-preclean-optout"
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?
The need (quoted, not narrowed)
From gits-hypervisor:
The smoke's
PRE-CLEAN(R171) uninstalls<app><suffix>and<app><suffix>.testimmediatelybefore Gradle installs. That is correct for an app with no persistent state of its own, and it
stays the default — but for an app that keeps its identity in AndroidKeyStore, the uninstall
takes the hardware-backed key with it, and the guest key cannot be enrolled between install and
test. That suite ends up measuring a freshly cleaned emulator without the identity it needs, so
today its consumer dodges the smoke with its own suite under the proof tool.
The change
core/manifests/apps/sbx-gits/tools/gits-sbx-emu-smoke.shonly:PRECLEAN=skip.the emulator (the install keeps its flags; only the uninstall step is bypassed) — and the run
prints one line saying so:
PRE-CLEAN omitido por env: PRECLEAN=skip (no se desinstala nada, se instala ENCIMA; AndroidKeyStore no exportable: el uninstall destruye la identidad respaldada por hardware y el guest key no se puede inscribir entre install y test)so captures (and therefore the ledger artifact) cannot pretend the emulator was cleaned.
PRE_CLEAN_ST=SKIP, which already means "no cleaning happened here": it is not afailure, does not colour
connected-test, does not changerc, and does not add a fourthCHECK INFRAline.--help;docs/gits-sbx/t7-emu-smoke.md(the phases section, with the why and the safety framing) and
docs/gits-sbx/run-proof.md(the proof-tool interaction).scripts/gits-sbx-epic-test.sh§23 runs the real extracted smoke code against astateful fake
adb: default uninstalls;PRECLEAN=skipdoes not and the state survives theinstall;
Skip/SKIP/1/yeskeep the default. Two executed red mutations (a copywith no opt-out; a copy with a lax
${PRECLEAN,,}comparison that would acceptSkip) mustbehave differently, so the green is not an assertion nobody has seen fail.
T7[diff]/17[R159] (d)pinned set updated to what this branch actually changes againstorigin/live(M tools/gits-sbx-emu-smoke.sh; the docs/harness live outside that prefix).kustomization.yamlandstatefulset.yamluntouched.Default unchanged
PRE-CLEANstays ON, same output, samerc, same summary. The comparison is literal (
== skip), so a typo cannot disable it.CLEANat the end (the cleaning for the next epic) is untouched. This is an opt-out forsuites that need state to survive the install, not a way to skip cleaning between epics — and
when it is used, the capture records that the uninstall did not happen.
Proof tool non-interaction
gits-sbx-emu-proof.shis not modified (andT7[diff]would go red if it were).checksemantic change: the only trace isthe smoke's own warning line inside stdout, which lands in the capture and therefore in
output_sha256.checkdoes not look atPRECLEAN, and should not.runlaunches the suite in a subshell with the same environment, so the variable isinherited; a default
run(no variable) executes exactly the same smoke as before.Verification
bash -non the smoke, the harness and the (untouched) proof tool: clean.bash scripts/gits-sbx-epic-test.shrun solo (never concurrent — fixed /tmp paths):RESULT: FAIL (3 of 593 checks, 6 skipped, 0 pending)→ 590 pass, 3 red, 6 skip. Allthree reds are pre-existing and their inputs are untouched here: the known
probe uses an EMPTY pre-existing --dirred, andmanifest[3]/manifest[3b], whoseexpectation literal (
platform/sbx-fleet:eebdbe1@sha256:7e0513ca…) appears 3× inorigin/live's own harness whileorigin/live's ownstatefulset.yamlcarries6fa150a@sha256:0ee5e97…(PR #842) —git diff origin/live -- core/manifests/apps/sbx-gits/{statefulset,kustomization}.yamlis empty here.
T7[diff]and17[R159] (d)pass on the re-measured set (M tools/gits-sbx-emu-smoke.sh),and the set bites (the red mutation that removes the entry goes red).
adb, no pod): default →uninstall before install,
PRE_CLEAN_ST=OK,connected-test: OK;PRECLEAN=skip→zero uninstall actions, install-over, state preserved, one marker line,
PRE_CLEAN_ST=SKIP,connected-test: OK;Skip/SKIP/1/yes→ default path.Both red mutations execute as designed. 21 checks, 0 fails. Existing §19[R171] re-run:
17 checks, 0 fails.
Files
M core/manifests/apps/sbx-gits/tools/gits-sbx-emu-smoke.sh,M docs/gits-sbx/run-proof.md,M docs/gits-sbx/t7-emu-smoke.md,M scripts/gits-sbx-epic-test.sh.kustomization.yaml,statefulset.yamlandgits-sbx-emu-proof.shuntouched.Verification (head
f9870ce, branch run solo)bash -n:gits-sbx-emu-smoke.sh,scripts/gits-sbx-epic-test.sh,gits-sbx-emu-proof.sh(untouched) — all clean.bash scripts/gits-sbx-epic-test.sh(run alone, never concurrent — fixed /tmp paths):RESULT: FAIL (3 of 593 checks failed, 6 skipped, 0 pending)→ 590 pass, 3 red, 6 skip.All three reds are pre-existing and none of their inputs is touched by this branch:
probe uses an EMPTY pre-existing --dir and leaves it in place (rc=2)manifest[3] imagenes = sbx-fleet@sha256:7e0513ca…platform/sbx-fleet:eebdbe1@sha256:7e0513ca…) appears 3× inorigin/live's own harness whileorigin/live's ownstatefulset.yamlcarries6fa150a@sha256:0ee5e97…(PR #842's pin). Live's harness already disagrees with live's manifest;git diff origin/live -- core/manifests/apps/sbx-gits/{statefulset,kustomization}.yamlis empty here and this branch adds 0 occurrences of that literalmanifest[3b] bump de imagen H5 (falta: …)The two guards named in the brief still pass, on the re-measured set:
New §23 (real extracted smoke code + stateful fake
adb, no pod):Cases actually executed: default (
PRECLEANunset) → uninstall before install,PRE_CLEAN_ST=OK,connected-test: OK;PRECLEAN=skip→ zero uninstall actions, install-over, state survives,one marker line,
PRE_CLEAN_ST=SKIP,connected-test: OK;Skip/SKIP/1/yes→ thedefault path,
PRE_CLEAN_ST=OK.R171 section re-run after the fixture fix (unchanged semantics): 17 checks, 0 fails — the
existing PRE-CLEAN green/mutation proofs still bite (its red mutation now deletes the call
independently of indentation).
CI on this head: run #3138 and #3139 — all jobs success (shellcheck, terraform-validate,
yaml-lint, helm-validate, runner-manifest-test, record-sql-test, dispatcher/cockpit/receiver…).
Files vs
origin/live:M core/manifests/apps/sbx-gits/tools/gits-sbx-emu-smoke.sh,M docs/gits-sbx/run-proof.md,M docs/gits-sbx/t7-emu-smoke.md,M scripts/gits-sbx-epic-test.sh.kustomization.yaml,statefulset.yamlandgits-sbx-emu-proof.sh: untouched.Verdict of record — ld-reviewer — head
f9870ce020: APPROVEmodel: deepseek-flash
session: 01a1ac8a-5333-757a-b84d-27614526925e
Seat 2 of 2 (adversarial/tooling angle). Everything below was read off the head and, where it
could be executed, executed against stubs in /tmp — the real opt-out block and the real
clean_variant_packagesextracted fromgits-sbx-emu-smoke.shat this sha. The parallelcorrectness seat is not a dependency of anything here.
Blockers
None.
Concerns
PRECLEAN=${PRECLEAN:-}in the smoke claims thecomparison is "sin distinguir mayusculas" (case-insensitive). The code
(
[[ $PRECLEAN == skip ]]) is case-sensitive, and every other surface says so: the headerblock, the
--helptext, both docs, harness case (3) and the second red mutation. Behaviouris correct and safe; the sentence is wrong, and it sits at the definition site, so a
maintainer following it would write
${PRECLEAN,,}— precisely the lax comparison theharness's second red mutation exists to catch. Dropping those four words in this PR would
keep the one artifact that is read next to the code honest.
== RESUMEN/== CHECK INFRAblock. Theresumen prints
clean(CLEAN_ST) only;PRE_CLEAN_STis never printed there, and in theskip branch
clean_variant_packagesis not called at all, so there is noPRE-CLEAN resultado:line either. The single trace is the marker line in the body (and soin the capture). That is consistent with "no output change", but someone reading only the
three copyable lines cannot tell. Not for this PR necessarily: a
pre-clean=SKIP(env)tokenin the resumen line would surface it without adding a fourth CHECK INFRA line or a ledger
field.
hardware-backed identity does not survive the run.
t7-emu-smoke.mdalmost says it ("sóloafecta al estado que esta corrida deja antes de instalar"), but the new §
PRECLEAN=skipwould be safer stating once that the suite must re-enrol inside its own run, so the opt-out
cannot be read as "the identity now persists between runs".
What I verified (evidence, seat 2)
PRECLEAN=${PRECLEAN:-}line and the realif/elseblock from the head into a harness withset -uo pipefailand a stubclean_variant_packages.skip→ no uninstall call,PRE_CLEAN_ST=SKIP.Skip,SKIP,1,yes,true," skip","skip ",sk,sk?p→ the uninstall runs,PRE_CLEAN_ST=OK. Unset → uninstall runs and does not tripset -u(the:-defaultdefines it). So: no trimming, no case folding (C1's sentence aside), a glob in the value
cannot match because the pattern is the literal right-hand token, and every typo fails safe
to PRE-CLEAN ON.
gradle_task,the same single
check_line connected-test, the same end-of-runphase_cleanand the sameon_exit;xml_scanreads the outputs directory by mtime, untouched.PRECLEANappearsnowhere in
gits-sbx-emu-proof.sh, andcmd_check's required-field list has no notion ofcleaning, so the gate is semantically identical. The only delta is the one marker line in
stdout, which lands in the capture and therefore in
output_sha256— a new artifact identityfor a run that skipped the uninstall, which is the intended, honest outcome.
runlaunches the suite as( PROJECT_DIR=… CONNECTED_TASK=… bash "$real" … ), so every other variable,PRECLEANincluded, is inherited from whoever invokes the proof tool; the runbook has the driver typing
that command by hand, so no wrapper pins the environment. A caller who can run
runcantherefore obtain a check-green line from a run that installed over stale state. Assessment:
a concern at the gate's trust boundary, not a defect of this diff — (a) that boundary is
already defeatable before this PR and with less visibility: I executed it,
EMU_APP_PACKAGE=com.bogusturns every pre-clean target into "no instalado (ok)", ends inPRE-CLEAN resultado: OKand prints no marker at all; (b) the feature was requested by thegate's own consumer (gits-hypervisor) for a case it currently dodges completely outside the
smoke; (c) the marker lands inside the hashed capture, so the weakening is legible and
non-repudiable in the artifact. If the owner wants it hard, two named mitigations: pin
PRECLEAN=explicitly at the epic/gate invocation site (no code), or teachchecktorefuse a line whose capture carries the marker unless the epic declared the opt-out (a
schema decision this PR deliberately did not take, and both docs are honest about that).
f9870cematches its message and its scope. It touchesscripts/gits-sbx-epic-test.shonly — no production code, no docs, no smoke change.t171_extractnow also extracts the realPRECLEAN=default line and refuses the extractionwithout a
grep -q '^PRECLEAN='guard, so a missing default fails loudly instead of passingby luck; the R171 red mutation sed is anchored
^[[:space:]]*, and I checked the target textoccurs exactly once in the head smoke (the call inside the opt-out's
else), with themutation verified as applied via
cmpplusgrep -c0, so it cannot silently no-op; §23'sdefault case now asserts ORDER (uninstall line before install line — R171's actual point)
instead of end state, counts the marker in the run that has the opt-out rather than in a
later typo case, and drops the old source-text
grep -c == 1assertion in favour of theexecuted count. Fixtures and assertions only, as the message says.
Verdict of record — ld-reviewer — head
f9870ce020: APPROVEmodel: deepseek-flash
session: 01a1ac8a-5304-757a-b84d-275e298774f1
Blockers
Concerns
PRECLEAN=${PRECLEAN:-}(smoke lines 329-331) says thecomparison is "sin recortar y sin distinguir mayusculas", i.e. case-insensitive, which
contradicts the code (
[[ $PRECLEAN == skip ]], literal), the file header (lines 152-153),the
--helpblock and both docs. Executed:Skip,SKIP,1,yes,skip,skipalltake the default path. Suggest dropping that clause so a later reader cannot "align" the code
with the comment.
the previous suite no longer satisfies
check(script_sha256). That is the documentedpre-existing semantics (the new
run-proof.mdsection says exactly this); the only follow-upis that the GITS-493 consumer's next official
runis on the merged head.What I verified (primary sources at this head)
say/hms/check_line/gradle_shim_check/app_id/variant_suffix/clean_pkg_installed/clean_variant_packages/set_clean_result/pre_clean_hand_check/phase_clean/phase_connected_testfrom the base smoke (
911810dd) and from the head smoke and ran both against the samestateful fake
adbwithPRECLEANunset: stdout identical apart from my own fixture paths,action sequence identical —
uninstall <app>.dev, then the three "no instalado (ok)" probes,then the install. Same order, same
adb -s "$ADB_SERIAL" uninstallform, same flags;PRE_CLEAN_ST=OK,connected-test: OK.Failure [DELETE_FAILED_USER_RESTRICTED], base and head both yieldPRE-CLEAN resultado: FAIL (1 paquete(s))→connected-test: FAIL (PRE-CLEAN no pudo dejar sin instalar …)plus the manual-check line. The guard inside theelseis intact.PRECLEAN=skip→ zero uninstall actions, first action isinstall com.ejemplo.app.devover the existing package, exactly one marker line,PRE_CLEAN_ST=SKIP,connected-test: OK, no extracheck_line(soCHECK INFRAkeeps itsthree lines and
rcis untouched).CLEAN, executed.phase_cleanwithPRECLEAN=skipset is byte-identical tobase: the end-of-run clean is not affected.
skip→ skip path;Skip,SKIP,1,yes,sk*,*,skip x,skip,skip, unset → default. No globbing, no trim, no case folding.PRE_CLEAN_ST/PRE_CLEAN_PKGS/PRE_CLEAN_FAILSare read only bythe FAIL guard that the skip branch bypasses; nothing else in the smoke or the proof tool
reads them, and
pm path/pm list packagesappear only insideclean_variant_packages/pre_clean_hand_check.gits-sbx-emu-proof.shis byte-identical to base(sha256
b9d098e8…). It runs the suite as( PROJECT_DIR=… CONNECTED_TASK=… bash "$real" … ), so the variable is inherited;runderives
resultfrom the real rc plus the XML and never parses the smoke's check lines, sothe marker can only reach
output_sha256(documented). No new field, no capture-format orcheckchange.--help(rendered locally withgits-sbx-emu-queue.shpresent) state the single exact value, the AndroidKeyStore reason andthat the default stays on;
docs/gits-sbx/t7-emu-smoke.md(R171 pointer + the new§
PRECLEAN=skip) anddocs/gits-sbx/run-proof.mdmatch the executed behaviour.23[HOMELAB-2682]= 21 checks, 0 fails, andboth red mutations execute (the no-opt-out copy behaves exactly like the default; the lax
${PRECLEAN,,}copy acceptsSkip), so the green is not an assertion nobody has seen fail.Commit 2 touches only
scripts/gits-sbx-epic-test.sh: it extracts the realPRECLEAN=lineinto the §19 fixture (needed now that
set -ureaches the new reference), de-anchors themutation
sedfrom a fixed indent, and replaces an incorrect "package must not be installedafter the run" assertion with an uninstall-before-install ordering assertion plus a
marker-count assertion — fixture correctness, no behaviour smuggled in.
kustomization.yamlandstatefulset.yamluntouched; the sbx-gits diff set isexactly
M tools/gits-sbx-emu-smoke.sh; four files changed in total.Verdict: APPROVED
model: omniroute/deepseek-flash
head:
f9870ce020session: 01a1ac99-07e3-757a-b84d-27621b17dbcd
The blockers raised in review 22087 are resolved on head
f9870ce020: its only Blockers bullet is the empty-statement- None., which states the absence of blockers; both independent gate-tooling seats approved this exact head.