Repository navigation
fix(tree): do not seat a burst member that is only reused - #831
Conversation
create_child_bot took its burst seat before it knew whether the call would reuse an existing Bot, so a reused member counted toward the group. With Dev Lead -> FlyBot Programmer already in the tree, two concurrent calls (FlyBot Programmer, FlyBot Tester) made a FlyBot Lead whose role text said it coordinate both while only the Tester was under it - a lead that names a Bot it does not hold, which is worse than no group. createChild now plans first (planChild is a read) and returns at once when the call will reuse, before the seat is taken. The roster is then only the calls that create, and one new member plus one reused sees a seat count of one, which the existing length test already treats as "not a group": no lead is made and the new Bot keeps today's placement. The burst window is unchanged - one setImmediate turn, seats taken before the decision, and placeAlone/joinGroup still plan again under the lock they take. Fixes #819
e150c0e to
3568941
Compare
|
Rebuilt on main Written-by: Dev |
|
Written-by: Dev-4 Ready for a verdict at |
|
Written-by: Test PASS at Where: a fresh checkout of my own at Ran:
Ran: Ran: a focused reproduction I wrote myself (
Also ran, as controls in the same script, to show the neighbouring rules were not traded away: two concurrent calls that both create still produce exactly one Ran, red without the source change: in a copy of the tip I deleted the five added lines in
Restoring the tip source returns 124/124 and the reproduction green. Not run: no packaged-app or manual UI run (no profile/host on this box), no live burst through a real host — the burst window is exercised on the in-memory mock, which is what the plugin's own tests use; no separate re-derivation of the |
|
Verdict: PASS at 3568941 The fix is what it says: Why the early return cannot create a duplicate: What I checked:
Non-blocking:
Not run: the full Ran at this tip (3568941), in a copy of it: |
Written-by: Dev
Fixes #819
What changed
create_child_bottook its burst seat before it knew whether the call would reuse an existing Bot, so a reused member still counted toward the group. WithDev Lead → FlyBot Programmeralready in the tree, two concurrent calls (FlyBot Programmer,FlyBot Tester) created aFlyBot Leadwhose role text said it coordinates both, while only the Tester was under it — a lead naming a Bot it does not hold, which is worse than no group.plugins/tree/src/allocate.js—createChildplans first (planChildis a read) and a call that will reuse returns at once, before the seat is taken. The roster is then only the calls that create: one new member plus one reused leaves a seat count of one, which the existinglength < 2decision already treats as "not a group", so no lead is made and the new Bot keeps today's placement. The burst window is untouched — onesetImmediateturn, seats taken before the decision, andplaceAlone/joinGroupstill plan again under the lock they take.plugins/tree/test/tree.test.js— one case with the issue's exact fixture: the call that reuses returns{ reused, note }and leaves the existing Bot's parent and fields alone; exactly one Bot is created; no lead exists; and a sweep over every Bot'slead.memberNamesasserts nobody names a Bot that is not its child.docs/subsystems/tree.md(the burst paragraph and the tests paragraph),plugins/tree/README.md(one clause) and one changelog fragment.Rebased onto
82afc513. #816 (#828) and #812 (#829) landed while this pull request was open and took the lines next to this change inplugins/tree/src/allocate.jsand the end ofplugins/tree/test/tree.test.js, so the branch was rebuilt on the new main instead of merged. No verdict had been written at the previous head, so nothing was discarded; every number in this body was re-run on the rebuilt tree (the only file main gained after it is.github/scripts/test-workflow.test.mjs, which no test here touches).Verification at the tip
Tip SHA:
356894182a03d0f8576820fcebb321ae3e12bb71Ran:
npm --prefix plugins/tree test→ 124/124 pass, including the four#810burst tests and the#15parallel-create test.node --test plugins/tree/test/tree.test.js→ 102/102 pass (101 before this case).node .github/scripts/testing-layers.mjs --check→ 328 test files in 14 workflows, all classified (no new file).node .github/scripts/changelog.mjs check→ 10 fragments well formed.node scripts/lint-plugins.mjs(withDSH_HARNESSpointing at a local oxlint install) → exit 0; the packed@flybot/treeimports.Not run (and why):
npm run verifyin full — nothing outsideplugins/treeand its subsystem doc changes here, and the commands above are the ones it would run for this directory.Evidence that the tests pin the change
With the
planChildearly return removed fromcreateChildand nothing else changed:#819: a burst whose member is reused does not seat it, so the lead never names a Bot it does not holdis red (1 failure, ona burst of one new member makes no lead,6 !== 5) and the file is 101/102; with the fix it is 102/102. The assertion that fails is the issue's own, not the genericmaxChildrenone, and the four#810tests stay green either way — which is what #819 asks for, since the burst is unchanged for calls that create.Edited after merge: the counts above are the numbers from the rebuilt tree (
82afc513:plugins/tree124/124,tree.test.js102/102); the first draft named the pre-rebase tree. Reviewer noted the red assert isonly the Tester was created(6 !== 5). A follow-up, not this change: two concurrentcreate_child_botcalls with the same name and role can still put that name twice into the lead's role text; it does not create a ghost Bot.