soma-som-ring 0.1.0

Standalone ring execution engine for soma(som): cycle lifecycle, extension registration, boundary mediation
Documentation
// SPDX-License-Identifier: LGPL-3.0-only
#![warn(missing_docs)]
#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used, clippy::panic))]
#![doc = include_str!("../README.md")]

//! `soma-som-ring` — the standalone ring execution engine for [soma(som)].
//!
//! This crate owns the cycle lifecycle (genesis + standard cycles) and the
//! registration API for the five extension relationships (BEFORE / THROUGH /
//! AFTER / AROUND / WITHIN) defined in OPUS §3.
//!
//! [soma(som)]: https://somasom.io
//!
//! ## What lives here
//!
//! | Component | Module |
//! |---|---|
//! | `RingEngine` | [`engine`] |
//! | `RingProcessor` trait | [`processor`] |
//! | `CycleObserver`, `NoOpObserver` | [`engine`] |
//! | `GenesisReport`, `CycleReport` | [`engine`] |
//! | `RingEngineError` | [`error`] |
//! | `RingCommand`, `ViewIntent`, `CommandDispatcher` | [`command`], [`dispatch`] |
//! | `FederationBridge` | [`federation`] |
//! | `Boundary` (crossing attestation) | [`boundary`] |
//!
//! Structural primitives (`Quad`, `Tree`, `Ring`, `UnitId`, the extension
//! trait family, persistence abstractions, governance trait interfaces) live
//! in the foundation crate [`soma_som_core`]. The split is the layer-purity
//! boundary: foundation primitives below, execution mechanics above.
//!
//! ## Dependencies
//!
//! ```text
//! soma-som-core ◄─── soma-som-ring
//! ```
//!
//! Zero framework dependencies: no async runtime, no HTTP server, no libc
//! bindings. Signing is injected at construction via the
//! [`soma_som_core::CrossingSigner`] trait so the engine never names a
//! concrete crypto backend.
//!
//! ## Example
//!
//! Construct a `RingEngine`, register a passthrough processor for each unit,
//! and run a single genesis cycle:
//!
//! ```
//! # fn main() -> Result<(), soma_som_ring::RingEngineError> {
//! use soma_som_core::TimingConfig;
//! use soma_som_core::quad::Quad;
//! use soma_som_core::types::{Layer, UnitId};
//! use soma_som_ring::{RingEngine, RingEngineError, RingProcessor};
//!
//! // Minimal RingProcessor — passes input through unchanged.
//! struct Echo;
//! impl RingProcessor for Echo {
//!     fn process(
//!         &mut self,
//!         _unit: UnitId,
//!         _cycle: u64,
//!         input: &Quad,
//!         _data: &Quad,
//!     ) -> Result<Quad, RingEngineError> {
//!         Ok(input.clone())
//!     }
//! }
//!
//! let mut engine = RingEngine::new(TimingConfig::default());
//! engine.set_all_processors(|| Box::new(Echo));
//! assert_eq!(engine.active_units().len(), 6);
//!
//! // Genesis: bootstrap the ring with a seed.
//! let report = engine.genesis(b"example-seed")?;
//! assert!(engine.is_genesis_complete());
//! assert_eq!(report.crossing_records.len(), 12);
//! # Ok(())
//! # }
//! ```
//!
//! After genesis, drive standard cycles (each cycle traverses all 6 units +
//! the 12 crossings of the ring topology):
//!
//! ```
//! # use soma_som_core::TimingConfig;
//! # use soma_som_core::quad::Quad;
//! # use soma_som_core::types::UnitId;
//! # use soma_som_ring::{RingEngine, RingEngineError, RingProcessor};
//! # struct Echo;
//! # impl RingProcessor for Echo {
//! #     fn process(
//! #         &mut self,
//! #         _u: UnitId,
//! #         _c: u64,
//! #         input: &Quad,
//! #         _d: &Quad,
//! #     ) -> Result<Quad, RingEngineError> {
//! #         Ok(input.clone())
//! #     }
//! # }
//! # fn main() -> Result<(), soma_som_ring::RingEngineError> {
//! let mut engine = RingEngine::new(TimingConfig::default());
//! engine.set_all_processors(|| Box::new(Echo));
//! engine.genesis(b"seed")?;
//!
//! let cycle = engine.cycle()?;
//! assert_eq!(cycle.cycle_index, 1);
//! assert_eq!(cycle.crossing_records.len(), 12);
//!
//! // Run 3 more cycles in a batch.
//! let reports = engine.run_cycles(3);
//! assert_eq!(reports.len(), 3);
//! assert!(reports.iter().all(|r| r.is_ok()));
//! assert_eq!(engine.cycle_index(), 4);
//! # Ok(())
//! # }
//! ```

pub mod boundary;
pub mod command;
pub mod dispatch;
pub mod engine;
pub mod error;
pub mod federation;
pub mod passthrough;
pub mod processor;

// ── Primary re-exports ──────────────────────────────────────────────────

pub use engine::{
    CommandRegistry, CommandRegistryEntry, CycleObserver, CycleReport, GenesisReport, NoOpObserver,
    RingEngine,
};
// Schema types are declared on `soma_som_core::Extension`. Consumers wanting to
// build a `CommandSchema` import it directly from `soma-som-core`:
//
//     use soma_som_core::{CommandSchema, SchemaField, SchemaFieldType};
//
// `soma-som-ring` deliberately does NOT re-export these to keep the
// dependency direction honest (the trait surface owns the type) and to avoid
// a hidden semver coupling across the two crate boundaries.
pub use error::{RingEngineError, RingEngineResult};
pub use federation::{FederationBridge, LocalDescriptor};
pub use command::{
    COMMAND_PREFIX, CommandResult, CommandStatus, RESULT_PREFIX, RingCommand, VIEW_PREFIX,
    ViewIntent, inject_command, inject_view_intent, validate_payload,
};
pub use dispatch::{CommandDispatchError, CommandDispatcher, PolicyProvider};
pub use passthrough::PassthroughProcessor;
pub use processor::RingProcessor;