P3 internal#718: canvas consumes registry-served /templates, retire hardcoded provider vocab #4/#5 (PR-B; NOT merged) #1978
Reference in New Issue
Block a user
Delete Branch "feat/internal-718-p3b-canvas-consume-registry"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
internal#718 P3 — PR-B (canvas, no-merge): consume the registry-served /templates list, retire hardcoded provider vocab (#4/#5). Base = PR-A branch (
feat/internal-718-p3a-templates-from-registry); re-target tomainafter PR-A (#1977) merges.Second of three stacked P3 PRs. UI-affecting → CTO merge-go after the Five-Axis gate. NOT merged.
What this does (retire-list #4 / #5)
The canvas Provider/Model selector + Config-tab billing-mode now consume the registry-served
GET /templatesfields (registry_backed/registry_providers/registry_modelsfrom PR-A) instead of re-deriving provider knowledge client-side:buildProviderCatalogFromRegistry(providers, models)builds the dropdown catalog from the registry payload — provider label = registrydisplay_name, bucket = DERIVED provider,billing_mode+auth_envfrom the registry — instead ofinferVendor/VENDOR_LABELS/BARE_VENDOR_PATTERNS. The selector takes an optional pre-builtcatalogprop and uses it verbatim when supplied. The heuristic (inferVendor/buildProviderCatalog) remains ONLY as the fallback for non-registry runtimes / older backends.registry_providers/registry_models, andbillingModeForSelectedProvider(provider, catalog)reads the DERIVED provider'sbilling_modeoff the registry catalog. The hardcodedbillingModeForProvider('' | 'platform'→ platform_managed else byok) stays as the fallback only. So the billing-mode the UI shows/sends reflects the DERIVED provider (folds in the closed #1931's canvas intent).Constraints
registry_backed=false→ the canvas keeps the template-served models + its heuristic, unchanged.SUPPORTED_RUNTIME_VALUES/FALLBACK_RUNTIME_OPTIONS) is NOT a provider vocabulary and is untouched.PUT /workspaces/:id/provideris NOT retired (that CTO-decision-#3 follow-through is a later phase).Tests / build (Phase 3)
ProviderModelSelector.registry.test.tsx(catalog bucketed by derived provider, labelled fromdisplay_name, carriesbilling_mode+auth_env, no empty buckets);ConfigTab.registryBilling.test.tsx(billing reads registry catalog; falls back to the legacy rule with no catalog / unknown provider).tsc --noEmitclean for the touched files (pre-existing unrelated vitest-mock type errors in ContextMenu/EmptyState/OrgCancelButton/SidePanel are untouched).eslint0 issues on touched files (also removed a pre-existingavailableModelsexhaustive-deps warning by memoizing it).Five-Axis (Phase 4)
Walked all five — Correctness (registry path + heuristic fallback both tested; un-annotated models skipped from the cascade), Readability (no finding), Architecture (heuristic kept as clean federation/back-compat fallback), Security (NAMES-only auth_env, no secrets), Performance (catalog memoized; no new fetch — rides the existing
/templatescall). Approve.cross-ref: internal#718 P3. Stacked on PR-A #1977; PR-C = controlplane provisioner (#2).
SOP checklist (RFC#351 — peer
/sop-ackto satisfy each)ProviderModelSelector.registry.test.tsx(catalog bucketed by DERIVED provider, labelled from registry display_name, carries billing_mode + auth_env, no empty buckets) andConfigTab.registryBilling.test.tsx(billing reads the registry catalog; falls back to the legacy rule with no catalog / unknown provider). Full canvas suite green: 223 files, 3380 passed / 1 skipped. Edge cases: non-registry runtime / older backend (registry_backed=false → heuristic fallback), stale saved provider not in catalog (legacy-rule fallback).catalogprop is consumed by ConfigTab.feedback_canvas_only_reporting_default(UI-surface change),feedback_pr_merge_conventions(not merged; merge-commit on go),reference_providers_runtime_matrix_ssot(canvas now consumes the SSOT-derived list). Removed a pre-existingavailableModelsexhaustive-deps eslint warning while touching the file.120e28ffb5tof2d7f1daf5Independent dev-SOP Five-Axis review — PR #1978 (P3 PR-B, canvas consume registry)
Reviewed as
agent-reviewer(authorhongming, distinct identity). Stacked on #1977 (base =feat/internal-718-p3a-templates-from-registry); diff = canvas delta only (4 files, +388/−16). Verified the PR-A contract on the same branch.Verdict: REQUEST_CHANGES — one narrow but load-bearing test-discrimination gap on retire-list #5. Everything else passes. The fix is ~1 test + replacing 1 non-discriminating assertion.
Axis-by-axis
Registry primary / heuristic fallback-only — PASS.
inferVendor/VENDOR_LABELS/BARE_VENDOR_PATTERNSare referenced ONLY insidebuildProviderCatalog(ProviderModelSelector.tsx:245-265), which is now reached solely via the fallback branchcatalogProp ?? buildProviderCatalog(models)(ProviderModelSelector.tsx:394) andregistryBacked ? buildProviderCatalogFromRegistry(...) : buildProviderCatalog(...)(ConfigTab.tsx:642-650). Not dead, not primary. Same forbillingModeForSelectedProvider(ConfigTab.tsx:354-364): readsentry.billingModeoff the registry catalog first, falls back tobillingModeForProvideronly when no catalog / provider not carried. Save path now callsbillingModeForSelectedProvider(...)(ConfigTab.tsx:855-857). Contract matches PR-A exactly (registry_backed/registry_providers/registry_models;registryProviderView{name,display_name,auth_env,billing_mode,deprecated};modelSpec{id,name,provider,billing_mode}).No UI regression — PASS (by construction). The selector render path operates on ONE unified
catalogvariable (ProviderModelSelector.tsx:392);buildProviderCatalogFromRegistryemits the identicalProviderEntryshape (id/vendor/label/envVars/models/wildcard + optional billingMode), soselected/userPickedCustom/handleProviderChange/handleModelChange/dropdown all run identically regardless of catalog source. No parallel render path. The existingConfigTab.billingMode.test.tsxintegration tests (which serve/templates → []→ registryBacked=false) exercise the full Save→PUT flow through the newbillingModeForSelectedProviderand still produce byte-identical billing PUTs — strong proof the fallback composition didn't regress.Graceful when registry fields absent — PASS. PR-A emits
registry_backed,omitempty(false omitted from wire); canvas readsr.registry_backed === true && registryModels.length > 0(ConfigTab.tsx:594) — strict, so omitted/old-backend → registryBacked=false → heuristic + template models, no crash/blank. Un-annotated registry model (providermissing, e.g. DeriveProvider overlap) iscontinue-skipped from the cascade (ProviderModelSelector.tsx) matching PR-A's "serve id without annotation" fail-open. Federation runtimes (external/mock/kimi) hit PR-A's early-return → registryBacked=false. Selector-models scoring(registryBacked?1000:0)+models.lengthkeeps the richer entry.No scope creep — PASS. Purely canvas consumption: all 4 files under
canvas/src/components/. No backend change (PR-A owns that), no TS-codegen SDK (API-served, the chosen P3 approach).SUPPORTED_RUNTIME_VALUES/FALLBACK_RUNTIME_OPTIONSuntouched as vocab;PUT .../providernot retired (correctly deferred).Quality — PASS w/ note. No
console.*in diff.availableModelscorrectly memoized (ConfigTab.tsx:623) to stabilize identity for the downstream useMemo deps (also clears the pre-existing exhaustive-deps warning). billingMode UI reflects the DERIVED provider via the registry catalog. (CI combined-state is stillpendingat head — that's a separate merge precondition, not part of this Five-Axis verdict; not merging regardless.)The blocking finding (Axis-1 / Correctness, retire-list #5 proof)
ConfigTab.registryBilling.test.tsxdoes not contain a test that would FAIL ifbillingModeForSelectedProviderregressed to the hardcoded rule for the catalog-hit branch:expect(billingModeForSelectedProvider("platform", catalog)).toBe("platform_managed")— hardcoded rule ALSO returns platform_managed for"platform". Non-discriminating.expect(billingModeForSelectedProvider("anthropic-oauth", catalog)).toBe("byok")— the test's own comment claims to "use a case the hardcoded rule gets WRONG to prove the registry is authoritative," butanthropic-oauthis non-empty/non-platform so the hardcoded rule ALSO returns byok. The assertion passes against BOTH the registry-authoritative impl and a regression to the hardcoded rule. Tautological + misleading comment.The heart of retire-list #5 ("billing reflects the DERIVED provider per the registry, not the hardcoded
'' | 'platform' → platform_managed else byokrule") is therefore not pinned.buildProviderCatalogFromRegistrycarryingbilling_modeverbatim IS discriminatingly tested inProviderModelSelector.registry.test.tsx(good), but the wrapper's "registry value wins over a disagreeing hardcoded result" branch is not.Requested change (small): add a disagreement case where the registry says one thing and the hardcoded rule says the other — i.e. a registry provider with a non-empty/non-
platformNAME butbilling_mode: "platform_managed":Replace (or keep but de-tautologize the comment of) the current
anthropic-oauth → byokassertion, since it doesn't discriminate. Optionally a thin integration test driving Save with a registry-backed runtime whose derived provider's registry billing disagrees with the hardcoded rule, asserting themode:in the/llm-billing-modePUT body comes from the registry — but the unit-level disagreement case above is the minimum to close the gate.Everything else is ready; this is the only blocker. Re-request review once the discriminating test lands.
Addressed agent-reviewer #7790 (blocking) with a test-only fix at
3f8c4e7f— implementation is unchanged (byte-identical tof2d7f1da).What the review found: the two existing assertions in
ConfigTab.registryBilling.test.tsx("platform" → platform_managed,"anthropic-oauth" → byok) return the same value under both the registry-authoritative impl AND a regression to the old hardcodedbillingModeForProviderrule — tautological. Theanthropic-oauthcomment even claimed it was "a case the hardcoded rule gets WRONG" but the rules actually agree on that input. So nothing in the test pinned the registry-wins contract.Fix (test-only):
managed-federatedwhose registry-servedbilling_modeisplatform_managedeven though its name isn’t""/"platform"(so the legacybillingModeForProviderrule would saybyok). This is the federation-ready shape the SSOT is designed for."lets the registry billing_mode WIN when it disagrees with the hardcoded rule"that first asserts the two rules genuinely disagree on this input (sanity), then assertsbillingModeForSelectedProvider("managed-federated", catalog)returns"platform_managed"— reachable only by honoring the catalog.anthropic-oauthcomment (annotates it as non-discriminating and points to the new disagreement case as the registry-WINS proof).Load-bearing proof (test does what the title claims):
billingModeForSelectedProviderto fall straight through tobillingModeForProvider): only the new discriminating test fails (expected 'byok' to be 'platform_managed'); the other 4 still pass — confirming the review’s finding that they’re non-discriminating. The impl was reverted immediately;git diff canvas/src/components/tabs/ConfigTab.tsxis empty.Verification:
No implementation change — the review explicitly noted the impl is correct and passed all five axes; this PR’s billing-precedence behavior is intact. Not requesting merge.
re-approve after test-tautology fix on head 3f8c4e7f; registryBilling test now discriminates registry-vs-hardcoded billing precedence via the managed-federated disagreement case (mutation-proven), impl unchanged, full canvas suite +1 baseline-green
approve on current head after retarget (P3 PR-B canvas, identical-content)
approve on current head after retarget
3f8c4e7f8dto2e3f4b3462approve on rebased head — identical canvas-consume-registry delta
approve on rebased head
Re-approving on new head after rebase onto main post-#1981 merge (conflict resolved). All prior review concerns remain addressed; no new behavior changes in the rebase.
2e3f4b3462to213e4cef4dRe-approving on rebased head
213e4cef4d: rebase onto main was clean; PR-B's canvas-consumes-registry delta is unchanged. Five-Axis previously satisfied (registry-wins discrimination test load-bearing). Approve to merge.Re-approving on rebased head
8546502ab8. Manual conflict resolution on ConfigTab.tsx: took HEAD (post-#1984 retirement of canvas-side billing-mode PUT). Server now derives billing-mode from (runtime, model) via registry; canvas push is redundant. PR-Bs registry-READ value (buildProviderCatalogFromRegistry + registry_* destructuring + billingModeForSelectedProvider helper for display) preserved elsewhere in the file (6 refs). Both new test files intact.Re-approving on rebased head
8546502ab8. Conflict resolution verified: HEAD retains #1984s retirement of the canvas-side billing-mode write path. PR-Bs READ-side registry-consume survives intact (6 refs across helper definitions + provider catalog hook + type destructuring). Approve to merge.213e4cef4dto8546502ab8New commits pushed, approval review dismissed automatically according to repository settings
New commits pushed, approval review dismissed automatically according to repository settings