1use std::collections::BTreeMap;
4
5pub const MCP_MANIFEST_SCHEMA_VERSION: u32 = 1;
7pub const CONTEXT_PROOF_V1_SCHEMA_VERSION: u32 = 1;
8pub const CONTEXT_IR_V1_SCHEMA_VERSION: u32 = 1;
9pub const ATTENTION_LAYOUT_DRIVER_V1_SCHEMA_VERSION: u32 = 1;
10pub const VERIFICATION_OBSERVABILITY_V1_SCHEMA_VERSION: u32 = 1;
11pub const HANDOFF_LEDGER_V1_SCHEMA_VERSION: u32 = 1;
12pub const HANDOFF_TRANSFER_BUNDLE_V1_SCHEMA_VERSION: u32 = 1;
13pub const CCP_SESSION_BUNDLE_V1_SCHEMA_VERSION: u32 = 1;
14pub const KNOWLEDGE_POLICY_V1_SCHEMA_VERSION: u32 = 1;
15pub const GRAPH_REPRODUCIBILITY_V1_SCHEMA_VERSION: u32 = 1;
16pub const A2A_SNAPSHOT_V1_SCHEMA_VERSION: u32 = 1;
17pub const MEMORY_BOUNDARY_V1_SCHEMA_VERSION: u32 = 1;
18pub const GOTCHAS_REMINDERS_V1_SCHEMA_VERSION: u32 = 1;
19pub const PROVIDER_FRAMEWORK_V1_SCHEMA_VERSION: u32 = 1;
20pub const CONTEXT_PACKAGE_V1_SCHEMA_VERSION: u32 = 1;
21pub const CONTEXT_PACKAGE_V2_SCHEMA_VERSION: u32 = 2;
22pub const CONTEXT_SNAPSHOT_V1_SCHEMA_VERSION: u32 = 1;
23pub const TEAM_SEAT_VALUE_V1_SCHEMA_VERSION: u32 = 1;
24
25pub const PACKAGE_EXTENSION: &str = "ctxpkg";
26pub const LEGACY_PACKAGE_EXTENSION: &str = "lctxpkg";
27pub const MAX_PACKAGE_FILE_BYTES: u64 = 10 * 1024 * 1024; pub fn is_package_file(path: &std::path::Path) -> bool {
30 path.extension()
31 .and_then(|e| e.to_str())
32 .is_some_and(|ext| ext == PACKAGE_EXTENSION || ext == LEGACY_PACKAGE_EXTENSION)
33}
34
35pub fn default_package_filename(name: &str, version: &str) -> String {
36 format!("{name}-{version}.{PACKAGE_EXTENSION}")
37}
38
39pub const HTTP_MCP_CONTRACT_VERSION: u32 = 2;
41pub const TEAM_SERVER_CONTRACT_VERSION: u32 = 1;
42pub const CAPABILITIES_CONTRACT_VERSION: u32 = 1;
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum ContractStatus {
56 Frozen,
57 Stable,
58 Experimental,
59}
60
61impl ContractStatus {
62 pub fn as_str(self) -> &'static str {
63 match self {
64 ContractStatus::Frozen => "frozen",
65 ContractStatus::Stable => "stable",
66 ContractStatus::Experimental => "experimental",
67 }
68 }
69}
70
71pub struct ContractDoc {
74 pub id: &'static str,
76 pub doc_file: &'static str,
78 pub version: u32,
79 pub status: ContractStatus,
80}
81
82pub fn contract_docs() -> Vec<ContractDoc> {
87 use ContractStatus::{Experimental, Frozen, Stable};
88 let doc = |id, doc_file, version, status| ContractDoc {
89 id,
90 doc_file,
91 version,
92 status,
93 };
94 vec![
95 doc("http-mcp", "http-mcp-contract-v1.md", 1, Frozen),
97 doc("http-mcp-v2", "http-mcp-contract-v2.md", 2, Stable),
98 doc("context-ir", "context-ir-v1.md", 1, Frozen),
99 doc(
100 "local-free-invariant",
101 "local-free-invariant-v1.md",
102 1,
103 Frozen,
104 ),
105 doc(
108 "local-free-invariant-v2",
109 "local-free-invariant-v2.md",
110 2,
111 Stable,
112 ),
113 doc(
114 "oss-plane-separation",
115 "oss-plane-separation-v1.md",
116 1,
117 Frozen,
118 ),
119 doc(
121 "oss-plane-separation-v2",
122 "oss-plane-separation-v2.md",
123 2,
124 Stable,
125 ),
126 doc("wasm-abi", "wasm-abi-v1.md", 1, Frozen),
127 doc("delivery-manifest", "delivery-manifest-v1.md", 1, Frozen),
131 doc(
132 "deployment-rehearsal",
133 "deployment-rehearsal-v1.md",
134 1,
135 Frozen,
136 ),
137 doc(
138 "release-key-rotation",
139 "release-key-rotation-v1.md",
140 1,
141 Frozen,
142 ),
143 doc("capabilities", "capabilities-contract-v1.md", 1, Stable),
148 doc("evidence-bundle", "evidence-bundle-v1.md", 1, Stable),
151 doc("a2a", "a2a-contract-v1.md", 1, Stable),
152 doc(
153 "attention-layout-driver",
154 "attention-layout-driver-v1.md",
155 1,
156 Stable,
157 ),
158 doc("conformance", "conformance-v1.md", 1, Stable),
159 doc(
160 "context-plan-projection-digest",
161 "context-plan-projection-digest-v1.md",
162 1,
163 Stable,
164 ),
165 doc(
166 "ocla-cache-validator",
167 "ocla-cache-validator-v1.md",
168 1,
169 Stable,
170 ),
171 doc(
172 "ocla-verifier-conformance",
173 "ocla-verifier-conformance-v1.md",
174 1,
175 Stable,
176 ),
177 doc("extension-trust", "extension-trust-v1.md", 1, Stable),
178 doc("extractors", "extractors-v1.md", 1, Stable),
179 doc("contracts-readme", "README.md", 1, Stable),
180 doc("deprecation-policy", "DEPRECATION.md", 1, Stable),
181 doc("audit-schedule", "audit-schedule-v1.md", 1, Stable),
182 doc("branch-protection", "branch-protection-v1.md", 1, Stable),
183 doc(
184 "certification-levels",
185 "certification-levels-v1.md",
186 1,
187 Stable,
188 ),
189 doc("release-integrity", "release-integrity-v1.md", 1, Stable),
190 doc("evidence-bundle-v2", "evidence-bundle-v2.md", 2, Stable),
191 doc(
192 "evidence-bundle-v2-verification",
193 "evidence-bundle-v2-verification-v1.md",
194 1,
195 Stable,
196 ),
197 doc(
198 "public-product-claims",
199 "public-product-claims-v1.md",
200 1,
201 Stable,
202 ),
203 doc(
204 "gotchas-reminders",
205 "gotchas-reminders-contract-v1.md",
206 1,
207 Stable,
208 ),
209 doc(
210 "graph-reproducibility",
211 "graph-reproducibility-contract-v1.md",
212 1,
213 Stable,
214 ),
215 doc(
216 "handoff-transfer-bundle",
217 "handoff-transfer-bundle-v1.md",
218 1,
219 Stable,
220 ),
221 doc(
222 "knowledge-policy",
223 "knowledge-policy-contract-v1.md",
224 1,
225 Stable,
226 ),
227 doc(
228 "memory-boundary",
229 "memory-boundary-contract-v1.md",
230 1,
231 Stable,
232 ),
233 doc("persona-spec", "persona-spec-v1.md", 1, Stable),
234 doc(
235 "provider-framework",
236 "provider-framework-contract-v1.md",
237 1,
238 Stable,
239 ),
240 doc("wrapped-permalink", "wrapped-permalink-v1.md", 1, Stable),
241 doc("addon-manifest", "addon-manifest-v1.md", 1, Stable),
244 doc(
246 "decision-record-signature",
247 "decision-record-signature-v1.md",
248 1,
249 Stable,
250 ),
251 doc(
256 "team-context-source",
257 "team-context-v1.SOURCE-v1.md",
258 1,
259 Experimental,
260 ),
261 doc(
264 "context-candidate-admission",
265 "context-candidate-admission-v1.md",
266 1,
267 Experimental,
268 ),
269 doc("context-quality", "context-quality-v1.md", 1, Experimental),
272 doc(
273 "multi-agent-efficiency-benchmark",
274 "multi-agent-efficiency-benchmark-v1.md",
275 1,
276 Experimental,
277 ),
278 doc(
281 "test-deployment-evidence",
282 "test-deployment-evidence-v1.md",
283 1,
284 Experimental,
285 ),
286 doc(
289 "ocla-config-tuning",
290 "ocla-config-tuning-v2.md",
291 2,
292 Experimental,
293 ),
294 doc(
295 "personal-cloud-encryption",
296 "personal-cloud-encryption-v1.md",
297 1,
298 Experimental,
299 ),
300 doc(
303 "context-policy-packs",
304 "context-policy-packs-v1.md",
305 1,
306 Experimental,
307 ),
308 doc("quality-loop", "quality-loop-v1.md", 1, Experimental),
310 doc("edit-metering", "edit-metering-v1.md", 1, Experimental),
312 doc(
315 "context-snapshot",
316 "context-snapshot-v1.md",
317 1,
318 Experimental,
319 ),
320 doc(
321 "team-invite-links",
322 "team-invite-links-v1.md",
323 1,
324 Experimental,
325 ),
326 doc("pillar-boundaries", "pillar-boundaries-v1.md", 1, Stable),
327 doc(
330 "logical-session-presence",
331 "logical-session-presence-v1.md",
332 1,
333 Experimental,
334 ),
335 doc(
336 "tokenizer-calibration",
337 "tokenizer-calibration-v1.md",
338 1,
339 Experimental,
340 ),
341 doc(
342 "engine-interface-compatibility",
343 "engine-interface-compatibility-v1.md",
344 1,
345 Stable,
346 ),
347 doc("receipt-document", "receipt-document-v1.md", 1, Frozen),
352 doc(
353 "native-engine-context-proof",
354 "native-engine-context-proof-v1.md",
355 1,
356 Experimental,
357 ),
358 doc("context-gateway", "context-gateway-v1.md", 1, Experimental),
361 doc(
363 "context-gateway-v2",
364 "context-gateway-v2.md",
365 2,
366 Experimental,
367 ),
368 doc(
372 "egress-lifecycle",
373 "egress-lifecycle-v1.md",
374 1,
375 Experimental,
376 ),
377 doc(
378 "team-context-outcome",
379 "team-context-outcome-v1.md",
380 1,
381 Experimental,
382 ),
383 doc(
388 "engine-context-plan",
389 "engine-context-plan-v1.md",
390 1,
391 Experimental,
392 ),
393 doc(
394 "engine-context-sources",
395 "engine-context-sources-v1.md",
396 1,
397 Experimental,
398 ),
399 doc(
401 "engine-context-sources-v2",
402 "engine-context-sources-v2.md",
403 2,
404 Experimental,
405 ),
406 doc("engine-outcome", "engine-outcome-v1.md", 1, Experimental),
407 doc(
408 "engine-context-store",
409 "engine-context-store-v1.md",
410 1,
411 Experimental,
412 ),
413 doc("local-read", "local-read-v1.md", 1, Experimental),
414 doc("client-calls", "client-calls-v1.md", 1, Experimental),
415 doc("local-service", "local-service-v1.md", 1, Experimental),
416 doc(
417 "engine-provider-execution",
418 "engine-provider-execution-v1.md",
419 1,
420 Experimental,
421 ),
422 doc(
423 "engine-source-execution",
424 "engine-source-execution-v1.md",
425 1,
426 Experimental,
427 ),
428 doc(
429 "intelligence-runtime-install",
430 "intelligence-runtime-install-v1.md",
431 1,
432 Experimental,
433 ),
434 doc(
435 "reference-scheduler-estimates",
436 "reference-scheduler-estimates-v1.md",
437 1,
438 Experimental,
439 ),
440 doc("change-envelope", "change-envelope-v1.md", 1, Experimental),
441 doc(
442 "change-attestation",
443 "change-attestation-v1.md",
444 1,
445 Experimental,
446 ),
447 doc("managed-config", "managed-config-v1.md", 1, Experimental),
448 ]
449}
450
451pub fn status_kv() -> BTreeMap<&'static str, &'static str> {
454 contract_docs()
455 .into_iter()
456 .map(|d| (d.id, d.status.as_str()))
457 .collect()
458}
459
460pub fn versions_kv() -> BTreeMap<&'static str, u32> {
461 BTreeMap::from([
462 (
463 "leanctx.contract.mcp_manifest.schema_version",
464 MCP_MANIFEST_SCHEMA_VERSION,
465 ),
466 (
467 "leanctx.contract.context_proof_v1.schema_version",
468 CONTEXT_PROOF_V1_SCHEMA_VERSION,
469 ),
470 (
471 "leanctx.contract.context_ir_v1.schema_version",
472 CONTEXT_IR_V1_SCHEMA_VERSION,
473 ),
474 (
475 "leanctx.contract.attention_layout_driver_v1.schema_version",
476 ATTENTION_LAYOUT_DRIVER_V1_SCHEMA_VERSION,
477 ),
478 (
479 "leanctx.contract.verification_observability_v1.schema_version",
480 VERIFICATION_OBSERVABILITY_V1_SCHEMA_VERSION,
481 ),
482 (
483 "leanctx.contract.handoff_ledger_v1.schema_version",
484 HANDOFF_LEDGER_V1_SCHEMA_VERSION,
485 ),
486 (
487 "leanctx.contract.handoff_transfer_bundle_v1.schema_version",
488 HANDOFF_TRANSFER_BUNDLE_V1_SCHEMA_VERSION,
489 ),
490 (
491 "leanctx.contract.ccp_session_bundle_v1.schema_version",
492 CCP_SESSION_BUNDLE_V1_SCHEMA_VERSION,
493 ),
494 (
495 "leanctx.contract.knowledge_policy_v1.schema_version",
496 KNOWLEDGE_POLICY_V1_SCHEMA_VERSION,
497 ),
498 (
499 "leanctx.contract.graph_reproducibility_v1.schema_version",
500 GRAPH_REPRODUCIBILITY_V1_SCHEMA_VERSION,
501 ),
502 (
503 "leanctx.contract.a2a_snapshot_v1.schema_version",
504 A2A_SNAPSHOT_V1_SCHEMA_VERSION,
505 ),
506 (
507 "leanctx.contract.memory_boundary_v1.schema_version",
508 MEMORY_BOUNDARY_V1_SCHEMA_VERSION,
509 ),
510 (
511 "leanctx.contract.gotchas_reminders_v1.schema_version",
512 GOTCHAS_REMINDERS_V1_SCHEMA_VERSION,
513 ),
514 (
515 "leanctx.contract.provider_framework_v1.schema_version",
516 PROVIDER_FRAMEWORK_V1_SCHEMA_VERSION,
517 ),
518 (
519 "leanctx.contract.context_package_v1.schema_version",
520 CONTEXT_PACKAGE_V1_SCHEMA_VERSION,
521 ),
522 (
523 "leanctx.contract.context_package_v2.schema_version",
524 CONTEXT_PACKAGE_V2_SCHEMA_VERSION,
525 ),
526 (
527 "leanctx.contract.context_snapshot_v1.schema_version",
528 CONTEXT_SNAPSHOT_V1_SCHEMA_VERSION,
529 ),
530 (
531 "leanctx.contract.http_mcp.contract_version",
532 HTTP_MCP_CONTRACT_VERSION,
533 ),
534 (
535 "leanctx.contract.team_server.contract_version",
536 TEAM_SERVER_CONTRACT_VERSION,
537 ),
538 (
539 "leanctx.contract.capabilities.contract_version",
540 CAPABILITIES_CONTRACT_VERSION,
541 ),
542 (
543 "leanctx.contract.team_seat_value_v1.schema_version",
544 TEAM_SEAT_VALUE_V1_SCHEMA_VERSION,
545 ),
546 ])
547}
548
549#[cfg(test)]
550mod tests {
551 use super::*;
552
553 #[test]
554 fn contract_docs_have_unique_ids_and_files() {
555 let docs = contract_docs();
556 let mut ids: Vec<_> = docs.iter().map(|d| d.id).collect();
557 let mut files: Vec<_> = docs.iter().map(|d| d.doc_file).collect();
558 ids.sort_unstable();
559 files.sort_unstable();
560 let unique_ids: std::collections::BTreeSet<_> = ids.iter().collect();
561 let unique_files: std::collections::BTreeSet<_> = files.iter().collect();
562 assert_eq!(unique_ids.len(), docs.len(), "duplicate contract id");
563 assert_eq!(unique_files.len(), docs.len(), "duplicate doc file");
564 }
565
566 #[test]
567 fn frozen_set_covers_the_platform_promises() {
568 let docs = contract_docs();
572 for id in [
573 "http-mcp",
574 "context-ir",
575 "local-free-invariant",
576 "oss-plane-separation",
577 "wasm-abi",
578 "delivery-manifest",
579 "deployment-rehearsal",
580 "release-key-rotation",
581 ] {
582 let entry = docs.iter().find(|d| d.id == id).expect("listed");
583 assert_eq!(
584 entry.status,
585 ContractStatus::Frozen,
586 "{id} must stay frozen"
587 );
588 }
589 }
590
591 #[test]
592 fn status_kv_matches_docs() {
593 let kv = status_kv();
594 assert_eq!(kv.len(), contract_docs().len());
595 assert_eq!(kv["http-mcp"], "frozen");
596 assert_eq!(kv["personal-cloud-encryption"], "experimental");
597 assert_eq!(kv["context-candidate-admission"], "experimental");
598 assert_eq!(kv["multi-agent-efficiency-benchmark"], "experimental");
599 assert_eq!(kv["test-deployment-evidence"], "experimental");
600 }
601
602 #[test]
603 fn doc_files_follow_versioned_naming() {
604 for d in contract_docs() {
608 if d.doc_file == "README.md"
609 || d.doc_file == "DEPRECATION.md"
610 || d.doc_file.starts_with("v4-")
611 {
612 continue;
613 }
614 assert!(
615 d.doc_file.ends_with(&format!("-v{}.md", d.version)),
616 "{} must end in -v{}.md",
617 d.doc_file,
618 d.version
619 );
620 }
621 }
622}