9f32e448ab
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>