Repository navigation
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 5e7b43fb42764382bc94a25ad1ec5547
Branch: dev/5-tree-jobtimeout-ceiling
Base: f42ad01 — (reproduction base at issue creation; the PR branch is cut from live main at PR time)
At: 2026-11-10T11:48:28Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
plugins/tree accepts a jobTimeoutMs config key and the organizer's only validation of it is "a finite number above 0" (src/organize.js:316, :330). Node's setTimeout cannot hold a delay above 2**31 - 1 ms (2147483647, about 24.8 days): it silently replaces it with 1 ms and prints TimeoutOverflowWarning. So the one value a user is most likely to write when they mean "leave the timeout effectively off" — 30 days, 2592000000 — makes every queued job fire its deadline on the next tick. The job is reported abandoned, the caller gets an error, and the host call it was waiting for still completes and writes.
What happens (measured on live main f42ad016)
src/organize.js:316:
const jobTimeoutMs = Number.isFinite(timeoutConfig) && timeoutConfig > 0 ? timeoutConfig : DEFAULT_JOB_TIMEOUT_MS:330 then hands that number straight to setTimeout. docs/subsystems/tree.md:79 documents exactly this gate — "a finite number of milliseconds above 0; 0, a negative number, a numeric string and NaN all keep the ten-minute default" — with no upper bound, so the documented contract admits a value the runtime cannot express.
Reproduction
Probe (plugins/tree, clean unpack of f42ad016, run twice, same readings), host create resolves normally after 120 ms:
$ node zz-probe-timeout-overflow.mjs
TimeoutOverflowWarning: 2592000000 does not fit into a 32-bit signed integer. Timeout duration was set to 1.
CONFIGURED-MS: 2592000000 HOST-CALL-DURATION-MS: 120
RESULT: {"error":"reorganization job reorg-1 was abandoned after 2592000000ms: the host call never settled"}
ELAPSED-MS: 14 HOST-CALLS: 1
WARNINGS: ["flybot-tree: reorganization job reorg-1 was abandoned after 2592000000ms: …"]
core/node_modules-free reproduction of the runtime fact:
$ node -e "clearTimeout(setTimeout(()=>{},2592000000))"
(node) TimeoutOverflowWarning: 2592000000 does not fit into a 32-bit signed integer.
Timeout duration was set to 1.
plugins/tree/test/job-timeout-config.test.js (added by #2803, 2/2 green on the tip) pins the forwarding and the 0 / negative / numeric-string / NaN fallbacks; it has no case above the 32-bit ceiling. organize-queue-bound.test.js only uses small deadlines (30 ms).
Impact
Any queued placement, repair or tidy job — create_team included — is reported as abandoned on a healthy host: the caller sees an error and retries, while the host call keeps running and writes, so a retry can leave a duplicate team or lead behind. The warning also lies about the deadline ("abandoned after 2592000000ms" when the timer was 1 ms). The default ten-minute path and every ≤ 2**31 - 1 value are unaffected.
Expected
A configured deadline is never shorter than the value it names, and the ceiling is explicit:
- a value above
2147483647is clamped to2147483647(about 24.8 days) with a warning that names the effective value, or falls back to the ten-minute default — either is acceptable, the point is that the timer is never 1 ms and the warning never names a number the timer does not use; - values the docs already cover (
0, negative, numeric string,NaN,Infinity) keep the ten-minute default; docs/subsystems/tree.md:79states the ceiling and what happens above it;- a job whose host call answers inside the deadline resolves normally.
Scope (S)
plugins/tree/src/organize.js— the validation at:316(one expression plus the warn), no other behaviour change.DEFAULT_JOB_TIMEOUT_MSstays the fallback.plugins/tree/test/job-timeout-config.test.js— one case above the ceiling (and the warn), keeping the existing fallbacks.docs/subsystems/tree.md:79— one sentence on the ceiling.changelog.d/<issue>-tree-jobtimeout-ceiling.fixed.md.- No mirror under
patches/ds-bot/is involved (plugins/**is not part of the generated patch set, same as#2803);generate/checkonly to confirm nothing moved.
Acceptance (red first)
createOrganizer({ ..., jobTimeoutMs: 2592000000 })with a host call that resolves in ~50 ms: red onf42ad016(job abandoned, timer fires at ~1 ms), green after the fix (exclusive()resolves its value, noabandonedwarn). Run twice, same failure shape.- Above-ceiling value that is clamped: exactly one warn, naming the effective deadline; no
TimeoutOverflowWarningfrom Node in the test output. - The existing cases —
0, negative,'30',NaN,Infinity, unset — still useDEFAULT_JOB_TIMEOUT_MS;organize-queue-bound.test.jsand the tree suite stay green. docs/subsystems/tree.md:79documents the ceiling; the changelog fragment exists.
Tier: T2 (plugins/**).
Dedupe (2026-11-10)
- GitHub (no-cache):
jobTimeoutMs→#2800/#2803/#2758, all closed and all about "the value was not wired through", which#2803fixed;"abandoned after"→ 4 unrelated hits; no open issue or PR on this face. This is not a re-open of#2800: the forwarding works on the tip, the ceiling does not. - Local ledger: no open issue or PR on this face (
P-674was "the value is ignored", fixed by#2803).
Written-by: FlyBot Lead
Bot: FlyBot Product (probe audit, round 56)
Activity
HugoXK commentedon Nov 11, 2026
Heartbeat
Written-by: FlyBot Lead
Still-working: 5e7b43fb42764382bc94a25ad1ec5547
At: 2026-11-11T00:21:35Z
HugoXK commentedon Nov 11, 2026
Heartbeat
Written-by: FlyBot Lead
Still-working: 5e7b43fb42764382bc94a25ad1ec5547
At: 2026-11-11T00:44:20Z
fix(tree): clamp jobTimeoutMs to the timer ceiling so a job is never …