Fix J detach/re-parent on an already-nested sub-coordinator (#814 follow-up)#816
Merged
Conversation
…low-up) #814 added "Detach (make top-level)" to the J coordinator picker, but it could not be triggered on the exact case it was built for: an already-nested sub-coordinator. A nested sub-coordinator renders as a headerless worker "bridge" row in its parent (Role.Kind == worker), so heraCoordReparentTarget returned false for it and heraOpenAdopt fell through to the "select a freelancer or a coordinator" statusbar error. You could NEST a top-level coord (selected as its orch header) but not UN-NEST it. Fix: heraCoordReparentTarget now qualifies a THIRD shape — a non-archived worker row whose Selection.BridgeChildOrchID is non-zero (the SAME field the Ctrl+D cascade already reads). The rail stamps the bridged CHILD orchestrator id there; that worker row IS the child's coordinator, so it routes the existing heraAdoptCoordinator path (detach sentinel + DetachCoordinator, and ReparentCoordinator for symmetry) against the CHILD orch. Only a bridge row qualifies (BridgeChildOrchID != 0) — a plain worker is never misclassified, and cycles are still rejected by ReparentCoordinator. Inert in remote mode. No op-layer change (DetachCoordinator/ReparentCoordinator already resolve everything from the child orch id). No new keybinding; help modal / README unchanged. OpenSpec: fix-detach-nested-bridge (archived in-PR; hera-view delta merged into the base spec). Tests: TestHeraCoordReparentTarget bridge subtests + TestSmoke_HeraDetachNestedBridgeThroughPicker / TestSmoke_HeraReparentNestedBridgeThroughPicker. Gotcha added to hera-view.md. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Merging this branch will decrease overall coverage
Coverage by fileChanged files (no unit tests)
Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code. Changed unit test files
|
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.
Problem
PR #814 added the
— Detach (make top-level) —sentinel to theJcoordinator picker so an operator can un-nest a sub-coordinator. But it could not be triggered on the exact case it was built for: an already-nested sub-coordinator.When coordinator
Cis nested under parentP(viaReparentCoordinator), the rail rendersCas a worker "bridge" row inP— the bridging worker role ISC's coordinator (same multi-binding task) and no separate child orchestrator header is drawn (internal/tui/hera/rail.gobridge placement). So selecting the nested sub-coord yields aSelectionwhoseRole.Kind == HeraKindWorker.heraCoordReparentTargetonly returned ok for a coordinator-kind role row or a coordinator's own orchestrator header — it returnedfalsefor a worker row, soheraOpenAdoptfell through to the statusbar error "J: select a freelancer or a coordinator to adopt".The asymmetry: you could nest a top-level coordinator (selected as its orchestrator header) but could not un-nest it (now a headerless worker-bridge row).
Fix
heraCoordReparentTargetnow qualifies a third shape: a non-archivedworker-kind role whoseSelection.BridgeChildOrchID != 0— the same field theCtrl+Dcascade already reads, stamped byRail.Selectionwhen the cursor rests on a bridge row. That worker row IS the bridged child's coordinator, so it resolves the child orchestrator id and routes the existingheraAdoptCoordinatorpath:DetachCoordinator(childOrchID).ReparentCoordinatoragainst the child orch; cycles still rejected authoritatively (ReparentCoordinatorrejects nesting under self/descendant).Guards preserved:
BridgeChildOrchID != 0) — a plain (non-bridging) worker is never misclassified and still surfaces the "select a freelancer or coordinator" feedback.heraAdoptOps == nil).roleReclaimTask→BridgeTaskIDelse liveTaskID).No op-layer change —
DetachCoordinator/ReparentCoordinatoralready resolve everything from the child orchestrator id alone. No new keybinding; help modal / README unchanged.Tests
TestHeraCoordReparentTarget— bridge-worker row qualifies (returns the child orch id, bridge role name, bridge task); prefersBridgeTaskID; plain worker (==0) and archived bridge row do not qualify.TestSmoke_HeraDetachNestedBridgeThroughPicker— select the bridge-row shape,J, Enter on the detach sentinel → parent link gone (child top-level again), child's own coord binding intact.TestSmoke_HeraReparentNestedBridgeThroughPicker— re-parent the nested coord under a different parent through the picker.OpenSpec
fix-detach-nested-bridge(archived in-PR): thehera-viewJrequirement now defines a coordinator selection to include a worker-bridge sub-coordinator row; delta merged into the base spec, folder moved toopenspec/changes/archive/2026-06-25-fix-detach-nested-bridge/.openspec validate --all --strictpasses (47/47).make pre-pr-racegreen)vulnreports 2 stdlib-only CVEs (net/textproto,crypto/x509in go1.26.3) — advisory, matching CI'scontinue-on-errorfor the vuln step; no first-party code affected.🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com