R-426: hostinstall gate gets decoys; two live holes closed, exemption removed

The R-185 check counted the bare word `felhom-backup-target-apply grant`, so the
dry-run echo stood in for a deleted real grant (2 resolutions, 2 "grants"); now
only path-qualified invocations at a command start count. The age check matched
a commented-out install; now comment lines are excluded. Decoys (plus a version
const in a new hub sub-package, and a comment naming the identifier that must
pass) live in test_gate_decoys.py; all three convicting decoys were seen to PASS
against the pre-fix gate. EXEMPT drops `felhom.eu/hostinstall`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-06 01:04:56 +02:00
parent 70304a53df
commit c6c6cb7676
3 changed files with 54 additions and 5 deletions
+10 -2
View File
@@ -109,7 +109,10 @@ else:
# ── 2. age package (F-10) ───────────────────────────────────────────────────────
# must match the REAL install invocation, not the log_dry echo (red-proof-hardened twice:
# a prefix regex matched "agekit", then a loose one matched the dry-run print line).
if re.search(r'DEBIAN_FRONTEND=noninteractive apt-get install -y -q age\b', src):
# R-426 (2026-10-06): and not a COMMENTED-OUT one — `# DEBIAN_FRONTEND=… age` (a line disabled while
# debugging) matched the bare search, so the label stayed and the install was gone. Decoy:
# test_gate_decoys.py `hostinstall/age-commented-out`.
if re.search(r'^[^#\n]*DEBIAN_FRONTEND=noninteractive apt-get install -y -q age\b', src, re.M):
ok("age is in the installed package set")
else:
fail("`age` install not found (F-10 — the fresh-box escrow ceremony dies without it)")
@@ -221,7 +224,12 @@ if not fn:
else:
body = fn.group(1)
resolutions = len(re.findall(r'BACKUP_TARGET_RESOLVED="\$BACKUP_TARGET_ID"', body))
grants = len(re.findall(r'felhom-backup-target-apply grant', body))
# R-426 (2026-10-06): count only REAL invocations — the path-qualified binary at the start of a
# command line. The bare name also matched the `log_dry "felhom-backup-target-apply grant …"`
# echo, so deleting the Scenario-F arm's real grant (R-185's exact regression) left 2 resolutions
# against 2 "grants" — the dry-run label — and this check printed ok. Decoy: test_gate_decoys.py
# `hostinstall/R-185-dry-run-echo-only`.
grants = len(re.findall(r'^[ \t]*/usr/local/sbin/felhom-backup-target-apply grant\b', body, re.M))
if resolutions == 0:
fail("configure_backup_target no longer resolves BACKUP_TARGET_ID anywhere — re-read it")
elif grants >= resolutions: