From efe76093ce50cef67ebada9869703326f13dfc0e Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Mon, 5 Oct 2026 21:17:28 +0200 Subject: [PATCH] =?UTF-8?q?R-130:=20the=20local-lvm=20minimum=20is=20named?= =?UTF-8?q?=20as=20what=20it=20does=20=E2=80=94=20a=20recommendation=20tha?= =?UTF-8?q?t=20warns?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HARD_MIN_LVM_GIB -> RECOMMENDED_MIN_LVM_GIB; the warning says the install continues and to proceed only with deliberately sized grows (the day0-install runbook's wording). Behaviour unchanged. scripts/test_hostinstall.py: test_lvm_minimum_is_named_as_what_it_does. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS --- scripts/felhom-host-install.sh | 8 ++++++-- scripts/test_hostinstall.py | 11 ++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/scripts/felhom-host-install.sh b/scripts/felhom-host-install.sh index 3d7727bf..6c45a80b 100644 --- a/scripts/felhom-host-install.sh +++ b/scripts/felhom-host-install.sh @@ -345,7 +345,11 @@ PVE_SCRATCH_VMID_MAX=990009 STATE_DIR="${FELHOM_INSTALL_STATE_DIR:-/var/lib/felhom-install}" STATE_FILE="${STATE_DIR}/state.json" AGENT_CONFIG="" # resolved in preflight -HARD_MIN_LVM_GIB=120 # a useful appliance won't fit below this on local-lvm +# R-130: a RECOMMENDATION, not a floor — the install proceeds below it (runbooks/day0-install.md: +# "proceed only if you sized the grows deliberately"; a 75 GiB box installed fully, 2026-07-03). The +# old name called it a hard floor while the check only warned. No measured floor exists. Pinned by +# scripts/test_hostinstall.py (test_lvm_minimum_is_named_as_what_it_does). +RECOMMENDED_MIN_LVM_GIB=120 # Runtime carriers (never logged) PASSPHRASE="" @@ -1877,7 +1881,7 @@ step_preflight() { free_gib=$(lvs --noheadings --units g -o lv_size,data_percent /dev/pve/data 2>/dev/null | awk '{gsub(/[^0-9.]/,"",$1); used=$2; print int($1*(100-used)/100)}' 2>/dev/null || echo 0) if [[ "${free_gib:-0}" -gt 0 ]]; then log_info " local-lvm free: ~${free_gib} GiB" - [[ "$free_gib" -ge "$HARD_MIN_LVM_GIB" ]] || log_warn "local-lvm free ~${free_gib} GiB < hard min ${HARD_MIN_LVM_GIB} GiB" + [[ "$free_gib" -ge "$RECOMMENDED_MIN_LVM_GIB" ]] || log_warn "local-lvm free ~${free_gib} GiB is below the recommended ${RECOMMENDED_MIN_LVM_GIB} GiB — the install continues; proceed only if you sized the grows deliberately" else log_warn " could not read local-lvm free space (continuing)" fi diff --git a/scripts/test_hostinstall.py b/scripts/test_hostinstall.py index 5bd76384..bdf7e5f1 100644 --- a/scripts/test_hostinstall.py +++ b/scripts/test_hostinstall.py @@ -11,7 +11,7 @@ functions act on are variables the test points into the temp directory. Nothing Where behaviour cannot be isolated, a STATIC test checks the wiring (the function is CALLED, from the right place) — a helper defined and never called is the seam-built-never-wired shape. -Rows: R-275, R-276, R-881 (uninstall residue); R-306 (--preflight-only writes no state). +Rows: R-275, R-276, R-881 (uninstall residue); R-306 (--preflight-only writes no state); R-130 (lvm minimum wording). Run: python3 scripts/test_hostinstall.py """ import os @@ -372,6 +372,15 @@ def test_state_json_has_no_other_writer(): assert "_state_put dnsmasq_preexisting" in body, "the ownership record no longer goes through _state_put" +# ── R-130: the local-lvm minimum says what it does (it warns; the install continues) ──────────── +def test_lvm_minimum_is_named_as_what_it_does(): + assert not re.search(r"HARD_MIN_LVM|hard min", SRC), "a 'hard min' that only warns is back" + body = func("step_preflight") + m = re.search(r'^.*RECOMMENDED_MIN_LVM_GIB.*$', body, re.M) + assert m and "log_warn" in m.group(0) and "die" not in m.group(0), "the lvm check is not a warning: %s" % (m and m.group(0)) + assert "recommended" in m.group(0) and "continues" in m.group(0), m.group(0) + + def main(): tests = [(n, f) for n, f in sorted(globals().items()) if n.startswith("test_") and callable(f)] fails = 0