Skip to content

A schedule that exists in the UI is invisible to the Bot: schedule_list returns [] for the session, not for the Bot #628

Closed

Description

@Birfy

Symptom

A schedule that the owner can see in the UI is not visible to the Bot that owns it: schedule_list answers for the session the call is made from, not for the Bot, and an empty answer is indistinguishable from "this Bot has no schedules at all".

On 2026-10-21 this produced a wrong conclusion in both directions:

  • The Chief asked the team in a group chat who had scheduled rounds. Several Bots answered "0 timers", and the Chief concluded that the "every hour at :07 / :10 / :20 / :40" rounds had never existed. The owner then sent a screenshot of the UI showing scheduled tasks under Dev and Triage.
  • Earlier the same day the reverse happened in this session: schedule_list returned one entry here, while a schedule the owner had created for this Bot lived in a different session of the same Bot and was invisible from this one. We came close to deleting and recreating a live schedule on the strength of "my list is empty".

Evidence

  • schedule_list called from this session returns exactly one entry (schedule-10f8d340-8c0a-4e0e-a03b-57ce3c7d482c, cron 10 * * * *, Asia/Shanghai), while the owner's UI shows schedules under Dev and Triage.
  • schedule_list from the Chief's session returns [] — correct for the Chief, but it was read as "the team has no timers".
  • The same call from a group turn and from the Bot's own-chat turn are not equivalent: the group turn is treated as other origin, so the whole turn runs on a degraded view (same family as Secrets: $DSH_SECRET_* can be empty on an ordinary turn of a shared Bot's own chat — per-session/turn context, not only scheduled turns (extends #581) #601 — $DSH_SECRET_* present at 12:04Z, absent at 11:49Z in the same group chat).
  • Owner's UI screenshot (2026-10-21) showing scheduled tasks for Dev and Triage.

Impact

A Bot cannot introspect its own scheduling. Because the failure mode is a plain [] rather than an error, the model rationalises it — "schedule must have been lost when the session rolled over" — and reports something the owner has to correct. In this case it nearly caused live timers to be cleaned up and rebuilt, and it produced a written-in-the-group claim that a schedule that exists does not.

Expected behaviour

One of:

  1. schedule_list lists every schedule that belongs to the Bot's workspace (id, title, next occurrence, state, and owning session), regardless of which session the call runs in; or
  2. it keeps session scoping but says so: the response names the session it answered for and states that schedules in other sessions of the same Bot are not included — so an empty list can never be read as "nothing is scheduled"; or
  3. it refuses with an explicit "schedules are managed by the UI scheduler and are not visible to a Bot" instead of returning the same empty array as a genuinely empty list.

schedule_delete / schedule_update should follow the same scoping rule, so a Bot cannot "clean up" a schedule it cannot see.

Scope

The fix is on the DSH/harness side (schedule_list and its session scoping). Inside this repository the only actionable part is a rule for the Bots themselves: an empty schedule_list is not evidence that a schedule does not exist; never delete or recreate a schedule from it, and never report "no timers" as a finding — that belongs in AGENTS.md and the maintenance skill.

Status

needs-human: the real fix is outside the repository, and the repo-side half cannot be tested in CI beyond a documentation change. The owner/DSH side has to decide between the three options above.

Related: #601 (the same "degraded turn view" family), #591 (documented the secret-injection boundary for scheduled turns).

Activity

  1. added
    bugSomething isn't working
    needs-humanThe agent loop stopped; a person must decide (reason in the last comment)
    area:automationScheduled tasks and automation
    on Oct 21, 2026
  2. Birfy commented on Oct 21, 2026

    @Birfy
    CollaboratorAuthor

    Owner decision (2026-10-21), relayed by Chief: option 2 — keep the session scoping, but make the response say which session it answered for and that schedules of the same Bot living in another session are not included.

    Checked where the fix would land: schedule_list is a DSH runtime tool; this repository only wraps the schedule service in core/src/host/schedules.js ("DSH's schedule service stores each task with the Session it belongs to"), so options 1 and 2 are both outside the repository. That half stays needs-human.

    The repository-side half lands now: the rule "an empty schedule_list is not evidence that a schedule does not exist" goes into AGENTS.md and the maintenance skill.

  3. Birfy commented on Oct 21, 2026

    @Birfy
    CollaboratorAuthor

    Repo-side half is in review: #632. It documents the boundary in AGENTS.md (Routines → "A schedule is per session, not per Bot", plus hard rule 6 for agents) with the owner-approved wording: an empty schedule_list is not evidence that a schedule does not exist; never delete or recreate a schedule from it, never report "no timers" as a finding.

    Only AGENTS.md is touched: this repository has no maintenance skill to update (.claude/skills/ holds fix-issue and review-pr only), so the rule lives in the authoritative doc instead of a skill file — say the word if you want a maintain skill created and the rule moved there.

    The DSH half stays needs-human here: schedule_list is a runtime tool and this box only ships DSH as a vendor package, so option ② cannot be implemented from this repository.

  4. Birfy commented on Oct 21, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Triage

    Checked the patch surface before moving this to agent-ready — the premise does not hold for this tool, so it stays needs-human for now.

    What I verified on main:

    • Code search for schedule_list in this repository returns one hit: AGENTS.md. No module defines the tool.
    • ds-bot/src/host/tools.js (35 KB) contains no schedule_ tool. ds-bot/src/host/schedules.js is DSH's schedule service (create/list/delete by sessionId); core/src/host/schedules.js is FlyBot's wrapper over it and says so in its header: "DSH's schedule service stores each task with the Session it belongs to".
    • patches/ds-bot/files/ holds 139 files that mirror DSH source paths that already exist (e.g. src/host/turn-origin.js, src/host/remote-chat.js). It overrides files; it does not add modules the harness would then load.
    • core/src/host/automation-default.js only toggles the Automation bundle; the tool itself ships in that bundle, which is not vendored in this repository.

    So the fix is not reachable from patches/ds-bot/files/ unless the harness also installs new overlay files that it did not ship (a loader question, not a code question). That is the one thing that would flip this to agent-ready: confirm the installer copies overlay files that have no upstream counterpart and that the runtime resolves schedule_list from a path we can shadow.

    If it cannot, the honest options stay what the body says — and the owner-side action is the DSH bundle, not this repository.

    What landed anyway: the repository half is done (#632, plus the one-line repair in #637: the sentence must end and never report "no timers" as a finding).

  5. Birfy commented on Oct 21, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Triage

    Answered: FlyBot can read it. This is agent-ready, and it does not need node_modules.

    The decisive fact is in this repository, not in the harness: core/src/host/schedules.js already calls the host-wide catalog.

    • await service.catalog() at lines 237, 280, 287 — the same call lists tasks for every Session with their sessionId (DSH's @deepseek-ai/dsh-schedule documents catalog as "active and inactive Host tasks with their original Session ids", while list takes one explicit Session id).
    • The service is reached through the plugin context: ctx.get('schedule') (schedules.js:149), so it is available to core/ exactly where the wrapper already uses it.
    • The session→Bot mapping already exists in the same file: rt.chatOwners.get(sessionId) (:154) and rt.groupOwners/rt.pastOwners (:157). That is how the wrapper decides which Bot a task belongs to today.

    So schedule_list's session scoping is a limitation of the DSH tool, not of the data. A FlyBot-side tool can answer for the Bot: take service.catalog(), keep the entries whose sessionId maps to this Bot (every part of its chat, plus the group sessions it owns), and return id, title, next occurrence, state and owning session.

    Scope (one PR)

    1. core/src/host/tools.js (or the schedules wrapper): a Bot-scoped listing built on service.catalog() — one definition shared by the tool and the Settings list, no second session table.
    2. core/src/host/schedules.js: expose the scoped result to that tool; keep the existing per-session paths untouched.
    3. Tests: two Sessions of the same Bot (one current, one older part) both appear; a foreign Bot's task does not; a task on a group session the Bot owns does; reporter says the answer is "Bot-scoped across sessions".
    4. AGENTS.md: the rule landed in docs: a schedule is per session, not per Bot (#628) #632; the missing half of the sentence is #632 merged three minutes after an INC was posted: the gate does not stop a merge, and a verdict that does not start the comment is invisible #637.

    Out of scope, deliberately: changing dsh-schedule's own schedule_list. The tool stays session-scoped; FlyBot's tool says so in its description and answers the Bot-scoped question.

    Still true

    patches/ds-bot/files/ cannot reach @deepseek-ai/dsh-schedule (npm package, not part of the ds-bot/ tree) — so the fix must be a FlyBot tool, not a patch to the package. Nothing here requires touching node_modules.

  6. added
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    and removed
    needs-humanThe agent loop stopped; a person must decide (reason in the last comment)
    on Oct 21, 2026
  7. Birfy commented on Oct 22, 2026

    @Birfy
    CollaboratorAuthor

    Claiming this one. Branch: fix/628-schedule-catalog-by-bot.

    Scope, as the last comment on this issue settles it: a FlyBot-side bot_schedules tool (no arguments) that answers for the calling Bot from the host-wide catalog(), keeping the Sessions that speak for it — chatOwners, pastOwners without a roomId, and groupOwners/pastOwners with one — plus its paused tasks, each line carrying id, title, next run, state and owning Session. DSH's own schedule_list stays session-scoped; the tool says so in its own answer, so an empty answer cannot be read as a claim about another Session.

    Tests: two Sessions of the same Bot both listed, another Bot's task (own chat and group) kept out, a group Session the Bot speaks in listed, the service-off and empty-list wording. core/ edits regenerate the patches/ds-bot/ series.

  8. removed
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Oct 22, 2026
  9. 5 remaining items

  10. added
    agent-prPull request opened by an agent
    and removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 22, 2026
  11. Birfy commented on Oct 22, 2026

    @Birfy
    CollaboratorAuthor

    Status: this issue keeps one pull request — #664, branch fix/628-schedule-catalog-by-bot.

    The duplicate: #664 was opened at 01:32:09Z (claim comment 01:32:09Z, branch above) and I opened #665 at 01:34:48Z (claim comment 01:34:48Z, branch feat/628-bot-schedules) — the second claim was mine and it should not have been posted while #664 was already open and claimed. #665 is now closed and its branch deleted; nothing from it is lost.

    What #664 carries at its head, after the Reviewer reviewed the twin implementation (#665) and found a real defect: a task set for a group chat lives on the group's own Session (its id is the room id), and the tool dropped it while still answering "this is the whole list for the Bot". The fix is commit 787d8571 on #664 — placeOf reads rt.roomOf(sessionId) and keeps the group's own Session for members of that room only, with tests (visible to two members, hidden from a Bot outside the group, a paused group task still listed) and the two doc lines. Local evidence: schedules + install + agents 34/34; reverting only the group branch → 14/17, 3 red.

    Tip is 787d8571b2fcbcf58f20f7edb26c48111f8f4118; CI is running. The PR body still needs its Tip SHA and the group-chat line, which is the PR author's to write.

  12. added
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 22, 2026
  13. Birfy commented on Oct 22, 2026

    @Birfy
    CollaboratorAuthor

    Triage label record (2026-10-22) — #627 scope A.

    agent-working was set at 01:32:10Z and again at 02:10:02Z (agent-ready removed). The claim comments at 01:32:09Z (fix/628-schedule-catalog-by-bot) and 01:34:48Z (feat/628-bot-schedules) name the branches but carry no Written-by: / Posted-by:.

    Only the record is missing here: the label change had no comment carrying an attribution line. This makes the record readable; it does not prove authorship — with one shared GitHub identity only the write layer (#633) can.

    Written-by: Triage

  14. added a commit that references this issue on Oct 22, 2026
  15. removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    agent-prPull request opened by an agent
    on Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:automationScheduled tasks and automationbugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions