//! Access tiers for the anonymous processing nodes spawned by the //! hive-mind orchestrator (`app::workflow::hive_mind`). //! //! Nodes have no persistent identity of their own — the Core Intelligence //! addresses each one only by directive and access tier. Since node //! designations are system-assigned coordinates rather than named roles, //! tool access can't be a lookup table keyed by role name. Instead the //! Core Intelligence picks one of these three tiers per node, matched to //! what that node's specific directive needs — this keeps the Harness //! gate meaningful while the node roster itself stays fully dynamic. /// The three tool-access tiers a hive-mind node can be granted. pub mod tool_scope { /// Read-only investigation: no file mutation, no shell, no VCS. pub const READ: &str = "read"; /// Read-tier plus file mutation and non-destructive shell (tests/builds). pub const WRITE: &str = "write"; /// Write-tier plus delete, git, and the remaining LSP actions. pub const FULL: &str = "full"; const READ_TOOLS: &[&str] = &[ "read", "grep", "glob", "search", "seqthink", "recall", "lsp_connect", "lsp_diagnostics", "lsp_hover", "lsp_definition", "lsp_references", "read_findings", ]; const WRITE_TOOLS: &[&str] = &[ "read", "grep", "glob", "search", "seqthink", "recall", "lsp_connect", "lsp_diagnostics", "lsp_hover", "lsp_definition", "lsp_references", "read_findings", "write", "edit", "bash", "todowrite", "todofinish", "remember", ]; const FULL_TOOLS: &[&str] = &[ "read", "grep", "glob", "search", "seqthink", "recall", "lsp_connect", "lsp_diagnostics", "lsp_hover", "lsp_definition", "lsp_references", "read_findings", "write", "edit", "bash", "todowrite", "todofinish", "remember", "delete", "git_operator", "lsp_completion", "lsp_disconnect", ]; /// Resolve a tier name to its concrete tool allowlist. /// /// Unrecognized scope strings fall back to `READ` — the least-privileged /// tier — rather than silently granting broader access. /// /// Return: an owned `Vec` suitable for `AgentDefinition::with_allowed_tools`. pub fn tools_for(scope: &str) -> Vec { let tools: &[&str] = match scope { FULL => FULL_TOOLS, WRITE => WRITE_TOOLS, _ => READ_TOOLS, }; tools.iter().map(|s| (*s).to_string()).collect() } } #[cfg(test)] mod tests { use super::tool_scope::{tools_for, FULL, READ, WRITE}; #[test] fn read_tier_excludes_write_tools() { let tools = tools_for(READ); assert!(!tools.contains(&"write".to_string())); assert!(!tools.contains(&"bash".to_string())); } #[test] fn write_tier_includes_bash_but_not_delete_or_git() { let tools = tools_for(WRITE); assert!(tools.contains(&"bash".to_string())); assert!(tools.contains(&"write".to_string())); assert!(!tools.contains(&"delete".to_string())); assert!(!tools.contains(&"git_operator".to_string())); } #[test] fn full_tier_includes_delete_and_git() { let tools = tools_for(FULL); assert!(tools.contains(&"delete".to_string())); assert!(tools.contains(&"git_operator".to_string())); } #[test] fn unknown_scope_falls_back_to_read() { let tools = tools_for("bogus"); assert!(!tools.contains(&"write".to_string())); assert!(!tools.contains(&"delete".to_string())); } }