Forge
csharpdeeb25a2
1using CascadeIDE.Cockpit.Composition.HostSurface;
2using CascadeIDE.Models;
3
4namespace CascadeIDE.Services;
5
6internal interface ISettingsValidationSpecification
7{
8 IEnumerable<string> Validate(CascadeIdeSettings settings);
9}
10
11internal sealed class DisplaySettingsValidationSpecification : ISettingsValidationSpecification
12{
13 public IEnumerable<string> Validate(CascadeIdeSettings settings)
14 {
15 var display = settings.Display;
16
17 var im = display.Mount;
18 if (!IsScore(im.MinSa))
19 yield return "[display.mount] min_sa must be in [0..1].";
20 if (!IsScore(im.MinPerformance))
21 yield return "[display.mount] min_performance must be in [0..1].";
22 if (!IsScore(im.MaxWorkload))
23 yield return "[display.mount] max_workload must be in [0..1].";
24
25 for (var i = 0; i < im.Rules.Count; i++)
26 {
27 var rule = im.Rules[i];
28 if (string.IsNullOrWhiteSpace(rule.Style))
29 yield return $"[display.mount.rules][{i}] style is required.";
30 if (rule.SaScore is { } sa && !IsScore(sa))
31 yield return $"[display.mount.rules][{i}] sa_score must be in [0..1].";
32 if (rule.PerformanceScore is { } perf && !IsScore(perf))
33 yield return $"[display.mount.rules][{i}] performance_score must be in [0..1].";
34 if (rule.WorkloadScore is { } workload && !IsScore(workload))
35 yield return $"[display.mount.rules][{i}] workload_score must be in [0..1].";
36 }
37
38 if (display.Instruments is { Count: > 0 } routing)
39 {
40 foreach (var kv in routing)
41 {
42 if (string.IsNullOrWhiteSpace(kv.Key))
43 {
44 yield return "[display.instruments] key must not be empty.";
45 continue;
46 }
47
48 var k = kv.Key.Trim();
49 var isPrimary = k.Equals(InstrumentRoutingSlotKeys.PfdPrimary, StringComparison.OrdinalIgnoreCase)
50 || k.Equals(InstrumentRoutingSlotKeys.MfdPrimary, StringComparison.OrdinalIgnoreCase);
51 var isStrip = InstrumentRoutingSlotKeys.IsStatusStripKey(k);
52
53 if (!isPrimary && !isStrip)
54 {
55 yield return $"[display.instruments] unknown key '{k}' (expected {InstrumentRoutingSlotKeys.PfdPrimary}, {InstrumentRoutingSlotKeys.MfdPrimary}, {InstrumentRoutingSlotKeys.PfdStatusStrip}, or {InstrumentRoutingSlotKeys.ForwardStatusStrip}).";
56 }
57
58 if (string.IsNullOrWhiteSpace(kv.Value))
59 yield return $"[display.instruments] value for '{k}' is required.";
60 else if (isStrip)
61 {
62 if (!InstrumentStatusStripRouting.TryParse(kv.Value, out var showStrip, out _))
63 yield return $"[display.instruments] unknown value for '{k}' (expected {InstrumentStatusStripRouting.None} or background_status).";
64 }
65 else if (!InstrumentRoutingAliasResolver.TryResolve(kv.Value, out _))
66 yield return $"[display.instruments] unknown instrument alias or id for '{k}'.";
67 }
68 }
69 }
70
71 private static bool IsScore(double value) => value is >= 0 and <= 1;
72}
73
View only · write via MCP/CIDE