fix(tours): name an actual track's metrics and a tour's stages as derived in get_tour_plan

What a recorded track measures is read off its line on every read, and a
multi-day tour's stage count and stops are counted from its stage ends,
yet derived did not list them, so an assistant would take them for saved
facts.
This commit is contained in:
Maurice
2026-10-20 16:52:08 +02:00
parent a249c861e6
commit 5e0f216b0c
2 changed files with 21 additions and 2 deletions
+5 -1
View File
@@ -151,7 +151,9 @@ interface PlanExtras {
* The fields of this answer worked out when it was read rather than stored
* with the tour. The distance, heights and walking time of a tour are stored
* when it is saved, and the days are the trip's own assignments, so neither
* is listed here.
* is listed here. What a recorded track measures (ACT-01) is read off its
* line on every read, and a multi-day tour's stages (MDT-01) are counted from
* its stage ends, so both are.
*/
export function derivedFields(detail: TourDetailResponse, { controlsFromTrack, line, run }: PlanExtras): string[] {
const type = detail.tour.tour_type;
@@ -166,5 +168,7 @@ export function derivedFields(detail: TourDetailResponse, { controlsFromTrack, l
...(type === 'walk' ? ['tour.station_count', 'tour.station_stay_minutes', 'tour.station_stays_unknown'] : []),
...(run ? ['run.open'] : []),
...(type === 'kayak' ? ['tour.paddle_check', 'obstacle_check'] : []),
...((detail.activities?.length ?? 0) > 0 ? ['activities[].metrics'] : []),
...(detail.tour.stage_count != null ? ['tour.stage_count', 'tour.stage_stops'] : []),
];
}
+16 -1
View File
@@ -4,7 +4,7 @@ import type { TourDetailResponse, TourWaypoint } from '@trek/shared';
import { describe, expect, it } from 'vitest';
// TOUR-PLAN-READ-001 to TOUR-PLAN-READ-006
// TOUR-PLAN-READ-001 to TOUR-PLAN-READ-007
/** The detail of a tour of this type, only as far as the plan reads it. */
function detailOf(tourType: TourDetailResponse['tour']['tour_type']): TourDetailResponse {
@@ -107,4 +107,19 @@ describe('tour plan read (MCP-T01)', () => {
});
expect(planLegs([free, point(1)], { recorded: true })).toEqual([expect.objectContaining({ kind: 'free' })]);
});
it('TOUR-PLAN-READ-007: an actual track names its metrics as worked out, a multi-day tour its stage count and stops', () => {
const none = { controlsFromTrack: false, line: null, run: null };
const plain = derivedFields(detailOf('hike'), none);
expect(plain).not.toContain('activities[].metrics');
expect(plain).not.toContain('tour.stage_count');
const tracked = { ...detailOf('hike'), activities: [{ id: 1 }] } as unknown as TourDetailResponse;
expect(derivedFields(tracked, none)).toContain('activities[].metrics');
expect(derivedFields({ ...detailOf('hike'), activities: [] }, none)).not.toContain('activities[].metrics');
const staged = {
...detailOf('hike'),
tour: { tour_type: 'hike', stage_count: 2 },
} as unknown as TourDetailResponse;
expect(derivedFields(staged, none)).toEqual(expect.arrayContaining(['tour.stage_count', 'tour.stage_stops']));
});
});