diff --git a/CHANGES.md b/CHANGES.md index 2de084b..ff9a295 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ Fork of open-pstack v1.4.1. Additive changes, all in port-owned files: - OAuth-leak guard: a gateway lane refuses to start (in-process, `unauthenticated` receipt, exit 77) when its API key variable is missing or when its config dir carries a claude.ai OAuth credentials file, so a claude.ai login can never be pointed at a third-party endpoint. - Gateway preflight is `claude --version`; the one-shot invocation is the real auth test. Gateway receipts force `costUsd` to null (the CLI prices at Anthropic rates) and match served models case-insensitively, falling back to `modelEvidence: "pinned-argv"` like Codex. - `provider-dispatch.md`: new additive "Flex model matrix" section, extended route table, gateway preflight semantics, and the panel-diversity rule (arena runners and interrogate reviewers span at least two providers unless the operator explicitly confirms otherwise). The stock model matrix is byte-unchanged. +- Optional GPT-6 families: the additional model matrix declares `codex:gpt-6-astra`, `codex:gpt-6-sol`, and `codex:gpt-6-luna` with default effort `high` and selectable `low`, `medium`, `high`, `xhigh`, and `max`. Setup can assign and probe each for `architect runners` or another configurable role. Codex parents use native `spawn_agent`; Claude Code parents use the external Codex runner. GPT-6 Sol has its own `sol-6` family. Stock models and first-run role assignments stay unchanged. - `setup-pstack`: role assignments are selected first, and only assigned families get effort questions and probes; there is no requirement to assign every matrix family (mirrors upstream PR #73 / issue #72). The first-run sheet, its stock quad, and the fail-closed write rules are unchanged. - Tests: the model-matrix contract gains a flex-matrix section check cross-validated against the runner's gateway specs; runner, commands, parse-output, and CLI tests cover env injection, the guard, cost nulling, and case-insensitive verification. Nothing in the suite performs network I/O. diff --git a/README.md b/README.md index 7a2acbd..745ea4e 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ In Codex, ask: Use pstack:setup-pstack to configure pstack. ``` -Setup checks the models you can actually run, shows how each one will start, and asks before saving the choices. The current default group uses Fable, GPT-5.6 Sol, Grok 4.6, and Opus. +Setup checks the models you can actually run, shows how each one will start, and asks before saving the choices. The current default group uses Fable, GPT-5.6 Sol, Grok 4.6, and Opus. You can also assign GPT-6 Astra, Sol, or Luna to any role through Codex. An older model sheet starts using the rolling aliases in memory as soon as this release is installed. Run setup once after updating to persist that migration. It replaces versioned Fable and Opus entries while preserving every role assignment and effort selection. diff --git a/UPSTREAM-FLEX.md b/UPSTREAM-FLEX.md index f061742..7ecbf21 100644 --- a/UPSTREAM-FLEX.md +++ b/UPSTREAM-FLEX.md @@ -22,7 +22,7 @@ All flex changes are additive and live in port-owned files so upstream merges st - `plugins/pstack/skills/poteto-mode/scripts/runner/flex-providers.ts` and `flex-providers.test.ts` (new) - Gateway-provider hooks in `runner/{types,commands,run,parse-output,cli}.ts` and their tests -- The "Flex model matrix" section and route-table columns in `references/provider-dispatch.md` +- The "Additional model matrix" and "Flex model matrix" sections and route-table columns in `references/provider-dispatch.md` - The assignment-first restructure of `skills/setup-pstack/SKILL.md` - `docs/LANES.md`, this file, the README fork section, and the NOTICE/LICENSE/CHANGES additions diff --git a/docs/LANES.md b/docs/LANES.md index 2ed9884..cf72549 100644 --- a/docs/LANES.md +++ b/docs/LANES.md @@ -8,11 +8,23 @@ Prices and endpoints below were verified 2026-09-25 and drift. Re-verify against | Kind | Lanes | Auth | Billing | Route | | --- | --- | --- | --- | --- | -| Subscription | `claude:fable`, `claude:opus`, `codex:gpt-5.6-sol`, `grok:grok-4.6` | each CLI's own login | that CLI's plan | native or external per the route table | +| Subscription | `claude:fable`, `claude:opus`, `codex:gpt-5.6-sol`, `grok:grok-4.6`; optional `codex:gpt-6-astra`, `codex:gpt-6-sol`, `codex:gpt-6-luna` | each CLI's own login | that CLI's plan | native or external per the route table | | Gateway (flex) | DeepSeek Flash / V4 Pro; MiniMax M3 / M3.1 Flash Preview | API key in the environment | provider billing; preview requires Token Plan | always the external runner | A gateway lane is the stock `claude` binary env-pointed at the lab's Anthropic-compatible endpoint. There is no custom agent loop and no separate harness: the same runner that spawns Codex and Grok lanes spawns gateway lanes with injected environment. Both labs document this Claude Code setup themselves (DeepSeek: `deepseek-ai/awesome-deepseek-agent`, `docs/claude_code.md`; MiniMax: platform.minimax.io, Claude Code guide). +## Optional GPT-6 Codex families + +The additional model matrix adds three Codex families. They use the same ChatGPT login as `codex:gpt-5.6-sol`: + +| Family | Descriptor at default requested effort | Codex's own description | +| --- | --- | --- | +| astra | `codex:gpt-6-astra@high` | Frontier tier for the most demanding work | +| sol-6 | `codex:gpt-6-sol@high` | Coding and everyday workhorse | +| luna | `codex:gpt-6-luna@high` | Fast, low-cost tier for easier tasks | + +These are choices, not replacements. The first-run sheet still uses `codex:gpt-5.6-sol@max`. An existing sheet changes only when you assign a role to a GPT-6 family in `/setup-pstack`. The `sol-6` family is separate from the stock `sol` family, so each keeps its own effort. All Codex families count as one provider for panel diversity, so Astra plus Sol does not satisfy the two-provider rule. The route matches Sol: native `spawn_agent` in a Codex parent, and the external runner (`codex exec`) in a Claude Code parent. Codex also lists an `ultra` effort for Astra and GPT-6 Sol. It is outside the pstack effort universe and is not selectable. The descriptions and effort lists come from the Codex CLI 0.157.1 model list, checked 2026-09-27. + ## Multiple models per provider The flex matrix now includes four independently assignable model families: diff --git a/docs/USAGE.md b/docs/USAGE.md index b4f1ac6..9819c96 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -232,6 +232,16 @@ Every external lane writes a JSON receipt next to its output. The fields that ma | A panel ran with fewer lanes than configured | a lane dropped out with a named receipt | read that receipt; pstack proceeds N-1 and never silently substitutes a model | | Everything gateway broke after a claude CLI update | Anthropic doesn't support third-party endpoints; compatibility can shift | pin the CLI version on machines that depend on gateway lanes; see [LANES.md](LANES.md#safety-and-policy) | +## Selecting the GPT-6 Codex models + +Run `/setup-pstack` and assign `astra` (`codex:gpt-6-astra@high`), `sol-6` (`codex:gpt-6-sol@high`), or `luna` (`codex:gpt-6-luna@high`) to named roles, such as `architect runners`. Every role you do not change keeps its current descriptor, including the stock `codex:gpt-5.6-sol@max` defaults. Each GPT-6 family gets its own effort question and live probe. They need only your Codex login. See [optional GPT-6 Codex families](LANES.md#optional-gpt-6-codex-families). + +For example, this row puts Astra on the architect panel and keeps the other providers: + +```text +architect runners: claude:fable@max, codex:gpt-6-astra@high, grok:grok-4.6@xhigh, claude:opus@xhigh +``` + ## Selecting the additional gateway models Run `/setup-pstack` and assign `deepseek-pro` (`deepseek:deepseek-v4-pro@high`) or `minimax-preview` (`minimax:MiniMax-M3.1-Flash-Preview@high`) to named roles. Existing `deepseek` and `minimax` choices remain available. Each model has its own effort selection and live probe. MiniMax preview requires an eligible Token Plan key in `MINIMAX_API_KEY`; see [model choices and thinking controls](LANES.md#multiple-models-per-provider). No existing assignment changes until setup succeeds and you confirm the rendered sheet. diff --git a/docs/reference.md b/docs/reference.md index 2301514..f070eb3 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -86,7 +86,7 @@ The Codex build shares one `skills/` tree with the Claude Code build. Nothing is - **Tool and built-in mapping.** Claude tool names and built-in skills resolve through [`codex-tools.md`](../plugins/pstack/skills/poteto-mode/references/codex-tools.md). Model execution resolves separately through [`provider-dispatch.md`](../plugins/pstack/skills/poteto-mode/references/provider-dispatch.md), so Codex can keep Sol native while invoking Claude and Grok externally. - **Subagents.** The `Agent` tool maps to Codex `spawn_agent` / `wait_agent`, enabled by `multi_agent = true`. Parallel fan-out is multiple `spawn_agent` calls in one turn. If the native Codex lane is unavailable, record that lane as a dropout; external Claude and Grok lanes still run, and no provider is silently substituted. There is no `poteto-agent` subagent type on Codex; route ad-hoc subagents by dispatching a `spawn_agent` told to read `poteto-mode` first. - **Auto-fire.** The `hooks/` SessionStart injection is Claude Code-only; Codex has no plugin hook runtime. Enter `pstack:poteto-mode` by name, or add a standing instruction to `~/.codex/AGENTS.md` if you want the same always-on routing. -- **Models.** `/setup-pstack` writes provider-qualified descriptors and asks one requested effort per frontier family (`low`, `medium`, `high`, `xhigh`, `max`). The first-run panel is Fable max, GPT-5.6 Sol max, Grok 4.6 xhigh, and Opus xhigh. Fable and Opus use Claude's rolling aliases. Runtime dispatch normalizes older versioned descriptors in memory, so an installed sheet stops pinning immediately. A setup rerun persists that migration while keeping each role's family and effort. In Codex, Sol uses native `spawn_agent`; Claude and Grok use the deterministic external runner. In Claude Code, Fable and Opus use native agents; Sol and Grok use the runner. Children never detect the parent or reroute themselves. The `bug-fix`, `perf-issue`, and `hillclimb` roles stay on GPT-5.6 Sol max instead of upstream's Fable default because Sol costs less for these frequent delegated code roles. +- **Models.** `/setup-pstack` writes provider-qualified descriptors and asks one requested effort per frontier family (`low`, `medium`, `high`, `xhigh`, `max`). The first-run panel is Fable max, GPT-5.6 Sol max, Grok 4.6 xhigh, and Opus xhigh. Fable and Opus use Claude's rolling aliases. Runtime dispatch normalizes older versioned descriptors in memory, so an installed sheet stops pinning immediately. A setup rerun persists that migration while keeping each role's family and effort. Optional GPT-6 Astra, Sol, and Luna Codex families can be assigned to any role and never change the first-run sheet. In Codex, Sol and the GPT-6 families use native `spawn_agent`; Claude and Grok use the deterministic external runner. In Claude Code, Fable and Opus use native agents; Sol, the GPT-6 families, and Grok use the runner. Children never detect the parent or reroute themselves. The `bug-fix`, `perf-issue`, and `hillclimb` roles stay on GPT-5.6 Sol max instead of upstream's Fable default because Sol costs less for these frequent delegated code roles. Verified in fresh installed Claude Code and Codex sessions: the user-facing skills are discovered and namespaced under `pstack`; both parents fan out the frontier quad through the documented native/external route table, retain long-running handles without a default timeout, and cross-judge only after every candidate is terminal. The `principle-*` leaves remain available for `poteto-mode` to read by path. Claude honors their `user-invocable: false` metadata; Codex 0.149.0 does not ([#8](https://github.com/ericlitman/open-pstack/issues/8)). diff --git a/plugins/pstack/skills/poteto-mode/references/provider-dispatch.md b/plugins/pstack/skills/poteto-mode/references/provider-dispatch.md index ae60d07..729c096 100644 --- a/plugins/pstack/skills/poteto-mode/references/provider-dispatch.md +++ b/plugins/pstack/skills/poteto-mode/references/provider-dispatch.md @@ -19,6 +19,18 @@ The allowed effort universe is exactly `low`, `medium`, `high`, `xhigh`, `max`. `fable` and `opus` are Claude Code's rolling aliases. Claude resolves each alias to the latest available family revision. A runner receipt keeps the requested alias in `model` and the concrete provider-reported revision in `reportedModel`; verification accepts only a numeric `claude-fable-*` or `claude-opus-*` revision from the matching family. +## Additional model matrix + +pstack-flex additions using the existing provider routes. These optional families do not change the stock matrix or first-run role assignments. Default effort is pstack's proposed requested effort when assigning a family, not the provider's default. `-` in Upstream pstack choice means there is no upstream default to replace. + +| Family | Upstream pstack choice | Provider | Model | Default effort | Selectable efforts | Claude-native agent stem | +|---|---|---|---|---|---|---| +| astra | - | codex | gpt-6-astra | high | low medium high xhigh max | - | +| sol-6 | - | codex | gpt-6-sol | high | low medium high xhigh max | - | +| luna | - | codex | gpt-6-luna | high | low medium high xhigh max | - | + +These Codex families use native `spawn_agent` under a Codex parent and the external Codex runner under a Claude Code parent. Setup may assign them to any configurable role, including `architect runners`, after each requested model and effort passes the parent-specific probe. The `sol-6` family is independent of the stock `sol` family; existing GPT-5.6 Sol assignments stay unchanged. + ## Flex model matrix pstack-flex addition. The stock matrix above is upstream-owned and unchanged; these lanes are additive. A flex lane runs the stock `claude` binary env-pointed at the provider's Anthropic-compatible endpoint, with the provider's own API key and an isolated `CLAUDE_CONFIG_DIR`, so it uses no Anthropic account, no claude.ai login, and no subscription. diff --git a/plugins/pstack/skills/poteto-mode/scripts/runner/model-matrix.test.ts b/plugins/pstack/skills/poteto-mode/scripts/runner/model-matrix.test.ts index af7258f..b82be28 100644 --- a/plugins/pstack/skills/poteto-mode/scripts/runner/model-matrix.test.ts +++ b/plugins/pstack/skills/poteto-mode/scripts/runner/model-matrix.test.ts @@ -1,7 +1,10 @@ import { describe, expect, it } from "bun:test"; import { readdirSync, readFileSync } from "node:fs"; import { join } from "node:path"; +import { parseArgs } from "./cli.ts"; +import { invocationCommand } from "./commands.ts"; import { GATEWAY_SPECS } from "./flex-providers.ts"; +import { validateOptions } from "./run.ts"; import { EFFORTS, GATEWAY_PROVIDERS, @@ -105,11 +108,15 @@ function asEffort(value: string): Effort { throw new Error(`not an effort: ${value}`); } -function parseModelMatrix(markdown: string): MatrixRow[] { +function parseModelMatrix( + markdown: string, + heading = "## Model matrix", + rowCount: number = FAMILY_ORDER.length +): MatrixRow[] { const lines = markdown.split(/\r?\n/); - const start = lines.findIndex((line) => line.trim() === "## Model matrix"); + const start = lines.findIndex((line) => line.trim() === heading); if (start < 0) { - throw new Error("missing ## Model matrix"); + throw new Error(`missing ${heading}`); } let end = lines.length; for (let i = start + 1; i < lines.length; i++) { @@ -122,9 +129,9 @@ function parseModelMatrix(markdown: string): MatrixRow[] { .slice(start + 1, end) .map((line) => line.trim()) .filter((line) => line.startsWith("|")); - if (table.length !== 6) { + if (table.length !== rowCount + 2) { throw new Error( - `model matrix must be header, separator, and 4 data rows, got ${table.length}` + `${heading} must be header, separator, and ${rowCount} data rows, got ${table.length}` ); } const header = splitRow(table[0]); @@ -214,7 +221,9 @@ function firstRunSheet(setup: string): string { } describe("model matrix", () => { - const rows = parseModelMatrix(readFileSync(DISPATCH_PATH, "utf8")); + const dispatch = readFileSync(DISPATCH_PATH, "utf8"); + const rows = parseModelMatrix(dispatch); + const additionalRows = parseModelMatrix(dispatch, "## Additional model matrix", 3); const setup = readFileSync(SETUP_PATH, "utf8"); const quad = defaultDescriptors(rows); @@ -250,7 +259,7 @@ describe("model matrix", () => { it("ships exactly the declared Claude-native frontier agents", () => { const expected = new Set(); const familyBodies = new Map(); - for (const row of rows) { + for (const row of [...rows, ...additionalRows]) { const stem = row.claudeNativeAgentStem; if (stem === null) { continue; @@ -291,6 +300,76 @@ describe("model matrix", () => { expect(shipped).toEqual([...expected].sort()); }); + it("adds GPT-6 families without changing the stock matrix or first-run assignments", () => { + expect(additionalRows.map((row) => [row.family, row.model])).toEqual([ + ["astra", "gpt-6-astra"], + ["sol-6", "gpt-6-sol"], + ["luna", "gpt-6-luna"], + ]); + for (const row of additionalRows) { + expect(row.upstreamChoice).toBe("-"); + expect(row.provider).toBe("codex"); + expect(row.defaultEffort).toBe("high"); + expect(row.selectableEfforts).toEqual([...EFFORTS]); + expect(row.claudeNativeAgentStem).toBeNull(); + expect(firstRunSheet(setup)).not.toContain(row.model); + } + const allRows = [...rows, ...additionalRows]; + expect(new Set(allRows.map((row) => row.family)).size).toBe(allRows.length); + expect(new Set(allRows.map((row) => `${row.provider}:${row.model}`)).size) + .toBe(allRows.length); + expect(setup).toContain("Its model matrices (stock, additional, and flex)"); + expect(setup).toContain("Read the model matrices, stock, additional, and flex."); + expect(setup).toContain("any stock, additional, or flex matrix family"); + expect(setup).toContain("Offer Astra, GPT-6 Sol, and Luna from the additional matrix when changing `architect runners`"); + expect(setup).toContain("Read each model, proposed effort, and selectable efforts from its row."); + expect(setup).toContain("outside the stock, additional, and flex matrix families"); + expect(setup).toContain( + "| Astra | Astra additional row + selected effort | external runner | native `spawn_agent` |" + ); + expect(setup).toContain( + "| GPT-6 Sol | sol-6 additional row + selected effort | external runner | native `spawn_agent` |" + ); + expect(setup).toContain( + "| Luna | Luna additional row + selected effort | external runner | native `spawn_agent` |" + ); + expect(setup).toContain("each assigned Codex family gets a native `spawn_agent` probe"); + expect(dispatch).toContain( + "These Codex families use native `spawn_agent` under a Codex parent and the external Codex runner under a Claude Code parent." + ); + }); + + it("passes each additional family's selected model and effort to the existing runner", () => { + for (const row of additionalRows) { + for (const effort of row.selectableEfforts) { + const options = parseArgs([ + "--parent", "claude", + "--provider", row.provider, + "--model", row.model, + "--effort", effort, + "--mode", "read-only", + "--prompt", DISPATCH_PATH, + "--cwd", PLUGIN_ROOT, + "--output", join(PLUGIN_ROOT, `${row.family}-probe.md`), + "--receipt", join(PLUGIN_ROOT, `${row.family}-probe.json`), + ]); + if (options === null) { + throw new Error("model probe arguments must produce runner options"); + } + validateOptions(options); + expect(options.timeoutMs).toBeNull(); + const command = invocationCommand(options); + expect(command.command).toBe("codex"); + expect(command.args.slice(0, 5)).toEqual([ + "exec", "--model", row.model, + "--config", `model_reasoning_effort="${effort}"`, + ]); + expect(() => validateOptions({ ...options, parent: "codex" })) + .toThrow("provider codex is native to parent codex"); + } + } + }); + it("keeps setup's first-run default panel copy aligned with the matrix", () => { const sheet = firstRunSheet(setup); const roles = sheet diff --git a/plugins/pstack/skills/setup-pstack/SKILL.md b/plugins/pstack/skills/setup-pstack/SKILL.md index 06c8ed9..737452c 100644 --- a/plugins/pstack/skills/setup-pstack/SKILL.md +++ b/plugins/pstack/skills/setup-pstack/SKILL.md @@ -5,7 +5,7 @@ description: Configure pstack's provider-qualified models, per-family requested # Setup pstack -Configure one portable model sheet for the current parent harness. Read [`provider-dispatch.md`](../poteto-mode/references/provider-dispatch.md) before probing or writing anything. Its model matrices (stock and flex), descriptor grammar, and route table are the contract. Role assignments are selected first; then choose one requested effort per assigned matrix family. Do not add a second configuration file, a runtime resolver, or a weaker-model fallback. +Configure one portable model sheet for the current parent harness. Read [`provider-dispatch.md`](../poteto-mode/references/provider-dispatch.md) before probing or writing anything. Its model matrices (stock, additional, and flex), descriptor grammar, and route table are the contract. Role assignments are selected first; then choose one requested effort per assigned matrix family. Do not add a second configuration file, a runtime resolver, or a weaker-model fallback. Claude Code writes `~/.claude/pstack-models.md` and loads it from `~/.claude/CLAUDE.md` with: @@ -35,7 +35,7 @@ Treat the normalized values as current role-to-family assignments. Overlay those ### 3. Parse per-family efforts -Read the model matrices, stock and flex. Every non-alias value must match `:@`. Map it to exactly one matrix family by `(provider, model)`, require its effort to appear in that row's Selectable efforts cell, and collect the effort. `inherit-parent` and `auto` rows carry no family effort. +Read the model matrices, stock, additional, and flex. Every non-alias value must match `:@`. Map it to exactly one matrix family by `(provider, model)`, require its effort to appear in that row's Selectable efforts cell, and collect the effort. `inherit-parent` and `auto` rows carry no family effort. An unmatched provider/model, out-of-domain effort, duplicate role, or unknown role is inconsistent state. Stop, show the conflicting rows verbatim, and ask for an explicit matrix family or alias replacement. If one or more families have mixed efforts, show every conflicting family and role row, then ask for one normalized effort per family from its Selectable efforts cell. Do not invent a precedence rule. Do not probe or write while any inconsistency is unresolved. @@ -45,7 +45,9 @@ One distinct effort per family is the current value. A family with no non-alias ### 4. Choose role assignments, then collect efforts -Role assignments come first. Show the current role-to-family map (loaded and normalized from step 2, or the first-run map from step 7) and ask whether to keep it or change named roles. Keeping it is the default. A changed role may use any stock or flex matrix family, `inherit-parent`, or `auto`. Apply only role changes the operator names; never offer a reset of a customized sheet to the first-run assignments. +Role assignments come first. Show the current role-to-family map (loaded and normalized from step 2, or the first-run map from step 7) and ask whether to keep it or change named roles. Keeping it is the default. A changed role may use any stock, additional, or flex matrix family, `inherit-parent`, or `auto`. Apply only role changes the operator names; never offer a reset of a customized sheet to the first-run assignments. + +Offer Astra, GPT-6 Sol, and Luna from the additional matrix when changing `architect runners` or another configurable role. Read each model, proposed effort, and selectable efforts from its row. The additional families and stock Sol are separate families even though they share the Codex provider; changing one family's effort does not change another's. GPT-6 Sol uses the `sol-6` family; the stock `sol` family keeps GPT-5.6 Sol. The assigned families are exactly the matrix families that appear in the resulting role map. An unassigned family gets no effort question and no probe. There is no requirement to assign every matrix family. @@ -59,6 +61,9 @@ Probe only the assigned families' selected `provider:model@effort` pairs. Run on |---|---|---|---|---| | Fable | Fable matrix row + selected effort | native Agent `pstack-fable-` | Claude CLI | native one-turn probe or `claude auth status --json` plus one-turn probe | | Sol | Sol matrix row + selected effort | `codex exec` | native `spawn_agent` | `codex login status` plus one-turn probe or native one-turn probe | +| Astra | Astra additional row + selected effort | external runner | native `spawn_agent` | `codex login status` plus one-turn probe or native one-turn probe | +| GPT-6 Sol | sol-6 additional row + selected effort | external runner | native `spawn_agent` | `codex login status` plus one-turn probe or native one-turn probe | +| Luna | Luna additional row + selected effort | external runner | native `spawn_agent` | `codex login status` plus one-turn probe or native one-turn probe | | Grok | Grok matrix row + selected effort | Grok CLI | Grok CLI | `grok models` must list the requested model; one-turn probe | | Opus | Opus matrix row + selected effort | native Agent `pstack-opus-` | Claude CLI | native one-turn probe or `claude auth status --json` plus one-turn probe | | DeepSeek Flash / Pro | Each assigned DeepSeek flex row + selected effort | external runner | external runner | `DEEPSEEK_API_KEY` present; isolated config dir free of OAuth credentials; one-turn probe confirms the endpoint | @@ -66,7 +71,7 @@ Probe only the assigned families' selected `provider:model@effort` pairs. Run on For MiniMax M3.1 Flash Preview, disclose the Token Plan requirement before probing. Use the eligible subscription key through `MINIMAX_API_KEY`; do not assume a working M3 key grants preview access. A failed preview probe must not silently select M3. Keep preview thinking enabled and verify requested effort forwarding; distinguish request evidence from hidden applied reasoning depth. -Use a tiny read-only probe that returns a unique marker. A login-status command alone proves credentials, not that the requested model and effort flags run. Record native and external results separately. Never call the external launcher for the parent's own provider. On a Claude parent, the Fable and Opus probes are one-turn runs of the mapped `pstack--` agent. On a Codex parent, the Sol probe is native `spawn_agent` with the selected `reasoning_effort`. Every other pair, flex families always included, uses the external runner with the selected effort flag. A flex probe doubles as the base-URL confirmation: it proves the documented default (or the operator's override) actually serves the lane's model. +Use a tiny read-only probe that returns a unique marker. A login-status command alone proves credentials, not that the requested model and effort flags run. Record native and external results separately. Never call the external launcher for the parent's own provider. On a Claude parent, the Fable and Opus probes are one-turn runs of the mapped `pstack--` agent. On a Codex parent, each assigned Codex family gets a native `spawn_agent` probe with its matrix model and selected `reasoning_effort`. Every other pair, flex families always included, uses the external runner with the selected effort flag. A flex probe doubles as the base-URL confirmation: it proves the documented default (or the operator's override) actually serves the lane's model. Receipts and native transcripts prove the requested effort and the route. They do not prove a provider's hidden applied reasoning depth. There is no implicit timeout, weaker-model fallback, same-provider external fallback, or second mutable configuration source. @@ -83,7 +88,7 @@ Different models sharing a provider count as one provider, even when their effor Validate panel diversity: `arena runners` and `interrogate reviewers` must span at least two distinct providers. A single-provider panel is written only after the operator explicitly confirms the reduced diversity; record that confirmation in the setup report. -Rewrite every matrix-family descriptor to `provider:model@`. Leave `inherit-parent` and `auto` unchanged. An effort-only rerun cannot change a role's family. Changing Grok's effort updates every Grok occurrence and does not move a Sol role onto Grok. Refuse an unqualified slug, an unavailable route, a model outside the stock and flex matrix families, or a provider/model mismatch. +Rewrite every matrix-family descriptor to `provider:model@`. Leave `inherit-parent` and `auto` unchanged. An effort-only rerun cannot change a role's family. Changing Grok's effort updates every Grok occurrence and does not move a Sol role onto Grok. Refuse an unqualified slug, an unavailable route, a model outside the stock, additional, and flex matrix families, or a provider/model mismatch. ### 7. Confirm and commit