Skip to content

v0.27.3

Choose a tag to compare

@ux287 ux287 released this 14 Jul 21:08

Three P0s: the Build Governor can now recover on its own.

A clean-machine greenfield UAT completed only because a human intervened twice. These are the two places it got stuck, plus the on-ramp that misled it.

exec no longer strands a story in executing

A story is at phase executing on ENTRY to exec — the plan writer makes that hop, exec only gates on it — so EVERY exit left it there unless something put it back, and the reset existed but was wired to 2 of ~12 exits. A scope violation, a quality gate, a divergence, or any thrown error stranded the story. rks_plan refuses that phase, so the re-plan the error message told you to run was IMPOSSIBLE: a recoverable failure became terminal and the story had to be deleted and recreated.

The fix is a THREE-REGION recovery, and the regions are not interchangeable — two of them destroy work if you pick the wrong one:

  • FINALIZED (the commit landed) → phase reset only. NEVER rollback(): it would git branch -D the branch holding the commit, destroying a green build because a JSON write failed.
  • POST-MUTATION (a branch, backup or guardrails session exists) → rollback(), then reset. A bare reset would leak all three.
  • PRE-MUTATION (nothing mutated) → bare reset only. NEVER rollback(): its cleanup step is unguarded, so with no branch it degenerates to WIPING THE TREE — and on the dirty-tree precondition failure, that tree is dirty with the USER'S OWN uncommitted work.

Plus return-value inspection, because a try/catch does not intercept return and most of exec's failures are returns. Exactly two carve-outs — needs_approval and incomplete_previous_story — because both tell you to retry, and the retry re-enters exec through the same gate.

refine_apply no longer reports success after changing nothing

It returned ok:true AND requiredNext:rks_plan after a byte-identical no-op — telling the Build Governor "success, now go re-plan". The Governor re-planned an unchanged story, got the identical failure, refined again, and was told "success" again. Forever. The retry could never converge because the feedback never changed the input.

The dedup was merely how it got there: add_test_exemplar checked for a bare "### Test Exemplar:" header, so ANY prior exemplar suppressed every future injection — on BOTH sides of the loop. The suggester never emitted the correction, so fixing only the apply half would have been useless. It is now effect-aware, matching the two siblings in the same file that already worked that way.

A genuine no-op now returns status:"refine_noop", names what was skipped, and does NOT tell anyone to re-plan. The chain moves to a new escalated state which permits neither rks_plan, rks_refine, rks_refine_apply nor rks_exec — every one of them is a way back into the loop — and the Build Governor aborts and hands back to a human. A manual:true request and a decompose that declines are NOT no-ops: a false escalation kills a healthy build as surely as a missed one loops.

The clean-machine on-ramp stops lying

  • The detached-HEAD advice shipped in 0.27.2 printed git checkout -B staging --track origin/staging, which FAILS on a public-mirror clone — the mirror publishes only main and tags, so there is no origin/staging to track. The fix that detected the problem prescribed a cure that fails in the environment it was most likely to run in. It is now mirror-aware.
  • rksVersion reported the version on DISK while the checks ran from the code loaded in MEMORY at server start. After a git checkout <newtag> without a restart those are different builds, and preflight confidently named the wrong one — it announced 0.27.2 while a check that only exists in 0.27.2 was absent from its own list. It now reports the LOADED version, and a new server_freshness check fails when the two diverge and tells you to restart the MCP server. Telemetry events carry the loaded version, so a failure can finally be attributed to a build.
  • .tmp-replan-* scratch dirs are gitignored. rks was tripping its own clean-tree guard on its own garbage, and auto-ship swept three of them into a commit.