Skip to content

fix(ui): floor both halves of a task duration - #862

Open
ANIRUDDHA ADAK (aniruddhaadak80) wants to merge 1 commit into
synthetic-sciences:mainfrom
aniruddhaadak80:fix/task-duration-60s
Open

ANIRUDDHA ADAK (aniruddhaadak80) wants to merge 1 commit into
synthetic-sciences:mainfrom
aniruddhaadak80:fix/task-duration-60s

Conversation

@aniruddhaadak80

Copy link
Copy Markdown
Contributor

What

formatTaskDuration in frontend/ui/src/components/research-trace.ts floors the larger unit and rounds the smaller one:

if (value < 3_600_000) return `${Math.floor(value / 60_000)}m ${Math.round((value % 60_000) / 1_000)}s`
return `${Math.floor(value / 3_600_000)}h ${Math.round((value % 3_600_000) / 60_000)}m`

Why it matters

Whenever the remainder is within half a second of the next unit, the rounded value reaches 60 — and nothing carries it, because the larger half was already floored:

formatTaskDuration(119_999)    -> "1m 60s"
formatTaskDuration(3_599_999)   -> "59m 60s"
formatTaskDuration(7_199_999)   -> "1h 60m"

60 is not a valid number of seconds, so a task card shows a duration that does not exist. The window is wide: within [119_500, 3_599,999] there are 29,500 values that print a 60.

The call site (message-part.tsx:1397) passes metadata.durationMs through with no clamp, so any finished Task landing in that window is affected.

The behaviour is pinned by its own sibling — elapsedLabel, six lines above, the counter for a still-ticking task, floors throughout and is right on the same input:

elapsedLabel(119_999)        // "1m 59s"   correct
formatTaskDuration(119_999)  // "1m 60s"   wrong, same value

Verification

New case in the existing duration test. Fails before:

Expected: "1m 59s"
Received: "1m 60s"
(fail) formats compact child durations   <- the new test
 34 pass  1 fail
(pass) formats compact child durations
(pass) never prints a 60 in the smaller unit
 35 pass
 0 fail

The pre-existing assertions (800 / 7,800 / 125,000) are untouched and still pass, so the ordinary values are unchanged. The new test checks all three magnitude branches and asserts the same input through elapsedLabel, which is what makes the floor behaviour a stated contract rather than a coincidence.

The wider frontend/ui suite is flaky in this checkout (231 pass / 12 fail on upstream/main; 232/12 and 233/11 with this change across runs — order and timing dependent), so this is judged on the targeted file.

The change

-  if (value < 3_600_000) return `${Math.floor(value / 60_000)}m ${Math.round((value % 60_000) / 1_000)}s`
-  return `${Math.floor(value / 3_600_000)}h ${Math.round((value % 3_600_000) / 60_000)}m`
+  // Floor both halves. Rounding the remainder reaches 60 and prints a duration
+  // that does not exist, where the ticking counter above floors throughout.
+  if (value < 3_600_000) return `${Math.floor(value / 60_000)}m ${Math.floor((value % 60_000) / 1_000)}s`
+  return `${Math.floor(value / 3_600_000)}h ${Math.floor((value % 3_600_000) / 60_000)}m`

Touched files are Prettier-clean (verified on LF-normalized copies; this Windows checkout's core.autocrlf=true makes Prettier flag every file repo-wide).

Fixes #861

@vercel

vercel Bot commented Sep 30, 2026

Copy link
Copy Markdown

ANIRUDDHA ADAK (@aniruddhaadak80) is attempting to deploy a commit to the InkVell Team on Vercel.

A member of the Team first needs to authorize it.

The seconds were rounded while the minutes were floored, so a value within half a second of the next minute printed an impossible 1m 60s. The ticking counter next to it floors throughout.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A task duration within half a second of the next minute displays as 1m 60s

1 participant