Follow-up from #268 (PR #275). Explicitly deferred in that epic's plan as risk R1 / decision D4.
The problem
After #270 there are two preset tables:
- The authoritative eight ladder cells in Rust (
src-tauri/src/cli/tier_ladder.rs), and
- The ~40-case
applyPreset switch in src/lib/components/AgentConfigEditor.svelte (around :402), with inferSelectedPreset (:277) as its inverse and stripManagedEffortFlags (:363) as its cleaner.
A provider change edited in one will not reach the other. This is a real drift hazard, not a theoretical one — the preset ids encode model slugs and effort flags that rotate (gpt-5.5 was already stale in a prompt template when #268 shipped).
What already protects us, and what doesn't
PR #275 added a parity test in tier_ladder.rs that include_str!s the real AgentConfigEditor.svelte and asserts the exact applyPreset case bytes for the eight ladder cells. Editing those eight in the frontend fails the Rust build.
That covers only eight of ~40 presets. The other ~32 remain unguarded, and the parity test is deliberately brittle to reformatting (it matches literal indented bytes), so a prettier run over that component would break the build for a non-reason.
Suggested direction
Make Rust the single source and have the popup consume an endpoint rather than a hardcoded switch. GET /api/tier-ladder already exists (src-tauri/src/http/routes.rs:55) and returns per-cell provider/tier/model/flags plus typed omissions — it is a reasonable shape to generalise.
Whoever picks this up should decide whether inferSelectedPreset (the inverse mapping, used to show which preset a config matches) can also be served, or whether it stays client-side.
Acceptance sketch
- One authoritative preset table.
- The popup renders presets from server data.
- The byte-matching parity test can be deleted, because the duplication it guards no longer exists.
Follow-up from #268 (PR #275). Explicitly deferred in that epic's plan as risk R1 / decision D4.
The problem
After #270 there are two preset tables:
src-tauri/src/cli/tier_ladder.rs), andapplyPresetswitch insrc/lib/components/AgentConfigEditor.svelte(around:402), withinferSelectedPreset(:277) as its inverse andstripManagedEffortFlags(:363) as its cleaner.A provider change edited in one will not reach the other. This is a real drift hazard, not a theoretical one — the preset ids encode model slugs and effort flags that rotate (
gpt-5.5was already stale in a prompt template when #268 shipped).What already protects us, and what doesn't
PR #275 added a parity test in
tier_ladder.rsthatinclude_str!s the realAgentConfigEditor.svelteand asserts the exactapplyPresetcase bytes for the eight ladder cells. Editing those eight in the frontend fails the Rust build.That covers only eight of ~40 presets. The other ~32 remain unguarded, and the parity test is deliberately brittle to reformatting (it matches literal indented bytes), so a prettier run over that component would break the build for a non-reason.
Suggested direction
Make Rust the single source and have the popup consume an endpoint rather than a hardcoded switch.
GET /api/tier-ladderalready exists (src-tauri/src/http/routes.rs:55) and returns per-cell provider/tier/model/flags plus typed omissions — it is a reasonable shape to generalise.Whoever picks this up should decide whether
inferSelectedPreset(the inverse mapping, used to show which preset a config matches) can also be served, or whether it stays client-side.Acceptance sketch