From 0309a58643d52d90f1d251c8d50f14e0fcd90429 Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Sat, 24 Oct 2026 00:10:14 -0400 Subject: [PATCH 1/3] fix(transit): count a 90-second report as one minute The card kept seconds through 89s, then rounded 90s up to 2 minutes. --- src/layers/transit/policy.js | 4 +++- .../transit/selectionCopy.i18n.test.mjs | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/layers/transit/policy.js b/src/layers/transit/policy.js index 010a2efc2..5dc17daeb 100644 --- a/src/layers/transit/policy.js +++ b/src/layers/transit/policy.js @@ -442,10 +442,12 @@ export function buildTransitSelectionCopy( ? entry.sample.latestReportAgeMs : vehicleFixAgeMs(record, nowMs, fetchedAtMs)) / 1000, ); + // Seconds through 89s, then whole minutes. Rounding 90s up would skip + // "1 min" and call a minute-and-a-half-old report two minutes old. const reported = ageS < 90 ? t('Reported {seconds} s ago', { seconds: ageS }) - : t('Reported {minutes} min ago', { minutes: Math.round(ageS / 60) }); + : t('Reported {minutes} min ago', { minutes: Math.floor(ageS / 60) }); // A time the feed did not give for THIS vehicle is labelled, so the card // never presents a borrowed or inferred time as the vehicle's own report. const ownTime = diff --git a/src/layers/transit/selectionCopy.i18n.test.mjs b/src/layers/transit/selectionCopy.i18n.test.mjs index 81fdfa0bb..26de5d28a 100644 --- a/src/layers/transit/selectionCopy.i18n.test.mjs +++ b/src/layers/transit/selectionCopy.i18n.test.mjs @@ -39,6 +39,26 @@ test('en: the copy is unchanged with and without the i18n t()', () => { ]); }); +test('a report 90 seconds old reads as 1 minute, not 2', () => { + setLocale('en'); + const line = (ageMs) => + buildTransitSelectionCopy( + feed, + { + id: 'age', + lat: 1, + lon: 1, + timestamp: Math.floor((now - ageMs) / 1000), + timestampSource: 'vehicle', + }, + 'bus', + now, + ).details[1]; + assert.equal(line(89_000), 'Reported 89 s ago'); + assert.equal(line(90_000), 'Reported 1 min ago'); + assert.equal(line(120_000), 'Reported 2 min ago'); +}); + for (const locale of ['es', 'ru']) { test(`${locale}: the Transit card is in the UI language`, () => { setLocale(locale); From 1469cc2ade2668079bdb1e4b7cbfc2b1546d2309 Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Sat, 24 Oct 2026 00:35:53 -0400 Subject: [PATCH 2/3] changelog: note the 90-second transit report age --- changelog.d/1353-transit-ninety-second-age.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog.d/1353-transit-ninety-second-age.md diff --git a/changelog.d/1353-transit-ninety-second-age.md b/changelog.d/1353-transit-ninety-second-age.md new file mode 100644 index 000000000..50611060d --- /dev/null +++ b/changelog.d/1353-transit-ninety-second-age.md @@ -0,0 +1,3 @@ +- Count a transit report that is 90 seconds old as one minute. The card kept + seconds through 89s, then rounded 90s up to "Reported 2 min ago" + (Rudy Celekli, @rudycelekli, #1353). From 6d47525e4e6103c5b3270cd956071c4824dd8fac Mon Sep 17 00:00:00 2001 From: Sameh Khamis Date: Sat, 24 Oct 2026 22:17:56 -0700 Subject: [PATCH 3/3] docs: record PR #1353 display behavior --- docs/CURRENT-STATE.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 3344a176d..483feadb8 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -4197,7 +4197,9 @@ to 0.45 at two minutes, 0.20 at ten minutes and 0.08 at fifteen minutes. **Cards and DETECT.** The card presents route, mode/operator, displayed motion, display delay and newest-report age, reported speed/stop, vehicle ID, and -available trail duration. Its anchor follows the rendered marker; text is +available trail duration. Report age is rounded to whole seconds and stays in seconds while that rounded +count is below 90; otherwise it shows completed minutes calculated from the +rounded second count. Its anchor follows the rendered marker; text is checked at 4 Hz and published when it changes. DETECT labels retain route, mode and motion, with the selected label suppressed beside its fuller card. Candidate membership changes on revisions, coalesced at 4 Hz; paints read