Repository navigation
Guard heightOf against a parent cycle and count the whole subtree (#677) - #686
Merged
Merged
Conversation
…subtree (#677) `heightOf` passed the child *node* to its own recursion, so `childrenOf` matched nothing and the height was always 1: `move_bot`'s maxDepth check counted only one level. It recurses on the id now, and a `seen` set ends the walk at a node already on the path, like `depthOf`, so a corrupted pair of parents is answered instead of dying on the stack. Docs-not-needed: the change is internal to the move check; docs/subsystems/tree.md already documents move_bot's maxDepth refusal, and no user-visible behaviour or command changes.
Collaborator
Author
|
Verdict: PASS at 8580b01 Ran:
Not run:
Reviewed at this tip only. All 9 checks are What I checked
Non-blocking
Risk: T2 ( |
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.
Written-by: Dev
heightOfgets the guarddepthOfhas, and the recursion now walks child ids — which is the half that actually made the bug visible.Fixes #677
Tip SHA: 8580b01
Reproduce
On
mainat8e80237b, the recursion passed the child node instead of its id:childrenOf(nodes, <node object>)comparesn.parent === <object>, which is never true, so the walk ends after one level and the height is always 1 for any node with children. Measured on a realChief → A → B → C:heightOf(nodes, A)returned1where the subtree is 2 levels.moveBotbuilds its depth check from it —bottom = depthOf(parent) + 1 + heightOf(bot)— so a move that should hitmaxDepthwas allowed:A note on the issue's stated symptom, because it changes what the red test can be: with that same object-passing bug the recursive call cannot re-enter anything, so a two-node parent cycle does not overflow the stack on
main— it returns 1 instead. The stack overflow appears the moment the ids are threaded correctly, which is exactly what the guard has to survive. Both defects are fixed here, because fixing only the ids would turn a wrong answer into a crash on a corrupted snapshot.What changed
plugins/tree/src/tree.js,heightOfonly:k.idinstead ofk: the subtree height is measured, not assumed 1.seenthreaded likedepthOf: a node already on the current path ends the walk, so a snapshot whereA.parent = BandB.parent = Ais answered instead of recursing until the stack dies.depthOf,traceOfand every refusal (cycle,maxChildren, duplicate name, own parent) keep their current messages and order of checks.plugins/tree/test/tree.test.jsgains two cases: the corrupted pair through themove_botpath (assert.doesNotRejectplus the depth refusal, andheightOfbounded at 2), and a validA → B → Csubtree whose move must be refused bymaxDepth— the undercount itself.No docs change: the invariant is internal, and
docs/subsystems/tree.mdalready documentsmove_bot's maxDepth refusal. The commit carriesDocs-not-needed:for the arch-docs gate. Nocore/change, so nothing to regenerate.What I ran
At this tip (
8580b011), from a tarball of it:node --test "plugins/tree/test/*.test.js"is 90/92:host.test.jscannot run here (ERR_MODULE_NOT_FOUND: ds-bot, the package is not installed in this environment), andclassify-model,load,web-entrypass. CI runs the plugin suite in full.Red without the source change
Two reverts, both at this tip, measured on the same two test files:
heightOfback tomain's version (object recursion, noseen): 83 tests, 81 pass, 2 fail — exactly the two new cases (#677: a two-node parent cycle …fails onheightOfreturning 1 and on the move being allowed;#677: heightOf measures the whole subtree …fails because the too-deep move is allowed).seenguard removed, ids kept: 83 tests, 82 pass, 1 fail — the cycle case fails withRangeError, which is the crash the guard exists for.Not run
plugins/tree/test/host.test.js: needs theds-botpackage, absent on this machine. CI'splugins (tree)job runs it.npm run verifyas one command, and bench smoke: no dependencies installed here (and no model routing for bench).move_botpath the product uses.Risk
T2 by the repository's
risk-gate(path-only rules:plugins/tree/src/tree.jsis not a T3 path; the diff is ~20 lines across two files), and the one behaviour change is deliberate: a move that puts a subtree deeper thanmaxDepthis now refused where it used to be allowed. That refusal is the documented contract, and #678 is the follow-up that adds the missingmaxDepthcase in the create-path tests. A corrupted pair no longer crashes the move; it is refused by the depth check, or moved when the depth allows it.