Repository navigation
Risky changes need a person, loopstra retro, and acceptance tests from Done when - #91
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, gate rows, phases Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
stages.build.acceptance_tests (off by default; init's template turns it on), the acceptance step under build, its envelope and prompt, a steerable work session, and the yes/no question in setup gates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gates.merge.risky names patterns of files (Bun.Glob, repo paths with /), an optional size in lines, and who decides (pr or status). src/risk.ts scores a branch against main from where they parted, outside intent/, from git diff --numstat -z -M: binary files add no lines, a rename counts under whichever of its names a pattern matches. It also words the gate row's evidence and the owner's note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reach The acceptance step may write only tests and test fixtures; build, fix, reconcile and revise may not edit the files in LOOPSTRA_ACCEPTANCE, and each refusal is logged for the block note. The fix rule is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Frontmatter gains merge_gate (pr or status; blank reads as absent and gets no line). changeGates gives one change's gates: the config's, with merge_gate on the merge gate when the config has nobody there; it never takes a person off. waitsForPerson, isRunnable and offers apply it themselves, so the scheduler, queue.md, status, the console and chat all see a risky change as waiting for a person; apply's approve and send-back check, the attention note and plan-ahead's mayMergeFirst use it too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rds it passMergeGate scores the change in its worktree once the merge checks pass, on the code that will merge, and writes a merge/risk gate row (pass "nothing risky", or waiting with the files and size) when the config names anything risky. With nobody on the config's merge gate, a risky change gets merge_gate (gates.merge.risky.human) in the same record as its move to merge-review, with a note naming up to three files; a change that is not risky loses the field in that record (or in the record of its merge). Without a remote, merge_gate pr acts as status. mergeHuman gives a change's own merge gate; the pull request watcher, the no-remote merge-review wait and mergeRetry read it. setStatus takes frontmatter fields to set or remove in the same record. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es, spending, waits, and suggestions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… decisions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When stages.build.acceptance_tests is on, a fresh acceptance session writes tests from Done when before the build session. The runtime commits them on the branch, records acceptance.md on main, and keeps the files in the run folder's acceptance marker, once per build. Every session gets them in LOOPSTRA_ACCEPTANCE; a refusal is named in the block note, and the drift check leaves them out. A failed session does not block: its files are dropped and the build goes on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With nobody on the merge gate, loopstra setup's GitHub section asks which files need a person before merging, suggesting .github/**, **/migrations/** and the dependency and build files at the top of the repository; the file's own list is kept as the suggestion, - empties it, and --defaults never adds one. The README covers gates.merge.risky under GitHub and Configuration and merge_gate under When something needs a person; intent/README.md tells owners what merge_gate means; the config template shows a commented example; decisions.md records each call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uments Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The done-check prompt gets {{acceptance}}: acceptance.md's Covered by
tests list, or a sentence saying none were written. A passing acceptance
test meets its criterion. A repository's older done-check.md without the
variable gets the list appended.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # docs/decisions.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README (How it works, the step tables, Configuration, Steering and the test-protection hook), the owners' guide on acceptance.md, and the decisions behind them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With acceptance_tests the flow map passed the YAML line width, so the stamped config no longer read back exactly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # README.md # docs/decisions.md
…one when Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # README.md # docs/decisions.md # src/config.ts # src/models.ts # src/phases.ts # src/prompts.ts # src/stages/merge.ts # templates/config.yaml # tests/unit/console-agent-settings.test.ts # tests/unit/models.test.ts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…k ignores a stale acceptance.md Review findings: the acceptance step protected any file it touched or named, fixture folders like testdata/ were refused, and the done-check read acceptance.md from an earlier build. The test-path rule now lives in src/test-paths.ts, shared by the hook and the step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Risk is scored only when nobody is on the config's merge gate, so no waiting row is written that changes nothing. - The risky note says how to stop the change, and a pull request's wait stands in for it like the other merge-gate notes (isRiskNote). - Retro leaves merge/risk out of its gate lines: waiting there is a person deciding, not a failed check. - Retro finds each move's next move in one pass instead of a scan per move. - Stale-while-waiting (from #90) reads each change's own merge gate, so a risky change waiting without a remote is kept mergeable too. - hookSettings' comment names every phase the hook acts in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <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.
Three features that make the loop safer to leave alone and easier to tune. Design:
docs/superpowers/specs/2026-10-27-risk-retro-acceptance-design.md; plan:docs/superpowers/plans/2026-10-27-risk-retro-acceptance.md; each call is a bullet indocs/decisions.md.Risky changes need a person
gates.merge.risky: { paths, lines, human }. A change that touches a matching file (Bun.Glob, renames count under either name), or changes more thanlineslines, waits for a person even withgates.merge.human: none.passMergeGate, on the code that will merge. It is recorded as a runtimemerge_gate: pr | statusfrontmatter field in the same record as the move tomerge-review, plus amerge/riskgate row. Its note names up to 3 files.changeGatesgives every reader the change's own gate:waitsForPerson,isRunnable,offers, attention,mayMergeFirst, the merge stage, and Per-change resources and automatic conflict resolution #90's kept-mergeable check.loopstra setup githubsuggests paths from the files in the repo.loopstra retro [--days N]Acceptance tests from Done when
stages.build.acceptance_tests(schema default off;loopstra initturns it on). Before each build, a freshacceptancesession writes tests from the owner's Done when list.intent/<slug>/acceptance.md. The protect-tests hook keeps build/fix/reconcile/revise off them, and the done-check reads them as evidence.acceptance(model follows the build stage), steerable like build.Review
I ran
/code-review highon the branch and fixed these findings:src/test-paths.ts, shared by the hook, which now also allows fixture folders.acceptance.md.merge/riskout of gate lines.Left as designed:
merge_gatestays on a merged change as a record.buildRetrokeeps its own window filter, since it is a pure function over all-time status moves.Merged with main after #90;
staleWhileWaitingnow reads each change's own gate.Test plan
bun run check: typecheck, lint, dead-code, and 1953 tests pass, 0 failtests/unit/risk.test.ts,tests/integration/risk-gate.test.ts,tests/unit/retro.test.ts, the acceptance cases instages-build/stages-verify/hook, the risky kept-mergeable case inconflicts🤖 Generated with Claude Code