51degrees: extend device detection module with new fields#4740
51degrees: extend device detection module with new fields#4740justadreamer wants to merge 1 commit intoprebid:masterfrom
Conversation
associated PBS PRs: - prebid/prebid-server-java#4458 - prebid/prebid-server#4740
antoxas1986
left a comment
There was a problem hiding this comment.
Review: PR #4740 — 51degrees: extend device detection module with new fields
The intent is good but there are several correctness bugs that would silently corrupt bid requests in production.
[CRITICAL] HardwareName[0] is a byte, not a model name
File: hook_raw_auction_request.go, "model" closure
if len(fiftyOneDd.HardwareName) > 0 {
return fiftyOneDd.HardwareName[0] // BUG: returns uint8 byte value
}HardwareName is a string, not a []string. Indexing a Go string with [0] yields a uint8 (e.g., 72 for "H"). This would write a numeric byte as device.model for every device that lacks both prefix and version — silent data corruption for every fallback case.
Suggested fix:
if fiftyOneDd.HardwareName != "" && fiftyOneDd.HardwareName != ddUnknown {
return fiftyOneDd.HardwareName
}
return nil[CRITICAL] hwv returns "" instead of nil, and hwv_legacy injects a non-spec field into every request
"hwv": func() any {
if fiftyOneDd.HardwareNamePrefix != "" && fiftyOneDd.HardwareNameVersion != "" {
return fiftyOneDd.HardwareNameVersion
}
return "" // BUG: should be nil
},
"hwv_legacy": func() any {
return "" // BUG: unconditionally writes "hwv_legacy":"" into every request
},The setMissingFields loop skips writing a field only when the closure returns nil. Returning "" bypasses this guard, so every device object missing hwv will now get "hwv": "" when the new fields are empty. hwv_legacy is not an OpenRTB field and must be removed.
Suggested fix:
"hwv": func() any {
if fiftyOneDd.HardwareNameVersion != "" && fiftyOneDd.HardwareNameVersion != ddUnknown {
return fiftyOneDd.HardwareNameVersion
}
return nil
},
// remove "hwv_legacy" entirely[MAJOR] HardwareModel fallback silently dropped from model logic
The existing code tries HardwareModel first, falls back to HardwareName, and returns nil when neither is available. The new code skips HardwareModel entirely — any device that previously resolved via HardwareModel but lacks HardwareNamePrefix/HardwareNameVersion will get a corrupted or empty model.
Suggested fix — layer the new logic on top of the existing fallback chain:
"model": func() any {
if fiftyOneDd.HardwareNamePrefix != "" && fiftyOneDd.HardwareNamePrefix != ddUnknown &&
fiftyOneDd.HardwareNameVersion != "" && fiftyOneDd.HardwareNameVersion != ddUnknown {
return fiftyOneDd.HardwareNamePrefix
}
newVal := fiftyOneDd.HardwareModel
if newVal == ddUnknown {
newVal = fiftyOneDd.HardwareName
}
if newVal != ddUnknown && newVal != "" {
return newVal
}
return nil
},[MAJOR] hwv guard requires both fields — version-only data is silently dropped
If HardwareNameVersion is populated but HardwareNamePrefix is empty, hwv currently returns "" and throws the version away. The hardware version value does not logically depend on whether the prefix is present. The fix above (checking only HardwareNameVersion) addresses this.
[MAJOR] New closures don't guard against the "Unknown" sentinel
The rest of setMissingFields consistently checks != ddUnknown. When a 51Degrees property has no match, getValue returns "Unknown" — not "". The new closures only check != "", so a device resolving HardwareNamePrefix = "Unknown" would pass the guard and set device.model = "Unknown" and device.hwv = "Unknown". The suggested fixes above include the != ddUnknown guards.
[MAJOR] Missing integration tests for the new behavior
- No test covers the happy path (both prefix + version populated) for
hwvor the newmodel - No test covers partial cases: prefix-only, version-only, or both empty
- The
mockValueshelper indevice_info_extractor_test.gois not updated with the new properties — tests that exercise the new fields without it may panic on unexpected mock calls
Please add table-driven test cases in TestHandleRawAuctionHookEnrichment / TestHydrateFields covering at minimum:
- Both
HardwareNamePrefix+HardwareNameVersionpopulated →model= prefix,hwv= version - Only
HardwareNameVersionpopulated →modelfalls back toHardwareModel,hwv= version - Neither populated →
hwvabsent from output,modeluses existing fallback
[MINOR] model returns "" instead of nil as last resort
The existing code returned nil when no model could be determined, causing the field to be omitted. Returning "" now unconditionally writes "model": "" into every unresolvable device. This is a behavior change for all bidders. The suggested fix above uses return nil.
|
Hi @antoxas1986 Thanks for the careful read, but most of the claims in this review don't match the code that's actually in the PR (commit 9afa7ac9). Walking through them: [CRITICAL] newVal := fiftyOneDd.HardwareModel
if newVal == ddUnknown {
newVal = fiftyOneDd.HardwareName
}
if newVal != ddUnknown {
return newVal
}
return nil
[CRITICAL] "hwv": func() any {
if fiftyOneDd.HardwareNameVersion != "" && fiftyOneDd.HardwareNameVersion != ddUnknown {
return fiftyOneDd.HardwareNameVersion
}
return nil
},There is no [MAJOR] [MAJOR] [MAJOR] New closures don't guard against [MAJOR] Tests /
[MINOR] On the design point in the suggested fix — gating Happy to add a few more table-driven cases for prefix-only / version-only / both-empty if that helps, but none of the correctness changes proposed here should land — they would either reintroduce real issues (silently dropping a valid prefix when version is missing) or change behavior to match a version of the code that wasn't actually committed. Could you double-check you were looking at |
* 51d: introduce hwv into PBS module associated PBS PRs: - prebid/prebid-server-java#4458 - prebid/prebid-server#4740 * fix table styles to satisfy markdownlint
Type of change
Description of change
51DegreesRtdProvider now populates
device.hwvand introduces smarter logic populatingdevice.modelwith a less specificHardwareNamePrefixproperty that would exclude specific device version. F.e. ifHardwareNameisiPhone 12 Pro Max,HardwareNamePrefixwould beiPhoneandHardwareNameVersionwould be12 Pro Max.This PR should improve chances of correct targeting for bidders that expect a less specific model name and prefer receiving hardware version separately.
Other information