Commit graph

23 commits

Author SHA1 Message Date
7c0d8479d4 test: add synthetic platform smoke test using real book cover images
No camera hardware is on hand yet. This script composites public
Open Library cover images onto a synthetic platform background at
small/medium/large footprints and drives the real intake pipeline
(IntakeSession, Catalogue, capture strategies) end to end, in place
of solid-color test frames. Not part of the pytest suite — it fetches
over the network and is meant for human-visible verification.
2026-07-13 19:07:20 -07:00
f9553373d6 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.
2026-07-13 11:22:22 -07:00
043cc4bcce fix: handle fetch failures and stop keying UI logic off display text
- refreshStatus()/observe() now check response.ok and catch fetch
  errors, showing a clear "Connection problem" state instead of
  silently rendering blank/undefined status on a non-2xx response.
- Track session state in a currentState variable (set in
  refreshStatus) and branch the trigger button's click handler on
  currentState === "book_complete" instead of parsing statusEl's
  displayed text, so future copy changes can't silently break the
  next-book/manual-trigger branch.
2026-07-13 11:22:15 -07:00
2b4875d77c fix: handle empty-platform captures, no-op fires, and observe races
- IntakeSession.observe_frame now catches ValueError from crop_to_book
  (empty-platform capture), cleans up any orphan wide-image file/dir,
  resets the strategy, and does not advance session state. The error
  is surfaced via a new last_error field.
- /api/observe adds an "error" field to the response when a capture
  fires but fails, instead of an unhandled 500.
- observe_frame only reports fired=True (and only runs capture logic)
  when state is WAITING_FRONT or WAITING_BACK, so a completed book
  left on the platform can no longer produce a no-op "fired" capture
  from an auto-strategy re-triggering.
- observe_frame now holds a per-session threading.Lock for its whole
  body, since the frontend polls /api/observe every ~500ms without
  chaining requests and Catalogue.update_row() does a non-atomic
  read-all-then-rewrite-whole-file rewrite of catalogue.csv.

Adds tests for empty-platform front/back captures and the
BOOK_COMPLETE no-op-fire case, plus an API-level empty-platform test.
2026-07-13 11:22:08 -07:00
857489a695 docs: add README with setup and end-to-end smoke test
Expand Development section with complete setup instructions (venv, calibration, config, run), add Running tests section, and include end-to-end smoke test checklist for real-hardware validation. Update phase-status table to reflect that Phase 1 is built and unit-tested, pending real-hardware validation.
2026-07-13 11:12:23 -07:00
c28afe0ac4 feat: add config loading, calibration script, and production entrypoint
Wires together AppConfig.load() (JSON config -> markers/guide_box),
calibrate.py (one-time empty-platform reference capture), and run.py
(build_strategy dispatch + camera/session/FastAPI wiring via uvicorn)
to complete Phase 1 intake station integration.
2026-07-13 11:08:48 -07:00
7807e32133 feat: add kiosk frontend for guided intake flow 2026-07-13 11:03:45 -07:00
7d0bebf16d fix: return structured 503 on camera read failure in /api/observe
Wrap camera.read_frame() call in try/except to catch RuntimeError and
return a 503 Service Unavailable response with structured error JSON
(error + detail fields) instead of letting the exception propagate
as an unhandled 500. This gives kiosk operators a friendly, actionable
error message when the camera becomes unavailable.

Added FailingCamera test fixture and regression test that verifies
the 503 response with expected error details.
2026-07-13 10:58:30 -07:00
ae73ab2329 feat: add FastAPI backend for intake session 2026-07-13 10:51:43 -07:00
a74a5d7c38 feat: add intake session state machine 2026-07-13 10:47:47 -07:00
efe3f65cd5 fix: release camera capture handle on failed or repeated open
- Fix critical resource leak when cv2.VideoCapture.isOpened() returns False:
  create capture in local variable, verify it opened, call .release() before
  raising RuntimeError, only assign to self._capture after confirming success
- Fix potential leak on repeated open(): release any existing self._capture
  before creating a new one
- Add regression test: test_open_raises_when_capture_not_opened now verifies
  .release() is called on failed capture
- Add new test: test_open_twice_releases_first_capture verifies first capture's
  .release() is called before second is assigned

All 28 tests passing (5 camera + 23 existing).
2026-07-13 10:44:47 -07:00
ab7664cd51 feat: add OpenCV camera source wrapper 2026-07-13 10:41:10 -07:00
d5f5b47cef feat: add stable-centered auto-detect capture strategy 2026-07-13 10:36:54 -07:00
aaac91f03c feat: add motion-stop countdown capture strategy 2026-07-13 10:33:12 -07:00
b707aef137 feat: add capture strategy interface and manual button strategy 2026-07-13 10:28:10 -07:00
f93d51d500 feat: add book-region cropping from wide captures 2026-07-13 10:24:05 -07:00
b9ddbee81e feat: add deterministic marker-based size bucketing 2026-07-13 10:19:10 -07:00
9af936518d docs: add project README for early-stage stakeholder visibility 2026-07-13 10:17:31 -07:00
df63ffa846 chore: add MIT LICENSE and CONTRIBUTING.md, set SPDX license in pyproject
Bookmark is fully open source (donated to Books in Hand nonprofit, no
BSL tiering). Adds an MIT LICENSE file, a CONTRIBUTING.md scoped to an
early-stage volunteer project, and a PEP 639 license field in
pyproject.toml. Repo description and topics were also updated via the
Forgejo API for discoverability.
2026-07-13 10:17:05 -07:00
27c066de1c feat: add CSV catalogue data layer
Implement Catalogue class with BookRecord dataclass for managing the
CSV-based book inventory. Provides operations to append records, read all
rows, update specific books, and generate unique book IDs.

5 tests passing, all functionality working as specified.
2026-07-13 10:11:49 -07:00
4aee1e5181 chore: scaffold bookmark project structure 2026-07-13 10:08:41 -07:00
b16d6b4250 docs: add AGENTS.md project context (CLAUDE.md symlinked for compatibility) 2026-07-13 10:06:17 -07:00
827d0d2e2a chore: initial empty commit 2026-07-13 10:04:53 -07:00