Skip to content

Add GPT 6 Astra and Claude Fable 5.1; refresh Go dependencies - #186

Merged
Desperado merged 2 commits into
mainfrom
Desperado/qmax-models-claude-harness
Sep 5, 2026
Merged

Add GPT 6 Astra and Claude Fable 5.1; refresh Go dependencies#186
Desperado merged 2 commits into
mainfrom
Desperado/qmax-models-claude-harness

Conversation

@Desperado

Copy link
Copy Markdown
Contributor

Adds GPT 6 Astra to the native Codex harness and Claude Fable 5.1 to Claude Code and the Anthropic API loop. Both models can be selected through /orch or --model; fable resolves to claude-fable-5-1.

  • Persist Codex model selection separately from Claude preferences and retain it across resumed turns and /clear, while preserving the native Codex default option.
  • Apply Anthropic picker selections to the actual API routes and omit incomplete thinking blocks from tool continuations.
  • Document the Go subprocess integrations, native subscription authentication, API-key billing overrides, and Fable plan restrictions with provider references. Claude Code and Codex remain separately installed CLIs.
  • Refresh Go modules on their existing import paths and raise the source-build minimum to Go 1.25.13 for dependency compatibility and standard-library security fixes.

Validation passed: go test ./..., go vet ./..., release-style build, golangci-lint v1.64.8, go mod verify, and git diff --check. govulncheck reported no vulnerabilities. Regression tests cover model selection, persistence, Codex initial/resume/clear arguments, and Fable tool continuations. Diff review found no blocking issues; the changed-file secret scan found no candidates.

Native CLI authentication and approval/sandbox policies remain in the providers' control; no credential extraction or API client SDK was introduced. Live model inference was not exercised.

@sigilix

sigilix Bot commented Sep 4, 2026

Copy link
Copy Markdown

Sigilix Overview

Effort: 4/5 (large)

Quality gates

  • ⚠️ PR title follows convention — Title doesn't match repo convention: ^(?:feat|fix|chore|docs|refactor|test|perf|style|build|ci|revert)(?:\([^)]+\))?!?: .+
  • ✅ PR description is complete
  • ℹ️ PR is linked to an issue — No Closes #N / Closes SIG-N keyword found in PR body or commit messages.

Summary — latest push

Adds GPT 6 Astra and Claude Fable 5.1 model support, persisting the Codex model selection separately from Claude preferences across resumed turns and /clear. It also refactors model resolution into a unified resolveSessionModel function, omits incomplete thinking blocks from Fable 5.1 tool continuations, and refreshes Go dependencies while raising the minimum toolchain to Go 1.25.13. The CI linter invocation is updated to build with the project's Go toolchain to fix incompatibility with the 1.25 target.

Important files

File Score Notes Next step
main.go 5/5 Replaces inline model validation with a unified resolveSessionModel call and threads CodexModel through to the Codex agent constructor. Verify resolveSessionModel correctly handles all edge cases for backend-specific model overrides and auto-routing.
internal/repl/repl.go 5/5 Wires CodexModel into the orchestration picker result, applies API model selection for the default backend, and persists Codex model selection separately. Confirm applyAPIModelSelection correctly sets AutoRoute and ChatModel defaults when model is auto.
main_models.go 5/5 New file containing resolveSessionModel which routes CLI model selection to the correct backend and validates it, but contains a critical logic flaw where non-Codex backends fail to persist the requested model. Fix the logic bug where cfg.ModelOverride is only set when cfg.Backend == "cc", causing the API and other backends to drop the user's explicit model selection on the floor.
main_models_test.go 4/5 Adds unit tests for the new resolveSessionModel function covering Codex, Claude, and API backends. Add a test case for resolveSessionModel when an explicit Claude model is requested on the cc backend to ensure ModelOverride is set correctly.
internal/agent/fable_test.go 4/5 Tests that Fable 5.1 tool continuations strip incomplete thinking blocks before replaying messages. Add a test case verifying that redacted_thinking blocks are also correctly omitted or handled in the continuation payload.

Sequence diagram

sequenceDiagram
    participant User
    participant TUI as Picker (tui_backend)
    participant Repl as Orchestrator (repl.go)
    participant Main as Main (main.go)
    participant Agent as Agent / CodexRunner

    User->>TUI: Select model & backend
    TUI->>Repl: result (backend, modelID)
    Repl->>Repl: persistOrchModelSelection()
    alt backend == codex
        Repl->>Repl: cfg.CodexModel = modelID
    else backend != codex
        Repl->>Repl: cfg.ModelOverride = modelID
    end
    Repl->>Agent: NewCodexAgent(modelID) / applyAPIModelSelection(modelID)
    Agent->>Agent: Route to selected model
    Agent-->>User: Response
Loading

Confidence: 2/5

The model resolution refactor introduces backend-specific branching logic with unverified edge cases around auto-routing and persistence, and the separate Codex model persistence path could silently erase user preferences if the branching conditions are not exhaustive.

  • In main.go, resolveSessionModel consolidates model validation but the diff truncates its implementation; verify it correctly handles all combinations of --model flags, saved configs, and backend-specific defaults without dropping overrides.
  • In internal/repl/repl.go, applyAPIModelSelection sets both Model and ChatModel to the same value, but the original auto-routing logic assigned Sonnet to Model and Haiku to ChatModel; confirm this unification is intentional and doesn't break auto-routing behavior.
  • In internal/repl/repl.go, persistOrchModelSelection now writes to cfg.CodexModel for the codex backend, but the test in main_models_test.go expects the savedCodex field to be reset to empty when an unrecognized legacy model is passed; verify this doesn't silently discard valid saved preferences on picker re-entry.
  • In internal/agent/fable_test.go, the test asserts that incomplete thinking blocks are stripped from tool continuations, but the implementation for this filtering is not visible in the diff; confirm the agent loop actually performs this omission rather than the test merely asserting the desired outcome.

Suggested labels: breaking-change


Posted · 3ec7d2b · 4 findings — View review
Proof: 4 model-only
runner-verified = CI receipt · reproduced = sandbox observed diff · grounded = deterministic detector/worker-token · model-only = model judgment only
Dismiss @sigilix dismiss <reason> (not-a-bug | bad-anchor | already-covered | too-minor | wrong-context) · Re-run /sigilix review · Review #2
Sigilix · 0 of 50 reviews used in past 5h

@qualitymaxapp

qualitymaxapp Bot commented Sep 4, 2026

Copy link
Copy Markdown

QualityMax Review

Verdict: COMMENT · Confidence: evidence-backed scan

Files eligible: 29 · Files reviewed: 29 · Files with findings: 0 · Findings: 0 · Inline cards: 0

Priority findings

priority location finding
No blocking findings

Review gates

gate status
AI diff review completed · eligible 23, reviewed 23 · LLM · served gemini-3.1-flash-lite
SAST completed · eligible 29, reviewed 29 · hybrid · served qwen3.7-plus
Overall review evidence clean
Inline evidence not needed

Important files

file risk note next step
No findings

Change diagram — Flow

graph TD
    User[User Selects Model] --> TUI[TUI Picker]
    TUI --> Persist[persistOrchModelSelection]
    Persist --> Config[Update Config]
    Config --> Agent[Agent Execution]
    Agent --> API[API Call]
    API --> Filter[Filter Thinking Blocks]
    Filter --> Response[Return Cleaned Response]
Loading

Review lifecycle

Use the inline cards to inspect evidence and suggested remediation. Re-run the QualityMax review after pushing a fix; unchanged cards are identified by their stable finding marker. Dismiss with a reason through the existing QualityMax/GitHub review feedback flow. 0 prior card(s) are stale/resolved on this head. @qmax Q&A is tracked separately.

Proof legend: VERIFIED independently judged patch · REPRODUCED verified finding · GROUNDED deterministic evidence · MODEL-ONLY model judgment.

QualityMax project results are available in the configured project.

Receipt · commit 3ec7d2bfe586347c89e1c4628d1c899e05e20ecf · run 2026-09-05T05:35:51+00:00 · model served qwen3.7-plus, gemini-3.1-flash-lite · model requested qwen3.7-plus, gemini-3.1-flash-lite · model review recorded — 2425 model output tokens · model source repository ai_review_preferences.preferred_model · re-review 2 · proof counts {}

@sigilix sigilix Bot added documentation Improvements or additions to documentation enhancement New feature or request labels Sep 4, 2026
@socket-security

socket-security Bot commented Sep 4, 2026

Copy link
Copy Markdown

@qualitymaxapp qualitymaxapp Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

QualityMax Review — canonical overview updated; inline findings are attached to this review.

sigilix[bot]
sigilix Bot previously requested changes Sep 4, 2026

@sigilix sigilix Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📊 Reviewed 21 of 28 changed files across this PR so far — the remaining 7 were below the priority cutoff for this very large PR. Split into smaller PRs to cover them.

Comment thread internal/agent/agent.go
Comment thread internal/repl/repl.go
Comment thread main_models.go
Comment thread internal/tui/tui_backend_cc_test.go
@qualitymaxapp

qualitymaxapp Bot commented Sep 4, 2026

Copy link
Copy Markdown

⚠️ QualityMax Pipeline

Gate Result
🔍 AI diff review ✅ Clean · gemini-3.1-flash-lite · completed · 23 eligible / 23 reviewed · gemini-3.1-flash-lite
🔍 SAST completed · 29 eligible / 29 reviewed · qwen3.7-plus
🔍 Canonical PR review delivery completed · 0 eligible / 0 reviewed · exact-head review #5119954367 and overview #5547501742 confirmed
🧪 Repo Tests ✅ 751/751 passed (go)

Powered by QualityMax — AI-Powered Test Automation

@Desperado
Desperado dismissed sigilix[bot]’s stale review September 5, 2026 05:30

Dismissed after checking all four findings against the code and passing targeted tests. In-place compaction is safe; display labels do not enter persisted model IDs; resolver mutation is intentional and documented; picker and persistence cases are already covered. Per-finding evidence is recorded in the inline replies.

Comment thread main_models.go
Comment on lines +36 to +40
if !api.IsValidClaudeModelName(model) {
return "", fmt.Errorf("unrecognized Claude model %q; valid: %s", model, api.ValidClaudeModelsHelp())
}
if cfg.Backend == "cc" && requested != "" {
cfg.ModelOverride = model

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 LOGICGROUNDED resolveSessionModel writes cfg.ModelOverride = model for the cc backend even when model is the resolved default, resurrecting a previously-cleared override

When cfg.Backend == "cc" and requested != "", the function sets cfg.ModelOverride = model where model is the result of api.ResolveClaudeModel(model). If requested is a non-empty alias like "fable" that resolves to api.ModelFable51, this is correct. But if requested is a non-empty value that resolves to the same model as the saved default, the write is still performed, overwriting any prior ModelOverride that may have been intentionally cleared (e.g., by a previous --model auto invocation). The if model == "auto" guard only clears the override when the resolved model is exactly "auto"; it does not handle the case where a non-auto requested model should clear a stale override. The invariant that ModelOverride reflects the user's most recent explicit CLI choice is broken when a non-auto request follows a cleared override.

More Info
  • Threat model: A user who previously ran qmax-code --model auto (clearing ModelOverride) and then runs qmax-code --model fable will have ModelOverride set to claude-fable-5-1. If they later run qmax-code --model auto again, the override is cleared. But if they run qmax-code --model sonnet (a non-auto alias), the override is set to claude-sonnet-5, which is correct. The bug is that a non-auto request always writes the override, even when the resolved model equals the saved DefaultModel, so a user who clears the override and then requests the default model by its full ID will have the override re-set, causing the next session to use the override instead of the saved default.
  • Specific code citations: main_models.go lines 36-44: if cfg.Backend == "cc" && requested != "" { cfg.ModelOverride = model; if model == "auto" { cfg.ModelOverride = "" } }
  • Existing protections: The if model == "auto" guard only clears the override for the literal "auto" value; it does not compare model against cfg.DefaultModel or any other sentinel.
  • Proposed mitigation: Only write cfg.ModelOverride when model != cfg.DefaultModel, or clear it when model == cfg.DefaultModel to preserve the invariant that the override is only set for a non-default explicit choice.
  • Alternative mitigations considered: A separate --model flag that always writes the override and a --reset-model flag to clear it would be more explicit but is a larger API change.
  • Severity calibration: The bug requires a specific sequence of user actions (clear override, then request the default model by full ID) and only affects the next session's model selection, so it is a likely production bug under plausible conditions but not a data-loss or crash.
Prompt To Fix With AI
This is a comment left during a code review.
Path: main_models.go
Line: 36-40

Comment:
**`resolveSessionModel` writes `cfg.ModelOverride = model` for the `cc` backend even when `model` is the resolved default, resurrecting a previously-cleared override**

When `cfg.Backend == "cc"` and `requested != ""`, the function sets `cfg.ModelOverride = model` where `model` is the result of `api.ResolveClaudeModel(model)`. If `requested` is a non-empty alias like `"fable"` that resolves to `api.ModelFable51`, this is correct. But if `requested` is a non-empty value that resolves to the same model as the saved default, the write is still performed, overwriting any prior `ModelOverride` that may have been intentionally cleared (e.g., by a previous `--model auto` invocation). The `if model == "auto"` guard only clears the override when the resolved model is exactly `"auto"`; it does not handle the case where a non-auto requested model should clear a stale override. The invariant that `ModelOverride` reflects the user's most recent explicit CLI choice is broken when a non-auto request follows a cleared override.

Threat model:
A user who previously ran `qmax-code --model auto` (clearing `ModelOverride`) and then runs `qmax-code --model fable` will have `ModelOverride` set to `claude-fable-5-1`. If they later run `qmax-code --model auto` again, the override is cleared. But if they run `qmax-code --model sonnet` (a non-auto alias), the override is set to `claude-sonnet-5`, which is correct. The bug is that a non-auto request always writes the override, even when the resolved model equals the saved `DefaultModel`, so a user who clears the override and then requests the default model by its full ID will have the override re-set, causing the next session to use the override instead of the saved default.

Specific code citations:
`main_models.go` lines 36-44: `if cfg.Backend == "cc" && requested != "" { cfg.ModelOverride = model; if model == "auto" { cfg.ModelOverride = "" } }`

Existing protections:
The `if model == "auto"` guard only clears the override for the literal `"auto"` value; it does not compare `model` against `cfg.DefaultModel` or any other sentinel.

Proposed mitigation:
Only write `cfg.ModelOverride` when `model != cfg.DefaultModel`, or clear it when `model == cfg.DefaultModel` to preserve the invariant that the override is only set for a non-default explicit choice.

Alternative mitigations considered:
A separate `--model` flag that always writes the override and a `--reset-model` flag to clear it would be more explicit but is a larger API change.

Severity calibration:
The bug requires a specific sequence of user actions (clear override, then request the default model by full ID) and only affects the next session's model selection, so it is a likely production bug under plausible conditions but not a data-loss or crash.

How can I resolve this? If you propose a fix, please make it concise.

Comment thread internal/repl/repl.go
Comment thread internal/repl/repl.go
Comment thread main_models.go

@qualitymaxapp qualitymaxapp Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

QualityMax Review — canonical overview updated; inline findings are attached to this review.

@Desperado
Desperado merged commit 6503fa1 into main Sep 5, 2026
7 checks passed
@Desperado
Desperado deleted the Desperado/qmax-models-claude-harness branch September 5, 2026 05:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request qualitymax:reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant