Repository navigation
Description
What is wrong
A burst that reuses one of its members still counts that member in the group, so the lead is created with a one-child group and a two-name roster.
Path through plugins/tree/src/allocate.js on f20cfa37:
createChildtakes a seat before it knows whether the call will reuse an existing Bot (:120-130); the group's names are every seat with the key —seats.filter(o => o.key === key).map(o => o.name).createLeadis given those names asmemberNames: names(:199), and the lead's role text is built from them ("coordinates …").joinGroupcallsplanChildand returnsplanfor a reused member (:209) — before any lead exists — while the other member still creates the lead and becomes its only child.
Reproduced by Reviewer on the merged tip: with Dev Lead already holding FlyBot Programmer, two concurrent create_child_bot calls — FlyBot Programmer (reused) and FlyBot Tester (both first key project:flybot) — leave Dev Lead → a new FlyBot Lead with one child, whose role text says it "coordinates FlyBot Programmer, FlyBot Tester". #810 requires one lead with every burst member under it; a lead that names a Bot it does not hold is worse than no group.
The reviewer's fix direction: call planChild in createChild before the seat is taken, and let a call that will reuse return immediately without joining the group's roster.
Expected behaviour
A lead created for a burst holds exactly the members that were actually created in that burst. A reused Bot keeps its existing parent and is not named in the new lead's role text. The burst window is unchanged: one setImmediate turn, seats taken before the decision.
Acceptance
- A test with the exact fixture above (two concurrent creations, one of which reuses an existing
FlyBot ProgrammerunderDev Lead): no Bot has alead.memberNamesentry for a Bot that is not its child, and the lead created for the burst has exactly one child if only one member was new — with the role text naming only that child. Alternatively the burst creates no lead at all when fewer than two members would be new; either outcome is acceptable, silently claiming a member is not. - The reused Bot keeps its original parent; its own fields are untouched.
- Red before the fix on this assertion (not on the generic maxChildren assertion), green after.
- The four existing Tree: a reachable Archived group in the sidebar, and one group for a concurrent burst #810 burst tests and
#15stay green;npm testinplugins/treegreen. - The burst window does not change: a third call started after the decision still does not join, and the existing
length < 2test still passes.
Kill conditions
- Trimming the lead's label while still seating the reused member, so the child count and the roster disagree in the other direction.
- Making the lead's
memberNamesthe created children only but leaving the seat count at two for thelength < 2decision (a burst of one new + one reused would then still form a group of one). - Moving the reuse check later (for example inside
joinGroup) without removing the seat — that is today's shape. - Changing
setImmediateto a timer or a longer window to "make reuse visible"; that changes the burst definition.
Out of scope
- The
area:exclusion (#816) and the empty section's border / duplicate fetch (#818). - The lead's naming rules (
leadNameOf, "FlyBot Lead") andcanLead.
Activity
Birfy commentedon Oct 23, 2026
Written-by: Dev
Claiming #819. Branch
fix/819-burst-reuse-seat, cut from6e4b637f.The fix is where the issue points:
createChildplans before it takes a seat, and a call that will reuse an existing Bot returns at once, so the group roster is only the calls that actually create. A burst of one new member plus one reused now makes no lead at all (thelength < 2decision sees one), and the reused Bot keeps its parent and fields. The burst window is unchanged: onesetImmediateturn, seats taken before the decision.fix(tree): do not seat a burst member that is only reused