Skip to content

FIX: distinguish catalog-unavailable from unregistered in Initializers page - #2464

Open
fei (feiiiiii5) wants to merge 7 commits into
microsoft:mainfrom
feiiiiii5:fix/initializer-catalog-unavailable
Open

FIX: distinguish catalog-unavailable from unregistered in Initializers page#2464
fei (feiiiiii5) wants to merge 7 commits into
microsoft:mainfrom
feiiiiii5:fix/initializer-catalog-unavailable

Conversation

@feiiiiii5

@feiiiiii5 fei (feiiiiii5) commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes #2442

When /api/initializers/settings succeeds but the registered-initializer catalog request (GET /api/initializers) fails transiently, the Initializers page preserved configured baseline settings but described valid entries as Initializer is no longer registered. A temporary metadata availability failure was therefore presented as a definitive registration problem.

Changes:

  • initializerLookup.ts: exports CatalogStatus = 'loading' | 'loaded' | 'error'; findRegisteredInitializer resolves a settings entry to its catalog entry or undefined (no synthetic placeholder objects); initializerFallbackDescription reports Initializer is no longer registered. only when the catalog loaded successfully — loading and error both render Catalog metadata temporarily unavailable.
  • Initializers.tsx: tracks catalogStatus derived from the Promise.allSettled result instead of a boolean flag
  • BaselineInitializers.tsx / AdditionalInitializers.tsx: rows render env vars and parameter summaries only for real catalog entries; a catalog error shows an inline "editing disabled" note and disables Edit so an outage cannot null out saved parameters via a schema-less editor
  • AvailableInitializersDialog.tsx: an empty list during a catalog error reports the catalog as unavailable instead of No registered initializers were found

Behavior note: Edit now requires a real catalog entry, so a genuinely unregistered name can no longer open the schema-less editor either.

Tests and Documentation

  • initializerLookup.test.ts: unit tests for the new lookup and status-based fallback copy
  • AdditionalInitializers.test.tsx: Edit stays disabled while the catalog is unavailable; new case asserting Edit stays disabled for a name missing from a loaded catalog (no synthetic env vars / parameter summary rendered)
  • BaselineInitializers.test.tsx / AvailableInitializersDialog.test.tsx: updated for the status-based props
  • Full Initializers suite (78 tests), tsc --noEmit, and eslint pass
  • No documentation changes needed (UI-only behavioral fix)

This contribution was developed with LLM assistance following repo conventions.

…s page

When the registered-initializer catalog request fails transiently, the
Initializers page preserved configured baseline settings but described
valid entries as 'Initializer is no longer registered.' A temporary
metadata availability failure was therefore presented as a definitive
registration problem.

Track catalog fetch success/failure and pass the availability flag
through to BaselineInitializers / AdditionalInitializers so unresolved
names render 'Catalog metadata temporarily unavailable.' when only the
catalog request failed. Names genuinely absent from a successful catalog
response still show 'no longer registered.'

Fixes microsoft#2442

Signed-off-by: fei <204683769+feiiiiii5@users.noreply.github.com>
initializer={resolveRegisteredInitializer(
item.initializer_name,
registeredInitializers,
catalogUnavailable,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the catalog request fails, this placeholder has no parameter schema, but Edit remains enabled. Clicking Save then replaces existing parameters, such as { mode: 'strict' }, with null; please disable editing until the catalog reloads or preserve the existing parameters while the schema is unavailable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in ddf816c (took the disable-until-reload option): Edit is disabled while catalogAvailable is false, the card states "Initializer catalog is unavailable; editing is disabled until it reloads." inline, and Apply/Remove stay enabled since they only operate on stored parameters — so a catalog outage can no longer null out existing parameters like {"mode": "strict"}. Covered by two new tests: Edit disabled + inline explanation while unavailable, and Apply/Remove remaining usable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correction to the reply above: the referenced ddf816c was never pushed to the remote. The fix is on the branch as 5796799, and a follow-up in d291d77 additionally reports catalog unavailability in the available-initializers dialog. The PR-level comments have the details.

@romanlutz

Copy link
Copy Markdown
Contributor

You may need to push your fix commit :-)

When the listRegistered request fails, each card renders the
catalog-unavailable placeholder with no parameter schema, but Edit
stayed enabled. Saving from that state replaced the stored parameters
(such as { mode: 'strict' }) with null.

Edit is now disabled while catalogUnavailable is true, and the card
states that editing resumes once the catalog loads. Apply and Remove
stay available because they use the stored parameters directly.

Signed-off-by: fei <204683769+feiiiiii5@users.noreply.github.com>
@feiiiiii5

Copy link
Copy Markdown
Contributor Author

You were right — the commit referenced above never made it to the remote. Apologies for that. It is now pushed as 5796799 (re-done on top of the branch): Edit is disabled while catalogAvailable is false, the card states that editing resumes once the catalog loads, and a regression test covers the disabled state with the stored parameters still visible. Apply and Remove remain available since they use the stored parameters directly.

<BaselineInitializers
items={settings.baseline}
registeredInitializers={registeredInitializers}
catalogUnavailable={catalogUnavailable}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we pass this unavailable state to AvailableInitializersDialog as well, or disable its trigger when the catalog request fails? On an initial failure, the dialog receives an empty array and says "No registered initializers were found," which still presents a temporary outage as a definitive empty catalog.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in d291d77: AvailableInitializersDialog now receives catalogUnavailable and reports that the catalog cannot be shown until it loads, instead of "No registered initializers were found". The trigger stays enabled since the dialog is a read-only reference; the empty-registry message is unchanged for a successful fetch that registers nothing.

On an initial catalog failure the dialog received an empty array and
said "No registered initializers were found", which states that nothing
is registered when the request failed. The dialog now receives the
unavailable state and reports that the catalog cannot be shown until it
loads. The empty-registry message is unchanged for a successful fetch
with no registered initializers.

Signed-off-by: fei <204683769+feiiiiii5@users.noreply.github.com>
@feiiiiii5

Copy link
Copy Markdown
Contributor Author

Done in d291d77 — took the first option: AvailableInitializersDialog now receives catalogUnavailable and reports that the catalog cannot be shown until it loads, instead of "No registered initializers were found". I kept the trigger enabled rather than disabling it: the dialog is a read-only reference, and a stale-but-real list after a refresh failure stays usable. The empty-registry message is unchanged for a successful fetch that registers nothing. Regression test covers both messages.

Roman Lutz (romanlutz) and others added 2 commits August 25, 2026 18:21
Replace the catalog-unavailable boolean with a CatalogStatus union
('loading' | 'loaded' | 'error') and stop synthesizing placeholder
RegisteredInitializer entries for missing lookups, per review feedback.

findRegisteredInitializer now returns undefined on a miss and callers
branch on the status: only a loaded catalog claims "no longer
registered"; loading and error both report the metadata as temporarily
unavailable. Edit requires a real catalog entry, which also keeps a
genuinely unregistered initializer from nulling its saved parameters
through a schema-less editor.
@feiiiiii5

Copy link
Copy Markdown
Contributor Author

Follow-up: 20a5d7c adopts the status-union design suggested in review and removes the synthetic placeholder entries. (The suggestion arrived on #2469 — a duplicate PR I opened by mistake, now closed in favor of this one. Apologies for the noise.)

  • CatalogStatus = 'loading' | 'loaded' | 'error' replaces the boolean flag; findRegisteredInitializer returns RegisteredInitializer | undefined
  • Only a loaded catalog renders the definitive Initializer is no longer registered. fallback; loading and error both report Catalog metadata temporarily unavailable.
  • Rows render env vars / parameter summaries only for real catalog entries; the inline unavailability note and disabled Edit from the earlier review rounds are preserved
  • One behavior change to flag: Edit now requires a real catalog entry, so a genuinely unregistered name can no longer open the schema-less editor — this closes the same parameter-nulling hazard Roman Lutz (@romanlutz) identified, for the unregistered case

Full Initializers suite (78 tests), tsc --noEmit, and eslint all pass.

setRegisteredInitializers(registeredResult.value.items)
setCatalogStatus('loaded')
} else {
setCatalogStatus('error')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a refresh fails after a successful load, registeredInitializers keeps the old entries while catalogStatus becomes error. That leaves stale metadata visible and the Add controls enabled even though catalog-dependent UI should be unavailable; could we clear the array here or make consumers ignore it unless the status is loaded, with a regression test for success followed by refresh failure?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 749e65e (merged main as acf7bb0 so this sits on current main).

Took the first option — the failure branch now drops the catalog instead of keeping the last good list:

} else {
  // Drop the previous catalog: entries left behind would keep rendering stale
  // descriptions and env vars, and would keep Add enabled off the first stale name.
  setRegisteredInitializers([])
  setCatalogStatus('error')

Both symptoms you named follow from that one change, with no new gating logic:

  • Stale metadata: every consumer resolves entries through findRegisteredInitializer, so an empty list makes the baseline/additional rows fall back to initializerFallbackDescription('error') → "Catalog metadata temporarily unavailable.", and the Required env vars: line stops rendering (it is inside {initializer && ...}).
  • Add controls: the select's existing registeredInitializers.length === 0 guard fires, and initializerName resolves to '', so disabled={creating || !initializerName} disables the button. A stale selectedInitializerName cannot keep it enabled — the section unmounts while loading is true, so that local state resets on remount.

Regression test: should drop the loaded catalog and disable Add when a refresh fails after a successful load (loads successfully and asserts the real description + env vars + enabled Add first, then fails the second listRegistered call). Verified it fails on the pre-fix code — the stale "Registers targets." description is still rendered — and passes with the fix.

Initializers folder: 79/79 passing (was 78 before this test), tsc --noEmit clean, eslint --max-warnings 0 clean, all re-run after the merge commit.

A refresh that failed after a successful load flipped catalogStatus to
error while leaving registeredInitializers populated, so rows kept
showing stale descriptions and required env vars and the Add controls
stayed enabled off the first stale entry. The failure branch now clears
the array, so every consumer sees an empty catalog and falls back to the
"temporarily unavailable" copy until the next successful load.

Adds the success-then-refresh-failure regression test for that path.

Signed-off-by: fei <204683769+feiiiiii5@users.noreply.github.com>
Signed-off-by: fei <204683769+feiiiiii5@users.noreply.github.com>
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.

Initializer catalog failure falsely marks configured entries as unregistered

2 participants