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:
@@ -36,9 +36,6 @@ EXEMPT = {
|
||||
("felhom.eu", "one-register"):
|
||||
"R-424 — a real defect parked under state `idea` is invisible. Declared in the gate's own "
|
||||
"docstring as residual hole 1; the decoy passes today.",
|
||||
("felhom.eu", "hostinstall"):
|
||||
"R-426 — no plausible decoy constructed yet. It asserts installer invariants against a "
|
||||
"shell script; a legitimate decoy needs a shape a real edit would produce.",
|
||||
("felhom.eu", "due-checks"):
|
||||
"R-426 — no legitimate decoy constructed; the attempt in the sweep was a no-op and its "
|
||||
"verdict was withdrawn rather than reported.",
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -72,6 +72,8 @@ COVERS = {
|
||||
"their sentences. Also: a prefix of the real sentence, the OLD Hungarian "
|
||||
"quote, a reworded bundle, a deleted key, and the scope case — an absent "
|
||||
"controller clone must be INCONCLUSIVE, never a pass"),
|
||||
"hostinstall": ("R-426: R-185's regression with only its dry-run echo left, the age install commented "
|
||||
"out, and a version const in a new hub sub-package; a comment naming the identifier passes"),
|
||||
"hub-copy": ("R-558: an English retrieval promise in the NEW bundle (the sentences moved "
|
||||
"out of templates.go, so the surface list had to move with them), the same "
|
||||
"in Hungarian, and an INNOCENT control using the identical verbs without the "
|
||||
@@ -393,6 +395,48 @@ decoy("site/unlisted-page", "site_gates.py",
|
||||
plant_file(os.path.join(ROOT, "website", "zz-r423-decoy.html"),
|
||||
u"\ufeff<!DOCTYPE html><html><body><nav></nav><footer></footer></body></html>\n"))
|
||||
|
||||
def replace_in(path, old, new):
|
||||
"""Mutate one exact span of a real file; restore it byte-for-byte. A span that is no longer there makes
|
||||
the decoy UNBUILDABLE, which is a failure of this suite — never a quietly skipped case."""
|
||||
def _plant():
|
||||
backup = io.open(path, encoding="utf-8").read()
|
||||
assert backup.count(old) == 1, "%s: the decoy's anchor is gone or ambiguous — rebuild the decoy" % path
|
||||
io.open(path, "w", encoding="utf-8").write(backup.replace(old, new, 1))
|
||||
return lambda: io.open(path, "w", encoding="utf-8").write(backup)
|
||||
return _plant
|
||||
|
||||
|
||||
# ── hostinstall (R-426, 2026-10-06) ──────────────────────────────────────────────────────────────
|
||||
#
|
||||
# Each decoy is a one-line edit a real session would make to felhom-host-install.sh, leaving the LABEL
|
||||
# the gate used to read while removing the fact. The first two PASSED before 2026-10-06 (live holes):
|
||||
# * R-185's own regression — the Scenario-F arm loses its real grant but keeps its dry-run echo. The
|
||||
# gate counted the bare word, so the echo stood in for the grant (2 resolutions, 2 "grants").
|
||||
# * the `age` install commented out while debugging — the bare search matched the comment.
|
||||
# * a host-install version const in a NEW hub sub-package — the scope is a walk, not a file list.
|
||||
# The genuine article is the unmodified tree, which the runner's own `hostinstall` row passes on every push.
|
||||
_HI = os.path.join(ROOT, "scripts", "felhom-host-install.sh")
|
||||
decoy("hostinstall/R-185-dry-run-echo-only", "hostinstall_gates.py",
|
||||
replace_in(_HI,
|
||||
' /usr/local/sbin/felhom-backup-target-apply grant "$BACKUP_TARGET_ID" \\\n'
|
||||
' || die "backup target grant failed on the pre-existing target',
|
||||
' true \\\n'
|
||||
' || die "backup target grant failed on the pre-existing target'))
|
||||
_AGE_CMD = (" DEBIAN_FRONTEND=noninteractive apt-get install -y -q age >/dev/null 2>&1 \\\n"
|
||||
" || { apt-get update -q >/dev/null 2>&1; DEBIAN_FRONTEND=noninteractive apt-get install -y -q age >/dev/null 2>&1; } \\\n"
|
||||
" || die \"failed to install the 'age' package (the escrow ceremony needs it)\"\n")
|
||||
decoy("hostinstall/age-commented-out", "hostinstall_gates.py",
|
||||
replace_in(_HI, _AGE_CMD, "".join("#" + l[1:] + "\n" for l in _AGE_CMD.splitlines())))
|
||||
decoy("hostinstall/hub-version-const-subpkg", "hostinstall_gates.py",
|
||||
plant_file(os.path.join(ROOT, "hub", "internal", "web", "zzr426decoy", "v.go"),
|
||||
u'package zzr426decoy\n\nconst hostInstallVersion = "1.32.0"\n'))
|
||||
# the genuine article beside the third: a comment that merely NAMES the identifier must pass (configs.go
|
||||
# carries exactly such a note), so the scope widening is not bought with false convictions.
|
||||
decoy("hostinstall/comment-names-identifier", "hostinstall_gates.py",
|
||||
plant_file(os.path.join(ROOT, "hub", "internal", "web", "zzr426decoy", "v.go"),
|
||||
u'package zzr426decoy\n\n// hostInstallVersion was deleted on purpose (R-94).\n'),
|
||||
expect="accept")
|
||||
|
||||
# ── script-tests (R-885) ─────────────────────────────────────────────────────────────────────────
|
||||
#
|
||||
# Its decoys are whole fake repos, so they live in their own file and are RUN from here (guide-quote's shape).
|
||||
|
||||
Reference in New Issue
Block a user