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(
414 "engine-provider-execution",
415 "engine-provider-execution-v1.md",
416 1,
417 Experimental,
418 ),
419 doc(
420 "engine-source-execution",
421 "engine-source-execution-v1.md",
422 1,
423 Experimental,
424 ),
425 doc(
426 "intelligence-runtime-install",
427 "intelligence-runtime-install-v1.md",
428 1,
429 Experimental,
430 ),
431 doc(
432 "reference-scheduler-estimates",
433 "reference-scheduler-estimates-v1.md",
434 1,
435 Experimental,
436 ),
437 ]
438}
439
440pub fn status_kv() -> BTreeMap<&'static str, &'static str> {
443 contract_docs()
444 .into_iter()
445 .map(|d| (d.id, d.status.as_str()))
446 .collect()
447}
448
449pub fn versions_kv() -> BTreeMap<&'static str, u32> {
450 BTreeMap::from([
451 (
452 "leanctx.contract.mcp_manifest.schema_version",
453 MCP_MANIFEST_SCHEMA_VERSION,
454 ),
455 (
456 "leanctx.contract.context_proof_v1.schema_version",
457 CONTEXT_PROOF_V1_SCHEMA_VERSION,
458 ),
459 (
460 "leanctx.contract.context_ir_v1.schema_version",
461 CONTEXT_IR_V1_SCHEMA_VERSION,
462 ),
463 (
464 "leanctx.contract.attention_layout_driver_v1.schema_version",
465 ATTENTION_LAYOUT_DRIVER_V1_SCHEMA_VERSION,
466 ),
467 (
468 "leanctx.contract.verification_observability_v1.schema_version",
469 VERIFICATION_OBSERVABILITY_V1_SCHEMA_VERSION,
470 ),
471 (
472 "leanctx.contract.handoff_ledger_v1.schema_version",
473 HANDOFF_LEDGER_V1_SCHEMA_VERSION,
474 ),
475 (
476 "leanctx.contract.handoff_transfer_bundle_v1.schema_version",
477 HANDOFF_TRANSFER_BUNDLE_V1_SCHEMA_VERSION,
478 ),
479 (
480 "leanctx.contract.ccp_session_bundle_v1.schema_version",
481 CCP_SESSION_BUNDLE_V1_SCHEMA_VERSION,
482 ),
483 (
484 "leanctx.contract.knowledge_policy_v1.schema_version",
485 KNOWLEDGE_POLICY_V1_SCHEMA_VERSION,
486 ),
487 (
488 "leanctx.contract.graph_reproducibility_v1.schema_version",
489 GRAPH_REPRODUCIBILITY_V1_SCHEMA_VERSION,
490 ),
491 (
492 "leanctx.contract.a2a_snapshot_v1.schema_version",
493 A2A_SNAPSHOT_V1_SCHEMA_VERSION,
494 ),
495 (
496 "leanctx.contract.memory_boundary_v1.schema_version",
497 MEMORY_BOUNDARY_V1_SCHEMA_VERSION,
498 ),
499 (
500 "leanctx.contract.gotchas_reminders_v1.schema_version",
501 GOTCHAS_REMINDERS_V1_SCHEMA_VERSION,
502 ),
503 (
504 "leanctx.contract.provider_framework_v1.schema_version",
505 PROVIDER_FRAMEWORK_V1_SCHEMA_VERSION,
506 ),
507 (
508 "leanctx.contract.context_package_v1.schema_version",
509 CONTEXT_PACKAGE_V1_SCHEMA_VERSION,
510 ),
511 (
512 "leanctx.contract.context_package_v2.schema_version",
513 CONTEXT_PACKAGE_V2_SCHEMA_VERSION,
514 ),
515 (
516 "leanctx.contract.context_snapshot_v1.schema_version",
517 CONTEXT_SNAPSHOT_V1_SCHEMA_VERSION,
518 ),
519 (
520 "leanctx.contract.http_mcp.contract_version",
521 HTTP_MCP_CONTRACT_VERSION,
522 ),
523 (
524 "leanctx.contract.team_server.contract_version",
525 TEAM_SERVER_CONTRACT_VERSION,
526 ),
527 (
528 "leanctx.contract.capabilities.contract_version",
529 CAPABILITIES_CONTRACT_VERSION,
530 ),
531 (
532 "leanctx.contract.team_seat_value_v1.schema_version",
533 TEAM_SEAT_VALUE_V1_SCHEMA_VERSION,
534 ),
535 ])
536}
537
538#[cfg(test)]
539mod tests {
540 use super::*;
541
542 #[test]
543 fn contract_docs_have_unique_ids_and_files() {
544 let docs = contract_docs();
545 let mut ids: Vec<_> = docs.iter().map(|d| d.id).collect();
546 let mut files: Vec<_> = docs.iter().map(|d| d.doc_file).collect();
547 ids.sort_unstable();
548 files.sort_unstable();
549 let unique_ids: std::collections::BTreeSet<_> = ids.iter().collect();
550 let unique_files: std::collections::BTreeSet<_> = files.iter().collect();
551 assert_eq!(unique_ids.len(), docs.len(), "duplicate contract id");
552 assert_eq!(unique_files.len(), docs.len(), "duplicate doc file");
553 }
554
555 #[test]
556 fn frozen_set_covers_the_platform_promises() {
557 let docs = contract_docs();
561 for id in [
562 "http-mcp",
563 "context-ir",
564 "local-free-invariant",
565 "oss-plane-separation",
566 "wasm-abi",
567 "delivery-manifest",
568 "deployment-rehearsal",
569 "release-key-rotation",
570 ] {
571 let entry = docs.iter().find(|d| d.id == id).expect("listed");
572 assert_eq!(
573 entry.status,
574 ContractStatus::Frozen,
575 "{id} must stay frozen"
576 );
577 }
578 }
579
580 #[test]
581 fn status_kv_matches_docs() {
582 let kv = status_kv();
583 assert_eq!(kv.len(), contract_docs().len());
584 assert_eq!(kv["http-mcp"], "frozen");
585 assert_eq!(kv["personal-cloud-encryption"], "experimental");
586 assert_eq!(kv["context-candidate-admission"], "experimental");
587 assert_eq!(kv["multi-agent-efficiency-benchmark"], "experimental");
588 assert_eq!(kv["test-deployment-evidence"], "experimental");
589 }
590
591 #[test]
592 fn doc_files_follow_versioned_naming() {
593 for d in contract_docs() {
597 if d.doc_file == "README.md"
598 || d.doc_file == "DEPRECATION.md"
599 || d.doc_file.starts_with("v4-")
600 {
601 continue;
602 }
603 assert!(
604 d.doc_file.ends_with(&format!("-v{}.md", d.version)),
605 "{} must end in -v{}.md",
606 d.doc_file,
607 d.version
608 );
609 }
610 }
611}