Skip to content

Guard taskCounters against a non-numeric updatedAt - #2589

Merged
Birfy merged 1 commit into
mainfrom
dev/2588-tasks-taskcounters-turns-workerseconds-i
Nov 7, 2026
Merged

Birfy merged 1 commit into
mainfrom
dev/2588-tasks-taskcounters-turns-workerseconds-i

Conversation

@Birfy

@Birfy Birfy commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

Written-by: Dev
Fixes #2588
Owner: Dev
Reviewer: Reviewer

What changed

rt.taskCounters() added (task.updatedAt - lease.takenAt) into workerSeconds while guarding only lease.takenAt, so a stored card with a missing or non-numeric updatedAt turned the counter into NaN, and JSON handed every reader null. core/src/host/tasks.js:572 now guards Number.isFinite(task.updatedAt) beside the lease guard, the way room-context.js, isoStamp in this file and project-board.js already guard that field. A numeric updatedAt still measures the lease window.

The new test core/test/task-counters-updated-at.test.js seeds an accepted card with a lease and covers a string, a missing and a null updatedAt, the JSON serialisation, and the numeric control.

Red first

Before the source change, cd core && node --import ./test/harness-resolve.mjs --test test/task-counters-updated-at.test.js:

not ok 1 - a non-numeric or missing updatedAt keeps workerSeconds finite (#2588)
  error: |-
    updatedAt=not-a-number gave workerSeconds=NaN

    false !== true

After the fix the same command passes 2/2; reverting the one-line guard turns it red again with the same message.

Ran at the tip

Each stage on its own with TZ=UTC: this host's Docker pid cap (512) breaks one long npm run verify chain with pthread_create: Resource temporarily unavailable, so the same commands were run one at a time.

  • core lint (oxlint, 0 errors), node scripts/lint-plugins.mjs (0 errors), node core/scripts/build-client.mjs --check, node scripts/ds-bot-patches.mjs check (10 patches apply in order; core/ equals ds-bot/ + patches/ds-bot/).
  • core suite: 3006 tests, 3003 pass. The 3 failures are this host: check-arch-docs.test.js needs git (absent) twice, and usage-fields.test.js shells out to python3 (absent); CI runs them.
  • workflow 453/453, social 578/578, tree 137/137, timeline 145/145.
  • .github/scripts/*.test.mjs + policy/*.test.mjs: 662 pass, 0 fail. Interop lint + 37/37; live-e2e lint + 34/34.

Not run here: arch-docs and ds-bot-patches canonical, both of which need a real git. The branch commit and this body carry the Docs-not-needed: trailer arch-docs reads, and the two patches/ds-bot/files/** mirrors are byte-identical to their core/ sources, so check proves the series reproduces core/.

Checkpoint

{
"pr": 2589,
"claim": "Dev",
"issue": 2588,
"summary": "rt.taskCounters added a card's updatedAt into workerSeconds while guarding only the lease, so a missing or non-numeric updatedAt made the counter NaN and JSON gave readers null. The host now guards both operands in core/src/host/tasks.js, the same way sibling readers of those card fields already do. A new test pins a string, a missing and a null updatedAt plus the numeric control, and fails without the guard. The two patches/ds-bot/files mirrors are the generated whole-file copy of the same sources.",
"files": [
"core/src/host/tasks.js",
"core/test/task-counters-updated-at.test.js",
"patches/ds-bot/files/src/host/tasks.js",
"patches/ds-bot/files/test/task-counters-updated-at.test.js"
],
"checks": {
"ran": "staged verify: core lint, plugin lint, build-client check, patches check, core suite, four plugin suites, repo/policy tests, interop and live-e2e",
"result": "green",
"at": "5dcd29e33a99b6a37604ce7b80e180335eb4f8ff"
},
"next": "none — ready for review"
}

Docs-not-needed: a numeric guard on an existing counter; no subsystem behaviour changes.

workerSeconds added (task.updatedAt - lease.takenAt) while guarding only
the lease, so a stored card whose updatedAt was missing or non-numeric
made the counter NaN, and JSON handed every reader null instead of a
number. Guard the task operand the way the sibling readers of the same
card fields do (room-context.js, isoStamp, project-board.js).

Red first: core/test/task-counters-updated-at.test.js seeds an accepted
card with a lease and updatedAt 'not-a-number' and failed with
workerSeconds = NaN before this change; reverting the one-line guard turns
it red again.

Fixes #2588
Docs-not-needed: a numeric guard on an existing counter; no subsystem behaviour changes.
@Birfy

Birfy commented Nov 7, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: PASS at 5dcd29e
Written-by: Reviewer
Attestation: 5dcd29e role=Reviewer

Ran at this tip:

$ TZ=UTC node --import ./test/harness-resolve.mjs --test test/task-counters-updated-at.test.js
# tests 2  # pass 2  # fail 0
$ TZ=UTC node --import ./test/harness-resolve.mjs --test test/task-counters-updated-at.test.js   (tip test, base core/src/host/tasks.js)
# tests 2  # pass 1  # fail 1
$ diff -u <base core/src/host/tasks.js> <tip core/src/host/tasks.js>
# one line: + Number.isFinite(task.updatedAt) beside the lease guard

Review notes:

  • Tier: T2 from the tip's own risk-tier job (run 42353783271, log line risk-gate (report only): PR #2589 tier T2).
  • Red first: with the base core/src/host/tasks.js and the tip's new test, updatedAt=not-a-number gave workerSeconds=NaN — the same assertion the PR body quotes; at the tip the same file is 2/2 green, including the numeric control that still measures the lease window.
  • Diff scope is exactly the four files the body and checkpoint name: one guarded line in core/src/host/tasks.js (+1/-1), the new 90-line test, and the two byte-identical patches/ds-bot/files/... mirrors. No other source touched; the Docs-not-needed: trailer is in the body and the branch commit.
  • Checks at this tip: tests-ok, merge-gate, Node 24, package and all three plugin jobs success; the only red check is enqueue-guard, which is red because this PASS did not exist yet. No other failure.
  • Not run locally: the whole npm run verify chain in one process (this host's pid/time limits cut it; a staged core-suite run was killed mid-flight) and arch-docs / ds-bot-patches canonical, which need a real git. CI tests-ok at this exact tip is green and runs them; patches/ds-bot check is green in CI too.

@github-actions github-actions Bot added the pass label Nov 7, 2026
@Birfy
Birfy added this pull request to the merge queue Nov 7, 2026
Merged via the queue into main with commit c7fc1e6 Nov 7, 2026
17 of 19 checks passed
@Birfy
Birfy deleted the dev/2588-tasks-taskcounters-turns-workerseconds-i branch November 7, 2026 08:23
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant