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: e8e7aee4b6e34f35b419e1b103f92908
Branch: dev/5-bot-schedules-next-run
Base: f2ef4df
At: 2026-11-10T01:13:24Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead
Bot: FlyBot Product
bot_schedules prints next <a time that has already passed> for any row whose status is not active, so a one-shot task that already ran keeps advertising the moment it was due; the settings page on the same data says Finished.
Where
core/src/host/schedules.js at f2ef4dfaccedd40315bd585474d0902118dc0ba8:
add(entry, status, when)(:633-640) printswhen === undefined ? 'no next run' :next ${when}``.- The catalog loop (
:641) passesentry.scheduledAtfor every entry and never looks at the status:for (const entry of await service.catalog()) add(entry, entry.status ?? 'active', entry.scheduledAt). DSH keeps the originally due time on a finished one-shot task, so that line readsnext 2026-10-29T07:20:46.458Z, inactive. - The paused loop (
:642) already passesundefinedand correctly printsno next run.
Why this is a defect and not a wording preference: the same product surface answers the same question two ways. The settings page formats the row in core/src/client/schedules.js:103-107 (nextText() — status !== 'active' → Finished, only active → Next: {time}). And bot_schedules is the Bot-level read the repository's own AGENTS.md rule points Bots at to judge their own timers; #628 was exactly a case of this read face answering with the wrong conclusion.
Reproduction
A live call on a Bot that owns both a finished one-shot task and an active one returns, verbatim:
- "…" (…) — next 2026-10-29T07:20:46.458Z, inactive, …
- "…" (…) — next 2026-11-03T05:57:48.368Z, inactive, …
- "…" (…) — next 2026-11-10T02:04:37.595Z, active, …
The first two times are in the past; the third is the only real next run.
Expected
A row that is not active has no next run, whatever DSH stores in scheduledAt:
- Non-active rows print
no next run— the same sentence the paused rows already print — and keep their status word as today (inactive,paused, …). activerows are byte-identical to today, including theirnext <time>.- Nothing else in the answer changes: the header, the
none — …answers, theplace/sessionsuffix, the sort order.
Red-first cases:
- A finished one-shot row (status
inactive, a pastscheduledAt) in the same answer as anactiverow: the answer containsno next runfor the former and nonext 2026-10-29…anywhere; the active row still carries its futurenext <time>. - A
pausedrow still printsno next run(unchanged). - An
activerow's line is byte-identical to the base answer for the same catalog entry.
Keep the change inside add() / the catalog loop: one condition on the status, no new field, no wording change beyond no next run, and no change to the sort (the ordering of dead rows is a separate, cosmetic report).
Dedupe
Checked live main f2ef4dfaccedd40315bd585474d0902118dc0ba8 and the open/closed issue list: #2026 (closed) fixed the settings-page half and did not follow into the tool; #628 (closed) was the scope problem of this tool (one Session vs the whole Bot); P-383 in the Product ledger adds a last-run field (a different change); github bot_schedules next run inactive returns only #628. Nothing open covers this line.
Risk tier: T2 (Bot-level read face; no stored value changes).
Activity
bot_schedules: an inactive task has no next run (ThinkFlowLab#2769)