[Backend] Provider conformance test suite #359

Closed
opened 2026-08-25 20:39:21 +00:00 by claude-bot · 1 comment
Contributor

Found in the August 2026 session lifecycle review (#319).

Why

An abstraction with one real implementation is not an abstraction. The point of this milestone is that providers can be swapped without a rewrite, and the only way that stays true is a suite every adapter must pass.

It also protects the fallback story: keeping a self-hosted adapter deployed and CI-tested means a managed provider's price rise, rate limit, or outage is an adapter switch rather than an emergency.

Proposed fix

A conformance suite each adapter runs against: submit and retrieve, track_id passthrough and association-by-id, word-timestamp normalisation, vocabulary bias accepted, declared constraints honoured, schema-constrained output where claimed, prompt-token reporting, concurrency limit respected, and correct behaviour on oversized input, a truncated response, and a provider error.

Run it in CI against a deterministic stub and a local self-hosted adapter. Provide a documented command to run it against a live managed provider on demand, plus a monthly canary through the fallback path so the escape hatch is known to work before it is needed.

Acceptance criteria

  • Conformance suite defined and documented as the bar for a new adapter
  • Stub and local adapters pass in CI
  • A documented command runs it against a configured live provider
  • Failure cases covered: oversized input, truncated response, provider error, rate limit
  • A monthly canary exercises the self-hosted fallback path
Found in the August 2026 session lifecycle review (#319). ## Why An abstraction with one real implementation is not an abstraction. The point of this milestone is that providers can be swapped without a rewrite, and the only way that stays true is a suite every adapter must pass. It also protects the fallback story: keeping a self-hosted adapter deployed and CI-tested means a managed provider's price rise, rate limit, or outage is an adapter switch rather than an emergency. ## Proposed fix A conformance suite each adapter runs against: submit and retrieve, `track_id` passthrough and association-by-id, word-timestamp normalisation, vocabulary bias accepted, declared constraints honoured, schema-constrained output where claimed, prompt-token reporting, concurrency limit respected, and correct behaviour on oversized input, a truncated response, and a provider error. Run it in CI against a deterministic stub and a local self-hosted adapter. Provide a documented command to run it against a live managed provider on demand, plus a monthly canary through the fallback path so the escape hatch is known to work before it is needed. ## Acceptance criteria - [ ] Conformance suite defined and documented as the bar for a new adapter - [ ] Stub and local adapters pass in CI - [ ] A documented command runs it against a configured live provider - [ ] Failure cases covered: oversized input, truncated response, provider error, rate limit - [ ] A monthly canary exercises the self-hosted fallback path
Author
Contributor

Landed in PR #493 (merged 2026-09-05, CI green; 1814 passed / 10 skipped / 1 xfailed).

  • tests/conformance/ — 15 ASR + 10 LLM cases parametrised over adapter cases, run in CI against deterministic wire fakes and the local WhisperX adapter; --live mode with QB_CONFORMANCE_* (skips when unset, refuses under CI); make conformance-live.
  • The suite earned its keep immediately: LocalWhisperProvider raised a bare RuntimeError for every failure (429 and 503 indistinguishable) → app/providers/errors.py typed errors with retry_after; declared max_audio_seconds/max_bytes were never enforced → enforce_input_limits() first in every submit; and a second adapter (StubAsrProvider, deliberately unregistered) now takes the opposite branch everywhere the contract allows.
  • Monthly canary provider_canary (beat every 30 days) round-trips the configured ASR and LLM and writes {ran_at, asr_ok, llm_ok, …} to app_settings key provider_canary.

Open, on purpose: the _structured_* LLM transports still raise bare RuntimeError (the case carries that expectation and tightens by one line when they are typed); the #356 enforcement case is an xfail placeholder until that lands; live word-level assertions skip on a silence probe until a speech fixture exists (#433).

Landed in **PR #493** (merged 2026-09-05, CI green; 1814 passed / 10 skipped / 1 xfailed). - `tests/conformance/` — 15 ASR + 10 LLM cases parametrised over adapter cases, run in CI against deterministic wire fakes and the local WhisperX adapter; `--live` mode with `QB_CONFORMANCE_*` (skips when unset, refuses under `CI`); `make conformance-live`. - The suite earned its keep immediately: `LocalWhisperProvider` raised a bare `RuntimeError` for every failure (429 and 503 indistinguishable) → `app/providers/errors.py` typed errors with `retry_after`; declared `max_audio_seconds`/`max_bytes` were never enforced → `enforce_input_limits()` first in every `submit`; and a second adapter (`StubAsrProvider`, deliberately unregistered) now takes the opposite branch everywhere the contract allows. - Monthly canary `provider_canary` (beat every 30 days) round-trips the configured ASR and LLM and writes `{ran_at, asr_ok, llm_ok, …}` to app_settings key `provider_canary`. Open, on purpose: the `_structured_*` LLM transports still raise bare `RuntimeError` (the case carries that expectation and tightens by one line when they are typed); the #356 enforcement case is an `xfail` placeholder until that lands; live word-level assertions skip on a silence probe until a speech fixture exists (#433).
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#359
No description provided.