From c7221ff6abd34eff1cfda55ec377892908e8c112 Mon Sep 17 00:00:00 2001 From: Danyang Chen Date: Fri, 23 Oct 2026 16:24:13 +0800 Subject: [PATCH] fix(tree): read the roster once per tick, and pin the order and the area rule The tree plugin's structure entry and its archived-Bots list both needed ctx.flybot.bots(), and each polled it on its own 10 s timer: a mounted sidebar asked the host for the same list twice per tick, and the archived list also fetched once on mount. One rosterFeed now owns the poll. The first subscriber starts it, a later subscriber joins it and gets the current list without a read of its own, a field change or bot.removed calls refresh() for an immediate read, a read that is still running sets `again` instead of stacking up behind the timer, and the last subscriber to leave clears it. apply() builds one feed for both consumers; registerStructure and makeArchivedSection still work when handed no feed. The archived list is registered at order 88 and the reorganization notice at 89, and a slot renders ascending, so the archived Bots sit above the notice. That was already true in the code and unstated in the README; it is stated now and pinned by a test, so a later edit cannot flip them silently. The burst path already refuses an `area:` key (`kindOf(first) !== 'area'`), so a batch of Bots the vocabulary cannot place is not forced under one "General Lead", but nothing pinned it: deleting the clause left the suite green. The new test creates two such Bots in flight at once and requires both at the caller and no lead, while the same fixture with a `project:` key still makes one group. Fixes ThinkFlowLab/FlyBot#816 --- changelog.d/816-one-roster-read.fixed.md | 1 + docs/subsystems/tree.md | 10 ++- plugins/tree/README.md | 2 +- plugins/tree/client.js | 76 +++++++++++----- plugins/tree/test/tree.test.js | 109 ++++++++++++++++++++++- 5 files changed, 172 insertions(+), 26 deletions(-) create mode 100644 changelog.d/816-one-roster-read.fixed.md diff --git a/changelog.d/816-one-roster-read.fixed.md b/changelog.d/816-one-roster-read.fixed.md new file mode 100644 index 000000000..3a5159124 --- /dev/null +++ b/changelog.d/816-one-roster-read.fixed.md @@ -0,0 +1 @@ +The tree no longer asks the host for the Bot list twice per refresh: the sidebar's structure entry and the archived-Bots list share one feed, so a mounted sidebar reads the roster once every 10 s instead of once per consumer, and the poll stops when the last of them goes away ([#816](https://github.com/ThinkFlowLab/FlyBot/issues/816)). The README now says the archived list is registered at `order: 88` and the reorganization notice at `order: 89`, and a slot renders ascending — so the archived Bots sit above the notice instead of being pushed down by it. diff --git a/docs/subsystems/tree.md b/docs/subsystems/tree.md index 906a4b0c8..2f92ad429 100644 --- a/docs/subsystems/tree.md +++ b/docs/subsystems/tree.md @@ -76,7 +76,7 @@ The tree organizes itself by role instead of leaving Bots outside it or a parent - **Leads.** A suitable existing lead is a member already marked as that group's lead, already coordinating that group (it has children and the key, project and domain only), or named for it ("Life", "FlyBot Lead") or as a lead ("Kitchen Manager", 负责人). It gets `lead { key, label }`. Only when none fits a new lead is created with a clear role (`