Box dimensions: enrich learns shelf math, dims reports the Kallax truth

Eric's brief, implemented to the letter. BGG keeps physical dimensions
on VERSIONS, not games, so enrich runs a second cached pass over
thing?versions=1 (same batching, token, rate limit, and cache as every
call). A game with a chosen version takes that exact version's numbers
(source "version", mirrored onto its version dict); a versionless game
gets numbers only when every printing with data agrees within 0.5" per
axis (source "unanimous", keeping the MAX per axis — the planning
question is "will it fit"); disagreement stores nulls as "conflicting"
— never a guess — and BGG's 0 parses as "never entered", not a real
dimension. rpgitems and local games are "absent". Read-only: upload
untouched.

The new offline `bggpipe dims` reports coverage by source, the ten
biggest footprints, and a Kallax fit check (13.2" square opening,
15.4" deep; a box fits if SOME orientation puts two axes through the
opening within the depth) — naming every misfit and every game whose
dimensions can't be verified, because can't-verify ≠ fits. Trusted
numbers surface on the Library detail page as a "box" row.

First real run: 54 version-exact, 16 unanimous, 39 conflicting, 27
absent; three genuine misfits (Bugs in the Kitchen's 17" box, History
of the World and Risk LotR both over the 15.4" depth).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
Eric Wagoner
2026-08-09 11:18:48 -04:00
co-authored by Claude Fable 5
parent 9d752c4109
commit 102507b040
10 changed files with 1767 additions and 131 deletions
+84
View File
@@ -0,0 +1,84 @@
"""The shelf-space report: fit math, coverage buckets, honest unknowns."""
from __future__ import annotations
import json
import pytest
import typer
from bggpipe.config import Config
from bggpipe.dims import fits_kallax, run_dims_report
def test_fits_kallax_tries_every_orientation():
assert fits_kallax(11.6, 11.6, 2.8) # ordinary big-box
# too tall to stand, but slides in lying down: depth axis takes 15.0
assert fits_kallax(15.0, 12.0, 3.0)
# two axes over the opening: no orientation works
assert not fits_kallax(16.2, 16.2, 4.0)
# fits the opening but too deep to close the wall behind it
assert not fits_kallax(12.0, 12.0, 15.5)
# exact boundary counts as fitting
assert fits_kallax(13.2, 13.2, 15.4)
def test_report_buckets_misfits_and_unknowns(tmp_path, capsys):
cfg = Config(data_dir=tmp_path / "data")
cfg.data_dir.mkdir(parents=True)
cfg.games_path.write_text(
json.dumps(
{
"1": {
"name": "Fits Fine",
"dims": {
"width_in": 11.6,
"length_in": 11.6,
"depth_in": 2.8,
"weight_lb": 4,
"source": "version",
},
},
"2": {
"name": "Monster Box",
"dims": {
"width_in": 16.2,
"length_in": 16.2,
"depth_in": 4.0,
"weight_lb": 7,
"source": "unanimous",
},
},
"3": {
"name": "Argued About",
"dims": {
"width_in": None,
"length_in": None,
"depth_in": None,
"weight_lb": None,
"source": "conflicting",
},
},
"4": {"name": "Never Measured"}, # pre-dims entry: absent
}
)
)
summary = run_dims_report(cfg)
assert summary["by_source"] == {
"version": 1,
"unanimous": 1,
"conflicting": 1,
"absent": 1,
}
assert summary["misfits"] == ["Monster Box"]
# can't verify is NOT the same as fits: both unknowns are named
assert summary["unknown"] == ["Argued About", "Never Measured"]
out = capsys.readouterr().out
assert "do NOT fit" in out and "Monster Box" in out
assert "can't be verified" in out and "Never Measured" in out
def test_report_without_games_json_exits_with_guidance(tmp_path):
cfg = Config(data_dir=tmp_path / "data")
with pytest.raises(typer.Exit):
run_dims_report(cfg)