Repository navigation
A goal its sprints did not meet is retired, and the loop moves on (M9.50) - #103
Merged
Merged
Conversation
….50) `mission goal retire GOAL --eval EVAL` records goal.retired in the committed ledger when every intent of the goal was sprinted, its sprints closed and the newest eval of it, made after those closes, still lists gaps. A retired goal takes no intents, sprints or close; `mission evaluate` covers the whole mission again and the next goal is derived. `mission tick` hands this out as RETIRE_GOAL (mission-planner) from the command's own rule (goal.retire_problems), else BLOCKED with its reason; a retirement counts toward the 3-failed-goals block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
8000
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiLhAWTRtwbgMCDQNJUbea
# Conflicts: # docs/ROADMAP.md
…e gaps it tried (M9.50 review) An adversarial review of the first commit found these, each reproduced: - A retirement could be made from a state measured before the sprints closed, or from an eval older than the newest state. Now the eval must be computed from the newest state report, and that state must be measured after the last close. Tick maps the gate's refusal to ASSESS or EVALUATE. - A second intent for a gap, still sprinting, was not counted. Now every intent of the goal counts, the same set tick reads. - The planner's stop gate refused every retirement. The goal check now reports `retired` as the planner's finding (roles.json verdicts). - The next goal re-derived the same gaps. A retired goal's open gaps are now held on that baseline until a new version or the human's next approval of the mission. - evaluate fell back to an older goal nobody works. active_goal is now only ever the newest goal. - The record is written before the status, and a bare `retired` status is repaired, never trusted (tick reads the record). - Malformed run-log lines and sprints.json rows no longer crash tick or retire. - Tick now asks the whole rule (derived content, status, met), not part of it. Tests pin each rule (goal check 13, tick checks 28 and 33, roles). M9.54 records the remaining one-goal-in-flight gap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
…lift the hold (M9.50 review 2) A second adversarial review found these, each reproduced: - `goal next` handed out only the first intent per gap, so a retry intent that `goal retire` and tick count could never be sprinted. It now queues every intent of the goal. - The retirement's `open` listed every gap of the eval, a regression elsewhere included. It now lists the goal's own gaps, and a regression is never held. - A BLOCKED with every gap held had no lift. It now carries grant GOALS on the newest retired goal, so the human's `tick --force --by` and `lift` line free those gaps (`goal.retired_gaps` reads the lift). - Two goals derived in the same second tied in `evaluate.active_goal`. The newer id now wins. Tests: mission-goal 14 checks, mission-tick 33 checks (status-only retirement, held BLOCKED with grant GOALS, `goal derive` refusing, the lift giving DERIVE_GOAL). Removing the lift clause fails check 33. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
…goal id (M9.50 review 3) A third adversarial review found these, each reproduced: - `goal next` skipped a goal intent whose file was gone, unreadable or another intent's copy, while tick and `goal retire` still counted it, so the loop repeated SPRINT until BLOCKED. Every goal intent now goes to `intent check`, and `goal next` names the one that fails. - A GOALS lift took its occurrence from the goal file, so after the retired goal's file was edited the lift recorded 0 and freed nothing while `tick --force` said it lifted. The occurrence now comes from the goal id the block names, as the hold reads the record. - The spoon-fed `derive --pick` refusal offered `tick --force` when it only works once every gap is held. The message and docs now say so. Tests: mission-goal check 13 (gone, unreadable and copied retry intent), mission-tick check 33 (the retired goal's file edited before the lift). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM
# Conflicts: # docs/ROADMAP.md # docs/TRACKING.md
adeelahmad
marked this pull request as ready for review
October 20, 2026 16:09
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
…follow-up Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WBVFNrEg85XAnSfHQidCXN
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
… into the artifact gate fixes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197nSutKR1QAAqgJhFZ8fPj
adeelahmad
pushed a commit
that referenced
this pull request
Oct 20, 2026
…oop stop) into the M9.31 branch Conflicts: both sides' plugin constants and helpers kept (the door gate's timeout and read-only set beside master's NEEDS-HUMAN release), the dsh test's question helper renamed (master added a child named `ask`). This branch's open items move to M9.56–M9.65: master took M9.55 and #114 claims M9.48. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rsDo9GYzNx8tXucywZHnA
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.
Requested by Adeel · project thread
Before: suppose every intent of a goal was sprinted and the goal's eval still listed gaps.
goal closerefused, since the goal was not met, andgoal nexthad no intent left to hand out. Somission tickstopped atBLOCKED("the human decides") and the autonomous loop could not move past an unmet goal.After:
aloop mission goal retire GOAL --eval EVALrecordsgoal.retiredin the committed ledger. A retired goal takes no more intents, sprints or close.mission evaluatethen covers the whole mission again, and the loop derives the next goal from the gaps the retired goal did not try.mission tickhands this step tomission-plannerasRETIRE_GOAL. Three retired goals in a row still go to the human.How:
retire_problemsis the one rule, for the command and for tick. It requires all of these:deriverecorded, active and not met;plan.created;sprints.json, read the way tick reads it);cmd_retirewrites thegoal.retiredrecord first (rolemission-planner: the eval, its event, the goal's own open gap ids, the baseline and state), then the status. A bareretiredstatus is repaired, never trusted.check,next,intentsandcloserefuse a retired goal.checkreports stateretired, whichroles.jsontakes as the planner's finding at its stop.deriveon that baseline until a new baseline version or the human's next approval of the mission. A regression is never held.goal nexthands every intent of the goal tointent check, not only the first per gap, so a retry intent can be sprinted and a broken one is named.active_goalis only ever the newest goal (by start time, then id), andNonewhen that goal is met or retired.goal.retiredjoinsLEDGER_EVENTSand is gate-owned (events emitrefuses it).BLOCKED, it asksG.retire_problems. A stale state or eval becomesASSESSorEVALUATE; any other refusal isBLOCKEDwith the gate's reason; none hands outRETIRE_GOAL.goal.retiredrecord is not in flight, and it counts as "was retired" toward the 3-failed-goals block.BLOCKEDwith grantGOALSon the newest one, so the human'stick --force --byandliftline free them. The lift is dated by the goal id the block names, as the hold reads the record.Call I made: retire, not re-plan. Re-planning the same gaps repeats work the sprints already tried. The 3-failed-goals breaker bounds a run of retirements.
Review rounds
Three adversarial review workflows ran on this PR. Every confirmed finding is fixed with a test:
evaluatefalling back to an older goal; status written before the record; malformed run-log andsprints.jsonrows crashing tick.goal nextnever handed out a retry intent;opencould list another goal's gaps and regressions; a heldBLOCKEDhad no lift; two goals derived in the same second tied inactive_goal.goal nextskipped a retry intent whose file was gone or broken, so tick repeated SPRINT until BLOCKED; a lift after the retired goal's file was edited recorded occurrence 0 and freed nothing; the spoon-fedderive --pickrefusal offeredtick --forcewhen it only works once every gap is held.goal next's planned set differing from tick's (no real caller reaches it). Also refuted: a fresh checkout before retirement losing sprint history. It predates this PR and is tracked as M9.26.Evidence
scripts/test/mission-goal.test.py: 14 checks. Check 13 refuses each unmet condition with its own message, retires once (record fields asserted), repairs a bare status, names a gone, unreadable or copied retry intent atgoal next, then shows a retired goal refused everywhere, its gaps held, a regression not held, and approval freeing them.scripts/test/mission-tick.test.py: 33 checks. Check 33 is a real-clock run:ASSESS,EVALUATE,RETIRE_GOAL, a gate refusal asBLOCKED, a status-only retirement stillRETIRE_GOAL, retire, heldBLOCKED(grantGOALS) before and afterrm -rf .aladdinand an edit of the retired goal's file,goal deriverefusing, then the human's lift givingDERIVE_GOAL.scripts/test/mission-roles.test.py: the planner's stop passes with a retired verdict.goal nextexits 1).make pycheck,scripts/check-tracking.py(98 requirements) andmake test-hostspass locally on 29bd8f7 (master with Mission role gates: rounds 3 and 4 review fixes (M9.9, M9.42) #92 and aloop stop: one stop for the whole project (M10.4) #109 merged in).🤖 Generated with Claude Code
https://claude.ai/code/session_01Aw6CiQcdpzdzZZXKf8WbUM