fix(stella-cli): carry the typed abort through the goal loop and lead turn to the terminal writers - #1893
Merged
Merged
Conversation
added 3 commits
August 6, 2026 04:00
…sed writers too PR #1828 (#1653) taught the supervised registry writers to record SessionStatus::Stopped for a policy stop, but SessionPresence::finish and its callers still collapsed the outcome to a bool on the way in — so an UNSUPERVISED headless run (a pipe, CI, --foreground) that ended itself by policy still aged into the SESSIONS overlay as Error, indistinguishable from a crash, with no later supervised write to correct it. Widen SessionPresence::finish (and one_shot_notification's wording) past the bool: the caller now hands it the terminal SessionStatus, projected by the one existing decider (daemon::outcome_status) via a fifth projection in agent/outcome.rs, pipeline_session_status, so every writer reads a deliberate stop (Stopped), an interrupt (Cancelled), and a crash (Error) the same way. The goal loop still answers with a String that cannot carry the abort kind, and the deck's session_exit reads the same stringly run_lead_turn — both audited and filed as #1862. Witness: outcome::tests::an_unsupervised_deliberate_stop_projects_stopped_not_error (structural — the projection did not exist and the widened finish call sites do not compile on the old signature, mirroring the #1653 witness). Closes #1826 Refs #1653 Refs #1862
… turn to the terminal writers The goal loop and the deck's lead turn answered with a `Result<(), String>`, which has no room for the abort's typed `AbortKind` — so on their paths a deliberate stop (stuck-loop escalation, step cap, enforced budget) was indistinguishable from a crash by the time the terminal SESSIONS-registry status was written: a policy-stopped goal run aged into the registry as `Error`, never `Stopped`. Chase #1637's shape one level deeper: - `stella-core`: `GoalOutcome::Unmet` now carries the typed kind of the working turn's abort (`kind: Option<AbortKind>`; `None` for the backstops that are not turn aborts — round cap, unreachable verifier). - `run_goal_cmd` / `run_goal_turn` / `run_goal_pipeline_turn` answer with `CliFailure` instead of `String`; the folds that stringified `PipelineStatus::Aborted` and `GoalOutcome::Unmet` are now the shared projections `agent::outcome::goal_round_break` / `goal_unmet_failure`, and the terminal write projects through `daemon::outcome_status` with the real failure rather than a reconstructed `CliFailure::error`. A stopped goal run also exits 3, per the exit-code taxonomy. - The deck's `run_lead_turn` / `run_lead_pipeline_turn` answer with `CliFailure` through the existing `turn_outcome_result` / `pipeline_status_result` projections, and `session_exit` reads `outcome_status` — one decider for every terminal writer. Closes #1862 Refs #1826, #1653, #1637
…y the error row Refs #1862
Contributor
There was a problem hiding this comment.
Sorry @macanderson, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
Reviewer's GuidePropagates typed AbortKind through goal and lead turn loops so deliberate stops are recorded as Stopped (and exit with the appropriate CliFailure code) instead of generic Error, by switching loop results to CliFailure, enriching GoalOutcome::Unmet, and centralizing projections in agent::outcome for all terminal writers. Sequence diagram for goal run terminal status projection with typed AbortKindsequenceDiagram
actor User
participant GoalCmd as run_goal_cmd
participant GoalLoop as run_goal_turn
participant OutcomeProj as agent_outcome
participant Daemon as daemon_outcome_status
participant Registry as SessionRegistry
User->>GoalCmd: invoke goal command
GoalCmd->>GoalLoop: run_goal_turn / run_goal_pipeline_turn
GoalLoop-->>GoalCmd: Result<(), CliFailure>
GoalCmd->>OutcomeProj: goal_round_break / goal_unmet_failure
OutcomeProj-->>GoalCmd: CliFailure with AbortKind
GoalCmd->>Daemon: outcome_status(Result<(), CliFailure>)
Daemon-->>Registry: SessionStatus (Stopped | Error | Cancelled)
Registry-->>User: recorded session outcome and exit code
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
…oop-typed-outcome
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.
What & why
The goal loop (
run_goal_cmd/run_goal_turn/run_goal_pipeline_turn) and the deck's lead turn (run_lead_turn/run_lead_pipeline_turn) answered withResult<(), String>, which has no room for the abort's typedAbortKind— so on their paths a deliberate stop (stuck-loop escalation, step cap, enforced budget) was indistinguishable from a crash by the time the terminal SESSIONS-registry status was written. A policy-stopped goal run recordedSessionStatus::Error, neverStopped, and exited1instead of3.This chases #1637's shape one level deeper, exactly along the seam #1862 specs:
stella-core:GoalOutcome::Unmetnow carrieskind: Option<AbortKind>— the typed kind of the working turn's abort,Nonefor the backstops that are not turn aborts (round cap, unreachable verifier).GoalOutcomehas no consumer outsidestella-cli.stella-cligoal loop: the three drivers answer withcrate::failure::CliFailure. The folds that stringifiedPipelineStatus::Aborted/GoalOutcome::Unmetare now shared projections inagent/outcome.rs(goal_round_break,goal_unmet_failure— siblings ofpipeline_status_result/turn_outcome_result, same messages as before), andrun_goal_cmd's terminalpresence.finishprojects the real failure throughdaemon::outcome_statusinstead of a reconstructedCliFailure::error. The inbox notification for a deliberate stop now says "stopped by policy" rather than "FAILED".stella-clideck:run_lead_turn/run_lead_pipeline_turnanswer withCliFailurethrough the existingturn_outcome_result/pipeline_status_resultprojections, and thesession_exitwrite readsdaemon::outcome_status— one decider for every terminal writer (A deliberate stop is recorded in the session registry as Error, indistinguishable from a crash #1653/SessionPresence::finish and the deck's exit writer still collapse a deliberate stop to a bool #1826/The goal loop and the deck's lead turn answer with a String, so their terminal writers cannot record a policy stop #1862).command_deck.rsshrank by 7 lines;agent.rsstayed at its exact ceiling (one line-neutral visibility edit:pub(crate) mod outcome;).Design exemplar: the same total-
matchprojection module patternagent/outcome.rsalready established (andstd's "constructors on the error type" shape forCliFailure::from_abort) — no new patterns invented.Closes #1862
Refs #1826, #1653, #1637
The witness
main, passes here)Same family and justification as #1826's
an_unsupervised_deliberate_stop_projects_stopped_not_error:agent::outcome::tests::a_policy_stopped_goal_round_projects_stopped_not_error— the fold an aborted working round takes to the terminal registry write keepsAbortKind::DeliberateStop, andoutcome_statusprojectsStopped; theFailurekind still projectsError. Fails on the old code the way SessionPresence::finish and the deck's exit writer still collapse a deliberate stop to a bool #1826's witness does: the projection did not exist, and the old fold stringified the status so the terminal write could only reconstructCliFailure::error→Error.agent::outcome::tests::a_policy_stopped_raw_goal_loop_projects_stopped_not_error— the raw (--no-pipeline) half; the kind-less backstops (round cap) stayError.stella-core:goal::tests::session_budget_caps_total_spend_across_roundsnow asserts the enforced-budget stop reachesUnmetasSome(AbortKind::DeliberateStop), andaborted_working_turn_ends_the_goal_loopasserts a provider failure reaches it asSome(AbortKind::Failure)— neither pattern compiles against the old kind-less enum.The gate
cargo fmt --check(touched crates)-D warnings—stella-cli+stella-coreclean. Pre-existing break, not this PR's:stella-pipeline/src/pipeline/witness_stage.rs:55failsclone_on_copyon the base branch and onmain; open unbreak PRs fix(gate): unbreak main — clippy clone_on_copy, file-size baseline, gate-parity step count #1873 / fix(stella-pipeline): unbreak main — two clippy failures merged with #1813 #1859 own it. I verified my crates lint clean with that one line patched locally (patch not included — a peer PR owns the fix).cargo test -p stella-coregoal suite (18/18) andcargo test -p stella-cli --bin stella(1431/1431) — scoped per the 16GB-machine constraint; CI runs the full workspace.RUSTDOCFLAGS="-D warnings" cargo doc -p stella-core -p stella-cli --no-depscleanCloses #1862above and as a commit trailerscripts/check-file-size.shflagsstella-protocol/src/event.rs(+2) andstella-tui/src/deck_render.rs(+3): both overages exist verbatim on the base branch and are named by unbreak PR #1873 — untouched here.Nothing left behind
fix/1826-unsupervised-stop-status) is not merged yet, and this change builds directly on itsfinish(status, …)projections — so this PR targets that branch as base. Retarget tomainafter fix(stella-cli): record a deliberate stop distinctly on the unsupervised writers too (#1826) #1878 merges.3(was1), consistent with the exit-code taxonomy infailure.rsand with what run_resume answers with a String, so a resumed turn's deliberate stop cannot exit 3 #1637 already did for the resume driver;bench/harbor_adapterreads exactly this code. Also the deck's soft-stop (SOFT_STOP_REASON) session exit now records throughoutcome_statuslike every other writer.mainbreaks encountered during verification (pipeline clippy, two file-size overages) are already tracked by open PRs fix(gate): unbreak main — clippy clone_on_copy, file-size baseline, gate-parity step count #1873 / fix(stella-pipeline): unbreak main — two clippy failures merged with #1813 #1859 — nothing new to file.Summary by Sourcery
Preserve typed abort information through goal and lead execution paths so terminal session status and exit codes distinguish deliberate policy stops from crashes.
New Features:
Bug Fixes:
Enhancements:
Tests: