Skip to content

Derive LocationType from the primary Google type for keyword searches - #452

Merged
tim-eternos merged 1 commit into
masterfrom
fix/keyword-search-location-type
Aug 12, 2026
Merged

Derive LocationType from the primary Google type for keyword searches#452
tim-eternos merged 1 commit into
masterfrom
fix/keyword-search-location-type

Conversation

@timwangmusic

Copy link
Copy Markdown
Owner

Problem

Keyword (brand) searches (/v1/nearby-places) query Google with LocationTypeAny, and parsePlacesSearchResponse stamps every result with the searched type — so keyword results are cached with LocationType: "". The write path (SetPlacesAddGeoLocationsForBrand) is a blind upsert into the shared placeDetails:{id} records that category reads hydrate from, and restoreCachedDetails restores URL/Summary/Address/Hours but not LocationType. Net effect: every brand search wipes the type off previously typed records.

Observed downstream (OfferBee staging): a McDonald's row cached by an Eatery category search was served with LocationType: "" after brand searches rewrote its record, so the best-card ranking scored every card at its base rate — Chase Sapphire Reserve showed 1X at McDonald's instead of 3X dining.

Fix (both changes gap-filling only)

  • parsePlacesSearchResponse: when the searched type is LocationTypeAny, derive LocationType from POI.PrimaryLocationType(place.Types) — the same machinery ReclassifyForCategory already uses to re-tag places on category reads (Classify category-endpoint places by primary Google type #442). Google lists the most specific type first and umbrella types (food, point_of_interest, …) are skipped, so a McDonald's (["meal_takeaway", "food", ...]) comes out meal_takeaway. Typed searches keep their searched-type stamp — re-tagging those stays ReclassifyForCategory's job.
  • restoreCachedDetails: restore the stored LocationType when the rebuilt record has none — same "only ever fills a gap, never overwrites" rule the function already documents for the Details-sourced fields. Covers keyword results whose Types carry no meaningful primary.

Safety

  • Category geo buckets can't be poisoned: the brand write path never touches them, and SetPlacesAddGeoLocations already refuses unmapped types ("Refuse to guess a bucket").
  • Empty/umbrella-only TypesPrimaryLocationType returns "" → identical to today.
  • Existing blank-typed records stay blank until a fresh search rewrites them; this stops new wipes at the source. (OfferBee's section-fallback covers the residue meanwhile.)

Testing

  • New: TestParsePlacesSearchResponseKeywordDerivesLocationType (keyword derives from Types; umbrella-only stays blank; typed search stamp unchanged), TestRestoreCachedDetailsPreservesLocationType (untyped rebuild recovers stored type; fresh type never overwritten). Both watched fail before the fix.
  • go build ./... && go vet ./iowrappers/ && go test ./... all green.

🤖 Generated with Claude Code

https://claude.ai/code/session_011BmBJ2x6b7V36vywSMrYDy

Keyword (brand) searches query Google with LocationTypeAny, so
parsePlacesSearchResponse stamped every result with LocationType "".
The write path is a blind upsert into the shared placeDetails:{id}
records that category reads hydrate from, so each brand search wiped
the type off previously typed records — a McDonald's cached by an
Eatery search was then served with no type, and downstream consumers
(OfferBee best-card) scored it at base rate instead of dining.

Two changes, both gap-filling only:

- parsePlacesSearchResponse: when the searched type is LocationTypeAny,
  derive LocationType from POI.PrimaryLocationType(place.Types) — the
  same machinery ReclassifyForCategory already uses on category reads.
  Typed searches keep their searched-type stamp.
- restoreCachedDetails: restore the stored LocationType when the
  rebuilt record has none, same "fill a gap, never overwrite" rule as
  URL/Summary/Address/Hours.

Existing blank-typed records stay blank until a fresh search rewrites
them; this stops new wipes and types new keyword results at the source.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011BmBJ2x6b7V36vywSMrYDy

@tim-eternos tim-eternos left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@tim-eternos
tim-eternos merged commit 3c848be into master Aug 12, 2026
4 checks passed
@tim-eternos
tim-eternos deleted the fix/keyword-search-location-type branch August 12, 2026 05:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants