1use std::collections::BTreeMap;
2
3pub const MCP_MANIFEST_SCHEMA_VERSION: u32 = 1;
5pub const CONTEXT_PROOF_V1_SCHEMA_VERSION: u32 = 1;
6pub const CONTEXT_IR_V1_SCHEMA_VERSION: u32 = 1;
7pub const INTENT_ROUTE_V1_SCHEMA_VERSION: u32 = 1;
8pub const DEGRADATION_POLICY_V1_SCHEMA_VERSION: u32 = 1;
9pub const WORKFLOW_EVIDENCE_LEDGER_V1_SCHEMA_VERSION: u32 = 1;
10pub const AUTONOMY_DRIVERS_V1_SCHEMA_VERSION: u32 = 1;
11pub const TOKENIZER_TRANSLATION_DRIVER_V1_SCHEMA_VERSION: u32 = 1;
12pub const ATTENTION_LAYOUT_DRIVER_V1_SCHEMA_VERSION: u32 = 1;
13pub const VERIFICATION_OBSERVABILITY_V1_SCHEMA_VERSION: u32 = 1;
14pub const HANDOFF_LEDGER_V1_SCHEMA_VERSION: u32 = 1;
15pub const HANDOFF_TRANSFER_BUNDLE_V1_SCHEMA_VERSION: u32 = 1;
16pub const CCP_SESSION_BUNDLE_V1_SCHEMA_VERSION: u32 = 1;
17pub const KNOWLEDGE_POLICY_V1_SCHEMA_VERSION: u32 = 1;
18pub const GRAPH_REPRODUCIBILITY_V1_SCHEMA_VERSION: u32 = 1;
19pub const A2A_SNAPSHOT_V1_SCHEMA_VERSION: u32 = 1;
20pub const MEMORY_BOUNDARY_V1_SCHEMA_VERSION: u32 = 1;
21pub const GOTCHAS_REMINDERS_V1_SCHEMA_VERSION: u32 = 1;
22pub const PROVIDER_FRAMEWORK_V1_SCHEMA_VERSION: u32 = 1;
23pub const CONTEXT_PACKAGE_V1_SCHEMA_VERSION: u32 = 1;
24pub const CONTEXT_PACKAGE_V2_SCHEMA_VERSION: u32 = 2;
25
26pub const PACKAGE_EXTENSION: &str = "ctxpkg";
27pub const LEGACY_PACKAGE_EXTENSION: &str = "lctxpkg";
28pub const MAX_PACKAGE_FILE_BYTES: u64 = 10 * 1024 * 1024; pub fn is_package_file(path: &std::path::Path) -> bool {
31 path.extension()
32 .and_then(|e| e.to_str())
33 .is_some_and(|ext| ext == PACKAGE_EXTENSION || ext == LEGACY_PACKAGE_EXTENSION)
34}
35
36pub fn default_package_filename(name: &str, version: &str) -> String {
37 format!("{name}-{version}.{PACKAGE_EXTENSION}")
38}
39
40pub const HTTP_MCP_CONTRACT_VERSION: u32 = 1;
42pub const TEAM_SERVER_CONTRACT_VERSION: u32 = 1;
43pub const CAPABILITIES_CONTRACT_VERSION: u32 = 1;
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum ContractStatus {
57 Frozen,
58 Stable,
59 Experimental,
60}
61
62impl ContractStatus {
63 pub fn as_str(self) -> &'static str {
64 match self {
65 ContractStatus::Frozen => "frozen",
66 ContractStatus::Stable => "stable",
67 ContractStatus::Experimental => "experimental",
68 }
69 }
70}
71
72pub struct ContractDoc {
75 pub id: &'static str,
77 pub doc_file: &'static str,
79 pub version: u32,
80 pub status: ContractStatus,
81}
82
83pub fn contract_docs() -> Vec<ContractDoc> {
88 use ContractStatus::{Experimental, Frozen, Stable};
89 let doc = |id, doc_file, version, status| ContractDoc {
90 id,
91 doc_file,
92 version,
93 status,
94 };
95 vec![
96 doc("http-mcp", "http-mcp-contract-v1.md", 1, Frozen),
98 doc("team-server", "team-server-contract-v1.md", 1, Frozen),
99 doc("context-ir", "context-ir-v1.md", 1, Frozen),
100 doc(
101 "local-free-invariant",
102 "local-free-invariant-v1.md",
103 1,
104 Frozen,
105 ),
106 doc(
107 "oss-plane-separation",
108 "oss-plane-separation-v1.md",
109 1,
110 Frozen,
111 ),
112 doc("billing-plane", "billing-plane-v1.md", 1, Frozen),
113 doc("wasm-abi", "wasm-abi-v1.md", 1, Frozen),
114 doc("capabilities", "capabilities-contract-v1.md", 1, Stable),
119 doc("billing-plane-v2", "billing-plane-v2.md", 2, Stable),
120 doc("billing-plane-v3", "billing-plane-v3.md", 3, Stable),
122 doc("evidence-bundle", "evidence-bundle-v1.md", 1, Stable),
124 doc("team-server-v2", "team-server-contract-v2.md", 2, Stable),
126 doc("a2a", "a2a-contract-v1.md", 1, Stable),
127 doc(
128 "attention-layout-driver",
129 "attention-layout-driver-v1.md",
130 1,
131 Stable,
132 ),
133 doc("autonomy-drivers", "autonomy-drivers-v1.md", 1, Stable),
134 doc("ccp-session-bundle", "ccp-session-bundle-v1.md", 1, Stable),
135 doc("conformance", "conformance-v1.md", 1, Stable),
136 doc("degradation-policy", "degradation-policy-v1.md", 1, Stable),
137 doc("extension-trust", "extension-trust-v1.md", 1, Stable),
138 doc("extractors", "extractors-v1.md", 1, Stable),
139 doc(
140 "gotchas-reminders",
141 "gotchas-reminders-contract-v1.md",
142 1,
143 Stable,
144 ),
145 doc(
146 "graph-reproducibility",
147 "graph-reproducibility-contract-v1.md",
148 1,
149 Stable,
150 ),
151 doc(
152 "handoff-transfer-bundle",
153 "handoff-transfer-bundle-v1.md",
154 1,
155 Stable,
156 ),
157 doc("intent-route", "intent-route-v1.md", 1, Stable),
158 doc(
159 "knowledge-policy",
160 "knowledge-policy-contract-v1.md",
161 1,
162 Stable,
163 ),
164 doc(
165 "memory-boundary",
166 "memory-boundary-contract-v1.md",
167 1,
168 Stable,
169 ),
170 doc("persona-spec", "persona-spec-v1.md", 1, Stable),
171 doc(
172 "provider-framework",
173 "provider-framework-contract-v1.md",
174 1,
175 Stable,
176 ),
177 doc(
178 "tokenizer-translation-driver",
179 "tokenizer-translation-driver-v1.md",
180 1,
181 Stable,
182 ),
183 doc(
184 "workflow-evidence-ledger",
185 "workflow-evidence-ledger-v1.md",
186 1,
187 Stable,
188 ),
189 doc("wrapped-permalink", "wrapped-permalink-v1.md", 1, Stable),
190 doc("addon-manifest", "addon-manifest-v1.md", 1, Stable),
193 doc(
195 "hosted-personal-index",
196 "hosted-personal-index-v1.md",
197 1,
198 Experimental,
199 ),
200 doc(
201 "personal-cloud-encryption",
202 "personal-cloud-encryption-v1.md",
203 1,
204 Experimental,
205 ),
206 doc(
209 "context-policy-packs",
210 "context-policy-packs-v1.md",
211 1,
212 Experimental,
213 ),
214 doc("device-overview", "device-overview-v1.md", 1, Experimental),
215 doc("email-digest", "email-digest-v1.md", 1, Experimental),
216 doc("org-audit-log", "org-audit-log-v1.md", 1, Experimental),
217 doc("org-sso-oidc", "org-sso-oidc-v1.md", 1, Experimental),
218 doc("quality-loop", "quality-loop-v1.md", 1, Experimental),
220 doc("ctxpkg-registry", "ctxpkg-registry-v1.md", 1, Experimental),
222 doc(
223 "team-invite-links",
224 "team-invite-links-v1.md",
225 1,
226 Experimental,
227 ),
228 doc("org-policy", "org-policy-v1.md", 1, Experimental),
233 doc(
234 "compliance-report",
235 "compliance-report-v1.md",
236 1,
237 Experimental,
238 ),
239 ]
240}
241
242pub fn status_kv() -> BTreeMap<&'static str, &'static str> {
245 contract_docs()
246 .into_iter()
247 .map(|d| (d.id, d.status.as_str()))
248 .collect()
249}
250
251pub fn versions_kv() -> BTreeMap<&'static str, u32> {
252 BTreeMap::from([
253 (
254 "leanctx.contract.mcp_manifest.schema_version",
255 MCP_MANIFEST_SCHEMA_VERSION,
256 ),
257 (
258 "leanctx.contract.context_proof_v1.schema_version",
259 CONTEXT_PROOF_V1_SCHEMA_VERSION,
260 ),
261 (
262 "leanctx.contract.context_ir_v1.schema_version",
263 CONTEXT_IR_V1_SCHEMA_VERSION,
264 ),
265 (
266 "leanctx.contract.intent_route_v1.schema_version",
267 INTENT_ROUTE_V1_SCHEMA_VERSION,
268 ),
269 (
270 "leanctx.contract.degradation_policy_v1.schema_version",
271 DEGRADATION_POLICY_V1_SCHEMA_VERSION,
272 ),
273 (
274 "leanctx.contract.workflow_evidence_ledger_v1.schema_version",
275 WORKFLOW_EVIDENCE_LEDGER_V1_SCHEMA_VERSION,
276 ),
277 (
278 "leanctx.contract.autonomy_drivers_v1.schema_version",
279 AUTONOMY_DRIVERS_V1_SCHEMA_VERSION,
280 ),
281 (
282 "leanctx.contract.tokenizer_translation_driver_v1.schema_version",
283 TOKENIZER_TRANSLATION_DRIVER_V1_SCHEMA_VERSION,
284 ),
285 (
286 "leanctx.contract.attention_layout_driver_v1.schema_version",
287 ATTENTION_LAYOUT_DRIVER_V1_SCHEMA_VERSION,
288 ),
289 (
290 "leanctx.contract.verification_observability_v1.schema_version",
291 VERIFICATION_OBSERVABILITY_V1_SCHEMA_VERSION,
292 ),
293 (
294 "leanctx.contract.handoff_ledger_v1.schema_version",
295 HANDOFF_LEDGER_V1_SCHEMA_VERSION,
296 ),
297 (
298 "leanctx.contract.handoff_transfer_bundle_v1.schema_version",
299 HANDOFF_TRANSFER_BUNDLE_V1_SCHEMA_VERSION,
300 ),
301 (
302 "leanctx.contract.ccp_session_bundle_v1.schema_version",
303 CCP_SESSION_BUNDLE_V1_SCHEMA_VERSION,
304 ),
305 (
306 "leanctx.contract.knowledge_policy_v1.schema_version",
307 KNOWLEDGE_POLICY_V1_SCHEMA_VERSION,
308 ),
309 (
310 "leanctx.contract.graph_reproducibility_v1.schema_version",
311 GRAPH_REPRODUCIBILITY_V1_SCHEMA_VERSION,
312 ),
313 (
314 "leanctx.contract.a2a_snapshot_v1.schema_version",
315 A2A_SNAPSHOT_V1_SCHEMA_VERSION,
316 ),
317 (
318 "leanctx.contract.memory_boundary_v1.schema_version",
319 MEMORY_BOUNDARY_V1_SCHEMA_VERSION,
320 ),
321 (
322 "leanctx.contract.gotchas_reminders_v1.schema_version",
323 GOTCHAS_REMINDERS_V1_SCHEMA_VERSION,
324 ),
325 (
326 "leanctx.contract.provider_framework_v1.schema_version",
327 PROVIDER_FRAMEWORK_V1_SCHEMA_VERSION,
328 ),
329 (
330 "leanctx.contract.context_package_v1.schema_version",
331 CONTEXT_PACKAGE_V1_SCHEMA_VERSION,
332 ),
333 (
334 "leanctx.contract.context_package_v2.schema_version",
335 CONTEXT_PACKAGE_V2_SCHEMA_VERSION,
336 ),
337 (
338 "leanctx.contract.http_mcp.contract_version",
339 HTTP_MCP_CONTRACT_VERSION,
340 ),
341 (
342 "leanctx.contract.team_server.contract_version",
343 TEAM_SERVER_CONTRACT_VERSION,
344 ),
345 (
346 "leanctx.contract.capabilities.contract_version",
347 CAPABILITIES_CONTRACT_VERSION,
348 ),
349 ])
350}
351
352#[cfg(test)]
353mod tests {
354 use super::*;
355
356 #[test]
357 fn contract_docs_have_unique_ids_and_files() {
358 let docs = contract_docs();
359 let mut ids: Vec<_> = docs.iter().map(|d| d.id).collect();
360 let mut files: Vec<_> = docs.iter().map(|d| d.doc_file).collect();
361 ids.sort_unstable();
362 files.sort_unstable();
363 let unique_ids: std::collections::BTreeSet<_> = ids.iter().collect();
364 let unique_files: std::collections::BTreeSet<_> = files.iter().collect();
365 assert_eq!(unique_ids.len(), docs.len(), "duplicate contract id");
366 assert_eq!(unique_files.len(), docs.len(), "duplicate doc file");
367 }
368
369 #[test]
370 fn frozen_set_covers_the_platform_promises() {
371 let docs = contract_docs();
375 for id in [
376 "http-mcp",
377 "team-server",
378 "context-ir",
379 "local-free-invariant",
380 "oss-plane-separation",
381 "billing-plane",
382 "wasm-abi",
383 ] {
384 let entry = docs.iter().find(|d| d.id == id).expect("listed");
385 assert_eq!(
386 entry.status,
387 ContractStatus::Frozen,
388 "{id} must stay frozen"
389 );
390 }
391 }
392
393 #[test]
394 fn status_kv_matches_docs() {
395 let kv = status_kv();
396 assert_eq!(kv.len(), contract_docs().len());
397 assert_eq!(kv["http-mcp"], "frozen");
398 assert_eq!(kv["hosted-personal-index"], "experimental");
399 assert_eq!(kv["personal-cloud-encryption"], "experimental");
400 }
401
402 #[test]
403 fn doc_files_follow_versioned_naming() {
404 for d in contract_docs() {
407 assert!(
408 d.doc_file.ends_with(&format!("-v{}.md", d.version)),
409 "{} must end in -v{}.md",
410 d.doc_file,
411 d.version
412 );
413 }
414 }
415}