Skip to main content

lifeloop/router/
mod.rs

1//! Lifecycle router skeleton: pre-dispatch validation and adapter resolution.
2//!
3//! Lifeloop owns lifecycle event routing as a neutral mechanism. Clients
4//! own product behavior: a client receives the routed event via a
5//! callback and decides what (if anything) to deliver. The router is the
6//! seam that turns a `CallbackRequest` plus the adapter manifest registry
7//! into a typed [`RoutingPlan`] that downstream stages — capability
8//! negotiation, callback invocation, receipt emission, failure mapping —
9//! consume without re-validating wire-level invariants.
10//!
11//! # Boundary (issue #7, skeleton slice)
12//!
13//! This module owns:
14//! * pre-dispatch validation of [`crate::CallbackRequest`] envelopes
15//!   (schema version, non-empty identifiers, frame-context invariants,
16//!   payload-ref structure);
17//! * adapter manifest resolution by both `adapter_id` *and*
18//!   `adapter_version` (the two are distinguished failure classes —
19//!   wrong id is not the same as wrong version of a known id);
20//! * synthesis of a typed [`RoutingPlan`] that names the resolved
21//!   adapter and preserves opaque `PayloadRef`s for downstream stages;
22//! * the trait *seams* through which later issues plug in negotiation,
23//!   callback invocation, receipt emission, and failure mapping.
24//!
25//! This module does **not** own:
26//! * capability negotiation — see [`negotiate`] / [`NegotiatedPlan`];
27//! * callback invocation against renderers (issue #3 will wire a
28//!   protocol renderer into [`CallbackInvoker`]) — see
29//!   [`CallbackInvoker`];
30//! * receipt persistence/emission (future router issue) — see
31//!   [`ReceiptEmitter`];
32//! * failure-class mapping for receipt synthesis (future router
33//!   issue) — see [`FailureMapper`];
34//! * payload body inspection. The router treats
35//!   [`crate::PayloadRef`] and [`crate::PayloadEnvelope`] bodies as opaque: it does
36//!   not parse, transform, or pattern-match on payload contents.
37//!
38//! # Client compatibility
39//!
40//! This module has none. It is provider-neutral by construction. Any
41//! historic host-adapter flow that fused lifecycle routing with
42//! client product semantics is replaced by Lifeloop routing plus
43//! client callbacks — every client (including the first one) becomes
44//! a consumer of these seams, not a peer of the router.
45
46mod callbacks;
47mod failure_mapping;
48mod negotiation;
49mod plan;
50mod receipts;
51mod seams;
52mod subprocess;
53mod validation;
54
55pub use callbacks::{ClientCallback, DefaultCallbackInvoker, FnClientCallback, synthesize_request};
56pub use failure_mapping::{
57    LifeloopFailureMapper, TransportError, classes_for_negotiation_outcome,
58    failure_class_for_receipt_error, failure_class_for_route_error, failure_class_for_transport,
59    retry_class_for, validate_receipt_eligible,
60};
61pub use negotiation::{
62    CapabilityKind, CapabilityRequest, CapabilityRequirement, DefaultNegotiationStrategy,
63    NegotiatedPlan, PayloadPlacementDecision, PlacementRejection, negotiate,
64};
65pub use plan::{RoutingPlan, route};
66pub use receipts::{
67    IdempotencyKey, IdempotencyStore, InMemoryIdempotencyStore, LifeloopReceiptEmitter,
68    ReceiptContext, ReceiptError, SequenceGenerator, StoreOutcome,
69};
70pub use seams::{CallbackInvoker, FailureMapper, ReceiptEmitter};
71pub use subprocess::{
72    SubprocessCallbackInvoker, SubprocessInvokerConfig, SubprocessInvokerError,
73    failure_class_for_subprocess_error, transport_error_for,
74};
75pub use validation::{AdapterRegistry, AdapterResolution, BuiltinAdapterRegistry, RouteError};