refactor(cfg): replace LoopContext wrapper with continue_stack - #317
Merged
Merged
Conversation
After switch `break` handling moved to `break_stack`, `LoopContext` held only `continue_target`. Drop the one-field struct and store the loop header directly in `continue_stack: Vec<usize>`, so break and continue state read symmetrically. No CFG behavior or edge-contract change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jeremy-wayland
added a commit
that referenced
this pull request
Aug 9, 2026
* docs: document squash-merge + Unreleased changelog convention Records the repo git convention: main's history is a series of squash-merged PRs, each carrying its own CHANGELOG [Unreleased] entry. Release scope is decided after the work lands, and the release PR -- which renames [Unreleased] to a version heading -- comes last. Explicitly rules out long-lived release branches that accumulate feature PRs, superseding the v0.4.x stacked-PR-into-release-branch pattern. Opens the [Unreleased] section and backfills entries for the four v0.6.0 fixes already in review (#317, #318, #319, #320), which were authored before this convention existed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: scope PRs to one issue cluster, add stacked-PR rules Stacking is for work review surfaced -- a required fix to a PR under review, or a distinct issue found while reviewing it -- and stacks onto the PR branch, never onto a release branch. Documents the replant step (git rebase --onto main) that stacked-squash divergence requires, and notes the cheaper default: if the parent has not merged and the fix belongs to its issue, push another commit to the parent instead of stacking. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: tighten PR scope, stacking test, and replant procedure Scope a PR by coherent outcome -- reviewed, reverted, and explained as one unit -- rather than by issue count, and make the PR title the permanent squash subject. Replace the "review surfaced it" test for stacking with the stricter "child structurally depends on an unmerged parent"; discovery during review is not itself a reason to stack. Bound stacks to two or three, require the ordered stack in every description, and review bottom-up. Correct the replant procedure: fetch and rebase onto origin/main rather than a possibly stale local main, record each parent's old tip before rebasing it, and move shallowest to deepest so every descendant lands on its newly rebased parent. GitHub retargets a child only after the merged head branch is deleted, and retargeting never rewrites commits -- always rebase, inspect, and rerun CI. Add the repository settings that enforce the convention instead of relying on memory, and keep an empty [Unreleased] after each release. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Closes #307
LoopContextwas left holding a single field (continue_target: usize) once switchbreakhandling moved tobreak_stack. This drops the wrapper and stores the loop header directly incontinue_stack: Vec<usize>, so the break/continue state reads symmetrically at theCFGBuildStatedeclaration.Change
topos/engine/src/graphs/cfg/builder.rsonly, 6 insertions / 13 deletions:struct LoopContextloop_stack: Vec<LoopContext>->continue_stack: Vec<usize>start_looppushesheader;finish_looppops — same single push/pop pair as beforeContinueStmtreadscontinue_stack.last().copied()No edge-contract change
Push and pop sites are unchanged in number and position, so stack depth stays balanced on every path. No edge kind, target, or ordering is touched — this is a pure representation change to the builder's own scratch state.
Verification
cargo test -p topos-engine graphs::cfg— 25 passed, 0 failed (includespreserves_pre_refactor_edge_contracts_across_supported_languagesandfinally_paths_keep_distinct_completions_and_frames)cargo test -p topos-engine— 371 passed, 0 failed, 1 ignoredcargo clippy -p topos-engine --all-targets— cleancargo fmt --all— no other files touchedfinish_agent_contractwas flagged in the same review but belongs with #233; deliberately untouched here.🤖 Generated with Claude Code