@@ -86,10 +86,119 @@ Suggested action:
8686- Introduce a small shared internal package for cache semantics.
8787- Do it only if it can be done without creating import cycles.
8888
89+ ## 6. Centralize fallback-mode semantics in ` config `
90+
91+ Effort: low
92+ Risk: low
93+
94+ Why:
95+ - ` config.ResolveFallbackDefaultMode() ` now owns the blank-to-` auto ` defaulting rule.
96+ - ` internal/app/app.go ` still re-implements fallback-mode parsing in:
97+ - ` dashboardFallbackModeValue() `
98+ - ` fallbackFeatureEnabledGlobally() `
99+ - ` fallbackModeEnabled() `
100+ - Those helpers currently perform their own ` TrimSpace ` / case-folding instead of reusing config-owned semantics.
101+
102+ Suggested action:
103+ - Add small config-owned helpers for:
104+ - "is fallback enabled for this mode?"
105+ - "what dashboard mode should be exposed for this config?"
106+ - Remove the ad hoc mode parsing from ` internal/app/app.go ` .
107+ - This keeps blank, mixed-case, and future mode handling in one place.
108+
109+ ## 7. Collapse the duplicated translated fallback attempt loops
110+
111+ Effort: medium
112+ Risk: medium
113+
114+ Why:
115+ - ` internal/server/translated_inference_service.go ` has two near-identical fallback loops:
116+ - ` tryFallbackResponse() `
117+ - ` tryFallbackStream() `
118+ - Both:
119+ - fetch selectors
120+ - gate on ` shouldAttemptFallback() `
121+ - derive ` providerType `
122+ - log attempt/success messages
123+ - walk candidates while preserving the last error
124+
125+ Suggested action:
126+ - Extract one shared iterator that owns:
127+ - selector traversal
128+ - provider-type lookup
129+ - attempt logging
130+ - last-error handling
131+ - Keep the typed wrappers only for the response/stream result shapes.
132+
133+ ## 8. Precompute fallback source identity once per resolution
134+
135+ Effort: medium
136+ Risk: low to medium
137+
138+ Why:
139+ - ` internal/fallback/resolver.go ` recomputes trimmed selector identity several times per request:
140+ - ` sourceModelInfo() `
141+ - ` modeFor() `
142+ - ` manualSelectorsFor() `
143+ - ` matchKeys() `
144+ - ` sourceKey() `
145+ - ` modeFor() ` and ` manualSelectorsFor() ` each rebuild the same ordered match-key list.
146+
147+ Suggested action:
148+ - Introduce a small internal struct for one fallback resolution pass, containing:
149+ - source model info
150+ - canonical source key
151+ - ordered match keys
152+ - Build it once in ` ResolveFallbacks() ` and pass it through helper calls.
153+ - This would trim repeated string cleanup and make precedence rules easier to inspect.
154+
155+ ## 9. Extract manual fallback-rule file parsing from ` loadFallbackConfig `
156+
157+ Effort: medium
158+ Risk: low to medium
159+
160+ Why:
161+ - ` config.loadFallbackConfig() ` currently owns both:
162+ - fallback-mode validation/defaulting
163+ - the custom JSON loader for ` manual_rules_path `
164+ - The manual loader includes:
165+ - duplicate raw JSON key detection
166+ - ` null ` rejection
167+ - trailing-content validation
168+ - whitespace normalization
169+ - That makes the config loader harder to scan than the rest of the config pipeline.
170+
171+ Suggested action:
172+ - Move the manual-rule JSON parsing into a dedicated helper or file, for example ` loadFallbackManualRules(path string) ` .
173+ - Keep ` loadFallbackConfig() ` focused on policy validation and wiring.
174+ - Preserve the current strict error messages and test coverage while isolating the parser.
175+
176+ ## 10. Pick one owner for execution-plan fallback defaults
177+
178+ Effort: medium
179+ Risk: medium
180+
181+ Why:
182+ - The managed backend default is set in ` internal/app/app.go:defaultExecutionPlanInput() ` .
183+ - The dashboard draft default is separately hardcoded in ` internal/admin/dashboard/static/js/modules/execution-plans.js:defaultExecutionPlanForm() ` .
184+ - We already changed both once to keep them aligned, which confirms the drift risk is real.
185+
186+ Suggested action:
187+ - Prefer a single server-owned default surface for execution-plan authoring defaults.
188+ - Options:
189+ - expose default feature flags from the admin config endpoint
190+ - derive the initial dashboard form from the active managed default workflow
191+ - This reduces UI/backend drift for fallback and other execution-plan features.
192+
89193## Recommended order
90194
911951 . Remove ` CacheTypeBoth ` .
921962 . Deduplicate the dashboard empty-state object.
931973 . Keep cached-only policy in one layer.
941984 . Remove the legacy middleware path.
951995 . Centralize cache semantics in a shared package.
200+ 6 . Centralize fallback-mode semantics in ` config ` .
201+ 7 . Collapse the duplicated translated fallback attempt loops.
202+ 8 . Precompute fallback source identity once per resolution.
203+ 9 . Extract manual fallback-rule file parsing from ` loadFallbackConfig ` .
204+ 10 . Pick one owner for execution-plan fallback defaults.
0 commit comments