Website: machine estimator v3.1 — bar never below an 8 GB box; a single leftover app keeps its name (R-997)
gates / gates (push) Successful in 6m47s
gates / gates (push) Successful in 6m47s
Empty or tiny selections drew a ~2.3 GB box whose base system (1,636 MB) no real box has; the bar is now floored at the smallest named size (8 GB) for its parts only — the recommendation and the rule are unchanged. Grouping applies only to two or more leftover apps; a ninth app is shown by name in the group's colour. Tests: 12, the new ones red-proofed.
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
## 2026-10-13 (night) — estimator v3.1 tests
|
||||
|
||||
- `test_build_sizing_web.py` (12 tests): the bar is never below the smallest named box, its parts still sum to it
|
||||
within 1 MB (nothing ticked, one tiny app, household, all 62), the base system never below the 8 GB split (4,096);
|
||||
9 apps → 9 named parts, 10 apps → 8 named + a group of 2. Red-proofed: the floor removed from the JS and from the
|
||||
mirror, and grouping a single app in the JS and in the mirror, each convicted.
|
||||
|
||||
## 2026-10-13 (evening) — estimator v3: segments and the English article under test
|
||||
|
||||
- `build_sizing_web.py`: `bar_app_colours` (8) in the data file, so the script holds no number of its own.
|
||||
|
||||
@@ -63,12 +63,21 @@ def segments(d, slugs): # mirrors estimate().segments in sizi
|
||||
by = {a["slug"]: a for a in d["apps"]}
|
||||
apps = sorted((by[s] for s in slugs if not by[s].get("builtin")), key=lambda a: -a["peak_mb"])
|
||||
peak = d["platform_mb"] + sum(a["peak_mb"] for a in apps)
|
||||
well = min_box_gb(d, peak * d["headroom"])
|
||||
well = max(min_box_gb(d, peak * d["headroom"]), d["boxes_gb"][0]) # v3.1: never below the smallest named box
|
||||
box, guest = well * 1024, guest_mib(d, well)
|
||||
return well, [("base", box - guest), ("platform", d["platform_mb"])] + \
|
||||
[(a["slug"], a["peak_mb"]) for a in apps] + [("spare", guest - peak)]
|
||||
|
||||
|
||||
def legend_parts(d, slugs): # mirrors the grouping in sizing.js draw(): named parts + the group
|
||||
by = {a["slug"]: a for a in d["apps"]}
|
||||
apps = sorted((by[s] for s in slugs if not by[s].get("builtin")), key=lambda a: -a["peak_mb"])
|
||||
k = d["bar_app_colours"]
|
||||
if len(apps) - k >= 2:
|
||||
return [a["slug"] for a in apps[:k]], len(apps) - k
|
||||
return [a["slug"] for a in apps], 0
|
||||
|
||||
|
||||
def first(d, verdicts, want): # mirrors recommend_gb / tight_box_gb in sizing.js
|
||||
return next((gb for gb, v in zip(d["boxes_gb"], verdicts) if v == want), None)
|
||||
|
||||
@@ -134,6 +143,30 @@ class SizingWeb(unittest.TestCase):
|
||||
self.assertAlmostEqual(dict(segs)["spare"], 5515 * 0.5, delta=1)
|
||||
self.assertAlmostEqual(dict(segs)["base"], 4708, delta=1) # 4,096 for Proxmox + 612 MemTotal shortfall
|
||||
|
||||
def test_bar_never_below_the_smallest_named_box(self):
|
||||
small = min(self.d["boxes_gb"])
|
||||
base8 = small * 1024 - guest_mib(self.d, small)
|
||||
tiny = ["glance"] # 6 MB: its fits-well size is far below 8 GB
|
||||
self.assertLess(min_box_gb(self.d, (self.d["platform_mb"] + 7) * self.d["headroom"]), small)
|
||||
for name, sel in {"nothing": [], "tiny": tiny, "household": HOUSEHOLD, "all 62": self.all}.items():
|
||||
bar, segs = segments(self.d, sel)
|
||||
self.assertGreaterEqual(bar, small, name)
|
||||
self.assertAlmostEqual(sum(mb for _, mb in segs), bar * 1024, delta=1, msg=name)
|
||||
self.assertGreaterEqual(dict(segs)["base"], base8 - 1, name + ": base below the 8 GB split")
|
||||
bar, segs = segments(self.d, [])
|
||||
self.assertEqual(bar, small)
|
||||
self.assertEqual(dict(segs)["base"], 4096) # 8 GB: 8,192 - guest 4,096 — not the 1,636 of a 2.3 GB box
|
||||
self.assertEqual(dict(segs)["spare"], 4096 - self.d["platform_mb"])
|
||||
|
||||
def test_grouping_keeps_a_single_leftover_named(self):
|
||||
by_peak = [a["slug"] for a in sorted((a for a in self.d["apps"] if not a.get("builtin")), key=lambda a: -a["peak_mb"])]
|
||||
named, grouped = legend_parts(self.d, by_peak[:9])
|
||||
self.assertEqual((len(named), grouped), (9, 0)) # 9 apps -> 9 named parts, no „további 1”
|
||||
named, grouped = legend_parts(self.d, by_peak[:10])
|
||||
self.assertEqual((len(named), grouped), (8, 2)) # 10 apps -> 8 named + „további 2 alkalmazás”
|
||||
js = io.open(JS, encoding="utf-8").read()
|
||||
self.assertIn("appCount - data.bar_app_colours >= 2", js)
|
||||
|
||||
def test_english_article(self):
|
||||
with io.open(os.path.join(ROOT, "website", "en", "sizing.html"), encoding="utf-8-sig") as f:
|
||||
t = json.loads(re.search(r'id="sizer-strings">(.*?)</script>', f.read(), re.S).group(1))
|
||||
@@ -183,7 +216,8 @@ class SizingWeb(unittest.TestCase):
|
||||
allowed = {"0", "1", "2", "100", "1024"} # 100 = percent, 1024 = MiB per GiB; no rule constant
|
||||
self.assertTrue(nums <= allowed, "sizing.js holds its own numbers: %s" % sorted(nums - allowed))
|
||||
for need in ("data.bar_max_gb", "data.bar_marks_gb", "function minBoxGb", "guestMib(data, mid) >= needMib",
|
||||
"data.bar_app_colours", "boxMb - guestMb", "guestMb - peak"):
|
||||
"data.bar_app_colours", "boxMb - guestMb", "guestMb - peak",
|
||||
"Math.max(wellGb, data.boxes_gb[0])", "guestMib(data, barGb)"):
|
||||
self.assertIn(need, js)
|
||||
|
||||
def test_data_has_no_peak_below_typical(self):
|
||||
|
||||
Reference in New Issue
Block a user