feat(agent): RunSupervisor truncates a hung Run (run-liveness act rung)#393
Merged
Conversation
Completes the autonomy axis's wind-down half: the RunSupervisor already holds and resumes Runs on beam state; its run-liveness rule (a Run Running implausibly long past the operator ceiling) was shadow/advise-only. This adds the act rung, the de-facto-dead detection the original TruncateRun deliberately left to a human (its docstring: "the system itself does not detect de-facto-dead Runs"). When `run_supervisor_truncate_enabled` is on AND a `run_liveness_ceiling_seconds` is set, a Run that reads liveness-stale for `run_supervisor_truncate_settle_ticks` CONSECUTIVE ticks is autonomously truncated: the supervisor records one Decision(context=RunSupervision, choice=Truncate) and issues TruncateRun as the agent principal, linked via decided_by_decision_id, mirroring the beam-Hold act pattern (Decision first, then the authorized command, benign no-op on a state race, loud log + no bypass on an authz denial). Fail-safe by construction: a triple gate (ceiling set, act opt-in default off, settle window default 3) and a consecutive-stale counter that resets on the first non-stale tick, so a transiently-stale or recovering Run is never killed. The ceiling is operator-set to an implausible runtime, and a Run with no running_since is never evaluated (Lock 4: never act on missing data). TruncateRun / RunTruncated gain an additive `decided_by_decision_id` (default None, mirroring HoldRun / RunHeld) so the autonomous truncate links its Decision; operator-driven truncates and legacy streams are unaffected (REST / MCP do not expose it; from_stored reads it via payload.get). A new `Truncate` choice joins RunSupervisionChoice (a bare verb mirroring TruncateRun, as Hold / Resume mirror HoldRun / ResumeRun). Unit tests pin the act rung (disabled no-op, inert without a ceiling, fires only after the settle window with the Decision linked, settle clears on recovery, benign state-race + missing-run + unauthorized no-ops) and the settle-ticks validator. Cleared an adversarial gate review of the terminal action: no blockers; a missing-run race test was added in response. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Coverage reportClick to see where and how coverage changed
This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
…runcate # Conflicts: # apps/api/src/cora/infrastructure/config.py
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
Completes the autonomy axis's wind-down half. The RunSupervisor already holds/resumes Runs on beam state; its run-liveness rule (a Run Running implausibly long past the operator ceiling) was shadow/advise-only. This adds the act rung: the de-facto-dead detection the original
TruncateRundeliberately left to a human ("the system itself does not detect de-facto-dead Runs").When
run_supervisor_truncate_enabledis on and arun_liveness_ceiling_secondsis set, a Run that reads liveness-stale forrun_supervisor_truncate_settle_ticksconsecutive ticks is autonomously truncated: the supervisor records oneDecision(context=RunSupervision, choice=Truncate)and issuesTruncateRunas the agent principal, linked viadecided_by_decision_id— mirroring the beam-Hold act pattern (Decision first, then the authorized command; benign no-op on a state race; loud log + no bypass on an authz denial).Fail-safe by construction
running_sinceis never evaluated (never act on missing data).Provenance
TruncateRun/RunTruncatedgain an additivedecided_by_decision_id(defaultNone, mirroringHoldRun/RunHeld) so the autonomous truncate links its Decision. Operator-driven truncates and legacy streams are unaffected (REST/MCP don't expose it;from_storedreads it viapayload.get). A newTruncatechoice joinsRunSupervisionChoice(a bare verb mirroringTruncateRun, asHold/ResumemirrorHoldRun/ResumeRun).Verification
Unit (supervisor incl. 8 new truncate cases — disabled no-op, inert-without-ceiling, fires-only-after-settle + Decision link, settle-clears-on-recovery, state-race / missing-run / unauthorized no-ops, settle-ticks validator) · run BC 899 · decision vocab · architecture 27,059 · contract 3,225 (bootstrap blast-radius clean; truncate endpoint/MCP/handler round-trip the new field) · ruff + pyright clean. Cleared an adversarial gate review of the terminal action (no blockers; a missing-run race test added in response).
Independent of the RunInitiator work (PR #381) — different agent, branched off main.
🤖 Generated with Claude Code