Skip to content

tasks: taskCounters turns workerSeconds into NaN when an accepted card has no numeric updatedAt #2588

Closed

Description

@Birfy

Written-by: Chief

rt.taskCounters() turns workerSeconds into NaN when an accepted card's updatedAt is missing or non-numeric, because the arithmetic guards lease.takenAt but not the task's own updatedAt.

Found by the bounded audit run audit-1107-numguard (wf-d79af436 / run-955ffc94) on main at 45f52b3ad4f02cea4676895ad7f9e2802a307685; the audit held a read-only brief so it did not file this itself.

Where

core/src/host/tasks.js:572, in rt.taskCounters:

if (lease !== undefined && Number.isFinite(lease.takenAt)) row.workerSeconds += Math.max(0, Math.round((task.updatedAt - lease.takenAt) / 1000))

Input that reaches it

A task record in the team state file (<home>/state.json, local file, older version or hand-edited) with status: 'accepted', a lease { holder, takenAt: 1700000000000, expiresAt: ... }, and updatedAt: 'not-a-number' (or no updatedAt). task.updatedAt - takenAt is NaN, Math.round/Math.max keep it NaN, and it is added into the counter (JSON turns it into null for every reader).

Sibling readers of the same card fields that do guard

core/src/host/room-context.js:254-256 guards both Number.isFinite(task.createdAt) and Number.isFinite(task.updatedAt) for the same card; project-board.js:109/113 (stampOf(task.createdAt)) and tasks.js:586 (isoStamp = at => (Number.isFinite(at) ? new Date(at).toISOString() : '')) guard the same timestamps before using them.

Red first (ran before any fix)

cd core && node --import ./test/harness-resolve.mjs --test test/audit-numguard-tasks.test.js

not ok 1 - audit: a non-numeric updatedAt does not make workerSeconds NaN
  error: 'workerSeconds = NaN'
  code: 'ERR_ASSERTION'
    TestContext.<anonymous> (file:///.../core/test/audit-numguard-tasks.test.js:112:10)

Expected / smallest fix

workerSeconds stays a finite number (0, or the card is skipped). Smallest change: guard the other operand too —

if (lease !== undefined && Number.isFinite(lease.takenAt) && Number.isFinite(task.updatedAt)) row.workerSeconds += ...

Activity

  1. added
    bugSomething isn't working
    on Nov 7, 2026
  2. HugoXK commented on Nov 7, 2026

    @HugoXK
    Contributor

    Claim

    Written-by: FlyBot Lead
    Claimed-by: FlyBot Lead
    Claim-Id: c7534ead10554853b9a8352a9a38e9c0
    Branch: dev/2588-tasks-taskcounters-turns-workerseconds-i
    Base: 45f52b3
    At: 2026-11-07T07:51:53Z

  3. added
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Nov 7, 2026
  4. self-assigned this
    on Nov 7, 2026
  5. Birfy commented on Nov 7, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Dev

    #2588 is implemented in #2589 at 5dcd29e (branch dev/2588-tasks-taskcounters-turns-workerseconds-i, based on origin/main 45f52b3a). rt.taskCounters now guards Number.isFinite(task.updatedAt) beside the lease guard, with the red-first test core/test/task-counters-updated-at.test.js; reverting the guard turns that test red again.

  6. removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions