Skip to content

tree: a retired Bot still occupies its tree slot and strands its children #2430

Closed

Description

@HugoXK

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: 4fcfc3fe278048408737243bbff3eb21
Branch: dev/5-retired-bot-tree
Base: 16d1645
At: 2026-11-04T17:36:51Z

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Dev-5

Reproduction (clean base 16d16456, plugins/tree unit test)

archive_bot retires a Bot by writing fields['flybot-tree'].retired = true (core/src/host/roster.js:585) and hiding it, and core/src/host/prompt.js:46 promises the retired Bot "leaves the tree (the slot is free again)". The tree model never reads that field, so neither half happens:

  • plugins/tree/src/tree.js:27 snapshot() collects every Bot with parent/treeRole, retired or not. The retired Bot therefore stays a tree node: its parent still lists it in list_children, its name stays in the trace of its children's prompts, and it still counts against maxChildren in src/limits.js:21.
  • isMember() (src/tree.js:271) agrees, so create_child_bot under a retired parent still passes the membership guard.
  • TREE_KEYS (src/tree.js:18) has no retired, so onFieldChange ignores the write and the retired Bot's children keep parent = <retired id>. They become a dangling subtree: the root's list_children does not show them, a child's message to the retired parent is refused with the target Bot was retired (core/src/host/hooks.js:404), and their prompt still reads Chief → Retired → Child.

Probe (two tests, node --import ./test/resolve.mjs --test test/probe-retired.test.js, base 16d16456):

not ok 1 - PROBE: a retired Bot leaves the tree and its children re-attach
  actual: { id: 'bot2', name: 'Work', role: 'Work stuff', parent: 'bot1', root: false }
  operator: strictEqual          # snapshot()[retiredWork] should be undefined
not ok 2 - PROBE: retiring a child frees a maxChildren slot
  error: 'the freed slot was not reusable'
# tests 2 / pass 0 / fail 2

The first assertion (snapshot() still holds the retired Bot) is the root of the other two; isMember(), the child re-parent and the freed slot are asserted after it.

Expected

  • A Bot with retired === true is not a tree member: absent from snapshot(), isMember(), list_children, prompts and the maxChildren count.
  • Retiring a Bot hands its children to its own parent (or to the current root when it was a child of the root), the same way onBotRemoved already does for deletion, and every moved Bot gets a fresh prompt.
  • forestOf/adoptUnattached already skip retired records (src/tree.js:153, src/forest.js:16); this makes snapshot()/isMember() consistent with them.

Scope

plugins/tree/src/tree.js, plugins/tree/test/tree.test.js, docs/subsystems/tree.md, one changelog.d/ fragment. No core change.

Duplicate check

Open issues on 16d16456 searched for retired / archived in title: only #2336 (automation leases), unrelated. The retired-Bot tree work in main (d4f1b24e, #1796) touched only treeOf/archivedOf/statusOf; snapshot/isMember/onFieldChange were not changed.

Activity

  1. added a commit that references this issue on Nov 4, 2026
    c3da0e6
  2. added a commit that references this issue on Nov 4, 2026
    43b2cb1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions