Wire PointsPath matched-id join through gflight backend#10
Merged
Conversation
Empirically settled (and reverses the 'dead end' framing in pp_on_gflight.md): PP's enableGoogleFlightMatching=true mode DOES work — we just needed the real Google Flights opaque ID from data[0][17] and the right hint shape. With that, PP echoes matchedGoogleFlightId back per result, which the matcher uses as its primary join key — exact string equality, robust to codeshares where flight#+date fails. Verified end-to-end against PP Pro: 50 hints in, 41 award matches back, all 41 with matchedGoogleFlightId populated. AA38 surfaces 4 different PP programs (American, Etihad, Qantas, Alaska) where flight#+date would only have caught the marketing carrier. Architecture changes (one PR, multiple layers): - src/flight_cli/_gflight_ids.py — wraps fli's encoder + client, parses the response ourselves to capture data[0][17] (the opaque ID fli throws away). - src/flight_cli/_airline_names.py — IATA → human-readable name mapping for the airlines PP services. Required: the airline-search hint payload needs the human-readable name, NOT the IATA code, or PP returns 0 flights. - Slice.flight_id (optional): populated by the gflight adapter, None for Matrix cash itineraries. - AwardFlight.matched_google_flight_id: populated by PointsPathProvider from PP's response when enable_matching was used. - AwardProvider.search_leg gained cash_hints kwarg (Protocol-level so seats.aero and future providers see a uniform interface even if they ignore the hints). - registry.gather_awards accepts cash_hints_per_leg; PointsPathProvider consumes it and sets SearchSpec(enable_matching=True, cash_hints=...). - match.join: third index keyed on matched_google_flight_id with priority above the existing (flight#, date) and (route, time) heuristics. The heuristics stay as fallback for Matrix cash and gflight-without-IDs. - pp/cli.py:run_pp_for_search auto-builds hints from any SearchResult whose slices carry flight_id (gflight backend). Render is unchanged. PP's response data is the same shape with or without matching enabled; only the matcher's behaviour changes. Tests: 8 new (5 matcher, 3 adapter). All 128 green. Memory: - docs/memories/pp_matched_id_recipe.md (new) — full recipe + empirical evidence + counter-evidence vs the prior dead-end note. - MEMORY.md index updated to point at the new doc as the corrected story.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PP's
enableGoogleFlightMatching=truemode DOES work — earlier "dead end" framing was wrong. With Google's real opaque flight ID (fromdata[0][17], which fli throws away) and the right hint shape, PP echoesmatchedGoogleFlightIdback per result. The matcher uses that as an exact-equality primary key, which catches codeshares the (flight#, date) heuristic misses.Empirical verification (end-to-end live)
The matched-ID path surfaces awards from multiple PP programs per cash itinerary — for codeshare flights, flight#+date alone would only have found the marketing carrier.
Discovery path
Captured the PP browser extension's live traffic via Patchright + a snapshot of the user's Chrome profile. 549 events, 87 successful airline-search responses. Settled the format (per
docs/memories/pp_matched_id_recipe.md):firstFlightNumberMUST be IATA-prefixed ("VS6", not"6") — bare numbers → 0 flightsairlineMUST be the human-readable name ("Virgin Atlantic", not"VS") — IATA code → 0 flightsstartDateTime/endDateTimespace-separated ("2026-06-30 18:05"), noT, no TZflightId= Google's opaque ID, captured from raw API responsedata[0][17]Architecture
One PR, layered:
src/flight_cli/_gflight_ids.py— wraps fli's encoder + curl_cffi client, parses the response ourselves to capturedata[0][17](the opaque ID fli drops).src/flight_cli/_airline_names.py— IATA → human-readable name mapping for PP-supported airlines.Slice.flight_id— optional, populated by gflight adapter, None for Matrix cash.AwardFlight.matched_google_flight_id— populated from PP's response when matching was enabled.AwardProvider.search_leggainedcash_hintskwarg in the Protocol — uniform interface for future providers.registry.gather_awardsplumbscash_hints_per_legthrough to the provider.match.join— third index keyed onmatched_google_flight_id, priority above (flight#, date) and (route, time). Heuristics remain as fallback.pp/cli.py:run_pp_for_search— auto-builds hints from any SearchResult whose slices carryflight_id(gflight backend).Renderer untouched. PP response shape unchanged; only the matcher's join logic and provider's request flag differ.
Tests
128 green (was 120, +8). New tests cover:
Slice.flight_idpopulation fromGFlightWithIdcash_hints_from_search_resultoutput shape (matches PP-captured format exactly)matched_google_flight_idstill joins via heuristicsflight_idskips matched-id path (Matrix backend compat)Memory
docs/memories/pp_matched_id_recipe.md(new) — full recipe, empirical evidence, counter-evidence vs prior dead-end note.MEMORY.mdindex updated to point at the new doc.Test plan
flight search EWR MIA --dep 2026-08-15(plain gflight + PP) — verify award columns populate.flight search JFK LHR --dep 2026-08-15 --backend matrix— matrix path still works (no flight_id, falls back to flight#+date heuristics).flight search JFK LHR --dep 2026-08-15 --backend gflight --json— verify JSON includesflight_id.flight search JFK LHR --dep 2026-08-15 --no-pp— gflight only, no PP overlay.