Skip to content

feat(orchestrator): budget-pressure steering + non-destructive cutoff (IDE-210) - #71

Merged
mattias-ident merged 2 commits into
mainfrom
mattias/ide-210-layer-0-budget-pressure-steering-non-destructive-cutoff-ide
Jun 17, 2026
Merged

feat(orchestrator): budget-pressure steering + non-destructive cutoff (IDE-210)#71
mattias-ident merged 2 commits into
mainfrom
mattias/ide-210-layer-0-budget-pressure-steering-non-destructive-cutoff-ide

Conversation

@mattias-ident

Copy link
Copy Markdown

Context

IDE-189: a near-cap run was stopped with converging work that was never committed, so the fresh restart lost it (a brand-new untracked file). This adds steering + a non-destructive safety net.

TL;DR

Steer the agent to commit near the turn cap, and snapshot any dirty tree to a WIP ref before stopping a session.

Summary

  • New SymphonyElixir.Git.preserve_uncommitted_work/4: temp-index commit-tree snapshot to refs/symphony/wip/<id> (captures modified + staged + untracked); non-destructive (no HEAD/branch/worktree mutation); no-op on clean tree; local + SSH paths.
  • Mechanism A (steering): append_budget_pressure_directive/2 seam in agent_runner.ex, injected on continuation turns within agent.budget_pressure_turns of the cap, never on the final turn.
  • Mechanism B (cutoff): preservation fires in terminate_running_issue (terminal/Backlog/non-active/stall/dependency/shutdown) and on the :max_turns_reached DOWN path, before any workspace reclaim.
  • New global agent.* config: budget_pressure_turns (2), preserve_uncommitted_work (true), preserve_uncommitted_work_branch (false), cutoff_timeout_ms (60000) + Config accessors.
  • Docs updated: SPEC.md (§6, §9.4.1, config defaults), WORKFLOW.md, README.md, elixir/README.md.

Alternatives

  • git stash create rejected: it silently drops untracked files — exactly the IDE-189 stranded work.
  • before_remove hook rejected: only fires on workspace deletion; the max_turns/Backlog stops keep the workspace, so it would never run.

Test Plan

  • make -C elixir all
  • mix test test/symphony_elixir/git_test.exs (non-destructive capture, clean no-op, non-git, branch, HEAD-less, ref sanitization)
  • orchestrator e2e: :max_turns_reached DOWN + Backlog/non-active stop both preserve a dirty workspace to a WIP ref (IDE-189 regression)
  • steering unit tests (pluralization, threshold, no-op on final turn)
  • Manual live check (operator w/ Anthropic key): one near-budget claude turn observes the commit — best-effort; correctness guaranteed by Mechanism B

mattias-ident and others added 2 commits June 17, 2026 20:58
… (IDE-210)

Add two adapter-agnostic mechanisms so converging agent work is not lost
when a run approaches its continuation cap (IDE-189):

- Mechanism A (steering): inject a budget-pressure directive into the
  continuation prompt within `agent.budget_pressure_turns` of `max_turns`,
  telling the agent to commit now via the `commit` skill. Best-effort.
- Mechanism B (cutoff): new `SymphonyElixir.Git.preserve_uncommitted_work/4`
  snapshots a dirty tree (modified + staged + untracked) to a
  `refs/symphony/wip/<id>` commit via temp-index `commit-tree`, without
  touching HEAD, the branch, or the working tree. Fired before every session
  stop and on the `max_turns_reached` cutoff. This is the correctness
  guarantee; preservation is gated on `agent.preserve_uncommitted_work`.

New config: `agent.budget_pressure_turns`, `preserve_uncommitted_work`,
`preserve_uncommitted_work_branch`, `cutoff_timeout_ms`. Docs updated in
SPEC.md (§6, §9.4.1), README.md, elixir/README.md, WORKFLOW.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…-0-budget-pressure-steering-non-destructive-cutoff-ide
@mattias-ident mattias-ident added the symphony Symphony orchestrator workflow / agent label Jun 17, 2026
@mattias-ident
mattias-ident merged commit e019751 into main Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

symphony Symphony orchestrator workflow / agent

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant