product-recognition-demo/recognization/code
tngo 0cf64a18bf Coverage-first live labelling, merged catalog, shelf-intelligence decision
The live path abstained too much: a detected product whose best candidate
missed the accept line was left blank, so a shelf where 59% of in-catalog
facings were shown read as broken. Show the best candidate immediately as
`provisional`, keep the track re-classifiable so a later attempt upgrades or
corrects it, and never blank a label already on screen.

- identity.py / identity_lanes.py: every decision now carries
  `provisional_sku` - the row the evidence supports well enough to show,
  separate from `best_sku`, which still means "cleared the gate". The accept
  line does not move: far-unknown false accepts stay at 0.066%.
- live.py: a below-gate candidate labels the track with
  `identity_level: provisional` and `confirmed = False`, so the planner and
  the crop lane keep offering it. Accepted labels stay frozen. Inherited
  provisional labels stay re-classifiable.
- Clients render provisional distinctly (amber chip, dashed box) via
  `LiveScanOverlayPolicy.isProvisional(identity)`, which now reads the wire
  level instead of only the state.
- build_stock_all.py merges stock, stock-lopia, stock-mediya and
  stock-milk150 into stock-all (111 images, 60 SKUs). The server could only
  read one folder, so anything outside it came back blank. stock-demo is
  byte-identical to mediya+milk150 and is not a source.

Measured on add/image6.jpg at live resolution: in-catalog facings shown
59.4% -> 86.0%, correct shown 38 -> 55, precision 97.4% -> 87.3%. On the
wire at 8fps 0.5x: 65 of 79 tracks labelled, 742 accepted + 309 provisional
observations, first label 1.27s.

docs/research/2026-09-29-shelf-intelligence/ carries the experiments and the
decision: group signals (combined AUC 0.991 sibling / 0.990 unrelated),
OCR scheduling (group representatives cut calls 4.4x and wall 3.3x), and the
finding that group propagation damages more labels than it rescues on this
shelf, so groups schedule compute rather than overwrite labels.

331 tests pass.
2026-09-29 13:45:14 +09:00
..
web fix: restore reliable authenticated live recognition 2026-09-28 12:38:15 +09:00
__init__.py
app.py Coverage-first live labelling, merged catalog, shelf-intelligence decision 2026-09-29 13:45:14 +09:00
bench_engine.py feat: recognition engine and session tracker for multi-client serving 2026-09-24 11:52:59 +09:00
bench_identity.py feat: a multi-view embedding gallery, because one template per SKU cannot work 2026-09-24 23:43:27 +09:00
bench_ocr.py docs(decision): date the header and re-measure the OCR cost 2026-09-29 04:30:02 +09:00
build_stock_all.py Coverage-first live labelling, merged catalog, shelf-intelligence decision 2026-09-29 13:45:14 +09:00
build_store_from_shelf.py fix: require explicit safe shelf enrollment paths 2026-09-28 13:41:43 +09:00
collect_shelf_images.py chore(eval): reconcile the distractor sets and refresh the sweep numbers 2026-09-29 04:17:54 +09:00
detector.py
empty_shelf_detector.py
engine.py feat(decision): make the accept lines tunable from the environment 2026-09-29 10:09:25 +09:00
eval_distractors.py fix(recognition): calibrate the accept lines against unrelated shelves 2026-09-29 09:28:13 +09:00
eval_external.py feat(eval): report the external benchmark per SKU 2026-09-29 03:37:04 +09:00
eval_external_images.py fix(catalog): correct sku_l10 to 400g and enroll its packshot 2026-09-29 02:45:21 +09:00
eval_identity.py fix(recognition): calibrate the accept lines against unrelated shelves 2026-09-29 09:28:13 +09:00
eval_live.py fix(recognition): calibrate the accept lines against unrelated shelves 2026-09-29 09:28:13 +09:00
feature_matcher.py feat: recognition server API, reference stream client, and live label memory 2026-09-24 12:31:17 +09:00
finetune_identity.py fix(catalog): correct sku_l10 to 400g and enroll its packshot 2026-09-29 02:45:21 +09:00
gallery.py feat(identity): local-feature matcher plus text lane as the default backend 2026-09-28 22:27:21 +09:00
identity.py Coverage-first live labelling, merged catalog, shelf-intelligence decision 2026-09-29 13:45:14 +09:00
identity_lanes.py Coverage-first live labelling, merged catalog, shelf-intelligence decision 2026-09-29 13:45:14 +09:00
inventory.py
live.py Coverage-first live labelling, merged catalog, shelf-intelligence decision 2026-09-29 13:45:14 +09:00
ocr.py feat: add bounded crop evidence and keyed gallery cache 2026-09-28 15:49:34 +09:00
rebuild_catalog.py fix(catalog): re-source sku_l09 and enforce the pyramid floor 2026-09-29 09:28:16 +09:00
reconcile.py fix: a tag may not accuse on weak evidence, nor name a distant product 2026-09-25 01:30:03 +09:00
record.py fix: record and require the walk identity backend 2026-09-28 14:42:03 +09:00
score_stream.py fix(recognition): calibrate the accept lines against unrelated shelves 2026-09-29 09:28:13 +09:00
shelf_map.py feat: a shelf map, so a facing outlives the track id that found it 2026-09-25 01:54:38 +09:00
stream_client.py fix(replay): walk the sample at the app's real frame geometry 2026-09-29 10:09:22 +09:00
sweep_accept_lines.py fix(recognition): calibrate the accept lines against unrelated shelves 2026-09-29 09:28:13 +09:00
tag_cards.py fix: restore reliable authenticated live recognition 2026-09-28 12:38:15 +09:00
tags.py fix: bind tag projection to each frame origin 2026-09-28 14:41:49 +09:00
test_api.py feat(server): walk the replayed sample instead of freezing it 2026-09-29 09:28:07 +09:00
test_engine.py docs(decision): correct the record against the re-measured evidence 2026-09-29 09:28:19 +09:00
test_eval_labels.py feat: refuse a label file whose rows carry no provenance 2026-09-28 23:31:53 +09:00
test_eval_live.py fix(recognition): calibrate the accept lines against unrelated shelves 2026-09-29 09:28:13 +09:00
test_gallery.py fix: serialize gallery inference so Metal cannot be entered twice 2026-09-28 17:22:55 +09:00
test_identity.py fix(eval): confirm a leak signature before calling it one, and score external sets in code 2026-09-29 03:29:56 +09:00
test_live.py Coverage-first live labelling, merged catalog, shelf-intelligence decision 2026-09-29 13:45:14 +09:00
test_ocr_tags.py fix: bind tag projection to each frame origin 2026-09-28 14:41:49 +09:00
test_real_model.py docs: API contract, README for the server and live mode, real-model test 2026-09-24 12:46:54 +09:00
test_rebuild_catalog.py fix(catalog): re-source sku_l09 and enforce the pyramid floor 2026-09-29 09:28:16 +09:00
test_reconcile.py fix: a tag may not accuse on weak evidence, nor name a distant product 2026-09-25 01:30:03 +09:00
test_record.py fix: record and require the walk identity backend 2026-09-28 14:42:03 +09:00
test_score_stream.py fix(recognition): calibrate the accept lines against unrelated shelves 2026-09-29 09:28:13 +09:00
test_shelf_map.py feat: a shelf map, so a facing outlives the track id that found it 2026-09-25 01:54:38 +09:00
test_tag_cards.py fix: the number on the tag is the regular price, and a price must be corroborated 2026-09-25 01:29:46 +09:00
test_tag_identity.py fix: a tag may not accuse on weak evidence, nor name a distant product 2026-09-25 01:30:03 +09:00
test_tracking.py test: defend engine and tracking contracts 2026-09-24 12:43:32 +09:00
tracking.py fix: restore reliable authenticated live recognition 2026-09-28 12:38:15 +09:00
train.py
transport.py fix: guard reserved sessions and bounded response state 2026-09-28 13:41:35 +09:00