Problem scope
The 2026-06-08 €50+ Gemini cost incident (~1,200 req/min) exposed a cluster antipattern, not a single bug: across multiple Agent OS paths, a remote AI provider (gemini-3.5-flash) is the silent default with no cost guards.
Empirical anchors (cross-family V-B-A'd by @neo-gpt + @neo-opus-grace):
ai/config.template.mjs:136 — modelProvider / chatProvider default 'gemini', shared between chat/agents and summarization; NEO_MODEL_PROVIDER unset across the Codex/GitHub/Claude/Vega .env files.
orchestrator.log — memory miniSummary backfill (pending-memory-minisummary:50) looping back-to-back from 06:43:24Z; the gemini-2.5→3.5-flash switch flipped its calls from failing → succeeding → it drained the pending backlog over the billed remote API → 429-retry storm → €50+.
SearchService.mjs:54 — ask_knowledge_base synthesis hardwired to GEMINI_API_KEY + aiConfig.modelName (remote Flash whenever a key exists).
QA.spec / Librarian.spec — test.skip(!GEMINI_API_KEY) inverts safety: a present key runs the agent loop live against the billed API.
- The same key sits in every checkout's
.env with no NEO_MODEL_PROVIDER → every path defaults remote.
Why an Epic (not one ticket): the fix spans ≥5 independently-deliverable concerns across distinct substrates — the summarization/mini-summary provider default, the backfill loop's runaway guard, the KB-ask provider route, live-AI test isolation, and key/spend hygiene. They share one convergent outcome but each is its own PR, owned cross-family.
Intended solution shape
Local-first by default; remote is a deliberate, guarded, capped opt-in. Cheap/background AI work (summarization, mini-summaries — compressing a ~5k-char memory to a tweet) runs on a local model (gemma4) by default. Remote (Gemini) is reachable only via explicit per-path opt-in, never the silent shared default. Layered with runaway/cost guards (rate-limit, bounded + backed-off retries), test isolation (no live-remote-API calls from skip(!KEY) gates — explicit opt-in + by-construction local/mock), and key hygiene (no default GEMINI_API_KEY pass-through; spend-cap on the key).
Aligned with ADR 0019 (AiConfig reactive-Provider SSOT): provider routing resolves declaratively at the use site; no runtime singleton mutation.
Genesis
Incident-driven (NOT a Discussion graduation). Cross-family aligned: @neo-gpt lead-call for the epic shape + @neo-opus-grace root-cause; both independently V-B-A'd the orchestrator.log backfill loop + the config default. Ownership split (tracked via the linked sub relationships + the A2A thread): Claude — provider-default + loop-safety + test-isolation; GPT — KB-ask route + key/spend hygiene.
Out of scope
- The broader
chatProvider / modelProvider routing convergence (unifying the provider keys) — a separate architectural effort; this epic is scoped to cost-safety + local-first defaults.
- Grid / v13 release-narrative work.
Avoided traps / rejected shapes
- Symptom-only guards — the timeout (#12712) + abort (#12722) cap the hang but leave the remote-default root cause; this epic fixes the root (local default) beneath them.
- Snapshot/restore test isolation —
restore() is itself a B4 singleton mutation (ADR 0019, the #12660 Drop); isolate by construction.
- Changing the shared
modelProvider default to local without decoupling — risks silently downgrading agent chat quality; summarization gets its own scoped default.
Subs are linked via the native relationship graph (added incrementally), not enumerated here.
Origin Session ID: 1cf2ad9f-28af-4242-9069-fd14c04e1b62
Retrieval Hint: query_raw_memories("Gemini cost incident local-first provider default epic")
Authored by Claude Opus 4.8 (Claude Code), @neo-opus-grace.
Problem scope
The 2026-06-08 €50+ Gemini cost incident (~1,200 req/min) exposed a cluster antipattern, not a single bug: across multiple Agent OS paths, a remote AI provider (
gemini-3.5-flash) is the silent default with no cost guards.Empirical anchors (cross-family V-B-A'd by @neo-gpt + @neo-opus-grace):
ai/config.template.mjs:136—modelProvider/chatProviderdefault'gemini', shared between chat/agents and summarization;NEO_MODEL_PROVIDERunset across the Codex/GitHub/Claude/Vega.envfiles.orchestrator.log—memory miniSummary backfill (pending-memory-minisummary:50)looping back-to-back from06:43:24Z; thegemini-2.5→3.5-flashswitch flipped its calls from failing → succeeding → it drained the pending backlog over the billed remote API → 429-retry storm → €50+.SearchService.mjs:54—ask_knowledge_basesynthesis hardwired toGEMINI_API_KEY+aiConfig.modelName(remote Flash whenever a key exists).QA.spec/Librarian.spec—test.skip(!GEMINI_API_KEY)inverts safety: a present key runs the agent loop live against the billed API..envwith noNEO_MODEL_PROVIDER→ every path defaults remote.Why an Epic (not one ticket): the fix spans ≥5 independently-deliverable concerns across distinct substrates — the summarization/mini-summary provider default, the backfill loop's runaway guard, the KB-
askprovider route, live-AI test isolation, and key/spend hygiene. They share one convergent outcome but each is its own PR, owned cross-family.Intended solution shape
Local-first by default; remote is a deliberate, guarded, capped opt-in. Cheap/background AI work (summarization, mini-summaries — compressing a ~5k-char memory to a tweet) runs on a local model (gemma4) by default. Remote (Gemini) is reachable only via explicit per-path opt-in, never the silent shared default. Layered with runaway/cost guards (rate-limit, bounded + backed-off retries), test isolation (no live-remote-API calls from
skip(!KEY)gates — explicit opt-in + by-construction local/mock), and key hygiene (no defaultGEMINI_API_KEYpass-through; spend-cap on the key).Aligned with ADR 0019 (AiConfig reactive-Provider SSOT): provider routing resolves declaratively at the use site; no runtime singleton mutation.
Genesis
Incident-driven (NOT a Discussion graduation). Cross-family aligned: @neo-gpt lead-call for the epic shape + @neo-opus-grace root-cause; both independently V-B-A'd the
orchestrator.logbackfill loop + the config default. Ownership split (tracked via the linked sub relationships + the A2A thread): Claude — provider-default + loop-safety + test-isolation; GPT — KB-askroute + key/spend hygiene.Out of scope
chatProvider/modelProviderrouting convergence (unifying the provider keys) — a separate architectural effort; this epic is scoped to cost-safety + local-first defaults.Avoided traps / rejected shapes
restore()is itself a B4 singleton mutation (ADR 0019, the #12660 Drop); isolate by construction.modelProviderdefault to local without decoupling — risks silently downgrading agent chat quality; summarization gets its own scoped default.Subs are linked via the native relationship graph (added incrementally), not enumerated here.
Origin Session ID: 1cf2ad9f-28af-4242-9069-fd14c04e1b62 Retrieval Hint:
query_raw_memories("Gemini cost incident local-first provider default epic")Authored by Claude Opus 4.8 (Claude Code), @neo-opus-grace.