perf(agent): execution profiles with one-shot posture escalation (PR10b+PR10c)#740
Conversation
…UI /profile (PR10b+10c)
- fast escalates on critical-risk mutations, not high: the sandbox marks every shell command high before command analysis, so a high trigger spent the one-shot on the first go test of any task - escalation can now restore the provider-default effort a profile displaced (PostureEscalation.RestoreDefaultEffort; a plain empty target means leave untouched) - TUI /turns while a profile is active pins the budget: disarms the escalation turn target (mirroring exec's explicit --max-turns rule) and profile reverts use touched bits instead of value equality, so explicit choices survive even when they coincide with profile values - spec-draft runs get the same escalation policy as the main run instead of the displaced budget with no safety net - bench validates and canonicalizes --exec-profile before spawning: an unknown name previously produced an exit-0 report full of millisecond usage-error walls - turn summary prints exec-profile alongside mode; zero exec rejects an inline-empty --exec-profile=; balanced trace label documented and pinned as deliberate attribution
…t restore An explicit effort set AFTER profile selection could be cleared by a mid-run escalation (the effort analog of the /turns pin, introduced by RestoreDefaultEffort): TUI /effort and Ctrl+T now disarm the restore on a policy clone, and the spec-draft path only arms it when no explicit --spec-reasoning-effort governs the draft.
Zero automated PR reviewVerdict: No blockers found Blockers
Validation
ScopeHead: This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality. |
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 16 minutes Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughChangesThe PR adds balanced, fast, and thorough execution profiles across the CLI and TUI. Profiles tune agent posture, preserve explicit overrides, propagate through spec and benchmark runs, and appear in traces and turn-benchmark results. Execution profiles
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant zero_exec
participant execprofile
participant agent_Run
participant trace_Recorder
User->>zero_exec: Select --exec-profile
zero_exec->>execprofile: Lookup profile and build policy
execprofile-->>zero_exec: Profile settings and escalation policy
zero_exec->>agent_Run: Run with profile options
zero_exec->>trace_Recorder: Record selected profile name
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/cli/exec_parse.go`:
- Around line 150-162: Update the exec option validation flow after
`--exec-profile` application so profiles that enable self-correction cannot
remain active with `--use-spec`; reject this combination consistently with
explicit `--self-correct`. Use the existing profile application and validation
symbols in `internal/cli/exec_parse.go`, preserving current behavior for
compatible profiles rather than silently dropping self-correction.
In `@internal/perfbench/turn_bench.go`:
- Line 224: Update RunTurnBench to normalize and validate cfg.ExecProfile once
via execprofile.Lookup at the boundary, then use the returned canonical profile
name for both RunContext.ExecProfile and TurnBenchResult. Ensure equivalent
inputs such as whitespace- or case-variant “fast” produce the same execution
behavior and report label.
In `@internal/tui/profile_command_test.go`:
- Around line 172-175: Update the test around handleProfileCommand("fast") so an
unexpected reasoningEffort value fails the test instead of calling t.Skipf.
Preserve the assertion that the catalog supplies the expected low effort,
ensuring the effort-restore disarming path remains covered.
In `@internal/tui/session_controls.go`:
- Around line 394-399: Update the restoration branch in the session control
logic around execProfileDisplacedMaxTurns so restoring a displaced value of zero
also clears the profile-applied max-turns environment variable; retain
SetMaxTurnsEnv for positive values and explicitly unset or reset the environment
when the displaced value is zero.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e92ba83e-f97c-4bb9-b9cc-ca175e1dae58
📒 Files selected for processing (20)
cmd/zero-perf-bench/turn.gocmd/zero-perf-bench/turn_test.gointernal/agent/loop.gointernal/agent/profile_controller_test.gointernal/agent/types.gointernal/cli/app.gointernal/cli/exec.gointernal/cli/exec_parse.gointernal/cli/exec_profile_test.gointernal/cli/exec_spec.gointernal/cli/exec_test.gointernal/execprofile/profile.gointernal/execprofile/profile_test.gointernal/perfbench/taskbench.gointernal/perfbench/turn_bench.gointernal/perfbench/turn_bench_test.gointernal/tui/commands.gointernal/tui/model.gointernal/tui/profile_command_test.gointernal/tui/session_controls.go
- --use-spec projects away a profile's self-correct knob instead of silently arming an option the draft runner ignores (the explicit --self-correct --use-spec combination is already a parse-time error) - RunTurnBench canonicalizes and validates ExecProfile at the library boundary, so a direct caller's casing/whitespace cannot fork report labels and an unknown name fails before anything runs - reverting a profile whose displaced budget was zero clears ZERO_MAX_TURNS (SetMaxTurnsEnv ignores zero, so sub-agents would have kept the removed profile's budget) - the TUI effort-disarm test fails instead of skipping when the catalog stops filling low effort
|
All four addressed in 1c56a40:
|
gnanam1990
left a comment
There was a problem hiding this comment.
APPROVE (code) — high quality, thoroughly verified. One pre-merge requirement: rebase off the stacked chain (it genuinely cannot merge before #736).
Reviewed across 7 dimensions with an independent verifier re-checking each finding against the code. 0 logic blockers, 0 logic majors.
Verified correct:
- Precedence (flag > mode > profile):
applyExecProfileruns afterapplyExecModewith fill-only-if-unset; an explicit-r, a mode's effort, or--spec-reasoning-effortis never overwritten. ✅ - Balanced is byte-identical:
Balanced = Profile{Name:"balanced"}→ nil policy, fills nothing; asserted byreflect.DeepEqualinTestExecProfileBalancedLeavesOptionsUntouched. ✅ RestoreDefaultEffort: armed only when the profile actually filled effort (reasoningEffort=="" && profile.ReasoningEffort!=""); honored only when the target effort is empty (loop.go:203-207); disarmed on every user path (/effort, Ctrl+T, --spec-reasoning-effort) via policy-clone. #736 one-shot invariant intact. ✅- TUI /profile: never stacks (reverts before applying), revert is coincidence-safe (restores a knob only if untouched AND still equal to the applied value), /turns pins the budget by disarming the escalation turn target — all clone-by-value. ✅
- perfbench: schema v4→v5 additive-only, name validated/canonicalized before spawning, forwarded+stamped+printed next to
mode:, omitempty when unset; baseline.json diff empty. ✅ - Risk trigger =
criticalnothigh— sound rationale (sandbox floors shell at high). ✅
Findings:
1. [Major — process] Stacked on 5 unmerged PRs. upstream/main..pr740 = 8 commits; only the top 3 are real PR10b/c — the lower 5 are #737/#736/#730/#734/#732. Merging as-is drags their diffs into main and conflicts when they land on their own. Genuine hard dependency: loop.go/types.go here consume RestoreDefaultEffort/RestoreCompletionGate from #736, so this cannot merge before #736. Enforce merge order (#730→#732→#734→#736→#737), then rebase; review the isolated git diff 015452c..pr740 (~20 files).
2. [Nit] applyProfileTurnBudget(… explicitMaxTurns int …) also receives a mode-filled budget, so the name misleads (behavior is correct — mode must block the profile). Rename to pinnedMaxTurns or add a comment.
3. [Nit] ZERO_MAX_TURNS not cleared on revert when the displaced budget was 0 (session_controls.go:395-398 + SetMaxTurnsEnv no-op for n≤0). Effectively unreachable (TUI budget defaults to 80, only 0 on a failed config resolve), but unconditionally restoring/clearing on revert would close it.
Ship-quality once rebased. Merge is kevin's call per the program gate, after the base chain lands.
anandh8x
left a comment
There was a problem hiding this comment.
Reviewed latest head 1c56a40. The follow-up correctly fixes the benchmark boundary normalization and validation, zero-budget environment restoration, and the skipped effort regression; the spec-safe projection is coherent for a draft-only run. One TUI correctness blocker remains: active profile effort is applied only when /profile is selected, but both model-switch paths can change the model afterward without reconciling that profile state. For example, select fast on gpt-4.1 where low is unsupported, then switch through the provider/model picker to claude-sonnet-4.5: execProfileName remains fast, but reasoningEffort stays auto, so the next run is labeled fast without the catalog's low effort. The reverse cross-provider switch can retain a profile-applied effort unsupported by the destination. Reconcile an untouched active profile after both handleModelCommand and switchProviderModel: remove the old profile-applied effort, apply its configured level when the destination supports it, and update RestoreDefaultEffort consistently, while preserving explicitly touched effort choices. Please add regressions for unsupported-to-supported and supported-to-unsupported switches. Focused profile race tests, vet, formatting, diff hygiene, and govulncheck pass on this head.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/tui/profile_command_test.go`:
- Around line 167-185: Update TestProfileCommandRevertFromZeroClearsMaxTurnsEnv
to use os.LookupEnv for config.MaxTurnsEnv after reverting the profile, and fail
if the key is still present regardless of its value. Preserve the existing
expectation that the environment entry is removed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0b7b6728-2214-4400-bf60-427720962b14
📒 Files selected for processing (6)
internal/cli/exec.gointernal/cli/exec_profile_test.gointernal/perfbench/turn_bench.gointernal/perfbench/turn_bench_test.gointernal/tui/profile_command_test.gointernal/tui/session_controls.go
🚧 Files skipped from review as they are similar to previous changes (5)
- internal/perfbench/turn_bench_test.go
- internal/perfbench/turn_bench.go
- internal/cli/exec_profile_test.go
- internal/cli/exec.go
- internal/tui/session_controls.go
The fill is per-model, not a session preference: fast selected on a model without low fills nothing, and switching to a model that supports it should behave like selecting the profile there; the reverse switch must not keep sending a level the destination does not support. Both switch paths (the /model command and the cross-provider picker) now re-derive the fill, leaving explicitly touched efforts alone and keeping the escalation's effort restore in step. Also: the revert-env test asserts key removal via LookupEnv, and applyProfileTurnBudget's pinned-budget parameter is named and documented as covering mode presets, not just the flag.
|
All addressed in b621b5b. @anandh8x, good catch on the model-switch hole. Both switch paths (the /model command and the cross-provider picker) now call a shared reconcile step after the model changes: an untouched active profile re-derives its effort fill for the destination, so unsupported-to-supported fills the profile's level exactly as selecting it there would, supported-to-unsupported drops back to the model default instead of carrying a level the destination cannot take, and the escalation's effort restore arms/disarms in step. Explicitly touched efforts are never reconciled. Regressions added for all three: TestProfileEffortReconciledOnModelSwitch covers both directions end to end through switchProviderModel (real catalog model with low support on one side, custom no-catalog model on the other), and TestProfileEffortTouchedSurvivesModelSwitch pins the touched case. @gnanam1990, on the stacked-chain finding: I think your local upstream/main is behind. The branch is cut from 015452c, which is current main and already contains the whole chain merged (#730 dbd9443, #732/#734, #736 af875df, #737 015452c itself). GitHub's compare against main shows only this PR's 20 files, and there is nothing to rebase onto; a fresh fetch should show origin/main..this-branch as just the PR commits. The #736 dependency you flagged is real and satisfied, since #736 merged yesterday. Your env-clear nit landed one commit before your review (1c56a40), and the pinned-budget parameter is renamed with the mode case documented. CodeRabbit's LookupEnv tightening on the revert test is in as well. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/tui/command_center.go`:
- Around line 474-477: Preserve explicitly touched reasoning effort during
direct model switches: in internal/tui/command_center.go lines 474-477, update
the handleModelCommand reconciliation flow so unsupported destinations drop only
profile-filled effort, not a user-set effort, and let
reconcileProfileAfterModelSwitch apply the profile rules. Add the equivalent
explicit-effort scenario through handleModelCommand in
internal/tui/profile_command_test.go lines 76-93, verifying the touched effort
remains unchanged when switching to an unsupported model.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 4b1120dd-6593-42a1-9478-248512686d61
📒 Files selected for processing (4)
internal/cli/exec.gointernal/tui/command_center.gointernal/tui/profile_command_test.gointernal/tui/session_controls.go
🚧 Files skipped from review as they are similar to previous changes (2)
- internal/tui/session_controls.go
- internal/cli/exec.go
…erases it The /model path's pre-existing unsupported-effort drop ran before the profile reconciliation and left contradictory state behind: a dropped touched override kept blocking the profile from governing, and a dropped profile fill left a stale applied value with the effort restore still armed. The drop itself is load-bearing (the TUI run path forwards the effort to the provider unfiltered), so instead of preserving a known-unsupported level, the voided choice now resets the profile's effort bookkeeping and the reconcile re-derives from scratch. The whole sequence lives in one ring-parameterized helper driven by the switch target's authoritative ring, unit-tested against synthetic rings for both the void-then-refill arc and the supported-override survival.
|
Fixed in 86c2c03, with one deliberate divergence from the literal suggestion. Preserving a touched effort through the drop is not safe here: the TUI run path forwards m.reasoningEffort to the provider unfiltered (model.go, options.ReasoningEffort = string(m.reasoningEffort)), so a KNOWN-unsupported level surviving the switch goes straight into requests. That drop predates profiles and applies to a plain explicit effort too; a profile-touched effort should not be stickier than a plain one. What was genuinely wrong, and is now fixed: the drop ran before the reconciliation and left contradictory profile state behind. A dropped touched override kept blocking the profile from governing, and a dropped profile fill left a stale applied value with the effort restore still armed. Now the whole sequence lives in one helper driven by the switch target's authoritative ring: drop a known-unsupported preference, void the profile's effort bookkeeping when the drop erased its fill or an override of it, then re-derive the fill for the destination. So /profile fast, /effort high, then /model to a ringless model lands on auto with clean state, and a later switch to a low-supporting model fills the profile's low again with the restore re-armed. The difference from switchProviderModel is intentional and now documented at that call site: cross-provider targets are often custom models the catalog cannot vouch for either way, so an explicit preference is carried there (pre-existing behavior) while the profile's own fill stays conservative. Tests: the void-then-refill arc and the supported-override survival are covered against synthetic rings (TestProfileEffortVoidedByModelSwitchDrop, TestProfileEffortTouchedSurvivesSupportedModelSwitch), alongside the existing end-to-end switch tests. |
anandh8x
left a comment
There was a problem hiding this comment.
Re-reviewed latest head 86c2c03. The original model-switch blocker and the follow-on touched-effort inconsistency are resolved. Both switch paths now re-derive profile-filled effort for the destination; known-unsupported explicit effort is dropped without leaving stale touched/applied/restore state, supported destinations refill the profile, and unknown custom-provider models conservatively retain explicit user intent. The escalation restore flag stays synchronized. Focused TUI/profile race tests, vet, and diff hygiene pass. Approving.
gnanam1990
left a comment
There was a problem hiding this comment.
Re-approve — all my prior findings are resolved and the base is now clean.
1. Stacking (my prior Major) — RESOLVED. The base chain (#730/#732/#734/#736/#737) merged; upstream/main..pr740 is now just the 6 PR10b/c commits and the diff is the real ~21 files (+1605/-28), no longer inflated. The #736 dependency is satisfied on main.
2. Nit (param naming) — FIXED. applyProfileTurnBudget(explicitMaxTurns …) → pinnedMaxTurns, with a comment noting it covers a mode-preset fill too.
3. Nit (ZERO_MAX_TURNS on revert) — FIXED. revertExecProfile now os.Unsetenv(MaxTurnsEnv) when the displaced budget was 0, so spawned sub-agents can't inherit a removed profile's budget; covered by TestProfileCommandRevertFromZeroClearsMaxTurnsEnv.
New since my last pass — model-switch effort reconciliation, verified correct: reconcileEffortForModelSwitch/reconcileProfileAfterModelSwitch re-derive an active profile's per-model effort fill across switches — supported→unsupported clears the fill and disarms RestoreDefaultEffort; the reverse refills and re-arms; an explicitly touched effort is never reconciled; policy edits are clone-by-value so an in-flight run isn't mutated. Symmetric and correct, with 4 new directional tests. The spec-safe profile.SelfCorrect && !options.useSpec projection is a sensible edge fix.
Ran go test ./internal/tui ./internal/execprofile ./internal/cli ./internal/agent -run 'Profile|ExecProfile|Posture|Escalat|ModelSwitch' on the PR head — all green.
Ship-quality. Note CodeRabbit still shows CHANGES_REQUESTED from earlier commits — worth confirming those threads are addressed/dismissed before merge. Merge is kevin's per the gate.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/tui/command_center.go`:
- Around line 467-472: Update the model-switch reconciliation around
reconcileEffortForModelSwitch to pass whether target.reasoningEfforts is
authoritative, so explicit effort is dropped only when supported levels are
known to be unavailable; preserve explicit effort when the ring is nil because
support metadata is unknown. In internal/tui/profile_command_test.go lines
77-124, add separate coverage for authoritative-empty and unknown rings,
asserting reset behavior only for the former.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3ac8db5d-bbb4-4112-9509-79c428820f4d
📒 Files selected for processing (3)
internal/tui/command_center.gointernal/tui/profile_command_test.gointernal/tui/session_controls.go
🚧 Files skipped from review as they are similar to previous changes (1)
- internal/tui/session_controls.go
…itative A nil ring meant both a catalog model with no effort controls and a live-discovered custom model the catalog cannot vouch for. The drop now requires an authoritative ring (a resolved catalog entry, whose ring may legitimately be empty); an unknown ring preserves an explicit preference, matching the cross-provider picker's behavior, while the profile's own fill still applies only where support is known.
|
Point taken, fixed in 6778eb5. The drop now requires an authoritative ring: reconcileEffortForModelSwitch takes ringKnown (target.entry != nil), so a catalog model with a legitimately empty ring still drops a known-unsupported preference, while a live-discovered/custom target with no catalog entry preserves an explicit choice, matching the cross-provider picker. The profile's own fill is unchanged in both regimes: it only ever applies where support is known. Both regimes are tested separately (TestProfileEffortVoidedByModelSwitchDrop for authoritative-empty, TestProfileEffortUnknownRingPreservesExplicitChoice for unknown, including the untouched-fill retreat). For anyone skimming this thread: the other four comments in this round are re-posts of findings already resolved in 1c56a40 and b621b5b, and each carries its own addressed marker. |
gnanam1990
left a comment
There was a problem hiding this comment.
Re-approve (head 6778eb5). One new commit since my last pass — fix(tui): only drop an explicit effort when the target ring is authoritative — reviewed and correct.
It fixes an over-eager drop: previously a nil effort ring was treated as unsupported and cleared an explicit effort, but nil conflated a catalog model with no effort controls (authoritatively empty → drop is right) with a live-discovered/custom model the catalog can't vouch for (unknown → dropping a valid preference is wrong). The new ringKnown flag gates the drop on an authoritative ring (target.entry != nil); an unknown ring preserves the explicit preference, matching the cross-provider picker, while the profile's own fill stays conservative (applies only where support is known).
Verified:
- Callers consistent:
handleModelCommandpassestarget.entry != nil; the cross-providerswitchProviderModeluses only the conservativereconcileProfileAfterModelSwitchretreat (never the drop). ✅ - Tests updated coherently —
(nil, true)still drops (authoritative-empty ring), newTestProfileEffortUnknownRingPreservesExplicitChoicecovers(nil, false)for both an explicit choice (survives) and an untouched profile fill (retreats, restore disarmed). ✅ - Ran
go test ./internal/tui ./internal/execprofile ./internal/cli -run 'Profile|ExecProfile|ModelSwitch|Effort'on the head — all green.
All prior findings remain resolved (stacking, param naming, ZERO_MAX_TURNS revert). Ship-quality; merge is kevin's per the gate.
PR10b + PR10c of the performance program in one PR: user-visible execution profiles on every surface, built on the escalation machinery that landed inert in #736.
What this adds
zero exec --exec-profile fast|balanced|thorough: a loop-posture bundle (turn budget, reasoning effort, self-correction, escalation triggers). It composes with--mode: the mode picks what runs, the profile picks how hard the loop tries. Precedence is explicit flag > mode > profile, enforced by applying the profile last with the same fill-only-if-unset rule modes use. Unknown names are a usage error listing the valid ones; the legacy inert--profileis untouched and the two coexist (test extended)./profilewith the same catalog, applying to the next run. Profiles never stack (switching reverts first), and reverts only restore knobs the user has not explicitly touched since.zero-perf-bench turn --exec-profile: forwarded to every task invocation and stamped into the result (schema v5, additive only), printed in the summary next tomode:, so an A/B capture is self-describing. The bench validates and canonicalizes the name before spawning anything; an unknown name previously produced an exit-0 report whose walls were millisecond usage-error exits.--trace), balanced included, by design.The catalog
balancedis the empty profile. Selecting it changes nothing: options, turn budget, and loop behavior are identical to an unflagged run, asserted by test. Only the opt-in trace/bench artifacts record the name.fast: 30 turns, low effort, all four escalation triggers armed. When trouble hits (a same-tool failure streak, a second uncertain completion, a failing self-correct cycle, or a critical-risk mutation), a one-shot escalation restores the displaced posture: the pre-profile turn budget and the provider-default effort. The risk trigger is deliberately critical, not high; the sandbox floors every shell command at high before any command analysis, so a high threshold would spend the one-shot on the firstgo testof any real task.thorough: 160 turns, high effort, full self-correct. Already the maximum posture, so no triggers.Restoring the displaced effort needed a small addition to the #736 surface:
PostureEscalation.RestoreDefaultEffort. A profile only ever fills effort that was unset, so the displaced value is the provider default, and a plain empty target already means "leave untouched". The flag is armed only when the profile actually performed the fill; an explicit-r, a mode's effort, an explicit--spec-reasoning-efforton the draft path, or a TUI/effort/Ctrl+T choice made after selecting the profile all keep or regain control (the TUI disarms the restore on the policy clone, the same way/turnsunder a profile pins the budget by disarming the escalation's turn target).Tuning status, honestly
The Fast/Thorough numbers are provisional floors from the Phase 0 baseline's read-class evidence and are pinned by test so a retune is a visible diff. The mutating classes produced no successful samples to tune from (see the baseline investigation and #737), so the Fast-vs-Balanced A/B with the pass-rate gate comes with the post-#737 re-capture; the escalation safety net is what makes shipping provisional values safe in the meantime.
Program gates
Testing
internal/execprofile(catalog invariants, displaced-values-only escalation), cli (precedence, budget displacement, balanced identity, usage errors, full echo-provider runs asserting the trace stamp), tui (posture apply, pin/disarm, coincidence-safe reverts), perfbench + bench cmd (passthrough, validation, normalization, schema pin).go build ./...,go vet ./..., gofmt clean; agent, cli, execprofile, perfbench, tui, and bench-cmd suites pass locally (the two known environment-dependent failures on this machine, the symlink-privilege serve test and the alt-screen scroll test, fail identically on main).Summary by CodeRabbit
balanced,fast,thorough.--exec-profilesupport to execution and turn-benchmark commands, including stamping the selected profile into benchmark output; bumped turn benchmark schema to record it./profilecontrols for selecting and switching profiles.zero exechelp and benchmark summaries to reflect exec-profile behavior.