Forge
csharpdeeb25a2
1using CascadeIDE.Models;
2
3namespace CascadeIDE.Cockpit.Composition.HostSurface;
4
5/// <summary>
6/// Settings-backed strategy for mount mount-style resolution.
7/// Priority order:
8/// 1) exact current surface (slot+instrument -> slot/* -> */instrument -> */*)
9/// 2) global surface wildcard with the same specificity ladder.
10/// </summary>
11public sealed class SettingsBackedInstrumentMountPolicyResolver : IInstrumentMountPolicyResolver
12{
13 private static readonly IInstrumentMountPolicyRuleSpecification RuleMatches = new InstrumentMountPolicyRuleMatchesSpecification();
14 private static readonly IInstrumentMountPolicyEligibilitySpecification RuleEligibility = new RolloutMetricsEligibilitySpecification();
15
16 public string Resolve(
17 DisplaySettings displaySettings,
18 string surfaceId,
19 string slotId,
20 string instrumentId)
21 {
22 static string Normalize(string? value) => (value ?? string.Empty).Trim().ToLowerInvariant();
23
24 var mount = displaySettings.Mount;
25 var normalizedDefault = string.IsNullOrWhiteSpace(mount.DefaultStyle)
26 ? InstrumentMountPolicyIds.V1
27 : mount.DefaultStyle.Trim();
28 var rules = mount.Rules;
29 if (rules is null || rules.Count == 0)
30 return normalizedDefault;
31
32 var normalizedSurface = Normalize(surfaceId);
33 var normalizedSlot = Normalize(slotId);
34 var normalizedInstrument = Normalize(instrumentId);
35
36 string Pick(bool surfaceExact, bool slotExact, bool instrumentExact)
37 {
38 var context = new InstrumentMountPolicyMatchContext(
39 normalizedSurface,
40 normalizedSlot,
41 normalizedInstrument,
42 surfaceExact,
43 slotExact,
44 instrumentExact);
45 var match = rules.FirstOrDefault(rule =>
46 RuleMatches.IsSatisfiedBy(rule, in context)
47 && RuleEligibility.IsSatisfiedBy(rule, displaySettings));
48 return string.IsNullOrWhiteSpace(match?.Style) ? string.Empty : match.Style.Trim();
49 }
50
51 if (TryResolveForSurface(surfaceExact: true, out var surfaceSpecific))
52 return surfaceSpecific;
53
54 if (TryResolveForSurface(surfaceExact: false, out var globalFallback))
55 return globalFallback;
56
57 return normalizedDefault;
58
59 bool TryResolveForSurface(bool surfaceExact, out string resolvedPolicy)
60 {
61 resolvedPolicy = Pick(surfaceExact, slotExact: true, instrumentExact: true);
62 if (!string.IsNullOrWhiteSpace(resolvedPolicy))
63 return true;
64
65 resolvedPolicy = Pick(surfaceExact, slotExact: true, instrumentExact: false);
66 if (!string.IsNullOrWhiteSpace(resolvedPolicy))
67 return true;
68
69 resolvedPolicy = Pick(surfaceExact, slotExact: false, instrumentExact: true);
70 if (!string.IsNullOrWhiteSpace(resolvedPolicy))
71 return true;
72
73 resolvedPolicy = Pick(surfaceExact, slotExact: false, instrumentExact: false);
74 return !string.IsNullOrWhiteSpace(resolvedPolicy);
75 }
76 }
77}
78
View only · write via MCP/CIDE