Repository navigation
Let an edge pick where a cycle's rounds start, and warn about nodes that wait for a choice - #131
Merged
Merged
Conversation
…hat wait for a choice - Edge.closesCycle: true forces an edge on a cycle to close it, so each round starts at its target. Validation rejects it off a cycle. - GraphCycle.choiceGated lists choice edges whose target runs only once the decision picks it; Pi and DSH cycle notices name such nodes and how to start rounds there instead. - Waiting and timeout-pause reminders mention the graph timeout only when one is set and the job was not paused by it.
Epsirom
enabled auto-merge (squash)
October 27, 2026 12:16
4 of 5 tasks
Epsirom
added a commit
that referenced
this pull request
Oct 27, 2026
…and open the Pi panel on the timeline (#132) ## Change Part of RSI Mode (#118). Follows #131, from a second Pi run of the task-queue graph (`impl`, `tests`, `docs` → `merge` → `review`, with `review -> impl [choice=again]`). The cycle notice warned that `impl` would not run in the first round. The agent passed the warning on but did not set `closesCycle`, so `impl@1` was skipped and `merge` wrote the implementation itself. Two status texts also misled the agent. - **Guidance at submission.** The Pi `braid` description and the DSH `edges` description now cover this pattern. When an outside edge enters the cycle at another node, rounds start there, and a node whose only input is a choice edge runs only after the decision chooses it. That is right for a fix step, but if the node should also run in the first round, write `{"from":"review","to":"impl","choice":"again","closesCycle":true}` and set it at submission. The round-start sentence #131 added read badly; it now lists the order: the `closesCycle` target, else the outside entry, else the node listed first. The `closesCycle` field descriptions say when to set it. - **New `WaitReason` `"choice"`.** A pending instance whose non-closing inputs are all choice edges, while those inputs still wait, reports `choice` instead of `predecessors`, `stale`, or `hold`. Pi and DSH `braid_status` show it as `waiting: runs only after review chooses again`. Before, the agent saw "an input has not run yet" on a node it believed was a root. - **Graph-timeout reminder.** It said: `It waits on suspended node "merge" execution merge@2 (its graphTimeoutMs limit); the job pause (by its graphTimeoutMs limit).` The agent read "its" as a per-node limit. A job pause now names the executions it suspended, and limits are called "the job's": `It waits on the job pause (by the job's graphTimeoutMs limit), which suspended node "merge" execution merge@2.` - **Pi panel opens on the timeline view.** `g` switches to the live view, as before. Docs: `docs/execution-control.md` (wait reasons, cycles), the Pi README (views, wait reasons), and `docs/compatibility.md`. Compatibility: code that handles every `WaitReason` needs a case for `choice`; `compatibility.md` notes it. The panel views and the cycle features are unreleased since 0.5. ## Validation `npm run verify:checks` passes: core 313/313, Pi 197/197, DSH 71/71, plus type checks and examples. - Core: in the task-queue graph, `impl@1` waits with `choice`, and with `closesCycle` it starts in the first round. In the existing `check -> end [done]` loop, `end` now reports `choice` instead of `stale`. - Pi and DSH: full status and focused status show "runs only after review chooses again". A reminder for a graph-timeout pause names the suspended execution once. - Pi panel tests now start from the timeline; the `g` round trip through the live view is still covered. - [x] Relevant tests and type checks pass. - [x] User-facing docs are updated where needed. - [x] The title reads as a release-note line and the category label is correct (see [release notes](https://github.com/Epsirom/braid/blob/main/docs/releasing.md#release-notes)). - [x] Breaking changes, if any, include migration guidance in the docs. - [ ] For release PRs: `.github/upgrade-notes.md` lists what users must do to upgrade.
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.
Change
Part of RSI Mode (#118). Follows #127. Found while testing 0.6 in Pi with a task-queue graph:
impl -> tests/docs -> merge -> review, withreview -> impl [choice=again]andmaxRunsonimpl. Braid closed the cycle atimpl -> merge, so each round started atmerge.implran only after review choseagain, and the firstmergeran without it.The heuristic was not changed.
impl -> merge -> review -(again)-> implhas the same shape asbuild -> check -(again)-> fix -> build, where starting atbuildis right. So the graph author now says which one they mean, and Braid points out the ambiguity:Edge.closesCycle: truemakes an edge close the cycle it is on, so each round starts at its target. Braid still chooses closing edges for any other cycles. Validation rejects the flag on an edge that is not on a cycle. The flag is not part of the edge's identity, so changing it in an update means removing the edge and adding it back (tested). It is accepted by core, the replan tool schema, and the Pi and DSH edge schemas. Pi's panel keeps it onedge_created.GraphCycle.choiceGatedlists the cycle's non-closing choice edges whose target waits only on choice edges, meaning the target does not run until the decision picks it. Pi and DSH cycle notices add a line for each:WaitingNoticeandTimeoutPausenow carrygraphTimeoutMsfrom the snapshot's limits. The sentence appears only when it is set, and not when the job is paused bygraph_timeoutitself.Docs:
docs/execution-control.md(Cycles, Cycle notices), README, the Pi and DSH READMEs, and the 0.6 section ofdocs/compatibility.md.Compatibility: no changes needed from callers. Code that compares whole
GraphCycleobjects needs the newchoiceGatedfield.Validation
npm run verify:checkspasses: core 312/312, Pi 196/196, DSH 70/70, plus type checks and examples.New tests:
test/cycles.test.ts:choiceGatedis reported for the task-queue graph and disappears withclosesCycle; withclosesCycle,merge@1waits forimpl@1,tests@1, anddocs@1, andimpl@2followsreview@1; validation of the flag, and moving it with an update.closesCycle, and the reminder with and without a graph timeout and when paused bygraph_timeout. Pi also checks that its schema acceptsclosesCycle.Not re-tested in Pi yet, because the local Pi install points at the main checkout.
(see release notes).
.github/upgrade-notes.mdlists what users must do to upgrade.