You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Use semantic Provider dirty detection when edits are reverted #84
Provider dirty detection compares the raw draft and normalized Provider using JSON.stringify. Editing a model and then restoring the visible value can still leave hidden/default fields in the draft, so the Save button remains enabled and switching Providers incorrectly opens the unsaved-changes dialog even though the user made no material change.
Reproduction
Observed in the portable build from commit 7257701bf4c5d8be6fd3f49da0b0d86690dc4180.
Open an existing Provider whose model omits optional/default metadata fields.
Change a visible model value, such as the enabled toggle.
Change it back to its original value.
Observe that Save can remain enabled.
Select another Provider and observe the unsaved-changes dialog.
Model edits run through normalizeModel, which materializes otherwise omitted values including:
context_window: null
input_modalities: ["text"]
supported_reasoning_levels: []
default_reasoning_level: null
A deterministic replay shows the visible enabled value restored to its original value while dirty remains true solely because those hidden keys were added.
Expected behavior
Dirty state should represent a material, persistable configuration difference, not object shape, key order, omitted defaults, or normalization side effects.
Acceptance criteria
Introduce one canonical Provider comparison/serialization boundary used by Save enablement and the navigation guard.
Normalize both the persisted baseline and draft, including nested models, before comparison.
Treat omitted fields and their persisted default equivalents as equal.
Preserve meaningful ordering differences where order affects model priority.
Reverting every visible edit disables Save and allows Provider navigation without a confirmation dialog.
Add regression tests for model toggle revert, text-field revert, optional/default fields, and meaningful model reorder.
Verification: red-before/green-after regressions for toggle/text/default-field/reorder cases; frontend build and UI contract; report-only gate; diff hygiene; GLM route identity and normal shell/apply_patch/shell tool use; two-axis review
PR target: dev
This is the first real sidebar-visible GLM mechanical/standard Worker qualification after #105/#108 merged. Preserve meaningful model ordering, fail closed on ambiguous normalization, use the normal apply_patch tool contract, and deliver material WORKER_SIGNAL callbacks to the Orchestrator.
Root cause:ProviderDetail computes dirty state via JSON.stringify(draft) !== JSON.stringify(normalizedProvider). The baseline is normalized by normalizeProviderEndpointSelection (endpoint defaults only) but model edits run through normalizeModel, which materializes omitted defaults (context_window: null, input_modalities: ["text"], supported_reasoning_levels: [], default_reasoning_level: null). Reverting a visible toggle leaves these hidden keys in the draft, so JSON.stringify never matches the baseline.
Plan:
Add one canonical provider comparison helper under frontend/src/lib/providerComparison.ts that:
Normalizes both baseline and draft through the same boundary: endpoint selection + nested models.
Treats omitted fields and their persisted default equivalents as equal (e.g., missing context_window equals null).
Preserves meaningful models[] ordering - a reorder is a real change.
Produces a stable serialized form for comparison, not raw JSON.stringify of unequal-shape objects.
Replace the JSON.stringify dirty computation in ProviderEditor.tsx with the canonical comparison.
Update ui-contract.test.mjs to assert the new comparison boundary instead of the raw JSON.stringify pattern.
Add red-before/green-after regression tests for:
Toggle revert (enabled toggle changed and restored to not dirty)
Text-field revert (display_name changed and restored to not dirty)
Optional/default fields (omitted vs null vs empty array to not dirty)
Completed by PR #123 and merged into dev at 0360aed. The Orchestrator delta review passed; provider comparison regressions are 10/10 and all six CI checks passed.
Activity
NOirBRight commentedon Jul 13, 2026
Dispatch
This is the first real sidebar-visible GLM mechanical/standard Worker qualification after #105/#108 merged. Preserve meaningful model ordering, fail closed on ambiguous normalization, use the normal apply_patch tool contract, and deliver material WORKER_SIGNAL callbacks to the Orchestrator.
NOirBRight commentedon Jul 14, 2026
Implementation plan
Root cause:
ProviderDetailcomputes dirty state viaJSON.stringify(draft) !== JSON.stringify(normalizedProvider). The baseline is normalized bynormalizeProviderEndpointSelection(endpoint defaults only) but model edits run throughnormalizeModel, which materializes omitted defaults (context_window: null,input_modalities: ["text"],supported_reasoning_levels: [],default_reasoning_level: null). Reverting a visible toggle leaves these hidden keys in the draft, soJSON.stringifynever matches the baseline.Plan:
Add one canonical provider comparison helper under
frontend/src/lib/providerComparison.tsthat:context_windowequalsnull).models[]ordering - a reorder is a real change.JSON.stringifyof unequal-shape objects.Replace the
JSON.stringifydirty computation inProviderEditor.tsxwith the canonical comparison.Update
ui-contract.test.mjsto assert the new comparison boundary instead of the rawJSON.stringifypattern.Add red-before/green-after regression tests for:
Hotset:
frontend/src/pages/ProvidersPage.tsx,frontend/src/components/providers/ProviderEditor.tsx,frontend/src/lib/providerComparison.ts,frontend/scripts/ui-contract.test.mjsNon-goals: Provider persistence schema, model priority semantics, Gateway/routing/protocol behavior, unrelated settings UI.
Merge pull request #123 from NOirBRight/codex/issue-84-semantic-provi…
NOirBRight commentedon Jul 14, 2026
Completed by PR #123 and merged into dev at 0360aed. The Orchestrator delta review passed; provider comparison regressions are 10/10 and all six CI checks passed.