fix(map): a container pushes out what does not belong in it - #584
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
Code diff size+101 / −12 across 1 file (net +89)
Source files under |
Two ways a container could tell a lie about membership. Nothing stopped a non-member from sitting inside a box. An org-level service whose ring slot happened to land over a cluster, another user's agent that swung wide, the org aggregate — any of them could come to rest inside a container, and a box is a claim about who belongs to whom. That claim got sharper in #582, when services started joining containers legitimately: "it is drawn inside the box" stopped being obviously false for a service. A stray is now pushed out by the nearest edge, caption included, since a label lying across the edge makes the same claim the ball would. The stray takes the push and the cluster takes a quarter of it back: all of it on the stray and a node held to its ring target would shove forever, all of it on the cluster and one loose ball could walk a whole fleet across the map. Container-vs-container separation existed but did not do what its comment said. It applied a flat force to every member, and the integrator divides force by mass — so a mass-1 agent accelerated ten times harder than the mass-10 user it orbits, and the cluster sheared instead of translating. It is mass-scaled now, which is what "push whole clusters" was always supposed to mean. Neither force could win against the cooling. `sp < 5 && am < 30` freezes a node outright, and at the alpha floor an overlap of a few tens of units does not clear that bar — the push was real, and then the node was frozen mid-overlap. The layout now stays awake while anything is still overlapping and settles as soon as nothing is, with a small epsilon so a residual sliver does not keep the whole map shimmering.
The stray loop measures `m` against a rect already inflated by `STRAY_GAP`, so a node resting exactly at its clearance — nothing overlapping, everything where it should be — still reported `m === STRAY_GAP`, which is over the epsilon that keeps the layout above the cooling floor. One such node and the map never cools: it re-warms itself every frame, forever, for a state that is already correct. Report the penetration rather than the exit distance, the same convention the box pair above uses when it reports `mag - BOX_GAP`. The force is unchanged and was never wrong: it is proportional to the displacement needed to clear the gap, which is exactly what the inflated rect measures. Found by Seer on #584, which read the same line and diagnosed the force.
angel-manuel
force-pushed
the
fix/live-map-containers-push-strays
branch
from
August 28, 2026 09:51
f22ee36 to
872f885
Compare
`pushCluster` mass-scales, so what it takes is an acceleration, and dividing that by the member count made a cluster progressively harder to shift the bigger it got — a ten-node fleet reacting at a fortieth of the stray's push rather than the quarter the line above it claims. Backwards, because a big cluster is one with a big box, so it is exactly where a stray is most likely to be stuck inside and where the reaction has work to do. The reaction exists to break the deadlock when the stray and the cluster are both held by their own ring targets; diluting it by size removed it from the case it was written for. The box-vs-box path never did this — both clusters take the same acceleration whatever their size. A flat quarter now, which is what "the cluster takes a quarter of it back" says. Found by Seer on #584.
The comment added with the cooling fix said a stray "resting exactly at its clearance still reports `m === STRAY_GAP`". It does not. At the clearance `m` is zero — the guard skips that case before the arithmetic runs. `m` reaches `STRAY_GAP` when the stray is *touching* the box with nothing overlapping. The code was right either way; the comment named the wrong configuration, and described a phantom force at a boundary where in fact there is none. Both places `m` is used now say which quantity they want and why they differ: the force wants the distance still needed to reach the clearance, the cooling flag wants the penetration, and touching the box is a full push for the first and nothing at all for the second. No behaviour change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two ways a container could tell a lie about membership.
A non-member could sit inside a box
Nothing stopped one. An org-level service whose ring slot happened to land over a
cluster, another user's agent that swung wide, the org aggregate — any of them
could come to rest inside a container. A box is a claim about who belongs to
whom, and that claim got sharper in #582, when services started joining
containers legitimately: "it is drawn inside the box" stopped being obviously
false for a service.
A stray is now pushed out by its nearest edge, caption included, since a label
lying across the edge makes the same claim the ball would. The stray takes the
push and the cluster takes a quarter of it back — all of it on the stray and a
node held to its ring target would shove forever; all of it on the cluster and
one loose ball could walk a whole fleet across the map.
Container-vs-container separation did not do what its comment said
It applied a flat force to every member, and the integrator divides force by
mass — so a mass-1 agent accelerated ten times harder than the mass-10 user it
orbits, and the cluster sheared instead of translating.
pushClusterismass-scaled, which is what "push whole clusters" was always supposed to mean.
Neither force could win against the cooling
sp < 5 && am < 30freezes a node outright, and at the alpha floor an overlap ofa few tens of units does not clear that bar. The push was real, and then the node
was frozen mid-overlap — which is why containers still visibly intersected. The
layout now stays awake while anything is overlapping and settles as soon as
nothing is, with an epsilon so a residual sliver does not keep the map shimmering.
Verification
Same fixture both times — five users with two agents each, four org-level
services on the shared ring, laid out and recentred — built from this commit's
parent and then from this commit.
Before
chi's container cuts through bothdagmar.olsen's andbruno's, and bruno'sown caption sits across his box's left edge.
After
Three containers, three gaps.
githubstays outside on the ring.Full frames: before · after