Skip to content

feat(agent): RunSupervisor truncates a hung Run (run-liveness act rung)#393

Merged
xmap merged 2 commits into
mainfrom
worktree-supervisor-truncate
Jun 26, 2026
Merged

feat(agent): RunSupervisor truncates a hung Run (run-liveness act rung)#393
xmap merged 2 commits into
mainfrom
worktree-supervisor-truncate

Conversation

@xmap

@xmap xmap commented Jun 26, 2026

Copy link
Copy Markdown
Owner

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 TruncateRun deliberately left to a human ("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

  • Triple gate: ceiling set (rule on) + act opt-in (default off) + settle window (default 3).
  • 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; a Run with no running_since is never evaluated (never act on missing data).

Provenance

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 don't 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).

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

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>
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  apps/api/src/cora/agent
  __init__.py
  apps/api/src/cora/api
  _run_supervisor.py 563-564, 959, 962, 970-971
  main.py
  apps/api/src/cora/decision/aggregates/decision
  state.py
  apps/api/src/cora/infrastructure
  config.py
  apps/api/src/cora/operation
  conductor.py
  apps/api/src/cora/operation/aggregates/procedure
  events.py
  apps/api/src/cora/operation/features/end_iteration
  command.py
  apps/api/src/cora/run/aggregates/run
  events.py
  apps/api/src/cora/run/features/truncate_run
  command.py
Project Total  

This report was generated by python-coverage-comment-action

…runcate

# Conflicts:
#	apps/api/src/cora/infrastructure/config.py
@xmap xmap merged commit ea08ec9 into main Jun 26, 2026
16 checks passed
@xmap xmap deleted the worktree-supervisor-truncate branch June 26, 2026 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant