Same class of finding as round 1, one level in: I factored the DSN-scheme half of the kimi/qwen duplication into openaiCompatScheme and left the eager provider half copy-pasted, so a third built-in still had six lines to clone — including both credential rules, which is exactly the pair you do not want re-typed. registerOpenAICompatBuiltin now installs both halves from one call. The rules that matter hold by construction for every future caller: WithAPIKey passed unconditionally (an unset key must not fall through to OPENAI_API_KEY), and WithAPIKeyName naming that same variable in the 401 hint. Registering kimi and qwen is now one line each. Also fixed a cross-reference the ADR got wrong: Qwen's image-input caveat is README matrix footnote ⁴, not ³ — ³ is kimi's. I wrote "³, shared with kimi" in the ADR and then gave Qwen its own footnote in the README. The break-check harness needed fixing before any of this could be trusted: three of its mutations targeted lines this refactor moved, so they matched nothing, the code was never broken, and the suite reported "test still passed" — identical output to a test that genuinely misses the bug. Mutations are now verified to have landed (sha before/after) and the suite fails loudly if one doesn't. Two new cases cover the helper: dropping the unconditional WithAPIKey, and dropping the scheme-half registration. 8/8 apply and are caught. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Architecture Decision Records
One decision per file, append-only; supersede rather than rewrite.
| ADR | Title | Status |
|---|---|---|
| 0001 | Package layout — canonical types in leaf llm, root re-exports |
Accepted |
| 0002 | Canonical message/content model | Accepted |
| 0003 | Parse grammar — verbatim ids, inline alias expansion, chains | Accepted |
| 0004 | LLM_* env-DSN provider definitions (go-llm parity + eager load) | Accepted |
| 0005 | Provider interface and capabilities model | Accepted |
| 0006 | Model health tracking and backoff | Accepted |
| 0007 | Dependency policy — stdlib-first, hand-rolled REST clients | Accepted |
| 0008 | Failover-chain execution semantics | Accepted |
| 0009 | Multimodal strategy — normalize per target, enforce at provider | Accepted |
| 0010 | Tools and structured output — canonical shape, native mappings | Accepted |
| 0011 | Google provider on the official Gen AI SDK | Accepted |
| 0012 | Agent run loop | Accepted |
| 0013 | Skill model — additive instruction+tool bundles | Accepted |
| 0014 | Conversion-driven extensions (resolvers, typed tools, hooks, ops controls) | Accepted |
| 0015 | llama-swap provider — reuse openai for chat, tailored management + image | Accepted |
| 0016 | imagegen — a canonical text-to-image interface | Accepted |
| 0017 | audio — canonical speech synthesis + transcription interfaces | Accepted |
| 0018 | imagegen.Editor — image-to-image as a separate optional interface | Accepted |
| 0019 | videogen — canonical video-generation surface | Accepted |
| 0020 | Upstream-passthrough media surfaces (mask, upscale, background removal, interpolation, diarization, meshgen) | Accepted |
| 0021 | musicgen — blocking Generate over an async job queue | Accepted |
| 0022 | embeddings + rerank interface | Accepted |
| 0023 | Wave-3 image + document surfaces (segmentation, colorize, face restore, OCR) | Accepted |
| 0024 | Wave-3 audio surfaces (stems, SFX, speech enhance, voice clone, translate) | Accepted |
| 0025 | Wave-3 video surfaces (lipsync, video matte, video upscale, chain jobs) | Accepted |
| 0026 | Kimi (Moonshot AI) built-in provider — reuse openai client, KIMI_API_KEY | Accepted |
| 0027 | Qwen (Alibaba) built-in provider — OpenAI-compat, not Model Studio's Anthropic-compat endpoint | Accepted |