Repository navigation
feat(core): derive provider conformance matrix from registry declarations - #974
Conversation
Phase 7 of #860: derive rows from every ready registry entry and resolve each contract dimension to generated / named-override / explicit-N/A, as a pure function with no runtime behavior change.
Phase 7 of #860: run every generated cell against scripted local protocol servers, assert named overrides are registered, execute fallback reverse assertions, and fail CI on any coverage gap.
8fc6041 to
6bb0dda
Compare
Review hardening for the Phase 7 matrix (#860): discovery cells now assert the declared path, query, and credential placement before responding (public discovery must carry no credential; array-or-data runs both fixtures); Anthropic/Google/Cohere wire runners assert the second turn actually replays the tool result tied to the first-turn call id, matching the OpenAI runner; override registry entries bind to exact hand-written test titles so deleting or renaming an owned test fails the matrix instead of drifting silently. Every new assertion was mutation-verified red before restore.
|
Review hardening landed in
Every new assertion was mutation-verified: temporarily breaking the fetcher's path/query/auth consumption, each SDK's tool-result serialization, and one registry title each turned exactly the corresponding cells red with provider- and dimension-named messages, then restored. One seam surfaced by lm-studio: the plan derives discovery auth |
The plan derived discovery auth 'default' for authKind 'none' providers (lm-studio), forcing the runtime executor to second-guess the plan via providerAuthSupportsApiKey. Derive 'none' at the plan layer instead and drop the executor workaround: a generated 'none' cell now uniformly means the request must carry no credential.
|
Follow-up: the lm-studio seam noted above is closed in |
…ndings Rereview round two on the Phase 7 matrix (#860): the GitHub Copilot conformance test now asserts the second turn carries the exact model id, replays the assistant tool_calls id and reasoning_content verbatim, and links the tool result via tool_call_id; the github-copilot:discovery override rebinds to the dedicated picker/endpoint-gating test in model-fetcher.test.ts (bindings now name their source file); the binding check requires an enabled test( call so test.skip/test.todo no longer count as coverage. All new assertions mutation-verified red then restored.
|
Second external review round handled in
Recorded deferral: E2E note: the earlier red gate was the pre-existing MiniMax catalog spec timing out in window teardown with all assertions passing — no overlap with this diff; a clean rerun is green, so it is classified as infrastructure per the #860 guardrail. |
…ecks A binding matched any test( call merely opening with the bound title, so renaming a hand-written test by appending a suffix still counted as coverage. Match the complete quoted title instead; the commented-out residual stays documented for the Phase 8 executable override binding.
|
Third external review round returned no blockers; two P2 follow-ups, one fixed in
|
…#1105) Part of #860 (Phase 8), closing the preconditions recorded in #974: - optional_api_key discovery cells now derive auth: 'optional' and the generated matrix executes both credential branches (configured key reaches the wire; absent key sends no credential at all). - Override cells now bind to executable runs in provider-contract-overrides.ts that the matrix suite executes directly, replacing the textual test-title source check; the bound hand-written tests moved out of provider-conformance.test.ts / model-fetcher.test.ts so each contract runs exactly once. - The /^gpt-5/i Responses routing regex is lifted into the openAiAdapterApiProtocol declaration in core (ModelInfo.apiProtocol seam); runtime model-factory and the matrix sample-id derivation both consume the declaration, with a wire test locking gpt-5*->Responses and other ids->Chat Completions.
…ted matrix Part of #860 (Phase 8). With the #974 preconditions landed, remove the hand-written two-stage replay tests whose every assertion is owned by a generated matrix cell, and strengthen the generated wire to also assert the per-protocol request credential (Bearer / x-api-key / x-goog-api-key keyed off the registry authKind, and no credential for authKind none) so the deleted per-provider auth assertions stay locked. Deleted (replaced by the named generated cells): OpenCode Go, LocalAI, LM Studio, Cerebras, NVIDIA, SiliconFlow, MiniMax Coding Plan, xAI, Together AI, Mistral, Tencent TokenHub, and the Xiaomi + Z.AI pair. Kept (unique provider contracts): testConnection probes, per-model override Responses routing (OpenCode Zen), signed reasoning_details (ZenMux), buildProviderOptions wires (Vercel, Ollama Cloud, DeepInfra, Groq, OpenRouter, Cloudflare, Tencent Token Plan, Volcengine Ark), reasoning-source quirks (StepFun), full fallback-snapshot lists (Tencent/Volcengine/StepFun plans), and Hugging Face capability mapping. The conformance suite now shares the scripted-HTTP harness instead of carrying its own copy.
…ted matrix (#1108) * test(runtime): delete hand-written conformance replaced by the generated matrix Part of #860 (Phase 8). With the #974 preconditions landed, remove the hand-written two-stage replay tests whose every assertion is owned by a generated matrix cell, and strengthen the generated wire to also assert the per-protocol request credential (Bearer / x-api-key / x-goog-api-key keyed off the registry authKind, and no credential for authKind none) so the deleted per-provider auth assertions stay locked. Deleted (replaced by the named generated cells): OpenCode Go, LocalAI, LM Studio, Cerebras, NVIDIA, SiliconFlow, MiniMax Coding Plan, xAI, Together AI, Mistral, Tencent TokenHub, and the Xiaomi + Z.AI pair. Kept (unique provider contracts): testConnection probes, per-model override Responses routing (OpenCode Zen), signed reasoning_details (ZenMux), buildProviderOptions wires (Vercel, Ollama Cloud, DeepInfra, Groq, OpenRouter, Cloudflare, Tencent Token Plan, Volcengine Ark), reasoning-source quirks (StepFun), full fallback-snapshot lists (Tencent/Volcengine/StepFun plans), and Hugging Face capability mapping. The conformance suite now shares the scripted-HTTP harness instead of carrying its own copy. * chore: retrigger CI * test(runtime): harden the generated wire per external review of #1108 Accepted findings from the external review: - P1: wire runs expand optional_api_key into both credential branches (configured key must reach the wire; absent key must send no credential at all), matching the discovery-side expansion; assertWireCredential now also asserts every non-selected credential header (authorization, x-api-key, api-key, x-goog-api-key) is absent for all authKinds. - P2: five declared edge wire samples (opencode-go kimi-k2.7-code, localai localai/Qwen3-8B-Instruct-GGUF:Q4_K_M, lm-studio lmstudio-community/Qwen3-Coder-30B-A3B-Instruct-GGUF, minimax-coding-plan MiniMax-M2.7-highspeed, tencent-tokenhub hy3-preview) run end-to-end through the same wire executor (exact-model-id + tool-loop) on the per-id resolved wire; the declaration lives in the core matrix plan (EDGE_WIRE_SAMPLE_MODEL_IDS -> row.edgeWireSamples) so future providers enter by declaration. - P2: the generic OpenAI wire fixture issues an opaque tool-call id (D681PevKs9, no call_ prefix) and both turns assert it is replayed verbatim, so id canonicalization regressions cannot pass. - P2: wire connections carry a sentinel base-URL pathname (/contract-base/...) and every protocol runner asserts the final request path equals the sentinel prefix plus the protocol suffix, proving the runtime preserves configured baseUrl pathnames. Request-contract violations in wire handlers are recorded and rethrown after the call so injected regressions fail with the contract message instead of a destroyed-socket timeout. Each hardening was verified by injecting the corresponding runtime regression and observing the new assertion fail by name.
Summary
Refs #860 (Phase 7: contract foundation; the issue stays open).
Provider conformance today is hand-enumerated per provider, so ready providers can silently lack coverage (anthropic, openai, google, deepseek and others have no cell in
provider-conformance.test.ts) and every new provider must remember to add its own. This PR makes conformance an interpretation of the registry declarations instead:packages/core/src/provider-contract-matrix.tsderives a matrix plan fromproviderRegistry: 42 rows (everystatus === 'ready'entry with a wired runtime adapter) × 4 dimensions (discovery, exact-model-id, tool-loop, reasoning-replay). Each cell resolves to exactly one ofgenerated(145: expectations recoverable fromprotocol/runtimeAdapter/modelDiscovery),override(8: provider-specific contracts owned by named hand-written tests under stableprovider:dimensionkeys), ornot-applicable(15: machine-readable reasons;fallback-discovery providers still execute a reverse assertion that/modelsis never requested).The row set is intentionally not
READY_PROVIDER_TYPES: its membership is "has areadyOrder", which would silently dropgithub-copilot.Per the Phase 7 constraints in #860 the change is additive only: no runtime behavior, existing suite,
READY_PROVIDER_TYPESconsumer, or compatibility path changes. Overlap with the hand-writtenprovider-conformance.test.tsis intentional; consolidation belongs to Phase 8.Verification
@maka/core: 968/968 pass, typecheck clean (includes the new 19-test plan-derivation suite).@maka/runtime: 1691 pass / 0 fail, 7 pre-existing skips, typecheck clean (includes the new 89-test generated-conformance suite).main.Review focus
sampleModelIdForknowingly duplicates the runtime's/^gpt-5/iResponses-routing fact (commented at the source). Lifting it into anapiProtocoldeclaration is deferred to a follow-up PR: the regex is an open-world pattern (a newly discoveredgpt-5.xid still routes to Responses) whileapiProtocolis declared per exact model id today, so a naive lift would regress routing for newly discovered models. The follow-up needs a pattern-level declaration seam; both duplication sites disappear with it.