liminal-server 0.27.3

Standalone server for the liminal messaging bus
Documentation
//! A seat's own station (ACCESS-013 R1): the holder already is the identity
//! the record names, so placing it is not a deliberate act for anyone else
//! to approve. It is placed in Lys exactly as an approved create is, and
//! landed as an ordinary Create event with no draft receipt.

use super::AgentRegistry;
use super::storage::{Land, check_bytes, check_population, validate_act};
use crate::agents::error::AgentError;
use crate::agents::records::{AgentEvent, AgentHarness, AgentSpec, AgentTransition};

/// The one sentence a self-placed record carries as its purpose.
pub const SELF_PLACED_PURPOSE: &str = "Its own station, placed by the seat itself.";

impl AgentRegistry {
    /// Places the station `name` for the holder of the same name when the
    /// registry holds none; answers whether it placed one. The seat owns its
    /// own station, so one person's many seats never meet the per-owner bound.
    ///
    /// # Errors
    /// Bounds, Lys placement or the store, by name.
    pub fn place_own(&self, name: &str, at_ms: u64) -> Result<bool, AgentError> {
        let mut index = self.lock()?;
        if index.records.contains_key(name) {
            return Ok(false);
        }
        let transition = AgentTransition {
            holder: name.to_owned(),
            at_ms,
            change: AgentEvent::Create(AgentSpec {
                harness: AgentHarness::Seat,
                purpose: SELF_PLACED_PURPOSE.to_owned(),
                service: None,
            }),
        };
        validate_act(&self.bounds, name, &transition)?;
        check_population(&index, &self.bounds, name)?;
        let land = Land {
            version: 1,
            name: name.to_owned(),
            owner: name.to_owned(),
            transition,
            receipt: None,
        };
        let bytes = serde_json::to_vec(&land).map_err(|_| AgentError::Invalid("event encoding"))?;
        check_bytes(&self.bounds, bytes.len())?;
        if self.placer.is_some() {
            self.place(name, &format!("self:{name}"))?;
        }
        self.land(&mut index, land)?;
        drop(index);
        tracing::info!(agent = name, "AGENT_STATION_SELF_PLACED");
        Ok(true)
    }
}