Skip to content

fix(auth-profiles): repair stale auto runtime auth selection#87893

Closed
osolmaz wants to merge 13 commits into
mainfrom
codex/85126-auth-profile-recovery
Closed

fix(auth-profiles): repair stale auto runtime auth selection#87893
osolmaz wants to merge 13 commits into
mainfrom
codex/85126-auth-profile-recovery

Conversation

@osolmaz

@osolmaz osolmaz commented May 29, 2026

Copy link
Copy Markdown
Member

Summary

Control UI sessions could inherit a temporary fallback auth/model choice as if it were a real user choice.
That made a fresh WebChat/TUI session show or start from the fallback provider instead of the agent primary.
This change treats runtime-only auto auth fallback state as temporary, repairs it back to the configured primary, and keeps the auth resolver provider-scoped.

AI-assisted: yes.

Fixes #85126.

What Changed

The fix stays inside core session/model selection.
It does not add config, plugin SDK, plugin runtime, manifest, or provider contract surface.

  • Added an internal helper for the bad persisted shape: auto auth profile plus runtime provider/model, with no durable model override.
  • Made createModelSelectionState switch that shape back to the configured primary and clear stale runtime/auth fields together.
  • Made gateway model resolution ignore those stale runtime fields before dispatch/preflight code uses them.
  • Stopped sessions.create from copying runtime-only auto fallback auth/model state from a parent into a fresh dashboard session.
  • Added regressions for MiniMax primary plus DeepSeek runtime/auth fallback, gateway model resolution, and dashboard session creation.

Testing

I tested the focused state repair path locally, then ran the changed type/lint/guard gate remotely.
The remote broad proof used AWS Crabbox because Blacksmith Testbox was unavailable in this environment (blacksmith CLI was missing).

  • ./node_modules/.bin/oxfmt --write --threads=1 src/sessions/model-overrides.ts src/auto-reply/reply/model-selection.ts src/gateway/session-utils.ts src/gateway/server-methods/sessions.ts src/auto-reply/reply/model-selection.test.ts src/gateway/session-utils.test.ts src/gateway/server.sessions.create.test.ts
  • git diff --check
  • node scripts/run-vitest.mjs src/auto-reply/reply/model-selection.test.ts src/gateway/session-utils.test.ts src/gateway/server.sessions.create.test.ts src/sessions/model-overrides.test.ts src/agents/auth-profiles/session-override.test.ts src/agents/agent-scope.test.ts
  • node scripts/run-vitest.mjs src/auto-reply/reply/agent-runner-execution.test.ts -t "auto fallback"
  • node scripts/crabbox-wrapper.mjs run --provider aws --idle-timeout 90m --ttl 240m --timing-json --shell -- "pnpm check:changed"

Behavior addressed: runtime-only auto fallback auth/model state no longer pins a session to the fallback provider when the configured primary should be selected.
Real environment tested: local macOS worktree with synthetic session-store regressions; AWS Crabbox Linux changed gate.
Exact steps or command run after this patch: the commands listed above.
Evidence after fix: focused Vitest regressions passed; pnpm check:changed passed on AWS Crabbox provider aws, lease cbx_0417338a2dcb, run run_9b21f45d5a7d, exit code 0.
Observed result after fix: a session with primary minimax/MiniMax-M2.7, runtime deepseek/deepseek-v4-flash, and auto deepseek:default auth resolves back to MiniMax and clears stale runtime/auth fields before the next dispatch.
What was not tested: live MiniMax/DeepSeek provider credentials and a forced real provider fallback were not used; the proof is synthetic plus type/lint/guard coverage.

Risks

The behavior change is narrow and source-gated.
It only applies when the auth profile source is auto, an auth profile is present, and there is no persisted model override.

  • User model overrides still win through providerOverride/modelOverride.
  • User auth profiles are not treated as auto fallback state.
  • Normal auto fallback overrides with persisted provider/model provenance still use the existing primary-probe path.

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: M maintainer Maintainer-authored PR labels May 29, 2026
@clawsweeper

clawsweeper Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 3, 2026, 12:48 PM ET / 16:48 UTC.

Summary
The PR adds stale auto runtime auth/model detection and routes run selection, preflight, display, and child-session inheritance through selected-model handling instead of blindly trusting persisted runtime fallback fields.

PR surface: Source +355, Tests +1128. Total +1483 across 15 files.

Reproducibility: yes. Current main source shows persisted runtime model fields win in resolveSessionModelRef and are inherited by sessions.create; the PR’s fixtures encode the stale auto-fallback shapes that cause the wrong selected/active model behavior.

Review metrics: 1 noteworthy metric.

  • Persisted session fields cleared: 10 fields. The stale auto-runtime repair can delete this clear-list from existing session rows, so maintainers should inspect the compatibility boundary before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Get explicit maintainer acceptance of the stale predicate and cleared-field list before marking the draft ready.

Risk before merge

  • [P2] The stale repair can delete existing persisted runtime/auth/context/fallback-notice fields; an overbroad predicate would change provider or auth selection after upgrade.
  • [P1] The PR intentionally keeps a split between generic runtime identity and next-run selected model resolution; maintainers should accept that narrow split while the broader resolver cleanup remains in Refactor session model/auth state resolution #87957.
  • [P2] Proof is strong synthetic coverage plus reported AWS Crabbox changed-gate output, but it does not include live MiniMax/DeepSeek or equivalent forced provider fallback with real credentials.

Maintainer options:

  1. Accept the narrow repair (recommended)
    A maintainer can approve the stale predicate and clear-list semantics as the intended bug fix, with the broader resolver consolidation left to the open follow-up issue.
  2. Consolidate before merge
    If maintainers do not want an interim resolver split, ask for the PR to move more raw session interpretation behind one canonical resolver before merge.
  3. Require live fallback proof
    If synthetic fixtures are not enough for this auth/provider risk, ask for redacted live provider fallback proof before approving.

Next step before merge

  • [P2] Human maintainer review is the next action because the PR is draft/protected and intentionally changes persisted auth/session fallback semantics without a concrete automated repair finding.

Security
Cleared: No supply-chain, dependency, workflow, or secret-handling regression was found; auth-provider behavior risk is tracked as merge risk rather than a concrete security defect.

Review details

Best possible solution:

Land only after a maintainer explicitly accepts the stale predicate, cleared-field list, and narrow resolver split, while leaving the broader raw session model/auth refactor to #87957.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main source shows persisted runtime model fields win in resolveSessionModelRef and are inherited by sessions.create; the PR’s fixtures encode the stale auto-fallback shapes that cause the wrong selected/active model behavior.

Is this the best way to solve the issue?

Yes, as an immediate repair. The PR keeps the fix in core session/model selection, adds a shared stale predicate across run selection, display, inheritance, and preflight, and avoids new config/API surface; the broader cleanup can stay in the linked follow-up.

AGENTS.md: found and applied where relevant.

Codex review notes: reasoning high; reviewed against 158c4d75402d.

Label changes

Label justifications:

  • P1: The PR affects active WebChat/TUI/gateway session routing where stale auth-provider state can start user runs on the wrong provider.
  • merge-risk: 🚨 compatibility: Existing persisted session rows matching the stale predicate will be interpreted differently and have runtime/auth fields cleared.
  • merge-risk: 🚨 auth-provider: The changed behavior decides whether auto auth profile fallback state remains selected or is repaired back to the configured provider.
  • merge-risk: 🚨 session-state: The patch changes session inheritance, display, next-run resolution, and cleanup of persisted session state.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body and follow-up comments include after-fix focused regression output and an AWS Crabbox changed-gate run; live provider credentials were explicitly not used.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body and follow-up comments include after-fix focused regression output and an AWS Crabbox changed-gate run; live provider credentials were explicitly not used.
Evidence reviewed

PR surface:

Source +355, Tests +1128. Total +1483 across 15 files.

View PR surface stats
Area Files Added Removed Net
Source 8 400 45 +355
Tests 7 1128 0 +1128
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 15 1528 45 +1483

What I checked:

  • Repository policy applied: Root AGENTS.md and scoped gateway/server-methods AGENTS.md were read; their auth/session compatibility and gateway hot-path review guidance apply to this PR. (AGENTS.md:13, 158c4d75402d)
  • Current main trusts runtime model fields: On current main, resolveSessionModelRef returns persisted modelProvider/model before falling back to configured defaults, which explains how stale runtime fallback fields can win on read paths. (src/gateway/session-utils.ts:1627, 158c4d75402d)
  • Current main inherits parent runtime/auth fields: Current sessions.create inheritance copies parent modelProvider, model, contextTokens, authProfileOverride, and authProfileOverrideSource without stale-auto filtering. (src/gateway/server-methods/sessions.ts:179, 158c4d75402d)
  • PR adds a narrow stale predicate and clear list: The PR marks stale auto runtime auth state only when auto auth provenance, runtime provider/model, no durable override, and expected selection mismatch all hold, then clears the stale runtime/auth/context/fallback-notice fields. (src/sessions/model-overrides.ts:42, b0d73d733352)
  • PR repairs run selection before auth resolution: createModelSelectionState computes the expected selected model, switches stale auto runtime auth state back to that selection, and clears the stale fields before later auth-profile validation. (src/auto-reply/reply/model-selection.ts:249, b0d73d733352)
  • PR separates next-run selection from generic runtime identity: resolveSessionNextRunModelRef ignores stale auto runtime auth fields for dispatch/preflight while resolveSessionModelRef still preserves recorded runtime identity for generic history/read callers. (src/gateway/session-utils.ts:1757, b0d73d733352)

Likely related people:

  • Peter Steinberger: Recent commits touched gateway session metadata, session store behavior, and normalization around the same session-utils/server-methods surfaces. (role: recent area contributor; confidence: medium; commits: 2682c027746b, db4990d2605b, 00d8d7ead059; files: src/gateway/session-utils.ts, src/gateway/server-methods/sessions.ts, src/sessions/model-overrides.ts)
  • Vincent Koc: Recent current-main history and blame show work in gateway session utilities and adjacent session-store guard code. (role: recent area contributor; confidence: medium; commits: 207359a056b9, 158c4d75402d; files: src/gateway/session-utils.ts, src/gateway/server-methods/sessions.ts)
  • Frank Yang: Auth/model fallback reset cleanup in model-overrides and gateway session reset is directly adjacent to the stale auto fallback state being repaired here. (role: introduced adjacent behavior; confidence: medium; commits: 5d46e4dc4f45; files: src/sessions/model-overrides.ts, src/gateway/session-reset-service.ts)
  • Neerav Makwana: Recent auto-reply work cleared legacy auto fallback pins in the same run-selection area this PR extends. (role: adjacent fallback owner; confidence: medium; commits: 711ab45025a2; files: src/auto-reply/reply/model-selection.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aa76c28708

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/sessions/model-overrides.ts Outdated
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels May 29, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 29, 2026
@osolmaz

osolmaz commented May 29, 2026

Copy link
Copy Markdown
Member Author

Implementation report for current head dff39e50a0e3c9a92fa93f041e01696830b2be23.

Summary:

  • Repairs stale auto-owned runtime auth fallback state by comparing runtime provider/model against the effective expected selection before trusting it.
  • Prevents new dashboard/WebChat child sessions from inheriting stale parent fallback runtime/auth/context fields.
  • Preserves explicit /model directives, healthy auto auth profile rotation, inherited parent/channel model selections, and runtime-equivalent OpenAI/OpenAI Codex aliases.
  • No new config value and no plugin/SDK interface change.

Review/comment handling:

  • The stale inline review about over-broad auto auth cleanup was addressed and the review thread is resolved.
  • The older ClawSweeper display/read-path finding was addressed by routing the generic session model resolver back through runtime-preserving behavior plus stale-state comparison against the effective model, with gateway/session regressions added.
  • Latest local review command reported no actionable correctness issues.

Validation:

  • git diff --check passed.
  • node scripts/run-vitest.mjs src/sessions/model-overrides.test.ts src/auto-reply/reply/model-selection.test.ts src/gateway/session-utils.test.ts src/gateway/server.sessions.create.test.ts passed: 6 files, 377 tests.
  • node scripts/run-vitest.mjs src/auto-reply/reply/agent-runner-execution.test.ts -t "auto fallback" passed: 2 tests.
  • codex review --base main completed with no actionable correctness issues. Its sandbox test attempt hit listen EPERM: operation not permitted 127.0.0.1 for the gateway server suite; the same focused gateway suite passed locally through the repo test wrapper.
  • AWS Crabbox/Testbox-style broad gate passed on current head: node scripts/crabbox-wrapper.mjs run --provider aws --idle-timeout 90m --ttl 240m --timing-json --shell -- $'git fetch origin +main:refs/remotes/origin/main --deepen=1000\ngit fetch origin --deepen=1000\npnpm check:changed'; provider aws, lease cbx_fe5a8403f937, run run_2badb5cd84a0, exit 0.

CI state checked:

  • Relevant CI checks for the changed core/gateway/auth/session surfaces are passing.
  • Remaining red checks-windows-node-test failed during checkout before tests ran: fatal: fetch-pack: invalid index-pack output, exit 124. I classify this as runner/checkout infrastructure, not patch behavior.
  • Remaining red Scan changed paths (precise) reports src/gateway/server-discovery-runtime.test.ts, which is not in this PR diff. I classify this as unrelated to this patch.

Behavior addressed: stale auto-owned runtime auth fallback state no longer pins a session or child session to the fallback provider when the configured/effective selected model is different.
Real environment tested: local repo wrapper tests on this worktree; AWS remote changed gate on provider aws, lease cbx_fe5a8403f937, run run_2badb5cd84a0.
Exact steps or command run after this patch: focused Vitest commands above; git diff --check; codex review --base main; AWS pnpm check:changed command above.
Evidence after fix: focused synthetic regressions pass for MiniMax/DeepSeek stale fallback repair, legacy compaction-count provenance, healthy auto auth rotation, explicit model directive preservation, inherited parent/channel selection, child session inheritance, and OpenAI/OpenAI Codex runtime aliases; broad changed gate passes on AWS.
Observed result after fix: stale runtime/auth/context/fallback-notice fields are cleared only for auto-owned stale runtime selections, and normal explicit or healthy auto selections are preserved.
What was not tested: live MiniMax/DeepSeek provider fallback with real credentials; no live WebChat/TUI visual proof was run in this session.

@osolmaz

osolmaz commented May 29, 2026

Copy link
Copy Markdown
Member Author

@clawsweeper re-review

The display/read-path finding has been addressed in fe055af5a248377093f566342e077b76dfc49177.

The row/display resolver now ignores stale auto runtime auth state through the shared stale predicate, and src/gateway/session-utils.test.ts includes a MiniMax/DeepSeek row-display regression proving stale DeepSeek runtime metadata displays the configured MiniMax primary.

@clawsweeper

clawsweeper Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@osolmaz
osolmaz marked this pull request as draft May 29, 2026 13:00
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 1, 2026
@osolmaz

osolmaz commented Jun 1, 2026

Copy link
Copy Markdown
Member Author

@clawsweeper re-review

Follow-up cleanup pushed in 2402271 after maintainer review of code smells.

Changed only source shape, not behavior:

  • Named the stale runtime/auth and expected-model session entry shapes instead of repeating large Pick<SessionEntry, ...> types.
  • Added shared resolveSessionExpectedSelectedModelRef for default/model-override/channel-selected expected model calculation.
  • Reused that helper from sessions.create inheritance instead of duplicating channel override parsing there.
  • Moved stale clear fields into a typed field list and documented the legacy compaction-count provenance marker.
  • Added a short comment distinguishing generic runtime model resolution from next-run dispatch/preflight model resolution.

Proof run after the cleanup:

  • ./node_modules/.bin/oxfmt --write --threads=1 src/sessions/model-overrides.ts src/gateway/session-utils.ts src/gateway/server-methods/sessions.ts
  • ./node_modules/.bin/oxlint src/sessions/model-overrides.ts src/sessions/model-overrides.test.ts src/gateway/session-utils.ts src/gateway/session-utils.test.ts src/gateway/server-methods/sessions.ts src/gateway/server.sessions.create.test.ts src/gateway/server-methods/chat.ts src/gateway/server.chat.gateway-server-chat-b.test.ts src/auto-reply/reply/model-selection.ts src/auto-reply/reply/model-selection.test.ts
  • git diff --check
  • node scripts/run-vitest.mjs src/gateway/session-utils.test.ts src/gateway/server.sessions.create.test.ts src/gateway/server.chat.gateway-server-chat-b.test.ts src/sessions/model-overrides.test.ts src/auto-reply/reply/model-selection.test.ts passed: 3 Vitest shards, 5 files, 229 tests.

@clawsweeper

clawsweeper Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 1, 2026
@osolmaz

osolmaz commented Jun 2, 2026

Copy link
Copy Markdown
Member Author

@clawsweeper re-review

Please rerun on current head 24022718cb5bb1d88a2534dd4688c2bbc230741d.

The previous targeted re-review failed at the ClawSweeper/Codex workflow layer and did not report a patch finding. The cleanup commit only refactored the session expected-model helper shape; focused proof passed in the prior comment.

@clawsweeper

clawsweeper Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels Jun 2, 2026
@joshua-lehmann

joshua-lehmann commented Jun 2, 2026

Copy link
Copy Markdown

Related variant: stale entry.model/entry.modelProvider persist when /model selects the config default

@osolmaz I hit the same bug class (stale runtime fallback state) but from a different angle — model overrides only, no auth profile involved.

What I observed

  1. Primary opencode-go/qwen3.6-plus failed during a run (session file locked during CLI compaction → timeout).
  2. Auto-fallback to opencode-go/deepseek-v4-pro succeeded. The gateway persisted:
    entry.model = "deepseek-v4-pro"
    entry.modelProvider = "opencode-go"
    modelOverrideSource = "auto"  (then later cleared)
    
  3. Gateway restarted. Session store still had model/modelProvider pointing at deepseek.
  4. Running /model opencode-go/qwen3.6-plus (which is the configured agents.defaults.model.primary) should have cleared the stale runtime fields, but the status card still showed:
    • Selected: opencode-go/qwen3.6-plus
    • Active: opencode-go/deepseek-v4-pro
    • No modelOverride or modelOverrideSource persisted (both were deleted because the selection matched the config default → isDefault: true)

Root cause in applyModelOverrideToSessionEntry

The isDefault branch deletes override fields (providerOverride, modelOverride, modelOverrideSource, fallback origin) but does not clear stale runtime entry.model / entry.modelProvider:

if (selection.isDefault) {
    if (entry.providerOverride) { delete entry.providerOverride; ... }
    if (entry.modelOverride) { delete entry.modelOverride; ... }
    if (entry.modelOverrideSource) { delete entry.modelOverrideSource; ... }
    // ← MISSING: stale runtime model/modelProvider are not cleared here
}

The non-default branch does clear them:

const runtimeAligned = runtimeModel === selection.model && ...;
if (runtimePresent && (selectionUpdated || !runtimeAligned)) {
    if (entry.model !== undefined) { delete entry.model; updated = true; }
    if (entry.modelProvider !== undefined) { delete entry.modelProvider; updated = true; }
}

But this block only runs in the else branch (when !selection.isDefault), so it is skipped entirely when the user selects the config default.

Why the display is wrong

resolveSessionModelIdentityRef() (used by the status card) reads entry.model / entry.modelProvider first, before falling back to config:

const runtimeModel = entry?.model?.trim();
const runtimeProvider = entry?.modelProvider?.trim();
if (runtimeModel) return { provider: runtimeProvider, model: runtimeModel };
// ... only falls back to config if runtime fields are absent

So the stale entry.model = "deepseek-v4-pro" wins over the config default, even though no override is persisted.

Reproduction steps

  1. Configure agents.defaults.model.primary = "provider-a/model-a" with a fallback to "provider-b/model-b".
  2. Send a message. provider-a/model-a fails (rate limit, timeout, or any failover-worthy error).
  3. Auto-fallback succeeds — session now has entry.model = "model-b", entry.modelProvider = "provider-b".
  4. Run /model provider-a/model-a (select the config default).
  5. Run /status or session_statusActive shows provider-b/model-b instead of provider-a/model-a.
  6. sessions.json for that session: no modelOverride, no modelOverrideSource, but stale model/modelProvider still point at the fallback.

Evidence from journalctl

21:32:07 [model-fallback/decision] candidate_failed requested=opencode-go/qwen3.6-plus candidate=opencode-go/qwen3.6-plus reason=unknown next=opencode-go/deepseek-v4-pro
21:33:39 [model-fallback/decision] candidate_succeeded requested=opencode-go/qwen3.6-plus candidate=opencode-go/deepseek-v4-pro reason=unknown next=none

Why this matters

  • The status card becomes misleading — users cannot tell if the config default or a stale fallback is actually running.
  • Unlike the auth-profile variant, there is no modelOverrideSource to signal "this was auto-selected." After the user selects the default, it becomes null, so hasSessionAutoModelFallbackProvenance() also returns false (no fallback origin fields survived either).
  • The session silently carries stale runtime fields across gateway restarts.

Suggested fix

In the isDefault branch of applyModelOverrideToSessionEntry, also clear stale entry.model and entry.modelProvider when they do not match the default selection — the same logic the non-default branch already has.

@osolmaz

osolmaz commented Jun 3, 2026

Copy link
Copy Markdown
Member Author

@clawsweeper re-review

Addressed the latest review feedback in b0d73d7333.

Changes:

  • agent.run now uses resolveSessionNextRunModelRef for attachment/image preflight.
  • agent.request node events now use resolveSessionNextRunModelRef for attachment/image preflight.
  • Added regressions for stale auto runtime/auth metadata on both sibling preflight paths.
  • Added a regression for the related no-auth /model default-selection shape: stale runtime model / modelProvider fields are cleared when selecting the configured default.

Proof run after the patch:

  • ./node_modules/.bin/oxfmt --write --threads=1 src/gateway/server-methods/agent.ts src/gateway/server-node-events.ts src/gateway/server-node-events.runtime.ts src/gateway/server.agent.gateway-server-agent-a.test.ts src/gateway/server-node-events.test.ts src/sessions/model-overrides.test.ts
  • ./node_modules/.bin/oxlint src/gateway/server-methods/agent.ts src/gateway/server-node-events.ts src/gateway/server-node-events.runtime.ts src/gateway/server.agent.gateway-server-agent-a.test.ts src/gateway/server-node-events.test.ts src/sessions/model-overrides.ts src/sessions/model-overrides.test.ts
  • git diff --check
  • node scripts/run-vitest.mjs src/gateway/server.agent.gateway-server-agent-a.test.ts src/gateway/server-node-events.test.ts src/gateway/server.chat.gateway-server-chat-b.test.ts src/gateway/session-utils.test.ts src/sessions/model-overrides.test.ts passed: 2 Vitest shards, 5 files, 211 tests.

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. proof: sufficient ClawSweeper judged the real behavior proof convincing. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 3, 2026
@anyech

anyech commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Fresh current-release signal from a real Discord-backed install (not after-fix proof for this PR branch): I am still seeing the same stale auto runtime auth-selection failure class on OpenClaw 2026.6.1 (2e08f0f).

Setup shape, sanitized:

  • primary model/provider: openai/gpt-5.5
  • same-provider auth profiles: one primary/business OpenAI profile plus two personal/emergency OpenAI fallback profiles
  • affected sessions: existing Discord-backed sessions; no user auth-profile lock was set
  • persisted state shape observed: authProfileOverrideSource: "auto", provider: "openai", model: "gpt-5.5", with the override pointing at a personal/emergency OpenAI profile
  • the configured primary OpenAI auth profile was available at scan time

Fresh observation:

  • scanner saw 10 session-store entries checked
  • auto emergency auth-profile pins: 2
  • non-auto/user emergency auth-profile pins: 0
  • the primary profile was available in the affected store
  • a dry-run recovery that only clears authProfileOverrideSource == "auto" would clear one older auto emergency pin and temporarily skip one very recent auto emergency pin

Why this seems relevant to #87893:

  • this is not a cross-provider MiniMax/DeepSeek-only case; it also happens with same-provider OpenAI auth profiles
  • the bad state is not a user pin; the source is auto
  • the local recovery workaround has to treat the auto auth selection as transient runtime state and remove it from durable session state once the primary profile is healthy
  • the observed behavior matches the self-reinforcing/stale auto runtime auth state class that this PR is trying to repair

Caveat: I have not run this PR branch in a clean stage yet, so this comment is current-release failing evidence, not a verified after-fix result for b0d73d7. If useful, I can try to produce a public-safe staged before/after proof against this branch next.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui gateway Gateway runtime maintainer Maintainer-authored PR merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Control UI (TUI/WebChat) sessions auto-select wrong authProfileOverride (deepseek instead of minimax) at creation

3 participants