From a140c52f847b4b3cf7f9bfe1b6b4597afd25747f Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Sun, 11 Oct 2026 09:36:07 -0400 Subject: [PATCH 1/3] fix(directions): report truncation only when a maneuver was actually omitted --- CHANGELOG.md | 2 ++ docs/CURRENT-STATE.md | 5 +++++ src/data/route-cap-truthfulness.test.mjs | 24 ++++++++++++++++++++++++ src/data/routeSteps.js | 2 +- 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/data/route-cap-truthfulness.test.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7acdedf6b..e1518ce6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ the five borough cores load and `CCTV_NYC_MAX_SOURCES` changes the cap. The catalog-wide ceiling is unchanged; extra cameras share it round-robin with the other packs. +- Direction instruction limits report complete routes honestly and retain a final roundabout exit within the limit. + - Treat explicitly current, complete empty vessel coverage as a successful update, clearing obsolete contacts while retaining stale or incomplete snapshots. diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index c77d1d8e3..d6222d72e 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -5310,3 +5310,8 @@ datacenters, dams and the Nepal locator retain that shared credit while displaye Military fragments stitch by source identity. Different mapped parcels merge only when their footprints touch or contain one another, never across a seam tolerance gap. + + +### fix(directions): report truncation only when a maneuver was actually omitted + +Keep processing foldable exits after the cap and report truncation only when the next admissible independent instruction would exceed it. The returned list remains bounded to 200 steps. diff --git a/src/data/route-cap-truthfulness.test.mjs b/src/data/route-cap-truthfulness.test.mjs new file mode 100644 index 000000000..7d5d80153 --- /dev/null +++ b/src/data/route-cap-truthfulness.test.mjs @@ -0,0 +1,24 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { normalizeOsrmSteps, ROUTE_STEPS_MAX } from './routeSteps.js'; +const step = (type) => ({ + maneuver: { type, location: [10, 20] }, + distance: 10, + duration: 1, +}); +test('exact-cap routes remain complete and boundary exits retain their distance', () => { + const steps = Array.from({ length: ROUTE_STEPS_MAX }, () => step('turn')); + assert.equal(normalizeOsrmSteps({ legs: [{ steps }] }).truncated, false); + assert.equal( + normalizeOsrmSteps({ legs: [{ steps: [...steps, step('turn')] }] }) + .truncated, + true, + ); + steps[steps.length - 1] = step('roundabout'); + const result = normalizeOsrmSteps({ + legs: [{ steps: [...steps, step('exit roundabout')] }], + }); + assert.equal(result.truncated, false); + assert.equal(result.steps.length, ROUTE_STEPS_MAX); + assert.equal(result.steps.at(-1).distanceM, 20); +}); diff --git a/src/data/routeSteps.js b/src/data/routeSteps.js index 5ee11602a..e3144bdf7 100644 --- a/src/data/routeSteps.js +++ b/src/data/routeSteps.js @@ -185,9 +185,9 @@ export function normalizeOsrmSteps(route) { } continue; } + if (out.length >= ROUTE_STEPS_MAX) return { steps: out, truncated: true }; step.instruction = instructionFor(step); out.push(step); - if (out.length >= ROUTE_STEPS_MAX) return { steps: out, truncated: true }; } } return { steps: out, truncated: false }; From 69815a92bec2f3ceaf41aecf919b6f78edc8818a Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Mon, 12 Oct 2026 11:12:02 -0400 Subject: [PATCH 2/3] docs: address review scope and feature placement for #1030 --- docs/CURRENT-STATE.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index d6222d72e..607449cf8 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3317,6 +3317,10 @@ from fixtures (`providers/mapillary/coverageFixture.mjs`, photo flow. CI runs the fixture gate and `qa:panel-resize` against a production build served by `vite preview` with a dummy token. +Directions retains up to 200 turn instructions. Its truncation notice appears +only when another independent instruction is omitted; a complete route with +exactly 200 turns does not show the notice. + Directions is a keyless front end to the routing the voice agent already uses. Its row chips are the whole interface: DRIVE / WALK / BIKE pick the profile; SET A and SET B arm the next globe click (Escape or a second press @@ -5310,8 +5314,3 @@ datacenters, dams and the Nepal locator retain that shared credit while displaye Military fragments stitch by source identity. Different mapped parcels merge only when their footprints touch or contain one another, never across a seam tolerance gap. - - -### fix(directions): report truncation only when a maneuver was actually omitted - -Keep processing foldable exits after the cap and report truncation only when the next admissible independent instruction would exceed it. The returned list remains bounded to 200 steps. From 51d335b1db56a767ceab9aed3238889aaccebcdd Mon Sep 17 00:00:00 2001 From: Sameh Khamis Date: Wed, 14 Oct 2026 16:35:10 -0700 Subject: [PATCH 3/3] test: check the route cap at exactly 200 turns The existing "route that fits" case used 199 steps, which is how the off-by-one went unnoticed. Folds the docs note into the existing cap sentence and makes the changelog entry specific. --- CHANGELOG.md | 3 ++- docs/CURRENT-STATE.md | 11 ++++------- src/data/routeSteps.test.mjs | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31fa3b502..a770fbd35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,8 @@ the five borough cores load and `CCTV_NYC_MAX_SOURCES` changes the cap. The catalog-wide ceiling is unchanged; extra cameras share it round-robin with the other packs. -- Direction instruction limits report complete routes honestly and retain a final roundabout exit within the limit. +- Directions no longer shows a truncation notice for a route with exactly 200 + turns, and a roundabout at the 200th turn keeps its exit distance. - Weather records keep missing conditions unknown and refuse summaries without a measured temperature. diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index c98b2f667..1f794a5b5 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3327,10 +3327,6 @@ from fixtures (`providers/mapillary/coverageFixture.mjs`, photo flow. CI runs the fixture gate and `qa:panel-resize` against a production build served by `vite preview` with a dummy token. -Directions retains up to 200 turn instructions. Its truncation notice appears -only when another independent instruction is omitted; a complete route with -exactly 200 turns does not show the notice. - Directions is a keyless front end to the routing the voice agent already uses. Its row chips are the whole interface: DRIVE / WALK / BIKE pick the profile; SET A and SET B arm the next globe click (Escape or a second press @@ -3403,9 +3399,10 @@ rate limit from the routing service is reported as one instead of as "no route found". `src/data/routeSteps.js` turns OSRM maneuver type / modifier / exit / road name into one plain-English sentence per decision, folding `exit roundabout` steps into the roundabout they leave, and caps one route at -200 maneuvers — a route past that cap is reported as cut off, in the row -summary and as the last line of the list, because the arrival step is among -the ones dropped. +200 maneuvers — a route with more is reported as cut off, in the row summary +and as the last line of the list, because the arrival step is among the ones +dropped. A route of exactly 200 is complete, and a roundabout exit after the +200th keeps folding into it. A step's card opens from its dot on the globe or from its line in the list, and the list covers every step including departure and arrival, which have no dot. diff --git a/src/data/routeSteps.test.mjs b/src/data/routeSteps.test.mjs index a3c8cf227..6bf74dd08 100644 --- a/src/data/routeSteps.test.mjs +++ b/src/data/routeSteps.test.mjs @@ -206,9 +206,9 @@ test('the step list is capped, and the cap is reported rather than hidden', () = // would present a route that simply stops in the middle of a road. assert.equal(cut.truncated, true); const exact = normalizeOsrmSteps({ - legs: [{ steps: many.slice(0, ROUTE_STEPS_MAX - 1) }], + legs: [{ steps: many.slice(0, ROUTE_STEPS_MAX) }], }); - assert.equal(exact.steps.length, ROUTE_STEPS_MAX - 1); + assert.equal(exact.steps.length, ROUTE_STEPS_MAX); assert.equal(exact.truncated, false, 'a route that fits is not cut'); });