fix(bots): a leg that cannot be walked spurns its ground #249

Merged
sickday merged 1 commit from fix/fisher-spot-spread into main 2026-08-19 12:34:18 +00:00
Owner

A 75-bot fishing fleet lost nine bodies to a loop: fill a pack, set off for
the bank, fail the leg, and the brain re-initialises the goal -- which walks
them back to the water they just left, where a full pack means there is
nothing to do but set off for the bank again. Nine to fourteen times each,
banking nothing in eighteen minutes. From the outside it is a bot running to
the spot, doing nothing, and turning round.

The brain's ladder cannot break that, and it is worth saying why rather than
turning the backoff up. Five failures put Bot.Brain.recover/2 through
init/1, which builds fresh goal state -- so whatever the goal had learned
about which ground it could not walk to died with it, and the next choice,
made by distance from the same tile, was the same ground. Every lap was a
first attempt.

So :stuck and a timeout on either leg now add the ground to a spurned set
and choose again, skipping what has already failed, instead of answering
{:failed, ...}. Both legs are the ground's -- the water is its position and
the booth is ground.bank -- so a bank that cannot be reached condemns the
ground rather than the bank. When everything has been spurned the set clears
and choosing starts over, so the memory cannot become its own trap, and a
genuinely empty table still answers {:failed, :no_grounds}. What the goal
handles is only which ground, which is the goal's own question; whether the
goal can make progress at all is still the brain's.

Bot.Goals.GatherAndBank carries the same two branches for the same reason.
Its site table is derivable without a running world, so the clear-and-start-over
case is tested there -- Bot.Sites.fish_grounds/2 answers nothing outside a
live world, which is why the fisher's own tests cover only the spurn.

Measured on the three grounds that had killed every bot on them. The Al Kharid
one is fixed: its three bots spurned three grounds, settled at Draynor and
banked 108 fish each, 78% of their samples working, against nothing at all
before. The two on the Falador coast are not: they now spurn thirteen or
fourteen grounds and roam instead of looping, still banking nothing, because
every ground within reach of them is beyond what the travel planner will
route -- twelve route capped at 128 steps warnings during the sitting, which
is Movement's @max_path, and the real fix for those is the long leg itself.

A 75-bot fishing fleet lost nine bodies to a loop: fill a pack, set off for the bank, fail the leg, and the brain re-initialises the goal -- which walks them back to the water they just left, where a full pack means there is nothing to do but set off for the bank again. Nine to fourteen times each, banking nothing in eighteen minutes. From the outside it is a bot running to the spot, doing nothing, and turning round. The brain's ladder cannot break that, and it is worth saying why rather than turning the backoff up. Five failures put `Bot.Brain.recover/2` through `init/1`, which builds fresh goal state -- so whatever the goal had learned about *which* ground it could not walk to died with it, and the next choice, made by distance from the same tile, was the same ground. Every lap was a first attempt. So `:stuck` and a timeout on either leg now add the ground to a `spurned` set and choose again, skipping what has already failed, instead of answering `{:failed, ...}`. Both legs are the ground's -- the water is its position and the booth is `ground.bank` -- so a bank that cannot be reached condemns the ground rather than the bank. When everything has been spurned the set clears and choosing starts over, so the memory cannot become its own trap, and a genuinely empty table still answers `{:failed, :no_grounds}`. What the goal handles is only *which* ground, which is the goal's own question; whether the goal can make progress at all is still the brain's. `Bot.Goals.GatherAndBank` carries the same two branches for the same reason. Its site table is derivable without a running world, so the clear-and-start-over case is tested there -- `Bot.Sites.fish_grounds/2` answers nothing outside a live world, which is why the fisher's own tests cover only the spurn. Measured on the three grounds that had killed every bot on them. The Al Kharid one is **fixed**: its three bots spurned three grounds, settled at Draynor and banked **108 fish each**, 78% of their samples working, against nothing at all before. The two on the Falador coast are **not**: they now spurn thirteen or fourteen grounds and roam instead of looping, still banking nothing, because every ground within reach of them is beyond what the travel planner will route -- twelve `route capped at 128 steps` warnings during the sitting, which is `Movement`'s `@max_path`, and the real fix for those is the long leg itself.
fix(bots): a leg that cannot be walked spurns its ground
Some checks failed
ci / gates (pull_request) Failing after 21s
ci / gates (push) Failing after 28s
build / image (push) Successful in 38s
c01f507408
A 75-bot fishing fleet lost nine bodies to a loop: fill a pack, set off for
the bank, fail the leg, and the brain re-initialises the goal -- which walks
them back to the water they just left, where a full pack means there is
nothing to do but set off for the bank again. Nine to fourteen times each,
banking nothing in eighteen minutes. From the outside it is a bot running to
the spot, doing nothing, and turning round.

The brain's ladder cannot break that, and it is worth saying why rather than
turning the backoff up. Five failures put `Bot.Brain.recover/2` through
`init/1`, which builds fresh goal state -- so whatever the goal had learned
about *which* ground it could not walk to died with it, and the next choice,
made by distance from the same tile, was the same ground. Every lap was a
first attempt.

So `:stuck` and a timeout on either leg now add the ground to a `spurned` set
and choose again, skipping what has already failed, instead of answering
`{:failed, ...}`. Both legs are the ground's -- the water is its position and
the booth is `ground.bank` -- so a bank that cannot be reached condemns the
ground rather than the bank. When everything has been spurned the set clears
and choosing starts over, so the memory cannot become its own trap, and a
genuinely empty table still answers `{:failed, :no_grounds}`. What the goal
handles is only *which* ground, which is the goal's own question; whether the
goal can make progress at all is still the brain's.

`Bot.Goals.GatherAndBank` carries the same two branches for the same reason.
Its site table is derivable without a running world, so the clear-and-start-over
case is tested there -- `Bot.Sites.fish_grounds/2` answers nothing outside a
live world, which is why the fisher's own tests cover only the spurn.

Measured on the three grounds that had killed every bot on them. The Al Kharid
one is **fixed**: its three bots spurned three grounds, settled at Draynor and
banked **108 fish each**, 78% of their samples working, against nothing at all
before. The two on the Falador coast are **not**: they now spurn thirteen or
fourteen grounds and roam instead of looping, still banking nothing, because
every ground within reach of them is beyond what the travel planner will
route -- twelve `route capped at 128 steps` warnings during the sitting, which
is `Movement`'s `@max_path`, and the real fix for those is the long leg itself.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Revenant/Server!249
No description provided.