Repository navigation
Description
Where this comes from
Split out of #450 by the owner's call. #450 keeps items 1, 3, 5 and 7, each of which needs a core API for plugins or the owner raising a limit. These two are ordinary tree behaviour with no product decision left open: they were already decided when #450 was written.
A. An archived Bot becomes unreachable
plugins/tree/client.js:339 adds every archived Bot — fields['flybot-tree'].archived, or a leftover 归档-* / Archive-* name (ARCHIVE_NAME_RE at :279) — to the hidden set, and core/src/client/sidebar.js:366 drops hidden ids from the Bot list entirely. Keeping them out of the tree is #452's decision and stays; but the only way back to an archived Bot's chat is its right-click menu, and a Bot archived by a merge is invisible unless its name is remembered.
Expected behaviour — keep the list exactly as it is, and add one section of the tree's own through the slot that already exists (core/src/client/flybot-slots.js, used at client.js:466):
- A
flybot.sidebar.sectionentry with idflybot-tree-archived, rendered below the Bot list: collapsed by default, headerArchived (N), N = the number of archived Bots. - Renders nothing at all when N is 0 — no header, no border, no empty group.
- Expanded, one row per archived Bot, carrying the same tag
statusOf()already produces (:442):archived, orarchived · merged into <name>for a merge. - A row opens that Bot's chat through the same action every other row uses. No new endpoint, no new call.
- Expanded/collapsed is local state and survives the 10 s roster refresh (
REFRESH_MS): the section re-renders, it does not reset. - Archived Bots stay out of the default list and out of the tree:
include()keeps returning false for them, so ds-bot'sbotTree()never sees them.
Done when plugins/tree/test/web-entry.test.js (or a new client test beside it) covers: zero archived → nothing rendered; one archived → header Archived (1), collapsed, and the row present after a click; one merged archived → archived · merged into X; a 归档- named Bot with no field counted the same way; and the default list excluding all of them in the same fixture.
B. A concurrent burst is placed one Bot at a time
planChild() (allocate.js:92) plans each create_child_bot against a fresh snapshot, so two related Bots created at the same moment independently pick a home from homesFor(...). Both can land in a broader existing group — the #450 example is a Dev Lead that already has a Programmer — and only the daily tidy regroups them. create_team already owns the allocation this needs: planTeam (:158) under a per-parent lock (:173), one lead per key through createLead (:244).
Expected behaviour, and this is the whole definition:
- A burst is two or more
create_child_botcalls from the same caller in flight at the same time — the second started before the first returned. No timer and no settle window: a call that starts after the previous one returned keeps today's path untouched. - Members of a burst whose profiles share the first domain key (
keysOf(profileFor(name, role))[0]— the keycreate_teamalready uses at:158) are placed as one group: one lead for that key, reused whenleadIn()finds one, created once otherwise, with every burst member under it. The second member must not resolve to a broader pre-existing group. - A burst whose members fall into different domain keys is not forced together: each call keeps today's placement.
- Grouping is deterministic.
classify-modelis not consulted and no model call is added. - Limits are unchanged: every create is still gated by
checkCreate/limits; a member that cannot fit is refused with the existing message, never silently dropped, and one member failing does not undo the others. - Observable in the results: every placed member of the burst names the same lead path.
Done when plugins/tree/test/tree.test.js covers, against a fake fb that holds both createUnder promises until both calls have started: two concurrent creates in one domain produce exactly one lead and two children, both results naming that lead, and at most one createLead action for the batch. Negative control in the same file: with the burst path disabled the same fixture places them under two different parents, so the case fails for the right reason. Plus a serial fixture (the second call awaited after the first returns) whose tree is identical to today's.
Verification
node --test plugins/tree/test/*.test.js: the new cases pass; the negative controls fail without the change.plugins/tree/client.jsis hand-written and loaded as a classic script, sobuild-client --checkhas nothing new to compare;ds-bot-patches checkstill reports three ok lines.node scripts/testing-layers.mjs --checkstill classifies every file; achangelog.d/fragment is added.
Kill conditions
- Delaying a tool result to wait for more creates (a timer or a settle window). The burst is defined by overlap in flight, never by clock time.
- A and B may land in one pull request, but neither may hide the other's evidence, and B must not change the sidebar.
- Reversing Tree reorg must MOVE/reparent bots; never rename to 归档- and recreate #452: archived Bots must not come back into the Bot list or into
botTree(). - A new endpoint, a new stored field, or a model call used to decide grouping.
- Editing
plugins/tree/cordis.patch.ymlpermissions orlimits.jsonso a fixture fits.
Out of scope
#450 items 1, 3, 5 and 7 (memory handoff on merge, a notice in the Main Bot's chat, richer activity, the maxChildren limit); create_team's behaviour; the daily tidy's own regrouping in organize.js; how a Bot is archived or unarchived.
Activity
Birfy commentedon Oct 23, 2026
Written-by: Dev
Claiming. Branch
feat/810-archived-section-and-burstinBirfy/FlyBot, cut from main6f9b60c7.Plan: A and B in one pull request, each with its own fixtures and evidence. A renders an archived section through the existing
flybot.sidebar.sectionslot and leavesinclude()returning false, so #452 is untouched. B groups a concurrent burst through the allocationcreate_teamalready uses, keyed bykeysOf(profileFor(name, role))[0], with no timer and no settle window.feat(tree): list archived bots in the sidebar and group a concurrent …