Skip to content

fix(db): union dispatch-tagged registry models into authoritative live catalogs - #15599

Merged
diegosouzapw merged 7 commits into
diegosouzapw:release/v3.8.52from
woodsonl:fix/zai-live-catalog-registry-union
Oct 6, 2026
Merged

diegosouzapw merged 7 commits into
diegosouzapw:release/v3.8.52from
woodsonl:fix/zai-live-catalog-registry-union

Conversation

@woodsonl

@woodsonl woodsonl commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • OmniRoute builds authoritative per-provider model catalogs from live discovery and rejects models missing from them before dispatch. On z.ai that rejected a model the provider actually serves: discovery (the Anthropic-compat /models surface) omits the glm-5.3-flash coding-plan family, so every combo targeting zai/glm-5.3-flash-max returned 503 ALL_TARGETS_SKIPPED with model_not_in_catalog. Observed live on a v3.8.51 deployment: the factory-efficient combo was fully down while the model worked through every other path.
  • Fix: unionRegistryDispatchModels lets targetFormat-tagged registry models join the discovered set for providers that opt in via a new registryDispatchUnion registry flag (zai first). The union is bounded: only non-empty discovery sets, only ids discovery did not report; untagged models stay discovery-gated; custom rows alone still cannot establish authority (fix(catalog): union picker customModels into the dispatch-time live catalog (#12597) #12934). Same union shape as feat(models): live account catalog for Claude, Codex, Copilot, AGY #12866 (sibling catalogs) and fix(backend): chat dispatch ignores model-picker additions (customModels vs syncedAvailableModels) #12597 (customModels).
  • Unioned rows are listed alongside discovered ones (getAllActiveSyncedModels unions too, so listings agree with dispatch) and carry catalogOrigin: "registry", which normalizeSyncedAvailableModels refuses to copy from input records, so operator metadata cannot forge registry provenance.
  • Root-cause chain for reviewers: the zai connection had autoFetchModels: true and had synced that day; the snapshot contained glm-5.3, glm-5.2, glm-5.1, glm-5, glm-5-turbo, glm-4.7-flash, glm-4.7 and no flash family. lookupModelMeta rejected the request because liveBackedEffortVariant requires the base model in the synced set. Upgrading the deployment could not fix it, because the snapshot re-syncs from the same partial surface. Other targetFormat-tagged providers (github, vertex, grok-cli, and 8 more) do NOT opt in, so their feat(providers): filter explicit combo members against the GitHub Models live catalog (follow-up to #8134) #12137-style entitlement gating is untouched; the flag is an explicit per-provider decision with an instant kill-switch.

⚠️ base-red inherited: #15306 (release/v3.8.52). Not addressed here per policy.

Test Coverage

Tests: 6986 → 6987 (+1 new file, 7 tests)
Coverage: 92% value-weighted after strengthening (77% at first audit; 12 of 13 behaviors at ★★/★★★). 1 path left as a proposed integration test (visionBridgeRouter reading a real catalog) with value card below.
Test value: 7 regression tests written in the new file, 0 rejected, 3 existing tests extended during the coverage gate, 1 path weakly covered (noted in the audit diagram).
Regression proof — red on the pre-fix tree (2 of the first 4 tests failed before the union landed) · green after (7/7, including Object.isFrozen pins).

CODE PATHS (src/lib/db/models/activeSyncedCatalog.ts)
getActiveSyncedCatalog (wiring)
├── resolveStoredProviderId / empty-id guard .............. [★★ TESTED] (pre-existing; 8926/7620)
├── sibling union #12866 → unionModels .................... [★★ TESTED] (pre-existing)
├── unionRegistryDispatchModels (NEW)
│   ├── B1 entry=null → early return ...................... [★★ TESTED] (transitive: real-path suites)
│   ├── B2 tagged.length===0 → early return ............... [★★★ TESTED] (display-snapshot deepEqual, nvidia)
│   ├── B3 models.length===0 → early return ............... [★★★ TESTED] (openai tagged + empty discovery, #12934)
│   ├── B4a row mapping id/name → admission ............... [★★★ TESTED] (RED→GREEN proven)
│   ├── B4b row mapping capabilities ...................... [★★★ TESTED] (strengthened: outputTokenLimit, isFrozen pins)
│   ├── B5 merge: discovery precedence on id conflict ..... [★★★ TESTED] (strengthened: name + targetFormat precedence)
│   └── B6 identity fast path → replaced by added-flag .... [★★★ TESTED] (correct under unfiltered input)
├── registryDispatchUnion opt-in gate (NEW) ............... [★★★ TESTED] (openai tagged-but-unflagged stays vetoed)
├── customModels overlay #12934 ........................... [★★★ TESTED] (12597 + stale catalogOrigin stripped on overlay)
└── node-backed non-authoritative fallback ................ [★★ TESTED] (pre-existing; 8926/12849)

USER FLOWS
F1 combo target zai/glm-5.3-flash-max → getModelInfo ...... [★★★ TESTED] (RED→GREEN; targetFormat handoff asserted)
F2 combo wildcard provider/* ............................... [★★ TESTED] (providerWildcard real catalogs)
F3 GET /v1/models listing parity ........................... [★★★ TESTED] (tagged base listed with catalogOrigin)
F4 dashboard display REST .................................. [★★ TESTED] (active-catalog-display-snapshot)
F5 provider reconciliation (tagged provider) ............... [★★ TESTED] (8926, ghe-copilot)
F6 github live-catalog dispatch filter ..................... [★★ TESTED] (12597)
F7 visionBridgeRouter with real catalog .................... [GAP] proposed: integration test, Value: protects=vision rerouting of registry-union rows; fails_when=vBridge drops union rows; why_new=vBridge tests mock the catalog; seam=none

COVERAGE: 12/13 testable behaviors covered (92%) | QUALITY: 12/13 at ★★/★★★; ★ smoke count = 0

Pre-Landing Review

8 findings (0 critical) from 5 dispatched specialists (testing, maintainability, security, performance, simplification) plus the red team; security and simplification returned clean. All 8 fixed across 4 fix commits (memoized derivation with empty-discovery early-exit, maxInputTokens mapping, outputTokenLimit + empty-snapshot-guard + listing-parity tests, per-provider opt-in gate, catalogOrigin un-forge, effort-array freeze). PR quality score at audit time: 6/10; post-fix cluster 67/67, typecheck clean.

Outside review: unavailable. Codex passes skipped (model_unusable: the local gstack install's model resolver is broken, scripts/resolve-codex-generation-model.ts missing). Native adversarial coverage ran in 5 passes on this machine; final pass verdict: "approve because the delta is exactly pass 4's prescribed correction — runtime-proven on the current build (mutation attempts throw, both Object.isFrozen checks true, cached singleton identity holds across reads), with zero mutating consumers of the array anywhere in production code".

Exploratory QA

Live contracts probed on the operator deployment (omniroute.home.arpa, v3.8.51 + operator-side DB workaround, separate from this PR's code path):

  • factory-efficient → HTTP 200, served by glm-5.3-flash (the incident contract)
  • factory-capable → HTTP 200 (adjacent happy path)
  • zai/glm-5.3-flash present in /v1/models

Production verifies the operator workaround; THIS PR's fix is verified by the native regression suite (red before, green after) plus a runtime freeze/mutation check done by the adversarial pass. Full local unit suite: not run locally. It deadlocked on this machine (the repo's documented leaked-DB-handle hang), and CONTRIBUTING.md #8084 assigns the full suite to CI (4 shards); CI results govern this PR. Both suite types that do cover the change ran green locally: 67/67 targeted cluster, 493/493 vitest.

Design Review

No frontend files changed — design review skipped.

Eval Results

No prompt-related files changed — evals skipped.

Scope Drift

Scope Check: CLEAN
Intent: union dispatch-tagged registry models into authoritative live catalogs, with tests.
Delivered: exactly that, plus the opt-in flag, listing parity, and provenance stamping that review added; every commit maps to a recorded finding.

Plan Completion

Plan completion audit: not run (no plan is bound to this branch and no docs/designs/ file matches). Fix: add "Plan: " to the PR body, or run /autoplan.

Verification Results

  • Targeted regression cluster (10 files / 67 tests): PASS (exit 0, evidence receipt 22:27Z)
  • Vitest (54 files / 493 tests): PASS (exit 0, evidence receipt 21:14Z, post-final-code)
  • npm run typecheck:core: PASS (exit 0)
  • Live contract probes: 3/3 PASS (deployment workaround path)
  • Full local unit suite: NOT RUN (deadlock, documented above) — CI owns it
  • Production build: NOT RUN locally — CI owns it per CONTRIBUTING.md (feat(backend): PR preview artifacts with packaged-runtime validation and build-once promotion #8084)
  • Documentation audit: current (see below), 0 blockers

Documentation

Status: current — ship-owned documentation audit of fix/zai-live-catalog-registry-union (base 23a1148 → head 34b89ae) found no authored doc contradicted by the shipped registry-union change; no edits made, no blockers.

Audited scope: all 6 committed files (changelog fragment, zai registry entry, shared RegistryEntry interface, activeSyncedCatalog union logic, synced row marker, new regression test) plus 9 untracked .gstack/qa-reports receipts; no staged or unstaged changes existed. Cross-checked docs: ARCHITECTURE.md provider table, USER_GUIDE.md free-tier lists, CURSOR-DOCKER.md exclusive-catalog claim, MODEL_EXPOSURE_LIST.md, changelog.d/README.md fragment convention, and the PROVIDER_REFERENCE generator.

Documentation health:

  • changelog.d/fixes/0000-registry-union-dispatch-tagged-models.md — Current (fragment matches shipped diff: registryDispatchUnion opt-in, per-model targetFormat tagging, catalogOrigin "registry" stamp, model-lockout fallback on unentitled accounts)
  • docs/architecture/ARCHITECTURE.md — Current (Z.AI/GLM provider row unaffected; no diagram depicts the getActiveSyncedCatalog union pipeline, so no drift)
  • docs/guides/USER_GUIDE.md — Current (GLM free-tier list is an explicit "curated from providerRegistry.ts for v3.8.0" snapshot with a pointer to the live catalog; this diff changed no registry model rows)
  • docs/reference/PROVIDER_REFERENCE.md — Current (generated; gen-provider-reference.ts emits no field this diff changes; no regeneration needed)
  • docs/providers/CURSOR-DOCKER.md — Current (its "live catalog is exclusive when synced" claim is provider-scoped; the z.ai opt-in does not contradict it)

Documentation coverage:

  • registryDispatchUnion (RegistryEntry opt-in) — reference ❌ how-to ❌ tutorial ❌ explanation ❌ (code comments only)
  • catalogOrigin: "registry" row marker — reference ❌ how-to ❌ tutorial ❌ explanation ❌ (code comments only)
  • z.ai partial-discovery union fix — reference ✅ explanation ✅ (changelog fragment); bug fix, no how-to/tutorial needed

Documentation Debt:

  • Registry-to-catalog union precedence (discovery rows win → targetFormat-tagged registry rows fill gaps → customModels overlay last) is contributor-facing behavior with zero coverage under docs/architecture — an explanation paragraph in ARCHITECTURE.md or CODEBASE_DOCUMENTATION.md would close it; /document-generate suggested as follow-up. No user-facing critical gaps.

Diagram drift: none.

Test plan

  • node --import tsx/esm --test tests/unit/zai-partial-discovery-registry-union.test.ts (and 9 adjacent catalog suites): 67/67 passing on the final tree
  • npm run test:vitest: 493/493 passing on the final tree
  • npm run typecheck:core: clean
  • Live: POST /v1/chat/completions factory-efficient → 200 served by glm-5.3-flash

Tests Added Or Updated

  • tests/unit/zai-partial-discovery-registry-union.test.ts (new, 7 tests: incident repro, empty-snapshot authority guard, listing parity with provenance, opt-in gate negative for openai, union precedence + capability contract with freeze pins, untagged veto, registry precondition)
  • open-sse/config/providers/registry/zai/index.ts (registryDispatchUnion opt-in)
  • open-sse/config/providers/shared.ts (flag documentation on RegistryEntry)
  • src/lib/db/models/activeSyncedCatalog.ts, src/lib/db/models/synced.ts (fix + provenance)
  • changelog.d/fixes/0000-registry-union-dispatch-tagged-models.md (fragment)

…e catalogs

Partial discovery surfaces could veto registry-curated models that the
provider actually serves. z.ai's Anthropic-compat /models omits the
glm-5.3-flash coding-plan family, so a fresh authoritative snapshot built
from that surface rejected zai/glm-5.3-flash-max pre-dispatch with
model_not_in_catalog, 503ing every combo targeting it (observed live:
factory-efficient -> ALL_TARGETS_SKIPPED) even though both the static
registry (targetFormat: openai) and the capability sync knew the model.

getActiveSyncedCatalog now unions registry models that carry an explicit
per-model targetFormat into the discovered set. The union is bounded:
registry rows join only when discovery reported something and only for
ids it did not; untagged models stay discovery-gated and custom rows
alone still cannot establish authority (diegosouzapw#12934). Same union shape as
diegosouzapw#12866 (sibling catalogs) and diegosouzapw#12597 (customModels).
…ract

Extends the partial-discovery regression tests: the discovered row keeps
its synced metadata where both sources know the id (a flipped merge
direction would revert learned metadata to registry values for every
tagged model), and the unioned row carries the registry dispatch intent
and capability fields that visionBridgeRouter and the combo context
filter read without a registry fallback.
Pre-landing review findings, all INFORMATIONAL:
- Unioned rows carry catalogOrigin:"registry" so catalog rows derived
  from the static registry stay machine-distinguishable from discovery
  rows, and getAllActiveSyncedModels unions the same rows so listing
  surfaces agree with dispatch (pinned by a provenance test).
- The registry-row derivation is cached per provider and the
  empty-discovery guard runs before any registry work: the union sits on
  the per-resolution hot path and its inputs are static registry data.
- maxInputTokens maps to inputTokenLimit like its sibling budget fields
  (diegosouzapw#6191); the empty-snapshot authority guard and the row capability
  contract (outputTokenLimit) gained direct tests. The changelog notes
  the entitlement tradeoff.
Adversarial pass follow-ups: the merge loop tracks admission with an
added flag instead of comparing Map sizes (correct even if a future
caller passes unfiltered rows), supportsTools maps from toolCalling so
unioned rows carry the same tool metadata discovery rows do, and
catalogOrigin survives a normalizeSyncedAvailableModels round-trip so
the registry-vs-discovery marker cannot be laundered away.
Adversarial follow-up: targetFormat tags exist on ~11 providers, and on
several of them discovery omission means per-account entitlement, not a
partial surface. Union on every tagged provider would have bypassed
diegosouzapw#12137-style entitlement gating and re-armed doomed combos on github,
vertex, and friends.

The union now runs only for providers that opt in via
registryDispatchUnion (zai first: its discovery surface is known to
under-report the coding-plan family). Custom overlays drop the stale
catalogOrigin marker, and cached union rows are frozen so the shared
row objects cannot be mutated through catalog reads. A negative test
pins that a tagged-but-unflagged provider keeps discovery gating.
Adversarial pass 3 prescribed two one-liners: the cached union rows are
process-lifetime singletons, so their supportedThinkingEfforts arrays
are frozen too (model.ts hands one to runtime metadata by reference),
and normalizeSyncedAvailableModels no longer copies catalogOrigin from
input records - the construction site is the only source, so operator
custom-model JSON cannot self-stamp rows as registry-origin.
Pass 4 runtime-verified that the input-side freeze landed on the copy
normalizeSyncedAvailableModels discards: .filter() rebuilds the array
unfrozen, so model.ts still received a mutable singleton by reference.
Freeze post-normalize (row + array) where the cache is built, and pin
both with Object.isFrozen assertions.
@woodsonl
woodsonl requested a review from diegosouzapw as a code owner October 5, 2026 22:31
@diegosouzapw
diegosouzapw merged commit 8c1ccf5 into diegosouzapw:release/v3.8.52 Oct 6, 2026
42 of 51 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants