docs: drop AI/ML terminology in README, document marker ordering

- README "How it works" step 3: "not by any AI/ML step" -> "not by any
  model inference step", per AGENTS.md's terminology rule (no generic
  "AI" when describing system capability).
- AppConfig gets a docstring spelling out that markers must be ordered
  smallest-bucket-boundary first, since determine_size_bucket trusts
  this order and a misordered config would silently produce a wrong
  (tax-relevant) size bucket. AppConfig.load() also now validates that
  marker area is non-decreasing across the list and raises ValueError
  if not, since this project's nested physical markers get larger as
  bucket size increases.
This commit is contained in:
pyr0ball 2026-07-13 11:22:22 -07:00
parent 043cc4bcce
commit f9553373d6
2 changed files with 42 additions and 2 deletions

View file

@ -30,8 +30,9 @@ volunteer/client work — it isn't part of any commercial product line.
2. A volunteer centers the book; capture fires automatically or on a
button press (configurable).
3. The system photographs the front, determines size — **deterministically**,
by checking which physical markers are covered, not by any AI/ML step —
then prompts the volunteer to flip the book and photographs the back.
by checking which physical markers are covered, not by any model
inference step — then prompts the volunteer to flip the book and
photographs the back.
4. Every book gets a row in a CSV catalogue: images, size bucket, and a
status that later pipeline stages (OCR backfill, checkout) update.

View file

@ -7,6 +7,23 @@ from .sizing import MarkerRegion
@dataclass
class AppConfig:
"""
IMPORTANT `markers` ordering requirement:
`markers` must be listed smallest-bucket-boundary first, largest last
(see `bookmark.sizing.determine_size_bucket`, which trusts this order
and does not re-sort). The physical rig's nested markers get larger as
the size bucket grows, so marker area (width * height) should be
non-decreasing across the list in config.json. `AppConfig.load()`
validates this area ordering and raises `ValueError` if it's violated,
but it cannot verify that markers are ordered by *bucket name*
("small" < "medium" < "large") independent of that, since bucket
naming is config-defined an install with correctly-increasing marker
areas but mislabeled bucket names would still silently produce a wrong
(but plausible-looking) size bucket. Get the marker order right in
config.json; this is tax-report-relevant data for Books in Hand.
"""
device_index: int
catalogue_path: Path
captures_dir: Path
@ -19,6 +36,7 @@ class AppConfig:
def load(cls, path: Path) -> "AppConfig":
data = json.loads(Path(path).read_text())
markers = [MarkerRegion(**marker) for marker in data["markers"]]
_validate_marker_area_order(markers)
return cls(
device_index=data["device_index"],
catalogue_path=Path(data["catalogue_path"]),
@ -28,3 +46,24 @@ class AppConfig:
guide_box=tuple(data["guide_box"]),
trigger_strategy=data["trigger_strategy"],
)
def _validate_marker_area_order(markers: list[MarkerRegion]) -> None:
"""
`determine_size_bucket` requires `markers` ordered smallest -> largest
bucket boundary. We can't infer bucket order from names alone, but the
physical rig's nested markers get larger as the bucket size grows, so
marker area (width * height) should be non-decreasing across the
ordered list. A misordered config would silently produce a wrong (but
plausible-looking) tax-relevant size bucket, so fail loudly here
instead.
"""
areas = [marker.width * marker.height for marker in markers]
for previous, current in zip(areas, areas[1:]):
if current < previous:
raise ValueError(
"config.json 'markers' must be ordered smallest-bucket to "
"largest-bucket, with non-decreasing marker area — found a "
f"marker with area {current} listed after one with area "
f"{previous}. Check the marker order in config.json."
)