Let node commands address loops inside a composite by their own id - #223
Conversation
Node memo/refine/send/delete (and update, rename, promote, stop, edge create) resolved their target against the top-level graph's nodes only, so a loop created with --into got "no loop <id> in this graph" when it memoed or refined itself per its briefing, and sub-graph children could only be managed in the app. A command whose target names no top-level loop but lives inside a sub-graph is now wrapped for the composite that holds it and dispatched through the existing runInSubGraph descent, one hop per store level. Refusals raised inside a sub-graph store are now re-announced on the parent's connections instead of being said to nobody. (issue #217, item 15)
Review verdict: ✅ Approve(Formal approval is blocked because this account authored the PR, so the verdict is recorded here as a comment. Reviewed against #217 item 15 with a full build + test run on Verification
Correctness against the bugThe reported failure — child loops getting The error-forwarding fix is validated against how the CLI actually waits: the one-shot client takes the first of Non-regression audit
Minor findings (non-blocking, follow-up material)
None of these block: the reported bug is fixed, refusal messages are preserved, and the failure modes that changed are strict improvements (silent no-ops becoming announced errors). |
…dges A per-command sub-graph store cannot hold a timer: one armed there died with the store, so a goal loop inside a composite never had its stop condition polled, and node update's --poll or a promotion re-armed a poller into a store that was deallocated the moment the command finished — silently inert. Sub-graph stores now hand poller and heartbeat arm/cancel requests up through an ordered sink; the project store applies them (gated on the owning composite having been piloted, so a template's goal can never resolve work that never ran), and its ticks descend into the sub-graph, write the result back, and roll the composite up. Predicate fingerprints and failure tails move into a cache shared across those one-shot evaluations, so a failing predicate is still relayed once, not every poll. Piloting, spawning, and boot restoration arm the recurrence the pilot makes real, and deleting a composite cancels its workers' timers. An edge whose endpoints do not share a sub-graph is now refused out loud instead of dropped silently: no edge may span two graphs.
|
Both review findings are fixed in 61829e1, plus the nits. 1. Ephemeral poller — fixed via the "forward the re-arm up" shape.
2. Silent edge drop — fixed. Nits.
|
…essing # Conflicts: # GraphcodeKit/Sources/GraphStore.swift
Fixes item 15 of #217 (sub-graph children have no memo/playbook path from the CLI).
Problem
A loop created with
--into <composite>lives in a nestedGraphStoreon the composite node, but every node command exceptnode create --intoresolved its target against the top-level graph's nodes only. A piloted child following its briefing (graphcode node memo <project> <its-own-id> …) gotno loop <id> in this graph; same fornode refine,node send,node delete,node update, andedge create. Sub-graph children could only be managed in the app.Fix
GraphStore.handlenow auto-routes any command whose target id names no top-level loop but exists inside a sub-graph: it is wrapped assubGraphCommandfor the composite that holds it and dispatched through the existingrunInSubGraphmachinery. Each store level descends one hop, so arbitrarily nested composites need no path form — ids are already unique across the whole tree (LoopGraph.containsAtAnyDepth's documented rule).edge createroutes only when both endpoints share one sub-graph; anything else falls through to the existing guards.runInSubGraphnow buffers them and re-announces on the parent before itsgraphChangedbroadcast, so a one-shot CLI client sees the error instead of timing out.Tests
New
SubGraphAddressingTests(8 tests): memo/refine/send/delete/edge-create addressed to a child by its own id, a nested child reached through both levels, unknown-id refusal, and in-sub-graph refusal forwarding.Test run with 1301 tests in 141 suites passed; swiftlint clean, swift-format clean on touched files.