Round-4 remediation — model-contract honesty + memory injection on the completions path
2026-08-09
LOCKSTEP TRACEABILITY MATRIX --- api_endpoints: ["POST /v1/chat/completions", "POST /v1/messages", "none"] sdk_methods_updated: ["document new error code unknown_model (400) in TS+Py error enums — follow-up"] mcp_tools_updated: ["none"] ---
What We Built
Four Round-4 defects, all revert-tested and tsgo-clean.
- Unknown model ids fail loud. A typo'd/nonexistent model (
gpt-9-ultra-nonexistent,
anthropic/claude-sonet-9000) was silently served by a substitute (the router auto-recovers an unresolvable id when the request is flexible, and community requests are flexible by construction). A new API-boundary existence gate now returns a typed 400 unknown_model (naming the id + pointing at GET /v1/catalog/runnable) via router.hasModel(id) (alias-aware, registry-scoped). Known-but-keyless models still correctly 403 byok_required — the gate checks registry existence only, so it doesn't shadow BYOK.
/v1/messagesreports the served model. The Anthropic-format response body reported the
_requested_ model (model: requestModel) while a different model produced it. Now it reports the served model (from the upstream response), matching /v1/chat/completions and x-br-routed-model.
- Community-tier explicit pins stay strict. The earlier BYOK auto-cascade hotfix set
allowFallback=true for _every_ community request (Boolean(communityModel)), so an explicit pin on a community tenant got silently substituted. Narrowed to auto/virtual (+ omitted-model default), so genuine explicit pins are honored (strict) while auto still cascades.
- Memory injects on the completions path. Durable memory persisted (v68) but
/v1/chat/completions showed memory_facts:0 and couldn't recall a stored fact: the write path keys core memory by tenantId while the injector read by userId/agent:id — a key nothing writes. Unified both through a shared resolveMemoryReadScope (memoryKey = tenantId), and fixed the _memoryFactsInjected counter to include user facts. Injection now equals what GET /v1/memory/entries already returns to that key — no new disclosure.
Why It Matters
Round 4 (audited 6.6) capped api-integrator, claim-auditor, and agent-consumer on exactly these: model-contract dishonesty and the memory-injection gap. This wave targets those caps directly.
The Numbers
- 4 defects; new revert-tests (unknown-model-400, community-pin-strict, messages-format served-model, memory subject-alignment) all fail pre-fix and pass post-fix.
pnpm tsgoexit 0; 38 targeted tests green; memory-isolation 18/18, completions 20/20 unaffected.
Competitive Edge
An "authorization & evidence plane" that silently serves the wrong model or loses agent memory across tasks isn't one. This wave makes the router tell the truth about what it ran and gives agents memory that actually persists and injects.
Lockstep Checklist
- [x] API Routes: completions + messages updated; no route add/remove/method change.
- [x] TS/Python SDK: no wire-shape change; new
unknown_modelerror code to add to error enums (follow-up). - [x] MCP Schemas: none.
- [x] Master Record: no new capability; defects tracked in
docs/reviews/2026-08-08/ledger.json.
Follow-ups: x-br-context.memory_facts now counts user facts (doc note); /v1/explain no longer records unknown-model ids (A1 fires pre-routing). Next wave: cost-truthfulness + router explain/health.