ainl-mission 0.1.0

Host-neutral mission engine: state machine, DAG, scheduler, stall, task ledger (zero armaraos-* deps)
Documentation
//! [`MissionCapability`] — zero-cost gating when mission substrate is disabled.

use ainl_contracts::MissionId;

/// Host resolves whether mission tools, prompt blocks, and stall ticks are active.
pub trait MissionCapability {
    /// Manifest `[mission] enabled` and/or active mission graph presence.
    fn is_enabled(&self, agent_id: &str) -> bool;

    /// Optional: enabled because this agent has an active mission record.
    fn has_active_mission(&self, agent_id: &str, mission_id: &MissionId) -> bool {
        let _ = (agent_id, mission_id);
        false
    }

    /// Effective gate: explicit enable OR active mission.
    fn is_effective(&self, agent_id: &str, mission_id: Option<&MissionId>) -> bool {
        if self.is_enabled(agent_id) {
            return true;
        }
        if let Some(mid) = mission_id {
            return self.has_active_mission(agent_id, mid);
        }
        false
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    struct Cap {
        enabled: bool,
        active: bool,
    }

    impl MissionCapability for Cap {
        fn is_enabled(&self, _agent_id: &str) -> bool {
            self.enabled
        }

        fn has_active_mission(&self, _agent_id: &str, _mission_id: &MissionId) -> bool {
            self.active
        }
    }

    #[test]
    fn effective_when_manifest_or_active() {
        let cap = Cap {
            enabled: false,
            active: true,
        };
        let mid = MissionId("m1".into());
        assert!(cap.is_effective("a1", Some(&mid)));
    }

    #[test]
    fn off_when_disabled_and_no_mission() {
        let cap = Cap {
            enabled: false,
            active: false,
        };
        assert!(!cap.is_effective("a1", None));
    }
}