Skip to content

Matrix URL: pin selected itinerary via /itinerary route (work-2kny)#22

Merged
ak2k merged 1 commit into
mainfrom
worktree-matrix-itinerary-pin
May 19, 2026
Merged

Matrix URL: pin selected itinerary via /itinerary route (work-2kny)#22
ak2k merged 1 commit into
mainfrom
worktree-matrix-itinerary-pin

Conversation

@ak2k

@ak2k ak2k commented May 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • Closes the last open item on work-2kny — Matrix per-itinerary URL pinning.
  • RE'd Matrix's /itinerary URL state from a Playwright capture (fill form → click cheapest row → SPA navigates to /itinerary?search=... with a solution block).
  • The pin requires three server-generated IDs returned by /v1/search: session, solutionSet, and the chosen solution's id. We capture all three on the existing models, then wire them into _emit_urls so the Matrix line upgrades from search to pinned whenever the result carries them.

Field mapping

URL solution.<key> API response field
sessionId session
rh solutionSet
Si solutionList.solutions[i].id

What's new

  • links.matrix_itinerary_url(search, *, solution_id, session, solution_set)SpecificDateSearch only; raises TypeError for calendar/followup.
  • models.Itinerary.id field — explicit capture (the loose base config ignored it before).
  • cli._try_pinned_matrix_url() — mirrors _try_pinned_gflight_url; returns None when any of the three IDs is missing.
  • cli._emit_urls() — uses pinned URL when available; falls back to matrix_deep_link() otherwise (e.g. gflight-backend runs).
  • Regression test: byte-exact match against a captured /itinerary URL.

Session-scoped — known limitation

Matrix's session/rh/Si are ephemeral (~10–30 min observed). Stale URLs fail with Input error for "bookingDetails" (SolutionSummarizer), "x.solution" is required and the SPA shows no booking details. Docstring spells this out. Same model as Google's tfs= pinned cards in that pinning is intended for "share this result I just saw," not long-lived bookmarks.

A durable Matrix pin (encoding carriers + flight numbers, like Google's tfs= pinned form) would require either RE'ing Matrix's own "Open in Google Flights" button on the /itinerary page or a separate translation step. Out of scope here.

Test plan

  • make check (ruff + ruff format + basedpyright + pytest, 338 passed — 2 new tests)
  • Live: flight search HNL MIA --dep 2026-10-14 --return 2026-10-24 -n 1 --no-pp --backend matrix --matrix-url emits a pinned /itinerary URL
  • Live: Playwright-loaded URL renders the booking-details page ("American 143, HNL→LAX→MIA, $679.80") for the cheapest itinerary
  • Verified gflight-backend runs still emit the (search-only) Matrix deep-link — falls back cleanly when session IDs absent

Closes the last remaining item on work-2kny — Matrix per-itinerary URL
pinning. Mirrors the Google Flights pin pattern.

RE'd from the SPA: clicking a results row navigates to `/itinerary` with
a `solution` block carrying three IDs returned by `/v1/search`:
  - `sessionId` ← response.session
  - `rh`        ← response.solutionSet
  - `Si`        ← solutionList.solutions[i].id

`Itinerary.id` is now captured from the API response so the CLI can build
the URL. `_emit_urls` upgrades the Matrix line to the pinned form whenever
a Matrix-backed result carries all three IDs, falling back to the search
URL when missing (e.g. gflight-backend runs, where Matrix session is N/A).

Session-scoped: Matrix's IDs expire on the server (~10–30 min observed);
stale URLs fail with `Input error for "bookingDetails"`. Docstring spells
this out. Same model as Google's session-bound `tfs=` for pinned cards.

Includes a byte-exact regression test against a captured SPA URL and a
guard test that calendar searches raise TypeError instead of building a
nonsense URL.
@ak2k ak2k merged commit 0229407 into main May 19, 2026
2 checks passed
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.

1 participant