From add860bceba464ceb260e52a9896c6be33d288da Mon Sep 17 00:00:00 2001 From: araharah-executor Date: Sun, 25 Oct 2026 04:02:31 +0800 Subject: [PATCH] =?UTF-8?q?fix(07-02):=20refuse=20<2-point=20geometries=20?= =?UTF-8?q?before=20the=20draw=20path=20=E2=80=94=20pending=20card=20/=20r?= =?UTF-8?q?eroute-failed=20(T-07-12,=20FM4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - consult filters degenerate options (geometry.points < 2) into the pending-card class - reroute ladder: no drawable option = the honest reroute-failed degradation, never a half-drawn snap-in - GREEN for FM4; web suite 165/165, typecheck clean --- web/src/route/route.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/web/src/route/route.ts b/web/src/route/route.ts index 65e8256..b334407 100644 --- a/web/src/route/route.ts +++ b/web/src/route/route.ts @@ -225,13 +225,19 @@ export function createRouteController(deps: RouteControllerDeps): { const result: RouteResult | null = await deps.source .route({ origin: { lat: fix.lat, lng: fix.lng }, destinationId: destination.id }) .catch(() => null); // T-05-04: an exception renders pending — never a half-drawn line - if (result === null || result.options.length === 0) { + // T-07-12 (FM4, 07-02): a geometry decoding to fewer than two points is + // refused BEFORE the draw path — the degenerate option is dropped with + // the empty-answer class, so the pending card renders instead of a + // half-drawn line (the same law main.ts already applies to the ?g= + // envelope's decoded polyline). + const usable = result === null ? [] : result.options.filter((option) => option.geometry.points.length >= 2); + if (result === null || usable.length === 0) { deps.showRouteCard(deps.buildPendingCard(deps.locale, { onSearchAgain: () => walkBack() }), "center"); setState("pending"); console.log("ARAHARAH-ROUTE state=pending"); return; } - options = result.options; + options = usable; selectedIndex = 0; drawSelection(); setState("route"); @@ -443,14 +449,16 @@ export function createRouteController(deps: RouteControllerDeps): { result = null; // fail-honest (T-05-04, network edition) } if (guidance !== g || g.ended) return; // the trip ended mid-request — drop it - if (result === null || result.options.length === 0) { + // T-07-12 (FM4, 07-02): the same no-geometry law on the reroute ladder — + // an answer with no drawable (>= 2-point) option is the honest + // reroute-failed degradation, never a half-drawn snap-in. + const option = result === null ? undefined : result.options.find((o) => o.geometry.points.length >= 2); + if (option === undefined || result === null) { g.snap = stepGuidance(g.snap, { type: "reroute-failed" }, now()).snap; logGuideState(g.snap.state); renderCockpit(); return; } - const option = result.options[0]; - if (option === undefined) return; const model: GuidanceRouteModel = { points: option.geometry.points, cumulative: option.geometry.cumulativeDistanceM,