From 2b03f9a024d4bae1c940a043285310ecab624554 Mon Sep 17 00:00:00 2001 From: jubnl Date: Sat, 1 Aug 2026 12:49:22 +0200 Subject: [PATCH] fix(server): tidy transit itinerary quirks after the DI relocation --- .../nest/transit/transit-itinerary.helpers.ts | 33 ++++++++++++++----- server/src/nest/transit/transit.mcp.ts | 2 +- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/server/src/nest/transit/transit-itinerary.helpers.ts b/server/src/nest/transit/transit-itinerary.helpers.ts index 744745248..b3a0e44e6 100644 --- a/server/src/nest/transit/transit-itinerary.helpers.ts +++ b/server/src/nest/transit/transit-itinerary.helpers.ts @@ -17,6 +17,9 @@ import { z } from 'zod'; const MAX_ENDPOINT_DISTANCE_KM = 0.1; const MAX_LEG_GAP_KM = 1; const TIME_TOLERANCE_MS = 60_000; +// One budget for both limits: a single leg's geometry and the combined +// geometry of all legs share the same ceiling. +const MAX_GEOMETRY_CHARS = 60_000; export const transitCoordinatesSchema = z.object({ lat: z.number().min(-90).max(90), @@ -64,7 +67,7 @@ const transitLegSchema = z.object({ lineTextColor: colorSchema, agency: z.string().max(300).nullable(), intermediateStops: z.number().int().nonnegative(), - geometry: z.string().max(60_000).nullable(), + geometry: z.string().max(MAX_GEOMETRY_CHARS).nullable(), geometryPrecision: z.number().int().min(0).max(10), }); @@ -99,7 +102,7 @@ export const transitItinerarySchema = z }); } const geometrySize = itinerary.legs.reduce((total, leg) => total + (leg.geometry?.length ?? 0), 0); - if (geometrySize > 60_000) { + if (geometrySize > MAX_GEOMETRY_CHARS) { context.addIssue({ code: 'custom', message: 'Combined transit geometry is too large', path: ['legs'] }); } itinerary.legs.forEach((leg, index) => { @@ -207,8 +210,20 @@ export function buildTransitReservationParts( to: TransitPlaceInput, itinerary: TransitItinerary, ) { - const fromTimezone = timezoneAt(from.lat, from.lng); - const toTimezone = timezoneAt(to.lat, to.lng); + // The same stop appears up to three times below (transfer endpoint + the + // adjacent legs' metadata) — memoise the tz lookup per coordinate pair. + const timezones = new Map(); + const timezoneFor = (lat: number, lng: number): string => { + const key = `${lat},${lng}`; + let timezone = timezones.get(key); + if (timezone === undefined) { + timezone = timezoneAt(lat, lng); + timezones.set(key, timezone); + } + return timezone; + }; + const fromTimezone = timezoneFor(from.lat, from.lng); + const toTimezone = timezoneFor(to.lat, to.lng); const departure = transitLocalParts(itinerary.startTime, fromTimezone); const arrival = transitLocalParts(itinerary.endTime, toTimezone); const transitLegs = itinerary.legs.filter((leg) => leg.mode !== 'WALK'); @@ -228,7 +243,7 @@ export function buildTransitReservationParts( transitLegs.slice(0, -1).forEach((leg, index) => { const stop = leg.to; - const timezone = timezoneAt(stop.lat, stop.lng); + const timezone = timezoneFor(stop.lat, stop.lng); const stopTime = effectiveTransitStopTime(stop); const local = stopTime ? transitLocalParts(stopTime, timezone) : null; endpoints.push({ @@ -246,7 +261,9 @@ export function buildTransitReservationParts( endpoints.push({ role: 'to', - sequence: endpoints.length, + // 1 origin + (transitLegs.length - 1) transfer stops precede this — the + // destination's sequence is the transit leg count by construction. + sequence: transitLegs.length, name: to.name, code: null, lat: to.lat, @@ -277,12 +294,12 @@ export function buildTransitReservationParts( stops: leg.intermediateStops, from: { name: leg.from.name, - time: fromTime ? transitLocalParts(fromTime, timezoneAt(leg.from.lat, leg.from.lng)).time : null, + time: fromTime ? transitLocalParts(fromTime, timezoneFor(leg.from.lat, leg.from.lng)).time : null, track: leg.from.track, }, to: { name: leg.to.name, - time: toTime ? transitLocalParts(toTime, timezoneAt(leg.to.lat, leg.to.lng)).time : null, + time: toTime ? transitLocalParts(toTime, timezoneFor(leg.to.lat, leg.to.lng)).time : null, track: leg.to.track, }, geometry: leg.geometry, diff --git a/server/src/nest/transit/transit.mcp.ts b/server/src/nest/transit/transit.mcp.ts index c3bfccae8..e17c95f11 100644 --- a/server/src/nest/transit/transit.mcp.ts +++ b/server/src/nest/transit/transit.mcp.ts @@ -225,7 +225,7 @@ export class TransitMcp { isError: true, }; } - const endDay = this.days.list(tripId).days.find((day) => day.date === arrival.local_date); + const endDay = this.days.list(tripId).days.find((d) => d.date === arrival.local_date); if (!endDay) { return { content: [{ type: 'text' as const, text: `No trip day exists for the arrival date ${arrival.local_date}.` }],