bijux-dag-app 0.4.1

Application orchestration and response-shaping layer for Bijux DAG command surfaces.
Documentation
use super::{command_path_hidden_from_public_help, Commands};
use serde::Serialize;
use std::env;

pub(crate) const ENABLE_SIMULATED_ENV: &str = "BIJUX_DAG_ENABLE_SIMULATED";
pub(crate) const ENABLE_INTERNAL_ENV: &str = "BIJUX_DAG_ENABLE_INTERNAL";

#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub(crate) enum CommandLane {
    Stable,
    Experimental,
    Simulation,
    Internal,
}

#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub(crate) enum CommandAvailability {
    Default,
    ExplicitPath,
    OptIn,
}

#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq)]
pub(crate) struct CommandAccess {
    pub(crate) lane: CommandLane,
    pub(crate) availability: CommandAvailability,
    pub(crate) opt_in_env: Option<&'static str>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct CommandAccessDenial {
    pub(crate) root_command: &'static str,
    pub(crate) lane: CommandLane,
    pub(crate) opt_in_env: &'static str,
}

impl CommandAccessDenial {
    pub(crate) fn message(self) -> String {
        format!(
            "`{}` belongs to the {} command lane outside the stable v0.4.0 operator surface; set {}=1 to run it intentionally",
            self.root_command,
            lane_label(self.lane),
            self.opt_in_env,
        )
    }
}

pub(crate) fn command_access_for_command(command: &Commands) -> CommandAccess {
    command_access_for_head(root_command(command))
}

pub(crate) fn command_access_for_path(path: &str) -> CommandAccess {
    if is_path_scoped_experimental_route(path) {
        return CommandAccess {
            lane: CommandLane::Experimental,
            availability: CommandAvailability::ExplicitPath,
            opt_in_env: None,
        };
    }
    let head = path.split(' ').next().unwrap_or(path);
    let mut access = command_access_for_head(head);
    if access.availability == CommandAvailability::Default
        && command_path_hidden_from_public_help(path)
    {
        access.availability = CommandAvailability::ExplicitPath;
    }
    access
}

pub(crate) fn command_access_denial(command: &Commands) -> Option<CommandAccessDenial> {
    let root_command = root_command(command);
    let access = command_access_for_head(root_command);
    let opt_in_env = access.opt_in_env?;
    if opt_in_enabled(opt_in_env) {
        return None;
    }
    Some(CommandAccessDenial { root_command, lane: access.lane, opt_in_env })
}

pub(crate) fn lane_label(lane: CommandLane) -> &'static str {
    match lane {
        CommandLane::Stable => "stable",
        CommandLane::Experimental => "experimental",
        CommandLane::Simulation => "simulated",
        CommandLane::Internal => "internal",
    }
}

fn command_access_for_head(head: &str) -> CommandAccess {
    if matches!(
        head,
        "control-plane"
            | "dataset"
            | "enterprise"
            | "federation"
            | "fleet"
            | "governance"
            | "incident"
            | "lab"
            | "state-store"
    ) {
        return CommandAccess {
            lane: CommandLane::Simulation,
            availability: CommandAvailability::OptIn,
            opt_in_env: Some(ENABLE_SIMULATED_ENV),
        };
    }
    if matches!(
        head,
        "capabilities"
            | "durability"
            | "equivalence-proof"
            | "performance"
            | "release"
            | "runtime"
            | "schedule"
            | "security"
            | "semantic-portability"
            | "version-inspect"
    ) {
        return CommandAccess {
            lane: CommandLane::Internal,
            availability: CommandAvailability::OptIn,
            opt_in_env: Some(ENABLE_INTERNAL_ENV),
        };
    }
    if matches!(
        head,
        "adapters"
            | "canonical-bytes"
            | "canonical-diff"
            | "canonicalize"
            | "config"
            | "export"
            | "fingerprint"
            | "fsck"
            | "graph"
            | "graph-lint"
            | "hash"
            | "import"
            | "init"
            | "lint"
            | "migrate"
            | "node"
            | "policy"
            | "proof-summary"
            | "prove"
            | "show-effective-graph"
            | "status"
            | "trace-artifact"
            | "why-cache-missed"
            | "why-rerun"
    ) {
        return CommandAccess {
            lane: CommandLane::Experimental,
            availability: CommandAvailability::ExplicitPath,
            opt_in_env: None,
        };
    }
    CommandAccess {
        lane: CommandLane::Stable,
        availability: CommandAvailability::Default,
        opt_in_env: None,
    }
}

fn is_path_scoped_experimental_route(path: &str) -> bool {
    matches!(path, "explain-plan" | "run-bundle" | "trace-node")
        || path.starts_with("artifact fetch")
}

fn root_command(command: &Commands) -> &'static str {
    match command {
        Commands::Init { .. } => "init",
        Commands::Validate { .. } => "validate",
        Commands::Canonicalize { .. } => "canonicalize",
        Commands::Lint { .. } => "lint",
        Commands::GraphLint { .. } => "graph-lint",
        Commands::Fingerprint { .. } => "fingerprint",
        Commands::Hash { .. } => "hash",
        Commands::ArtifactInspect { .. } => "artifact-inspect",
        Commands::Artifact { .. } => "artifact",
        Commands::CommandCatalog { .. } => "commands",
        Commands::ControlPlane { .. } => "control-plane",
        Commands::StateStore { .. } => "state-store",
        Commands::Dataset { .. } => "dataset",
        Commands::Enterprise { .. } => "enterprise",
        Commands::Fleet { .. } => "fleet",
        Commands::Governance { .. } => "governance",
        Commands::Incident { .. } => "incident",
        Commands::Lab { .. } => "lab",
        Commands::Federation { .. } => "federation",
        Commands::Security { .. } => "security",
        Commands::Durability { .. } => "durability",
        Commands::Performance { .. } => "performance",
        Commands::Release { .. } => "release",
        Commands::CanonicalBytes { .. } => "canonical-bytes",
        Commands::CanonicalDiff { .. } => "canonical-diff",
        Commands::ShowEffectiveGraph { .. } => "show-effective-graph",
        Commands::ExplainPlan { .. } => "explain-plan",
        Commands::Plan { .. } => "plan",
        Commands::Schedule { .. } => "schedule",
        Commands::Runtime { .. } => "runtime",
        Commands::Run { .. } => "run",
        Commands::RunBundle { .. } => "run-bundle",
        Commands::Replay { .. } => "replay",
        Commands::Prove { .. } => "prove",
        Commands::ProofSummary { .. } => "proof-summary",
        Commands::Graph { .. } => "graph",
        Commands::Runs { .. } => "runs",
        Commands::Diff { .. } => "diff",
        Commands::WhyRerun { .. } => "why-rerun",
        Commands::WhyCacheMissed { .. } => "why-cache-missed",
        Commands::TraceArtifact { .. } => "trace-artifact",
        Commands::TraceNode { .. } => "trace-node",
        Commands::Explain { .. } => "explain",
        Commands::Node { .. } => "node",
        Commands::Status { .. } => "status",
        Commands::Verify { .. } => "verify",
        Commands::Fsck { .. } => "fsck",
        Commands::Doctor => "doctor",
        Commands::Migrate { .. } => "migrate",
        Commands::Cache { .. } => "cache",
        Commands::Adapters { .. } => "adapters",
        Commands::Export { .. } => "export",
        Commands::Import { .. } => "import",
        Commands::VersionInspect { .. } => "version-inspect",
        Commands::Capabilities { .. } => "capabilities",
        Commands::SemanticPortability { .. } => "semantic-portability",
        Commands::EquivalenceProof { .. } => "equivalence-proof",
        Commands::Version => "version",
        Commands::Config { .. } => "config",
        Commands::Policy { .. } => "policy",
    }
}

fn opt_in_enabled(env_name: &str) -> bool {
    let Some(value) = env::var_os(env_name) else {
        return false;
    };
    let normalized = value.to_string_lossy().trim().to_ascii_lowercase();
    !normalized.is_empty() && !matches!(normalized.as_str(), "0" | "false" | "no" | "off")
}

#[cfg(test)]
mod tests {
    use super::{
        command_access_for_path, CommandAvailability, CommandLane, ENABLE_INTERNAL_ENV,
        ENABLE_SIMULATED_ENV,
    };

    #[test]
    fn stable_commands_stay_on_default_surface() {
        let access = command_access_for_path("run");
        assert_eq!(access.lane, CommandLane::Stable);
        assert_eq!(access.availability, CommandAvailability::Default);
        assert_eq!(access.opt_in_env, None);
    }

    #[test]
    fn experimental_commands_stay_explicit_path_only() {
        let access = command_access_for_path("trace-artifact");
        assert_eq!(access.lane, CommandLane::Experimental);
        assert_eq!(access.availability, CommandAvailability::ExplicitPath);
        assert_eq!(access.opt_in_env, None);
    }

    #[test]
    fn hidden_helper_paths_stay_explicit_path_only() {
        let access = command_access_for_path("artifact fetch");
        assert_eq!(access.lane, CommandLane::Experimental);
        assert_eq!(access.availability, CommandAvailability::ExplicitPath);
        assert_eq!(access.opt_in_env, None);
    }

    #[test]
    fn hidden_config_root_stays_experimental() {
        let access = command_access_for_path("config");
        assert_eq!(access.lane, CommandLane::Experimental);
        assert_eq!(access.availability, CommandAvailability::ExplicitPath);
        assert_eq!(access.opt_in_env, None);
    }

    #[test]
    fn simulated_commands_require_opt_in() {
        let access = command_access_for_path("enterprise webhook");
        assert_eq!(access.lane, CommandLane::Simulation);
        assert_eq!(access.availability, CommandAvailability::OptIn);
        assert_eq!(access.opt_in_env, Some(ENABLE_SIMULATED_ENV));
    }

    #[test]
    fn internal_commands_require_opt_in() {
        let access = command_access_for_path("capabilities");
        assert_eq!(access.lane, CommandLane::Internal);
        assert_eq!(access.availability, CommandAvailability::OptIn);
        assert_eq!(access.opt_in_env, Some(ENABLE_INTERNAL_ENV));
    }
}