KEY .sub files (~35% of real captures) returned zero identification
because every path bailed on `not has_raw_data`, despite the file
already carrying a decoded Protocol name. Route those by protocol name
instead:
- category_router: add route_by_protocol() — device-specific brands
(CAME/Nice/KeeLoq/Security+/Honeywell) map to one confident category;
generic shared encoders (Princeton/EV1527/Holtek/Intertechno) map to a
broad allowed family set, since the same silicon spans
remote/doorbell/fan/gate.
- pattern_decoder.decode: emit a decoded_key DeviceMatch (details carry
predicted_category) for KEY files instead of [].
- device_identifier.identify: only bail when there is neither RAW data
nor a protocol name; gate statistical scoring on has_raw_data.
Adds scripts/benchmark_realworld.py — validates the real pipeline
against the real UberGuidoZ corpus (folder = ground-truth device type),
reporting top-1, routed (truth in allowed set), and coverage.
Measured on n=344 (seed 42): coverage 58%→93%, routed 59.3%→65.2%;
generalizes on seed 7 (93%/63.6%). RAW path byte-identical (no
regression); synthetic phase-0 gate still passes (top-3 67%).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>