Repository navigation
Conversation
Move NodeRoom's default model ids off retired or deprecated ones, per model-defaults SPEC Part A section A.2.9: - one DEFAULT_AGENT_MODEL (gemini-3.8-flash) in convex/modelDefaults.ts replaces the gemini-3.5-flash literals (Google deprecated it 2026-10-08); env chains unchanged - top_paid default anthropic/claude-sonnet-4 -> anthropic/claude-sonnet-5.5; Haiku defaults -> claude-haiku-5-5; pi-ai default gemini-2.5-flash -> DEFAULT_AGENT_MODEL - TTS gemini-3.1-flash-tts-preview -> gemini-3.8-flash-tts (shutdown 2026-11-17) - catalog: 5.5 and gemini pricing rows, tier allowlists, fallback chains pruned; the dotted claude-id regex becomes an explicit table (claude-opus-4.7 now maps to claude-opus-4-7) - Claude 5.5 request shape: forced tool_choice downgraded to auto for Sonnet/Opus 5.5, explicit effort on the AI-SDK path, 2048 max_tokens floor, @ai-sdk/anthropic >= 3.0.120 - judge scripts pinned to gemini-3.6-flash with temperature removed - ladder: --real needs a dollar cap, per-dispatch cost reservation, receipt carries the tested commit, budget and dispatch policy Merge is gated on the L1-L4 ladder receipt (not run here: paid). The adaptiveRouter fast lane stays on gemini-3.5-flash until that receipt exists. Spec: model-defaults SPEC Part A §A.2 (NodeRoom) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Scaffold Handoff — For Your Coding Agent
Immutability CheckMode: advisory ✅ No immutable files were modified in this branch. Changed Files
Needs Adversarial Review — Do NOT Apply YetThese proposals passed the reject check but have not been approved by
Safety Boundary
Immutable files (never modify):
Scaffold files (safe to modify):
|
HomenShum
marked this pull request as draft
October 14, 2026 20:09
- merge gate: PR is a draft with the needs-live-eval label; the ladder receipt, the gemini-3.8-flash-tts listen check and the top_paid Environment smoke are listed as explicit blockers (PR body, CHANGELOG lane) - ladder --json-out is now reviewable under A.0.3: command, candidateIds, echoedModels, per-dispatch rows (provider-echoed model from the raw body, usage, cost, fallbackUsed), environment, budget.requestCeiling - a refused reservation or unpriced id is terminal for the meter: no fallback model, retry or candidate dispatches after it; the provider-neutral Google fallback honours crossModelFallback: false - claude-haiku-5-5 is priced tier-aware (>100K prompt tokens: $0.50/$2.50) in every cost and reservation path; claude-opus-4-7 gets pricingAsOf and an agreement row - Sonnet/Opus 5.5 send strict tool definitions where a forced tool_choice becomes auto; capture reasoner and provider parser send the explicit effort - .env.example copies of the changed defaults now match the code (and a test pins them) - request-shape tests for the TTS route, private stream route, provider parser default, judge scripts; ladder budget tests (b) and (e) follow the specified scenarios Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Refreshes NodeRoom's stale default model ids (Google deprecated
gemini-3.5-flash2026-10-08; OpenRouter dropsgoogle/gemini-2.5-*2026-10-20;claude-sonnet-4retired 2026-06-15;gemini-3.1-flash-tts-previewshuts down 2026-11-17) and fixes the request shapes the new ids reject. Env chains and caller arguments are unchanged: if prod setsAGENT_MODEL,AGENT_ORCHESTRATOR_MODEL,AGENT_TOP_PAID_MODEL,VOICE_GEMINI_TTS_MODELetc., prod does not change - this PR moves code fallbacks only.This PR is a draft and carries the
needs-live-evallabel. Both stay until the three merge blockers below are closed. The label is a block, not a note (SPEC A.0.3). Nothing in this PR made a paid provider call.MERGE BLOCKERS (all three need a provider key; none was run here)
L1-L4 ladder receipt gates the
gemini-3.8-flashdefault (and theadaptiveRouter.ts:136fast-lane literal).tests/qaMatrix.test.ts("keeps the Convex interactive fallback on a ladder-safe route") fails on purpose until it exists:gemini-3.8-flashhas no PASS row indocs/qa/production-matrix.json. The check is not weakened.Pre-flight (re-run on this head with
fetchreplaced by a function that throws; 0 fetch calls): worst case $8.0552 for 2 routes x 4 rungs, request ceiling 144, so the cap must be at least that or the run refuses to start. Actual spend is expected to be a small fraction of it. Commit the receipt in a receipt-only commit on top of the tested commit (A.0.3 form a) with a clean tree.The
--json-outreport now carries everything A.0.3 reviews:command,candidateIds,echoedModels,rows[](one per provider request:requestedModel,resolvedModel,echoedModel,usage,costUsd,fallbackUsed,rung),environment,testedCommit(40-hex),gitDirty,constantSha256,budget(maxUsd,estimateUsd,spentUsd,requests,requestCeiling,stoppedBy) anddispatchPolicy. Reject the receipt unless:requestedRoutes == candidateIds == ["gemini-3.6-flash","gemini-3.8-flash"]; rungs are exactly L1-L4 with 8 passing result rows; every row hasresolvedModel == requestedModel,fallbackUsed == falseand anechoedModelequal to the requested id (agemini-3.8-flashrequest answered as another model is the failure this field exists to expose; 3.5 is already served as 3.6);budget.stoppedBy == null;budget.requests <= budget.requestCeiling;gitDirty == false;dispatchPolicy == {maxRetries:0, crossModelFallback:false}.echoedModelis read from the raw response body (modelVersion/model): the AI SDK'sresponse.modelIdis the requested id for Google, so it could never show a re-route.Manual listen check of
gemini-3.8-flash-tts(convex/http.ts:36, SPEC A.0.7: a frozen-class id with an announced shutdown inside 60 days moves to its vendor-named replacement, and a listen test is the gate). Shape-verified here by a fake-transport test throughPOST /voice/synthesize; the audio itself is unverified. To close it: on a deployment withGOOGLE_GENERATIVE_AI_API_KEYandVOICE_TTS_PROVIDER=gemini, POST one short line to/voice/synthesize, confirmX-Voice-TTS-Model: gemini-3.8-flash-ttsand a playable WAV in theKorevoice, and record the result on this PR. The oldgemini-3.1-flash-tts-previewshuts down 2026-11-17.Observed Environment smoke for
top_paid(convex/agentJobs.ts:2101,anthropic/claude-sonnet-5.5over OpenRouter). Whether OpenRouter rewrites a forcedtool_choice, and whether it passesstrict: truetool definitions through, is unobserved, so the request is sent astool_choice: autoplusstrict: trueand one live request has to show a 200 with a tool call (SPEC 1.3, A.2.9).Also not run:
prod:gate(network, audit, design and proof gates). CI'sverifyjob fails at thenpm auditstep on rootundici 8.10.0, the same version asorigin/main, so that failure is not from this PR (PR #256 bumps it); failing checks are not required for merge, which is why the block is the draft state plus the label.Runtime sites (44; migrate 26, freeze 16, defer 2 per spec)
convex/agent.ts:346gemini-3.5-flashconvex/agent.ts:345minimax/minimax-m3convex/agent.ts:783gemini-3.5-flashconvex/agent.ts:65z-ai/glm-4.7-flashconvex/agentJobs.ts:2103gemini-3.5-flashconvex/agentJobs.ts:2102minimax/minimax-m3convex/agentJobs.ts:2101anthropic/claude-sonnet-4AGENT_TOP_PAID_MODEL ?? AGENT_MODEL ?? constunchanged.convexModelnow sendstool_choice: autoplusstrict: truetool definitions for this id (SPEC 1.3) instead of a forced choice. Stays a draft until the observed Environment smoke (merge blocker 3).convex/agentJobRunner.ts:512gemini-3.5-flashconvex/agentJobRunner.ts:514openrouter/free-autoconvex/http.ts:175gemini-3.5-flashconvex/streaming.ts:68gemini-3.5-flashconvex/http.ts:35gemini-3.1-flash-tts-previewconvex/http.ts:36) - Google shutdown 2026-11-17, vendor-named replacement, frozen-class voice exception (A.0.7).VOICE_GEMINI_TTS_MODELprecedence unchanged. The manual listen check is merge blocker 2. A fake-transport test drivesPOST /voice/synthesizeand asserts the wire id.convex/http.ts:283gpt-4o-mini-transcribeconvex/http.ts:352gpt-4o-mini-ttsconvex/okfEmbeddingProvider.ts:43gemini-embedding-2src/landing/modelRegistry.ts:37z-ai/glm-5.2src/landing/modelRegistry.ts:48anthropic/claude-fable-5src/ui/Chat.tsx:1518moonshotai/kimi-k3src/ui/Chat.tsx:1690gemini-3.5-flashsrc/nodeagent/models/modelCatalog.ts:305moonshotai/kimi-k3src/nodeagent/models/modelCatalog.ts:232gpt-5.4src/nodeagent/models/modelCatalog.ts:272claude-haiku-4.5src/nodeagent/models/modelCatalog.ts:288gemini-3-flash-previewsrc/nodeagent/models/modelCatalog.ts:342gpt-5.4-minisrc/nodeagent/models/modelCatalog.ts:187claude-haiku-4.5src/nodeagent/models/modelCatalog.ts:612claude-sonnet-4.6claude-opus-4.7now maps toclaude-opus-4-7(it was silently rewritten toclaude-opus-4-8); theopusandclaude-opusshortcuts are pinned toclaude-opus-4-8, which is what they effectively resolved to before, so their behaviour is unchanged;claude-*-5.5dotted ids map toclaude-*-5-5; every other dotted 4.x id that can sit in a persisted row is listed.src/nodeagent/models/modelCatalog.ts:641z-ai/glm-5.2src/nodeagent/models/modelCatalog.ts:806z-ai/glm-5.2AGENT_FALLBACK_MODELSprecedence unchanged.src/nodeagent/models/adapter.ts:132claude-haiku-4-5sdkToolChoiceForModeldowngradesrequiredtoauto(withstrict: truetools) for forcedToolChoice-forbidden ids, and the ladder meter'sreserveDispatch+maxOutputTokenssit inside the threewithRetryclosures with the dispatch-policy option (A.2.9 Ladder budget).src/nodeagent/models/adapter.ts:152gemini-3.5-flashsrc/nodeagent/models/adapter.ts:216(env-provided)src/nodeagent/models/piAiAdapter.ts:9gemini-2.5-flashsrc/nodeagent/capture/reasoning.ts:23claude-haiku-4-5CAPTURE_REASONING_MODELprecedence unchanged; now sends the explicit SPEC 1.3 effort (claudeEffortProviderOptions).src/nodeagent/models/providerParserLive.ts:110gemini-3.5-flashsrc/nodeagent/models/providerParserLive.ts:111gpt-5.5src/nodeagent/models/providerParserLive.ts:112claude-haiku-4-5src/nodeagent/models/providerParserLive.ts:113z-ai/glm-5.2src/nodeagent/core/adaptiveRouter.ts:82minimax/minimax-m3src/lib/models/modelRouter.ts:47nebius/zai-org/GLM-5.2src/nodeagent/models/openRouterFreeModels.ts:59cohere/north-mini-code:freebackend/app/config.py:78nvidia/nemotron-3-nano-omniGET {GMI_MAAS_BASE_URL}/models+ the backend's pytest; not covered by npm gatesbtb_noderoom_agent/harbor_adapter.py:83z-ai/glm-5.2scripts/gemini-demo-media-judge.ts:21gemini-3.5-flashscripts/design-qa/rubric-panel.ts:31gemini-3.5-flashExecutable (E) and runtime-adjacent (R) sites (20; migrate 7, freeze 12, defer 1)
src/nodeagent/models/modelCatalog.ts:63claude-opus-4.7longContext, applied by every cost and reservation path), claude-sonnet-5-5 ($2/$10), claude-opus-5-5 ($4/$20), gemini-3.8-flash ($0.75/$3.75; $1.50/$7.50 from 2027-01-01), gemini-3.6-flash ($0.75/$3.75), gemini-3.5-flash-lite ($0.30/$2.50); the claude-opus-4-7 row ($5/$25) the alias table now needs carriespricingAsOf; retired 4.x rows kept for persisted rooms; all rows are in the agreement test (A.0.6).src/nodeagent/core/creditModel.ts:57z-ai/glm-5.2src/nodeagent/models/convexModel.ts:968(any claude-*)anthropicStepalready sent no temperature/thinking/tool_choice/prefill; added the 2048max_tokensfloor for 5.5 ids (thinking counts), reading blocks by type (test), andstrict: truetool definitions where a forced choice is downgraded toauto;tool_choiceforwarding at :842/:892 sendsauto(plus strict tools) for forcedToolChoice-forbidden ids.scripts/benchmark/modelEvalConfig.ts:126deepseek/deepseek-v4-flashscripts/benchmark/run.ts:63gemini-3.1-flash-litescripts/benchmark/probe.ts:13claude-opus-4-8evals/ladder.ts:670gpt-5.4-nanoevals/professionalLiveCatalog.ts:51deepseek/deepseek-v4-flashdeepseek-v4-flashretirement is a different transport - per-transport fact, B.1); research_champion by evidence; also financeModelLive.ts:983, halo-live-path-calibration.ts:22, package.json:241,245scripts/finch-official-judge.py:20gpt-5-miniscripts/finauditing-official-judge.py:26gpt-5-miniscripts/mbabench-official-sweep.py:26google/gemini-3-flash-previewscripts/judge-demo-gif.ts:24gemini-3.5-flashscripts/walkthroughs/judge-video.ts:53gemini-3.5-flashscripts/eval/providerParseSmoke.ts:21claude-haiku-4-5scripts/startup-diligence-provider-eval.ts:150gemini-3.5-flashscripts/bankertoolbench-nodeagent-full-sweep.ps1:7z-ai/glm-5.2scripts/bankertoolbench-nodeagent-clean-sequential.mjs:8gpt-4.1-miniscripts/inference-nodetrace/run.mjs:13gpt-5.4scripts/walkthroughs/voiceover.ts:60gpt-4o-mini-ttspackage.json:82gpt-5-miniClass N (24) dispositions - docs loop, test assertions, examples, fixtures
doc (5)
src/nodeagent/models/modelCatalog.ts:1header comment ("Primary NodeBench default: z-ai/glm-5.2"): freeze - glm-5.2 is untouched by this PR.README.md:1604(npx convex env set AGENT_MODEL gemini-3.5-flash): defer - an operator command that names the ladder-recorded route. It moves togemini-3.8-flashin the same commit as the ladder receipt (merge blocker 1), exactly like theadaptiveRouter.ts:136literal; moving it first would recommend a route with no PASS row.production-agent.json:108(modelMigration.pinnedModelz-ai/glm-5.2): freeze - pins the glm-5.2 default, unchanged.docs/eval/FIRST_USER_E2E.md:209(z-ai/glm-5.2 env example): freeze - recorded run instructions, glm-5.2 unchanged.docs/historical mentions (841 docs, 20 evidence, 30 .proofloop, 8 episodes files): freeze - hash-bound evidence and archived prototypes are never rewritten.eval-fixture (1)
public/eval/proofloop-prod-proxy-benchmark-matrix.json: freeze - generated benchmark artifact derived fromsrc/eval/proofloopProdProxyBenchmarkMatrix.ts; glm-5.2 unchanged.example (7)
.env.example:65NODEAGENT_FREE_AUTO_GOOGLE_MODEL: migrate ->gemini-3.8-flash(the code default)..env.example:116GEMINI_SEO_VIDEO_JUDGE_MODEL: migrate ->gemini-3.6-flash(the judge script default)..env.example:165PROVIDER_PARSER_GEMINI_MODEL: migrate ->gemini-3.8-flash,gemini-3.6-flash; the neighbouring:167PROVIDER_PARSER_ANTHROPIC_MODEL->claude-haiku-5-5,claude-sonnet-5-5and:168PROVIDER_PARSER_OPENROUTER_MODELwithout the unlistednex-agi/nex-n2-proare part of the same copy (the inventory records them under :165).:84VOICE_GEMINI_TTS_MODEL->gemini-3.8-flash-tts(the shutdown-deadline fix). Env vars beat code defaults, so a.envbuilt from the old file would have silently restored every one of these ids..env.example:66AGENT_MODEL=gpt-5.4-nano,:103AGENT_FILE_EGRESS_MODEL,:147FREE_AUTO_JOB_MODEL: freeze - values this PR does not change.src/nodeagent/core/subagentDispatcher.ts:32('minimax/minimax-m3'in a zod.describe): freeze - research lane champion.tests/modelRefreshServerRoles.test.ts, last describe) now fails if any of these.env.examplevalues drifts from what the code defaults to.test-assertion (11)
modelAliasClaude.test.ts:11(claude-opus-4.7 -> claude-opus-4-7),phaseModel.test.ts:73(the top_paid fallback fixture is nowanthropic/claude-sonnet-5.5; claude-sonnet-4 retired 2026-06-15),agentJobsRuntime.test.ts(new: default model per route policy, asserted as literals),openRouterFreeModels.test.ts(autofollows the constant),openAiTokenLimit.test.ts(gpt-6 case),providerEgressPolicy.test.ts(re-run, passes unchanged), and in this roundproviderParserLive.test.ts(env idgemini-3.6-flash, which is a default, so the de-duplication check still bites).kimiK3Default.test.ts:22,convexModelFreeAutoMode.test.ts,chatModelPickerPolish.test.tsx:168(claude-sonnet-4-6 is still a live catalog row),openRouterConvexBenchmark.test.ts,finchOfficialJudgeCostGuard.test.ts(frozen official judge),modelEvalMatrix.test.ts(promotion tags).Hash-bound evidence files untouched.
Pricing sources (A.0.6) - every source is enumerated and in
tests/modelPricingAgreement.test.tsmodelCatalog.modelPricing- the only hand-typed table. Every row this PR adds or relies on now carriespricingAsOf(2026-10-10), includingclaude-opus-4-7($5/$25, whichclaude-opus-4.7now resolves to) and is in the agreement cases.claude-haiku-5-5andanthropic/claude-haiku-5.5also carry the >100K-prompt tier ($0.50/$2.50) aslongContext.getModelPricing- accessor over (1).adapter.priceRun,priceRunStrict,reserveDispatch- tier-aware throughmodelCatalog.priceTokens(the ladder meter uses the strict price and the reservation).convexModel.convexPriceRun,exactConvexUsageCost,convexAttemptCostReservationUsd- tier-aware through the same helper.creditModelprivatepriceRunandproofloopModelTrackingcost estimate - tier-aware through the same helper.Chat.tsxprice chips (show the base tier) andscripts/benchmark/run.tscatalogPricingAtRun(records a flat{inputPer1M, outputPer1M}snapshot per run; benchmark prompts are short and it is not a spend guard, so it is left flat).The tier fix is behaviour, not just data: 120K input + the 8192-token cap now reserves $0.08048 (was $0.016096), and the pre-flight estimate prices each step by its prompt size.
Breaking-parameter fixes (spec section 1.3)
sdkToolChoiceForModel(adapter.ts),convexModel.openAiCompatibleToolChoice(OpenRouteranthropic/claude-*-5.5) and the LangChain bridge sendautoinstead of a forcedrequired/anyfor Sonnet/Opus 5.5 (and Fable 5.1); Haiku 5.5 keeps a forced choice. Keyed by exact wire id inmodelCatalog.forbidsForcedToolChoice. New this round: wherever that downgrade happens the tool definitions carrystrict: true(needsStrictTools: AI-SDK adapter, direct AnthropicanthropicStep, OpenRouteropenAiTool), which is SPEC 1.3's replacement for the forced choice. It is applied only on the downgrade, so no other path changes.modelMaxOutputTokens(id)(sharedsrc/nodeagent/models/outputTokens.ts): 2048 floor for 5.5 ids because thinking counts towardmax_tokens;anthropicStepreads content blocks by type (test).effort(haiku medium / sonnet high / opus medium) on every AI-SDK Anthropic path that moved to a 5.5 id: the adapter, and, new this round,capture/reasoning.tsandproviderParserLivethrough one helper (claudeEffortProviderOptions);@ai-sdk/anthropic^3.0.84->^3.0.120.openAiTokenLimitregex also matchesgpt-6(precondition only; no gpt-6 id lands here).gemini-3.6-flashwithtemperatureremoved (deprecated on 3.6+);GEMINI_JUDGE_MODELenv chains unchanged.resolveModelAlias: the dotted-id regex rewrite is deleted for an explicit table;claude-opus-4.7now maps toclaude-opus-4-7(was silently-4-8). Theopusandclaude-opusshortcuts are pinned toclaude-opus-4-8(their previous effective target, behaviour preserved). Old 4.x strings stay valid for persisted rows.--realrefuses to start withoutLADDER_MAX_COST_USD/--max-cost-usd; job-wide meter;reserveDispatchinside everywithRetrydispatch (maxRetries: 0on the SDK, one reservation per physical request);priceRunStrictthrowsUnpricedModelErrorinstead of a guessed $1/$5;dispatch: { maxRetries, crossModelFallback }option. New this round: a refused reservation or unpriced id is terminal for the meter (the failed dispatch can no longer fall through toAGENT_FALLBACK_MODEL, a retry, or a free-auto candidate), and the provider-neutralnodeagent/free-autoGoogle fallback honourscrossModelFallback: false(it previously always went to paid Gemini).ladder:freegets--max-cost-usd=1because a cap is now mandatory.Test proof
New request-shape tests build a real request through the repo's own builders with a fake
fetch, asserting the literal wire id (never imported from the code under test) and that forbidden keys are absent:tests/modelRefreshRequestShape.test.ts-convexModel(direct Anthropic, OpenRouter),adapter.model,aiSdkReasoner, the LangChain bridge, pi-ai default; now alsostricttools and effort.tests/modelRefreshServerRoles.test.ts(new) - the roles that had no fake-transport test: Gemini TTS (drivesPOST /voice/synthesize), private stream (drivesPOST /stream-private-reply, nothing injected: the route's ownAGENT_MODEL ?? DEFAULT_AGENT_MODELreachesgeminiStream), provider parser (runLiveProviderParserwith no model argument, so the default candidate reaches the wire; effort and wire id for haiku and sonnet), judge scripts (rubric-panel, visual-polish, mp4-workflow-review, SEO judge and walkthroughs/judge-video are executed with fixtures and a fakefetch; four scripts that need ImageMagick, LibreOffice or the benchmark workbooks are checked on the TypeScript AST for anytemperatureproperty), and.env.exampleagainst the code defaults.tests/modelPricingAgreement.test.ts(A.0.6 agreement, tier-aware),tests/modelCatalogRefresh.test.ts.evals/ladderBudget.test.tsdrives the actual adapter path. Round 1 tightened (b) to the specified sequence (charged response, then ECONNRESET) and (e) to usage that stays within every reservation: the cap is the pre-flight estimate itself, the context outgrows the scripted dry run, and the test asserts the grid stops before the cap (spentUsd < maxUsd, a refused reservation,budget.requestsequals the fetch count and is below the ceiling). Also covered: terminal-stop behaviour, per-dispatch receipt rows (echoedModel,fallbackUsed) and the report fields.tests/modelAdapterProviderNeutralRoute.test.ts-crossModelFallback: falsenever reaches paid Gemini.Each new assertion was checked by reverting the line it protects (TTS constant,
DEFAULT_AGENT_MODEL, a judge script'stemperature/model, the parser default and effort, strict tools, the tier, the terminal stop, the fallback guard): the matching test fails every time.Check output (
npm run check= typecheck + convex tsc + vitest)The files typechecked for the first time because the new tests import them needed two type-only fixes (
scripts/design-qa/rubric-panel.tscontent type, an unused import in the SEO judge); both lines are unchanged fromorigin/main.Not in this PR / for the human
backend/app/config.py:78-80,llm.py:37on GMI MaaS): defer - listGET {GMI_MAAS_BASE_URL}/models, confirm the ids, run the backend pytest.src/landing/modelRegistry.ts:48(anthropic/claude-fable-5): defer until the forced-tool-choice downgrade is observed live (merge blocker 3).README.md:1604andadaptiveRouter.ts:136: move togemini-3.8-flashwith the ladder receipt.gpt-5-mini(retires 2026-12-11, URGENT decision),google/gemini-3-flash-preview, benchmark judgegemini-3.1-flash-lite(2027-05-07).undiciinpackage.json/package-lock.jsonand PR fix(evals): reject unconfigured real-mode runs #260 ownsevals/runEval.ts; this PR touches neither. The lockfile change here adds a nested@ai-sdk/anthropic/node_modules/undici6.29.0 entry; re-runnpm ciafter whichever PR merges second.Spec: model-defaults SPEC Part A section A.2 (NodeRoom)