1use super::contract::LintDigest;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
6pub enum LintConfigSetting {
7 RerankerEnabled,
8 PageProjectionEnabled,
9 EpisodeChannelEnabled,
10 FactChannelEnabled,
11 SummaryPreludeEnabled,
12 TemporalGroundingEnabled,
13 KnowledgeGraphServingEnabled,
14 KnowledgeGraphSweepEnabled,
15 KnowledgeGraphProviderReady,
16 KnowledgeGraphHubCap,
17 SourceConfigurationCaptured,
18 SourceConfigurationCount,
19 SourceSnapshotIdentity,
20 PageRetrievalChannelEnabled,
21 FactChannelLimit,
22 RerankerLightConfigured,
23 RerankerDeepConfigured,
24 ProviderSlotsRequested,
25 ModelSlotsConfigured,
26 RerankerPathsRequested,
27 ModelConfigurationIdentity,
28 RuntimeObservationCaptured,
29 SemanticProviderReady,
30 SemanticProviderOnDevice,
31 SemanticExternalEgressEnabled,
32 SemanticCallingAgentEnabled,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
36pub enum LintConfigValue {
37 Enabled,
38 Disabled,
39 Count(u64),
40 Digest([u8; 32]),
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
44pub struct LintConfigSelection {
45 setting: LintConfigSetting,
46 value: LintConfigValue,
47}
48
49impl LintConfigSelection {
50 pub const fn new(setting: LintConfigSetting, value: LintConfigValue) -> Self {
51 Self { setting, value }
52 }
53
54 pub const fn count(setting: LintConfigSetting, value: u64) -> Self {
55 Self {
56 setting,
57 value: LintConfigValue::Count(value),
58 }
59 }
60
61 pub const fn digest(setting: LintConfigSetting, value: [u8; 32]) -> Self {
62 Self {
63 setting,
64 value: LintConfigValue::Digest(value),
65 }
66 }
67
68 fn bytes(self) -> Vec<u8> {
69 let setting = match self.setting {
70 LintConfigSetting::RerankerEnabled => 1,
71 LintConfigSetting::PageProjectionEnabled => 2,
72 LintConfigSetting::EpisodeChannelEnabled => 3,
73 LintConfigSetting::FactChannelEnabled => 4,
74 LintConfigSetting::SummaryPreludeEnabled => 5,
75 LintConfigSetting::TemporalGroundingEnabled => 6,
76 LintConfigSetting::KnowledgeGraphServingEnabled => 7,
77 LintConfigSetting::KnowledgeGraphSweepEnabled => 8,
78 LintConfigSetting::KnowledgeGraphProviderReady => 9,
79 LintConfigSetting::KnowledgeGraphHubCap => 10,
80 LintConfigSetting::SourceConfigurationCaptured => 11,
81 LintConfigSetting::SourceConfigurationCount => 12,
82 LintConfigSetting::SourceSnapshotIdentity => 13,
83 LintConfigSetting::PageRetrievalChannelEnabled => 14,
84 LintConfigSetting::FactChannelLimit => 15,
85 LintConfigSetting::RerankerLightConfigured => 16,
86 LintConfigSetting::RerankerDeepConfigured => 17,
87 LintConfigSetting::ProviderSlotsRequested => 18,
88 LintConfigSetting::ModelSlotsConfigured => 19,
89 LintConfigSetting::RerankerPathsRequested => 20,
90 LintConfigSetting::ModelConfigurationIdentity => 21,
91 LintConfigSetting::RuntimeObservationCaptured => 22,
92 LintConfigSetting::SemanticProviderReady => 23,
93 LintConfigSetting::SemanticProviderOnDevice => 24,
94 LintConfigSetting::SemanticExternalEgressEnabled => 25,
95 LintConfigSetting::SemanticCallingAgentEnabled => 26,
96 };
97 let mut bytes = vec![setting];
98 match self.value {
99 LintConfigValue::Enabled => bytes.push(1),
100 LintConfigValue::Disabled => bytes.push(2),
101 LintConfigValue::Count(value) => {
102 bytes.push(3);
103 bytes.extend_from_slice(&value.to_le_bytes());
104 }
105 LintConfigValue::Digest(value) => {
106 bytes.push(4);
107 bytes.extend_from_slice(&value);
108 }
109 }
110 bytes
111 }
112}
113
114#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
115#[serde(transparent)]
116pub struct LintConfigFingerprint(LintDigest);
117
118impl LintConfigFingerprint {
119 pub fn from_effective_config(selections: &[LintConfigSelection]) -> Self {
120 let mut sorted = selections.to_vec();
121 sorted.sort_unstable();
122 let mut hash = 0xcbf2_9ce4_8422_2325_u64;
123 for selection in sorted {
124 for byte in selection.bytes() {
125 hash ^= u64::from(byte);
126 hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
127 }
128 }
129 Self(LintDigest::from_u64(hash))
130 }
131
132 pub fn as_str(&self) -> &str {
133 self.0.as_str()
134 }
135}