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;
25pub const CONTEXT_SNAPSHOT_V1_SCHEMA_VERSION: u32 = 1;
26
27pub const PACKAGE_EXTENSION: &str = "ctxpkg";
28pub const LEGACY_PACKAGE_EXTENSION: &str = "lctxpkg";
29pub const MAX_PACKAGE_FILE_BYTES: u64 = 10 * 1024 * 1024; pub fn is_package_file(path: &std::path::Path) -> bool {
32 path.extension()
33 .and_then(|e| e.to_str())
34 .is_some_and(|ext| ext == PACKAGE_EXTENSION || ext == LEGACY_PACKAGE_EXTENSION)
35}
36
37pub fn default_package_filename(name: &str, version: &str) -> String {
38 format!("{name}-{version}.{PACKAGE_EXTENSION}")
39}
40
41pub const HTTP_MCP_CONTRACT_VERSION: u32 = 1;
43pub const TEAM_SERVER_CONTRACT_VERSION: u32 = 1;
44pub const CAPABILITIES_CONTRACT_VERSION: u32 = 1;
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum ContractStatus {
58 Frozen,
59 Stable,
60 Experimental,
61}
62
63impl ContractStatus {
64 pub fn as_str(self) -> &'static str {
65 match self {
66 ContractStatus::Frozen => "frozen",
67 ContractStatus::Stable => "stable",
68 ContractStatus::Experimental => "experimental",
69 }
70 }
71}
72
73pub struct ContractDoc {
76 pub id: &'static str,
78 pub doc_file: &'static str,
80 pub version: u32,
81 pub status: ContractStatus,
82}
83
84pub fn contract_docs() -> Vec<ContractDoc> {
89 use ContractStatus::{Experimental, Frozen, Stable};
90 let doc = |id, doc_file, version, status| ContractDoc {
91 id,
92 doc_file,
93 version,
94 status,
95 };
96 vec![
97 doc("http-mcp", "http-mcp-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("wasm-abi", "wasm-abi-v1.md", 1, Frozen),
113 doc("delivery-manifest", "delivery-manifest-v1.md", 1, Frozen),
117 doc(
118 "deployment-rehearsal",
119 "deployment-rehearsal-v1.md",
120 1,
121 Frozen,
122 ),
123 doc(
124 "release-key-rotation",
125 "release-key-rotation-v1.md",
126 1,
127 Frozen,
128 ),
129 doc("capabilities", "capabilities-contract-v1.md", 1, Stable),
134 doc("evidence-bundle", "evidence-bundle-v1.md", 1, Stable),
137 doc("a2a", "a2a-contract-v1.md", 1, Stable),
138 doc(
139 "attention-layout-driver",
140 "attention-layout-driver-v1.md",
141 1,
142 Stable,
143 ),
144 doc("autonomy-drivers", "autonomy-drivers-v1.md", 1, Stable),
145 doc("conformance", "conformance-v1.md", 1, Stable),
146 doc(
147 "ocla-verifier-conformance",
148 "ocla-verifier-conformance-v1.md",
149 1,
150 Stable,
151 ),
152 doc("degradation-policy", "degradation-policy-v1.md", 1, Stable),
153 doc("extension-trust", "extension-trust-v1.md", 1, Stable),
154 doc("extractors", "extractors-v1.md", 1, Stable),
155 doc("contracts-readme", "README.md", 1, Stable),
156 doc("deprecation-policy", "DEPRECATION.md", 1, Stable),
157 doc("audit-schedule", "audit-schedule-v1.md", 1, Stable),
158 doc("branch-protection", "branch-protection-v1.md", 1, Stable),
159 doc(
160 "certification-levels",
161 "certification-levels-v1.md",
162 1,
163 Stable,
164 ),
165 doc("release-integrity", "release-integrity-v1.md", 1, Stable),
166 doc(
167 "gotchas-reminders",
168 "gotchas-reminders-contract-v1.md",
169 1,
170 Stable,
171 ),
172 doc(
173 "graph-reproducibility",
174 "graph-reproducibility-contract-v1.md",
175 1,
176 Stable,
177 ),
178 doc(
179 "handoff-transfer-bundle",
180 "handoff-transfer-bundle-v1.md",
181 1,
182 Stable,
183 ),
184 doc("intent-route", "intent-route-v1.md", 1, Stable),
185 doc(
186 "knowledge-policy",
187 "knowledge-policy-contract-v1.md",
188 1,
189 Stable,
190 ),
191 doc(
192 "memory-boundary",
193 "memory-boundary-contract-v1.md",
194 1,
195 Stable,
196 ),
197 doc("persona-spec", "persona-spec-v1.md", 1, Stable),
198 doc(
199 "provider-framework",
200 "provider-framework-contract-v1.md",
201 1,
202 Stable,
203 ),
204 doc(
205 "tokenizer-translation-driver",
206 "tokenizer-translation-driver-v1.md",
207 1,
208 Stable,
209 ),
210 doc(
211 "workflow-evidence-ledger",
212 "workflow-evidence-ledger-v1.md",
213 1,
214 Stable,
215 ),
216 doc("wrapped-permalink", "wrapped-permalink-v1.md", 1, Stable),
217 doc("addon-manifest", "addon-manifest-v1.md", 1, Stable),
220 doc(
224 "context-candidate-admission",
225 "context-candidate-admission-v1.md",
226 1,
227 Experimental,
228 ),
229 doc(
230 "multi-agent-efficiency-benchmark",
231 "multi-agent-efficiency-benchmark-v1.md",
232 1,
233 Experimental,
234 ),
235 doc(
238 "test-deployment-evidence",
239 "test-deployment-evidence-v1.md",
240 1,
241 Experimental,
242 ),
243 doc(
246 "ocla-config-tuning",
247 "ocla-config-tuning-v2.md",
248 2,
249 Experimental,
250 ),
251 doc(
252 "personal-cloud-encryption",
253 "personal-cloud-encryption-v1.md",
254 1,
255 Experimental,
256 ),
257 doc(
260 "context-policy-packs",
261 "context-policy-packs-v1.md",
262 1,
263 Experimental,
264 ),
265 doc("quality-loop", "quality-loop-v1.md", 1, Experimental),
267 doc("edit-metering", "edit-metering-v1.md", 1, Experimental),
269 doc("ctxpkg-registry", "ctxpkg-registry-v1.md", 1, Experimental),
271 doc(
274 "context-snapshot",
275 "context-snapshot-v1.md",
276 1,
277 Experimental,
278 ),
279 doc(
280 "team-invite-links",
281 "team-invite-links-v1.md",
282 1,
283 Experimental,
284 ),
285 doc("pillar-boundaries", "pillar-boundaries-v1.md", 1, Stable),
286 doc(
289 "logical-session-presence",
290 "logical-session-presence-v1.md",
291 1,
292 Experimental,
293 ),
294 doc(
295 "tokenizer-calibration",
296 "tokenizer-calibration-v1.md",
297 1,
298 Experimental,
299 ),
300 ]
301}
302
303pub fn status_kv() -> BTreeMap<&'static str, &'static str> {
306 contract_docs()
307 .into_iter()
308 .map(|d| (d.id, d.status.as_str()))
309 .collect()
310}
311
312pub fn versions_kv() -> BTreeMap<&'static str, u32> {
313 BTreeMap::from([
314 (
315 "leanctx.contract.mcp_manifest.schema_version",
316 MCP_MANIFEST_SCHEMA_VERSION,
317 ),
318 (
319 "leanctx.contract.context_proof_v1.schema_version",
320 CONTEXT_PROOF_V1_SCHEMA_VERSION,
321 ),
322 (
323 "leanctx.contract.context_ir_v1.schema_version",
324 CONTEXT_IR_V1_SCHEMA_VERSION,
325 ),
326 (
327 "leanctx.contract.intent_route_v1.schema_version",
328 INTENT_ROUTE_V1_SCHEMA_VERSION,
329 ),
330 (
331 "leanctx.contract.degradation_policy_v1.schema_version",
332 DEGRADATION_POLICY_V1_SCHEMA_VERSION,
333 ),
334 (
335 "leanctx.contract.workflow_evidence_ledger_v1.schema_version",
336 WORKFLOW_EVIDENCE_LEDGER_V1_SCHEMA_VERSION,
337 ),
338 (
339 "leanctx.contract.autonomy_drivers_v1.schema_version",
340 AUTONOMY_DRIVERS_V1_SCHEMA_VERSION,
341 ),
342 (
343 "leanctx.contract.tokenizer_translation_driver_v1.schema_version",
344 TOKENIZER_TRANSLATION_DRIVER_V1_SCHEMA_VERSION,
345 ),
346 (
347 "leanctx.contract.attention_layout_driver_v1.schema_version",
348 ATTENTION_LAYOUT_DRIVER_V1_SCHEMA_VERSION,
349 ),
350 (
351 "leanctx.contract.verification_observability_v1.schema_version",
352 VERIFICATION_OBSERVABILITY_V1_SCHEMA_VERSION,
353 ),
354 (
355 "leanctx.contract.handoff_ledger_v1.schema_version",
356 HANDOFF_LEDGER_V1_SCHEMA_VERSION,
357 ),
358 (
359 "leanctx.contract.handoff_transfer_bundle_v1.schema_version",
360 HANDOFF_TRANSFER_BUNDLE_V1_SCHEMA_VERSION,
361 ),
362 (
363 "leanctx.contract.ccp_session_bundle_v1.schema_version",
364 CCP_SESSION_BUNDLE_V1_SCHEMA_VERSION,
365 ),
366 (
367 "leanctx.contract.knowledge_policy_v1.schema_version",
368 KNOWLEDGE_POLICY_V1_SCHEMA_VERSION,
369 ),
370 (
371 "leanctx.contract.graph_reproducibility_v1.schema_version",
372 GRAPH_REPRODUCIBILITY_V1_SCHEMA_VERSION,
373 ),
374 (
375 "leanctx.contract.a2a_snapshot_v1.schema_version",
376 A2A_SNAPSHOT_V1_SCHEMA_VERSION,
377 ),
378 (
379 "leanctx.contract.memory_boundary_v1.schema_version",
380 MEMORY_BOUNDARY_V1_SCHEMA_VERSION,
381 ),
382 (
383 "leanctx.contract.gotchas_reminders_v1.schema_version",
384 GOTCHAS_REMINDERS_V1_SCHEMA_VERSION,
385 ),
386 (
387 "leanctx.contract.provider_framework_v1.schema_version",
388 PROVIDER_FRAMEWORK_V1_SCHEMA_VERSION,
389 ),
390 (
391 "leanctx.contract.context_package_v1.schema_version",
392 CONTEXT_PACKAGE_V1_SCHEMA_VERSION,
393 ),
394 (
395 "leanctx.contract.context_package_v2.schema_version",
396 CONTEXT_PACKAGE_V2_SCHEMA_VERSION,
397 ),
398 (
399 "leanctx.contract.context_snapshot_v1.schema_version",
400 CONTEXT_SNAPSHOT_V1_SCHEMA_VERSION,
401 ),
402 (
403 "leanctx.contract.http_mcp.contract_version",
404 HTTP_MCP_CONTRACT_VERSION,
405 ),
406 (
407 "leanctx.contract.team_server.contract_version",
408 TEAM_SERVER_CONTRACT_VERSION,
409 ),
410 (
411 "leanctx.contract.capabilities.contract_version",
412 CAPABILITIES_CONTRACT_VERSION,
413 ),
414 ])
415}
416
417#[cfg(test)]
418mod tests {
419 use super::*;
420
421 #[test]
422 fn contract_docs_have_unique_ids_and_files() {
423 let docs = contract_docs();
424 let mut ids: Vec<_> = docs.iter().map(|d| d.id).collect();
425 let mut files: Vec<_> = docs.iter().map(|d| d.doc_file).collect();
426 ids.sort_unstable();
427 files.sort_unstable();
428 let unique_ids: std::collections::BTreeSet<_> = ids.iter().collect();
429 let unique_files: std::collections::BTreeSet<_> = files.iter().collect();
430 assert_eq!(unique_ids.len(), docs.len(), "duplicate contract id");
431 assert_eq!(unique_files.len(), docs.len(), "duplicate doc file");
432 }
433
434 #[test]
435 fn frozen_set_covers_the_platform_promises() {
436 let docs = contract_docs();
440 for id in [
441 "http-mcp",
442 "context-ir",
443 "local-free-invariant",
444 "oss-plane-separation",
445 "wasm-abi",
446 "delivery-manifest",
447 "deployment-rehearsal",
448 "release-key-rotation",
449 ] {
450 let entry = docs.iter().find(|d| d.id == id).expect("listed");
451 assert_eq!(
452 entry.status,
453 ContractStatus::Frozen,
454 "{id} must stay frozen"
455 );
456 }
457 }
458
459 #[test]
460 fn status_kv_matches_docs() {
461 let kv = status_kv();
462 assert_eq!(kv.len(), contract_docs().len());
463 assert_eq!(kv["http-mcp"], "frozen");
464 assert_eq!(kv["personal-cloud-encryption"], "experimental");
465 assert_eq!(kv["context-candidate-admission"], "experimental");
466 assert_eq!(kv["multi-agent-efficiency-benchmark"], "experimental");
467 assert_eq!(kv["test-deployment-evidence"], "experimental");
468 }
469
470 #[test]
471 fn doc_files_follow_versioned_naming() {
472 for d in contract_docs() {
476 if d.doc_file == "README.md" || d.doc_file == "DEPRECATION.md" {
477 continue;
478 }
479 assert!(
480 d.doc_file.ends_with(&format!("-v{}.md", d.version)),
481 "{} must end in -v{}.md",
482 d.doc_file,
483 d.version
484 );
485 }
486 }
487}