[feature] Configure departure-to-arrival journeys and combine compatible full and short-turn departures #28
- @github-anthodev opened this issue · Sep 19, 2026edited
Impact version (SemVer)
MINORproposed: selecting intermediate arrival stops is a new user-visible capability, alongside the short-turn departure fix. No version bump has been applied.
Description
A favorite must represent a journey from an exact boarding point to a selected arrival stop on the same line, rather than a terminal-specific service selection. This allows full-line and short-turn services to contribute to the same favorite when both serve the requested journey, including arrivals that are never a terminal.
The previous terminal-priority approach could show identical departures for incompatible journeys and place later full-service departures ahead of earlier compatible short-turn departures. PRIM destination references, names and displays can disagree, so no single field reliably identifies every live route.
Implementation is present in the local working copy. This ticket records the delivered scope and remaining acceptance work; it is not a release or deployment claim.
Expected behavior
- Select a departure stop, a line and exact boarding point, then an explicitly chosen reachable arrival. Include intermediate stops; do not merge different quays or infer stop identity from a shared name.
- Use ordered GTFS patterns and boarding/alighting restrictions to decide whether each PRIM visit can serve the selected departure and arrival in that order. Preserve express branches, opposite directions and repeated occurrences in loops.
- Recognized destination evidence selects the union of matching terminal candidates. An unknown nonempty hint, or no recognized hint, widens candidates to every pattern containing the exact boarding point. Do not invent abbreviation aliases or impose uncertainty solely because a name is unknown.
- Confirm a journey when every candidate permits it; exclude the visit when every candidate rules it out; mark it uncertain when candidates disagree or restrictions are conditional. Missing pattern data remains uncertain for an already resolved arrival.
- Combine confirmed full and short-turn departures chronologically, then retain uncertain departures chronologically in the remaining slots. Keep at most four. Intervals connect only confirmed, non-cancelled departures.
- Preserve all three admissible departures when PRIM provides three. Do not synthesize a third when it provides zero, one or two. The watch overview shows one summary per favorite; detail supports up to four visible departures on Emery and three on Gabbro. Native verification remains open.
- Mark uncertain summaries with
?while retaining actual times and cancellation/delay status in detail.
Acceptance criteria
- EN/FR configuration supports explicit intermediate arrivals, distinct same-name stops, distinct boarding points and six favorites. Selection changes cancel obsolete work; unavailable, invalid or timed-out responses cannot enable Add or erase existing favorites.
- Store complete per-line/mode journey patterns and proven terminal aliases in catalog v4, and publish complete revision-pinned annexes/groups atomically without changing existing service identities.
- Admit legitimate parent-only IDFM hierarchy relations without inventing physical-stop associations, while preserving source-row counts and rejecting malformed physical links.
- Migrate phone configuration to envelope v2 without losing IDs, labels, order, credentials or invalid-key state. Resolve old arrivals only through the exact service annex. Legacy page sessions are read-only; old close envelopes cannot overwrite configuration.
- Bind cache v3 entries and in-flight work to favorite ID, service ID and arrival ID. Arrival-only changes invalidate old results;
CACHE_ONLYperforms no catalog or PRIM requests. - Apply candidate-journey uncertainty consistently through the canonical helper, generated browser module and real companion normalizer. Preserve three provided admissible departures and never fill missing slots.
- Encode the uncertainty bit with display wire v3 without changing message IDs, record widths, queue limits or VM memory.
- Verify browser configuration, captured close serialization and replay through the actual companion. This does not certify delivery by the Pebble mobile app.
- Rebuild a real isolated IDFM catalog and replay retained real line 255 responses through the final classifier without further live requests.
- Complete native companion-to-watch verification on Emery and Gabbro in FR/EN, including three provided departures, mixed/uncertain detail rendering and cache-only behavior. Currently blocked by the existing Alloy startup outbox issue; SDK changes were explicitly left out of scope.
- Obtain a completed real-catalog performance measurement. The attempted
measure:catalogrun exceeded 120 seconds; no passing performance result is claimed.
Affected endpoints/routes
- Existing PRIM
GET /marketplace/stop-monitoring?MonitoringRef=...&LineRef=...; companion-only. No quantity parameter, retry or backend endpoint is added. - Static
/<revision>/journeys/services/<serviceId>.json. - Static
/<revision>/journeys/groups/<groupId>/index.jsonand numbered group pages. - Settings launch fragment and
pebblejs://close#...configuration envelope v2.
Tests to add or retain
Use the existing Node test suites, not a new test framework. The host regressions below are implemented.
Type Coverage Catalog import/publication Full/short/express/loop patterns; pickup/drop-off restrictions; proven aliases; parent-only relations; stable identities; complete paging; atomic failure. Classifier/normalizer Shared arrival confirmed despite ambiguous terminal; beyond-short-turn arrival uncertain; universally incompatible journey excluded; unknown/no hints widen candidates; strict dates; 0/1/2/3/>4 visits; stable ordering and no invented times. Configuration/cache integration Safe v1 migration; failed persistence; invalid-key marker; legacy read-only and rejected closes; distinct arrivals sharing one service; stale callbacks; arrival-only changes; cache-only with zero requests. Shared module and wire CJS/generated ESM parity; required uncertainty boolean; valid status bits 0–7; reject 8–15 and old wire dictionaries; unchanged byte budgets. Browser/native Browser flows and close replay are exercised. Native visual/delivery acceptance remains open rather than being inferred from host tests.
Constraints
- One selected line and boarding point, no transfers, fabricated trip IDs, synthetic schedules or guessed stop equivalences.
- Event-only fetching and the existing 60-second cache. No periodic fetching or automatic retries.
- Personal PRIM key remains phone-local and in the exact request header; never in watch messages, URLs, logs or evidence.
- Keep the 19 message aliases/IDs, 768/192-byte dictionaries, four-message watch queue and fixed 57,344-byte VM budget.
- Do not patch the SDK, install tools, touch physical devices or claim native readiness without separate authorization and evidence.
- No commit, tag, version bump or remote publication was performed for this work.
Dependencies
Extends the areas delivered by #3, #4, #5, #6 and #7. Those issues are historical context, not newly opened blockers.
Complete rollout requires the enriched real catalog, matching configuration page and matching PBW together. The rebuilt catalog and PBW currently exist locally only. Native acceptance and the real-catalog measurement remain open as noted above.
Impact on existing behavior
- Phone favorites gain a required nullable
arrivalPlaceId; unresolved migrated favorites remain visible instead of receiving a guessed arrival. - Configuration envelopes become v2, result cache becomes v3, display wire becomes v3. Domain schema remains v1.
- Catalog format becomes v4, with no in-place SQLite v3 migration. Static export format becomes v2.
- Old departure caches are discarded, not configuration or credentials. Traffic remains keyed by line/language.
- A resolved arrival with unavailable patterns receives uncertain live departures; an unresolved arrival does not trigger a guessed departure request.
Technical context and verification
Primary implementation locations:
packages/companion/src/journey-patterns.js:createJourneyClassifier,reachableArrivals,validateJourneyGroup,journeyKey.packages/catalog/src/catalog-import.ts:prepareSpecs,insertJourneys;packages/catalog/src/static-catalog.ts: revisioned journey publication.packages/companion/src/prim-departures.js:normalizePrimDepartureResponse;index.js:_startOverviewFlight,_dispatchDetail;configuration.js: migration andmergeOverview.packages/config-page/src/config-page.js,config-core.js,catalog-client.js: grouped boarding-point selection, arrival lookup and safe editing.packages/companion/src/display.js,packages/watch/src/embeddedjs/packed.jsandui.js: uncertainty encoding and display.
Latest verification: 360 host tests pass, 41 focused classifier/normalizer tests pass, independent review approved, Emery/Gabbro production build and radio gate pass. Page JS+CSS measures 38,989 / 204,800 gzip bytes.
Real IDFM reconstruction on 2026-09-19 produced 93,911 services across all five modes. Static revision:
9f595af74220fc1c54efa6d23c468fbad49e42afea73876b508d7bf55465b8dc.Four PRIM calls returned HTTP 200 in total. The first two were not usable because the verification script failed before normalization. The next two responses were retained and replayed after correcting the classifier, with zero additional network calls:
Real line 255 response Final replay result North, monitoring STIF:StopPoint:Q:25446:, two visits announced for Les PrévoyantsBoth visits confirmed for Mairie and Les Prévoyants. South, monitoring STIF:StopPoint:Q:34214:, two visits with full name Porte de Clignancourt and short/display name ClignancourtBoth visits confirmed for Porte de Paris; both remain uncertain for Porte de Clignancourt because widened candidate routes disagree beyond the short-turn terminal. Both responses contained two, not three, visits. There was no explicitly announced short-turn visit in this sample. Three-passage preservation is covered by regressions, not by a three-passage live or native observation.
Local evidence is gitignored and is not attached to this issue:
var/live-journey-verification/verification.json,candidate-uncertainty-replay.json, and the browser report undervar/journey-verification/browser/. The first native startup failure and SDK diagnosis are retained locally; no successful native rendering claim is made.
Sign in to comment.