Skip to content

feat(fleet): approved replacement routes for refused first requests - #6438

Merged
Hmbown merged 4 commits into
mainfrom
feat/fleet-approved-replacement-routes
Sep 24, 2026
Merged

Hmbown merged 4 commits into
mainfrom
feat/fleet-approved-replacement-routes

Conversation

@Hmbown

@Hmbown Hmbown commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

No-Issue: 0.10.1 release-readiness recovery and first-call tool work, found in dogfooding; no public issue tracks it.

A saved reviewer pin (xai/grok-4.6) answered its first request with
"Authorization failed: You have run out of credits or need a Grok
subscription." and the agent failed with no review. The only fallback
was the pre-flight SessionFallback for unusable pins; nothing covered a
provider refusing the request itself, and saved routes must not be
silently swapped.

[subagents.roles.<role>] replacements = ["provider/model", ...] lets
the operator approve up to three replacement routes. When the pin's
first request fails with a typed route refusal (QuotaExhausted,
AuthenticationError, AuthorizationError, ModelError) and the agent has
run nothing yet (run_subagent's steps == 1 seam), the same request moves
to the next approved route. The run keeps its role, grants, tool scope,
workspace and budgets: only the request route changes, bound through
the existing provider/model/protocol binders, and each route is tried
once. The existing route receipt records the effective provider/model,
route_source = "role.replacement", and a fallback note with the
original route, reason, provider message (redacted) and attempt.

Not replaced: failures after any tool ran, content-policy /
context-length / invalid-request errors, untyped messages that merely
mention credits, Codewhale permission denials, exact Fleet members and
task-level models. Entries must name their provider explicitly, so the
destination that may receive the task is always operator-chosen;
misconfiguration fails at spawn. Replacement authority is cleared for
every other route source and never inherited by descendants. The
observed Grok error is authorization-class (403), not QuotaExhausted.

Evidence: 114 passed, 0 failed (13,142 skipped) across route_replacement,
roster_routes, launch_receipt, fatal-provider, typed-retry and role-pin
selections; then 5/5 route_replacement tests after adding the spawn
refusal case. The end-to-end test runs a local 403 fixture with the
observed text and an approved backup fixture: the pin is asked once,
the backup completes the review, and the receipt names both routes. A
pin without replacements still fails and never contacts the backup.
TUI all-target/all-feature Clippy with CI flags and fmt passed; dead
code budget unchanged at 279.

🤖 Generated with Claude Code

A saved reviewer pin (xai/grok-4.6) answered its first request with
"Authorization failed: You have run out of credits or need a Grok
subscription." and the agent failed with no review. The only fallback
was the pre-flight SessionFallback for unusable pins; nothing covered a
provider refusing the request itself, and saved routes must not be
silently swapped.

`[subagents.roles.<role>] replacements = ["provider/model", ...]` lets
the operator approve up to three replacement routes. When the pin's
first request fails with a typed route refusal (QuotaExhausted,
AuthenticationError, AuthorizationError, ModelError) and the agent has
run nothing yet (run_subagent's steps == 1 seam), the same request moves
to the next approved route. The run keeps its role, grants, tool scope,
workspace and budgets: only the request route changes, bound through
the existing provider/model/protocol binders, and each route is tried
once. The existing route receipt records the effective provider/model,
`route_source = "role.replacement"`, and a fallback note with the
original route, reason, provider message (redacted) and attempt.

Not replaced: failures after any tool ran, content-policy /
context-length / invalid-request errors, untyped messages that merely
mention credits, Codewhale permission denials, exact Fleet members and
task-level models. Entries must name their provider explicitly, so the
destination that may receive the task is always operator-chosen;
misconfiguration fails at spawn. Replacement authority is cleared for
every other route source and never inherited by descendants. The
observed Grok error is authorization-class (403), not QuotaExhausted.

Evidence: 114 passed, 0 failed (13,142 skipped) across route_replacement,
roster_routes, launch_receipt, fatal-provider, typed-retry and role-pin
selections; then 5/5 route_replacement tests after adding the spawn
refusal case. The end-to-end test runs a local 403 fixture with the
observed text and an approved backup fixture: the pin is asked once,
the backup completes the review, and the receipt names both routes. A
pin without replacements still fails and never contacts the backup.
TUI all-target/all-feature Clippy with CI flags and fmt passed; dead
code budget unchanged at 279.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 23, 2026 15:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

The blocking-call ratchet counted the fixture's std::fs::write inside an
async test path (Lint on #6438). Evidence: route_replacement 5 passed,
0 failed; blocking-call budget 577 sites, within budget.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Hmbown
Hmbown merged commit 9c91380 into main Sep 24, 2026
32 checks passed
@Hmbown
Hmbown deleted the feat/fleet-approved-replacement-routes branch September 24, 2026 05:03
pull Bot pushed a commit to Mu-L/DeepSeek-TUI that referenced this pull request Sep 24, 2026
turn_operation_lookup_is_authenticated_read_only_and_survives_restart
failed on Ubuntu CI (Hmbown#6438 run 35886856223, job 107269234021) with
"Mock Runtime execution scope is already owned" and passed 3/3 locally.
The old test server tears its runtime down on its own thread after the
abort, so its mock TaskManager can still hold the execution-scope owner
lock after the RuntimeThreadManager the test waits on has dropped.
Refusing a second owner is correct product behavior; the restart now
retries only on that refusal, within the existing CI-scaled 10 s
deadline, and any other startup error still fails immediately.

Evidence: the test passes locally (1 passed, 0 failed); hosted load is
the acceptance. TUI all-target/all-feature Clippy with CI flags passed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Hmbown pushed a commit that referenced this pull request Sep 24, 2026
Resolves the child request setup against #6438's route override: the
request and the child's compaction both use the active route_runtime, so a
replacement route's client summarizes its own history.

Tests: cargo test -p codewhale-tui --lib -- tools::subagent compaction
=> 870 passed, 0 failed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

2 participants