1use serde::{Deserialize, Serialize};
4use std::collections::BTreeMap;
5
6use crate::{
7 AdapterRole, FailureClass, IntegrationMode, LifecycleEventKind, SCHEMA_VERSION, SupportState,
8 ValidationError, require_non_empty,
9};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
21#[serde(rename_all = "snake_case")]
22pub enum ManifestPlacementClass {
23 PreSession,
25 PreFrameLeading,
27 PreFrameTrailing,
29 ToolResult,
31 ManualOperator,
33}
34
35impl ManifestPlacementClass {
36 pub const ALL: &'static [Self] = &[
37 Self::PreSession,
38 Self::PreFrameLeading,
39 Self::PreFrameTrailing,
40 Self::ToolResult,
41 Self::ManualOperator,
42 ];
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
47#[serde(deny_unknown_fields)]
48pub struct ManifestLifecycleEventSupport {
49 pub support: SupportState,
50 #[serde(default, skip_serializing_if = "Vec::is_empty")]
53 pub modes: Vec<IntegrationMode>,
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
58#[serde(deny_unknown_fields)]
59pub struct ManifestPlacementSupport {
60 pub support: SupportState,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub max_bytes: Option<u64>,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
69#[serde(deny_unknown_fields)]
70pub struct ManifestContextPressure {
71 pub support: SupportState,
72 #[serde(skip_serializing_if = "Option::is_none")]
73 pub evidence: Option<String>,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78#[serde(deny_unknown_fields)]
79pub struct ManifestReceipts {
80 pub native: bool,
82 pub lifeloop_synthesized: bool,
84 pub receipt_ledger: SupportState,
86}
87
88#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
92#[serde(deny_unknown_fields)]
93pub struct ManifestSessionIdentity {
94 pub harness_session_id: SupportState,
95 pub harness_run_id: SupportState,
96 pub harness_task_id: SupportState,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
102#[serde(deny_unknown_fields)]
103pub struct ManifestSessionRename {
104 pub support: SupportState,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
112#[serde(deny_unknown_fields)]
113pub struct ManifestRenewal {
114 pub reset: ManifestRenewalReset,
115 pub continuation: ManifestRenewalContinuation,
116 #[serde(default, skip_serializing_if = "Vec::is_empty")]
119 pub profiles: Vec<String>,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub evidence: Option<String>,
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
129#[serde(deny_unknown_fields)]
130pub struct ManifestRenewalReset {
131 pub native: SupportState,
132 pub wrapper_mediated: SupportState,
133 pub manual: SupportState,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
141#[serde(deny_unknown_fields)]
142pub struct ManifestRenewalContinuation {
143 pub observation: SupportState,
144 pub payload_delivery: SupportState,
145}
146
147#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
150#[serde(deny_unknown_fields)]
151pub struct ManifestApprovalSurface {
152 pub support: SupportState,
153}
154
155#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
157#[serde(deny_unknown_fields)]
158pub struct ManifestTelemetrySource {
159 pub source: String,
160 pub support: SupportState,
161}
162
163#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
168#[serde(deny_unknown_fields)]
169pub struct ManifestKnownDegradation {
170 pub capability: String,
171 pub previous_support: SupportState,
172 pub current_support: SupportState,
173 #[serde(skip_serializing_if = "Option::is_none")]
174 pub evidence: Option<String>,
175}
176
177#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
187#[serde(deny_unknown_fields)]
188pub struct AdapterManifest {
189 pub contract_version: String,
190 pub adapter_id: String,
191 pub adapter_version: String,
192 pub display_name: String,
193 pub role: AdapterRole,
194 pub integration_modes: Vec<IntegrationMode>,
195 pub lifecycle_events: BTreeMap<LifecycleEventKind, ManifestLifecycleEventSupport>,
196 pub placement: BTreeMap<ManifestPlacementClass, ManifestPlacementSupport>,
197 pub context_pressure: ManifestContextPressure,
198 pub receipts: ManifestReceipts,
199
200 #[serde(default, skip_serializing_if = "Option::is_none")]
201 pub session_identity: Option<ManifestSessionIdentity>,
202 #[serde(default, skip_serializing_if = "Option::is_none")]
203 pub session_rename: Option<ManifestSessionRename>,
204 #[serde(default, skip_serializing_if = "Option::is_none")]
205 pub renewal: Option<ManifestRenewal>,
206 #[serde(default, skip_serializing_if = "Option::is_none")]
207 pub approval_surface: Option<ManifestApprovalSurface>,
208 #[serde(default, skip_serializing_if = "Vec::is_empty")]
209 pub failure_modes: Vec<FailureClass>,
210 #[serde(default, skip_serializing_if = "Vec::is_empty")]
211 pub telemetry_sources: Vec<ManifestTelemetrySource>,
212 #[serde(default, skip_serializing_if = "Vec::is_empty")]
213 pub known_degradations: Vec<ManifestKnownDegradation>,
214}
215
216impl AdapterManifest {
217 pub fn validate(&self) -> Result<(), ValidationError> {
218 if self.contract_version != SCHEMA_VERSION {
219 return Err(ValidationError::SchemaVersionMismatch {
220 expected: SCHEMA_VERSION.to_string(),
221 found: self.contract_version.clone(),
222 });
223 }
224 require_non_empty(&self.adapter_id, "manifest.adapter_id")?;
225 require_non_empty(&self.adapter_version, "manifest.adapter_version")?;
226 require_non_empty(&self.display_name, "manifest.display_name")?;
227 if self.integration_modes.is_empty() {
228 return Err(ValidationError::InvalidManifest(
229 "manifest.integration_modes must declare at least one integration mode".into(),
230 ));
231 }
232 for deg in &self.known_degradations {
233 require_non_empty(°.capability, "manifest.known_degradations[].capability")?;
234 }
235 for src in &self.telemetry_sources {
236 require_non_empty(&src.source, "manifest.telemetry_sources[].source")?;
237 }
238 if let Some(renewal) = &self.renewal
239 && let Some(evidence) = &renewal.evidence
240 {
241 require_non_empty(evidence, "manifest.renewal.evidence")?;
242 }
243 if let Some(renewal) = &self.renewal {
244 for profile in &renewal.profiles {
245 require_non_empty(profile, "manifest.renewal.profiles[]")?;
246 }
247 }
248 Ok(())
249 }
250}
251
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
258#[serde(rename_all = "snake_case")]
259pub enum ConformanceLevel {
260 V1Conformance,
264 PreConformance,
268}
269
270#[derive(Debug, Clone, PartialEq, Eq)]
273pub struct RegisteredAdapter {
274 pub manifest: AdapterManifest,
275 pub conformance: ConformanceLevel,
276}
277
278pub fn manifest_registry() -> Vec<RegisteredAdapter> {
282 vec![
283 RegisteredAdapter {
284 manifest: codex_manifest(),
285 conformance: ConformanceLevel::V1Conformance,
286 },
287 RegisteredAdapter {
288 manifest: claude_manifest(),
289 conformance: ConformanceLevel::V1Conformance,
290 },
291 RegisteredAdapter {
292 manifest: hermes_manifest(),
293 conformance: ConformanceLevel::PreConformance,
294 },
295 RegisteredAdapter {
296 manifest: openclaw_manifest(),
297 conformance: ConformanceLevel::PreConformance,
298 },
299 RegisteredAdapter {
300 manifest: gemini_manifest(),
301 conformance: ConformanceLevel::PreConformance,
302 },
303 RegisteredAdapter {
304 manifest: opencode_manifest(),
305 conformance: ConformanceLevel::PreConformance,
306 },
307 ]
308}
309
310pub fn lookup_manifest(adapter_id: &str) -> Option<RegisteredAdapter> {
313 manifest_registry()
314 .into_iter()
315 .find(|entry| entry.manifest.adapter_id == adapter_id)
316}
317
318fn synthesized() -> SupportState {
319 SupportState::Synthesized
320}
321
322fn native() -> SupportState {
323 SupportState::Native
324}
325
326fn unavailable() -> SupportState {
327 SupportState::Unavailable
328}
329
330fn manual() -> SupportState {
331 SupportState::Manual
332}
333
334pub fn codex_manifest() -> AdapterManifest {
339 let lifecycle_events = BTreeMap::from([
340 (
341 LifecycleEventKind::SessionStarting,
342 ManifestLifecycleEventSupport {
343 support: native(),
344 modes: vec![IntegrationMode::NativeHook],
345 },
346 ),
347 (
348 LifecycleEventKind::SessionStarted,
349 ManifestLifecycleEventSupport {
350 support: native(),
351 modes: vec![IntegrationMode::NativeHook],
352 },
353 ),
354 (
355 LifecycleEventKind::FrameOpening,
356 ManifestLifecycleEventSupport {
357 support: native(),
358 modes: vec![IntegrationMode::NativeHook],
359 },
360 ),
361 (
362 LifecycleEventKind::FrameOpened,
363 ManifestLifecycleEventSupport {
364 support: synthesized(),
365 modes: vec![IntegrationMode::NativeHook],
366 },
367 ),
368 (
369 LifecycleEventKind::ContextPressureObserved,
370 ManifestLifecycleEventSupport {
371 support: native(),
372 modes: vec![IntegrationMode::NativeHook],
373 },
374 ),
375 (
376 LifecycleEventKind::ContextCompacted,
377 ManifestLifecycleEventSupport {
378 support: native(),
379 modes: vec![IntegrationMode::NativeHook],
380 },
381 ),
382 (
383 LifecycleEventKind::FrameEnding,
384 ManifestLifecycleEventSupport {
385 support: native(),
386 modes: vec![IntegrationMode::NativeHook],
387 },
388 ),
389 (
390 LifecycleEventKind::FrameEnded,
391 ManifestLifecycleEventSupport {
392 support: native(),
393 modes: vec![IntegrationMode::NativeHook],
394 },
395 ),
396 (
397 LifecycleEventKind::SessionEnding,
398 ManifestLifecycleEventSupport {
399 support: unavailable(),
400 modes: Vec::new(),
401 },
402 ),
403 (
404 LifecycleEventKind::SessionEnded,
405 ManifestLifecycleEventSupport {
406 support: unavailable(),
407 modes: Vec::new(),
408 },
409 ),
410 (
411 LifecycleEventKind::SupervisorTick,
412 ManifestLifecycleEventSupport {
413 support: unavailable(),
414 modes: Vec::new(),
415 },
416 ),
417 (
418 LifecycleEventKind::CapabilityDegraded,
419 ManifestLifecycleEventSupport {
420 support: synthesized(),
421 modes: vec![IntegrationMode::NativeHook],
422 },
423 ),
424 (
425 LifecycleEventKind::ReceiptEmitted,
426 ManifestLifecycleEventSupport {
427 support: synthesized(),
428 modes: vec![IntegrationMode::NativeHook],
429 },
430 ),
431 (
432 LifecycleEventKind::ReceiptGapDetected,
433 ManifestLifecycleEventSupport {
434 support: unavailable(),
435 modes: Vec::new(),
436 },
437 ),
438 ]);
439
440 let placement = BTreeMap::from([
441 (
442 ManifestPlacementClass::PreSession,
443 ManifestPlacementSupport {
444 support: native(),
445 max_bytes: Some(8192),
446 },
447 ),
448 (
449 ManifestPlacementClass::PreFrameLeading,
450 ManifestPlacementSupport {
451 support: native(),
452 max_bytes: Some(8192),
453 },
454 ),
455 (
456 ManifestPlacementClass::PreFrameTrailing,
457 ManifestPlacementSupport {
458 support: unavailable(),
459 max_bytes: None,
460 },
461 ),
462 (
463 ManifestPlacementClass::ToolResult,
464 ManifestPlacementSupport {
465 support: unavailable(),
466 max_bytes: None,
467 },
468 ),
469 (
470 ManifestPlacementClass::ManualOperator,
471 ManifestPlacementSupport {
472 support: manual(),
473 max_bytes: None,
474 },
475 ),
476 ]);
477
478 AdapterManifest {
479 contract_version: SCHEMA_VERSION.to_string(),
480 adapter_id: "codex".into(),
481 adapter_version: "0.1.0".into(),
482 display_name: "Codex".into(),
483 role: AdapterRole::PrimaryWorker,
484 integration_modes: vec![IntegrationMode::NativeHook, IntegrationMode::ManualSkill],
485 lifecycle_events,
486 placement,
487 context_pressure: ManifestContextPressure {
488 support: native(),
489 evidence: Some(
490 "Codex CLI 0.129 exposes PreCompact before context pressure handling and PostCompact after context compacts"
491 .into(),
492 ),
493 },
494 receipts: ManifestReceipts {
495 native: false,
496 lifeloop_synthesized: true,
497 receipt_ledger: unavailable(),
498 },
499 session_identity: Some(ManifestSessionIdentity {
500 harness_session_id: native(),
501 harness_run_id: synthesized(),
502 harness_task_id: unavailable(),
503 }),
504 session_rename: None,
505 renewal: Some(ManifestRenewal {
506 reset: ManifestRenewalReset {
507 native: unavailable(),
508 wrapper_mediated: synthesized(),
509 manual: manual(),
510 },
511 continuation: ManifestRenewalContinuation {
512 observation: native(),
513 payload_delivery: synthesized(),
514 },
515 profiles: vec![crate::host_assets::CCD_RENEWAL_PROFILE.id.into()],
516 evidence: Some(
517 "Codex Stop block-as-continuation evidence plus the opt-in renewal host-hook profile proves wrapper-mediated reset prepare and out-of-band continuation-token delivery"
518 .into(),
519 ),
520 }),
521 approval_surface: None,
522 failure_modes: vec![FailureClass::TransportError, FailureClass::PayloadTooLarge],
523 telemetry_sources: Vec::new(),
524 known_degradations: Vec::new(),
525 }
526}
527
528pub fn claude_manifest() -> AdapterManifest {
530 let lifecycle_events = BTreeMap::from([
531 (
532 LifecycleEventKind::SessionStarting,
533 ManifestLifecycleEventSupport {
534 support: native(),
535 modes: vec![IntegrationMode::NativeHook],
536 },
537 ),
538 (
539 LifecycleEventKind::SessionStarted,
540 ManifestLifecycleEventSupport {
541 support: native(),
542 modes: vec![IntegrationMode::NativeHook],
543 },
544 ),
545 (
546 LifecycleEventKind::FrameOpening,
547 ManifestLifecycleEventSupport {
548 support: native(),
549 modes: vec![IntegrationMode::NativeHook],
550 },
551 ),
552 (
553 LifecycleEventKind::FrameOpened,
554 ManifestLifecycleEventSupport {
555 support: native(),
556 modes: vec![IntegrationMode::NativeHook],
557 },
558 ),
559 (
560 LifecycleEventKind::ContextPressureObserved,
561 ManifestLifecycleEventSupport {
562 support: native(),
563 modes: vec![IntegrationMode::NativeHook],
564 },
565 ),
566 (
567 LifecycleEventKind::ContextCompacted,
568 ManifestLifecycleEventSupport {
569 support: unavailable(),
570 modes: Vec::new(),
571 },
572 ),
573 (
574 LifecycleEventKind::FrameEnding,
575 ManifestLifecycleEventSupport {
576 support: native(),
577 modes: vec![IntegrationMode::NativeHook],
578 },
579 ),
580 (
581 LifecycleEventKind::FrameEnded,
582 ManifestLifecycleEventSupport {
583 support: native(),
584 modes: vec![IntegrationMode::NativeHook],
585 },
586 ),
587 (
588 LifecycleEventKind::SessionEnding,
589 ManifestLifecycleEventSupport {
590 support: native(),
591 modes: vec![IntegrationMode::NativeHook],
592 },
593 ),
594 (
595 LifecycleEventKind::SessionEnded,
596 ManifestLifecycleEventSupport {
597 support: native(),
598 modes: vec![IntegrationMode::NativeHook],
599 },
600 ),
601 (
602 LifecycleEventKind::SupervisorTick,
603 ManifestLifecycleEventSupport {
604 support: unavailable(),
605 modes: Vec::new(),
606 },
607 ),
608 (
609 LifecycleEventKind::CapabilityDegraded,
610 ManifestLifecycleEventSupport {
611 support: synthesized(),
612 modes: vec![IntegrationMode::NativeHook],
613 },
614 ),
615 (
616 LifecycleEventKind::ReceiptEmitted,
617 ManifestLifecycleEventSupport {
618 support: synthesized(),
619 modes: vec![IntegrationMode::NativeHook],
620 },
621 ),
622 (
623 LifecycleEventKind::ReceiptGapDetected,
624 ManifestLifecycleEventSupport {
625 support: unavailable(),
626 modes: Vec::new(),
627 },
628 ),
629 ]);
630
631 let placement = BTreeMap::from([
632 (
633 ManifestPlacementClass::PreSession,
634 ManifestPlacementSupport {
635 support: native(),
636 max_bytes: Some(16_384),
637 },
638 ),
639 (
640 ManifestPlacementClass::PreFrameLeading,
641 ManifestPlacementSupport {
642 support: native(),
643 max_bytes: Some(16_384),
644 },
645 ),
646 (
647 ManifestPlacementClass::PreFrameTrailing,
648 ManifestPlacementSupport {
649 support: unavailable(),
650 max_bytes: None,
651 },
652 ),
653 (
654 ManifestPlacementClass::ToolResult,
655 ManifestPlacementSupport {
656 support: unavailable(),
657 max_bytes: None,
658 },
659 ),
660 (
661 ManifestPlacementClass::ManualOperator,
662 ManifestPlacementSupport {
663 support: manual(),
664 max_bytes: None,
665 },
666 ),
667 ]);
668
669 AdapterManifest {
670 contract_version: SCHEMA_VERSION.to_string(),
671 adapter_id: "claude".into(),
672 adapter_version: "0.1.0".into(),
673 display_name: "Claude".into(),
674 role: AdapterRole::PrimaryWorker,
675 integration_modes: vec![IntegrationMode::NativeHook],
676 lifecycle_events,
677 placement,
678 context_pressure: ManifestContextPressure {
679 support: native(),
680 evidence: Some(
681 "Claude emits PreCompact and SessionEnd events that map directly to context.pressure_observed"
682 .into(),
683 ),
684 },
685 receipts: ManifestReceipts {
686 native: false,
687 lifeloop_synthesized: true,
688 receipt_ledger: unavailable(),
689 },
690 session_identity: Some(ManifestSessionIdentity {
691 harness_session_id: native(),
692 harness_run_id: synthesized(),
693 harness_task_id: unavailable(),
694 }),
695 session_rename: None,
696 renewal: None,
697 approval_surface: None,
698 failure_modes: vec![FailureClass::TransportError, FailureClass::PayloadTooLarge],
699 telemetry_sources: Vec::new(),
700 known_degradations: Vec::new(),
701 }
702}
703
704pub fn hermes_manifest() -> AdapterManifest {
708 pre_conformance_reference_adapter_manifest("hermes", "Hermes")
709}
710
711pub fn openclaw_manifest() -> AdapterManifest {
713 pre_conformance_reference_adapter_manifest("openclaw", "OpenClaw")
714}
715
716pub fn gemini_manifest() -> AdapterManifest {
718 pre_conformance_telemetry_only_manifest("gemini", "Gemini")
719}
720
721pub fn opencode_manifest() -> AdapterManifest {
723 pre_conformance_telemetry_only_manifest("opencode", "OpenCode")
724}
725
726fn pre_conformance_reference_adapter_manifest(
727 adapter_id: &str,
728 display_name: &str,
729) -> AdapterManifest {
730 let lifecycle_events = BTreeMap::from([
731 (
732 LifecycleEventKind::SessionStarting,
733 ManifestLifecycleEventSupport {
734 support: SupportState::Partial,
735 modes: vec![IntegrationMode::ReferenceAdapter],
736 },
737 ),
738 (
739 LifecycleEventKind::SessionStarted,
740 ManifestLifecycleEventSupport {
741 support: SupportState::Partial,
742 modes: vec![IntegrationMode::ReferenceAdapter],
743 },
744 ),
745 (
746 LifecycleEventKind::FrameOpening,
747 ManifestLifecycleEventSupport {
748 support: SupportState::Partial,
749 modes: vec![IntegrationMode::ReferenceAdapter],
750 },
751 ),
752 (
753 LifecycleEventKind::FrameEnded,
754 ManifestLifecycleEventSupport {
755 support: SupportState::Partial,
756 modes: vec![IntegrationMode::ReferenceAdapter],
757 },
758 ),
759 (
760 LifecycleEventKind::SessionEnded,
761 ManifestLifecycleEventSupport {
762 support: SupportState::Partial,
763 modes: vec![IntegrationMode::ReferenceAdapter],
764 },
765 ),
766 ]);
767
768 let placement = BTreeMap::from([
769 (
770 ManifestPlacementClass::PreSession,
771 ManifestPlacementSupport {
772 support: SupportState::Partial,
773 max_bytes: None,
774 },
775 ),
776 (
777 ManifestPlacementClass::PreFrameLeading,
778 ManifestPlacementSupport {
779 support: SupportState::Partial,
780 max_bytes: None,
781 },
782 ),
783 (
784 ManifestPlacementClass::ManualOperator,
785 ManifestPlacementSupport {
786 support: SupportState::Manual,
787 max_bytes: None,
788 },
789 ),
790 ]);
791
792 AdapterManifest {
793 contract_version: SCHEMA_VERSION.to_string(),
794 adapter_id: adapter_id.to_string(),
795 adapter_version: "0.0.1-pre".into(),
796 display_name: display_name.to_string(),
797 role: AdapterRole::Worker,
798 integration_modes: vec![IntegrationMode::ReferenceAdapter],
799 lifecycle_events,
800 placement,
801 context_pressure: ManifestContextPressure {
802 support: SupportState::Partial,
803 evidence: None,
804 },
805 receipts: ManifestReceipts {
806 native: false,
807 lifeloop_synthesized: true,
808 receipt_ledger: SupportState::Unavailable,
809 },
810 session_identity: None,
811 session_rename: None,
812 renewal: None,
813 approval_surface: None,
814 failure_modes: Vec::new(),
815 telemetry_sources: Vec::new(),
816 known_degradations: Vec::new(),
817 }
818}
819
820fn pre_conformance_telemetry_only_manifest(
821 adapter_id: &str,
822 display_name: &str,
823) -> AdapterManifest {
824 let lifecycle_events = BTreeMap::from([
825 (
826 LifecycleEventKind::SessionStarting,
827 ManifestLifecycleEventSupport {
828 support: SupportState::Partial,
829 modes: vec![IntegrationMode::TelemetryOnly],
830 },
831 ),
832 (
833 LifecycleEventKind::ContextPressureObserved,
834 ManifestLifecycleEventSupport {
835 support: SupportState::Partial,
836 modes: vec![IntegrationMode::TelemetryOnly],
837 },
838 ),
839 (
840 LifecycleEventKind::SessionEnded,
841 ManifestLifecycleEventSupport {
842 support: SupportState::Partial,
843 modes: vec![IntegrationMode::TelemetryOnly],
844 },
845 ),
846 ]);
847
848 let placement = BTreeMap::from([(
849 ManifestPlacementClass::ManualOperator,
850 ManifestPlacementSupport {
851 support: SupportState::Manual,
852 max_bytes: None,
853 },
854 )]);
855
856 AdapterManifest {
857 contract_version: SCHEMA_VERSION.to_string(),
858 adapter_id: adapter_id.to_string(),
859 adapter_version: "0.0.1-pre".into(),
860 display_name: display_name.to_string(),
861 role: AdapterRole::Observer,
862 integration_modes: vec![IntegrationMode::TelemetryOnly],
863 lifecycle_events,
864 placement,
865 context_pressure: ManifestContextPressure {
866 support: SupportState::Partial,
867 evidence: None,
868 },
869 receipts: ManifestReceipts {
870 native: false,
871 lifeloop_synthesized: true,
872 receipt_ledger: SupportState::Unavailable,
873 },
874 session_identity: None,
875 session_rename: None,
876 renewal: None,
877 approval_surface: None,
878 failure_modes: Vec::new(),
879 telemetry_sources: Vec::new(),
880 known_degradations: Vec::new(),
881 }
882}