use alloc::{string::String, vec::Vec};
use thiserror::Error;
mod environment;
mod parser;
mod render;
mod validate;
pub use environment::check_plan_environment;
pub use parser::parse_plan;
pub use render::{render_lane, render_topology};
pub use validate::{validate_plan_repository_path, validate_plan_structure};
pub const PLAN_SCHEMA: &str = "shepherd.plan/2";
pub const TOPOLOGY_SCHEMA: &str = "shepherd.plan-topology/2";
pub const PROBE_SCHEMA: &str = "shepherd.plan-probes/1";
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanDocument {
pub manifest: PlanManifestV2,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanManifestV2 {
pub schema: String,
pub run: String,
pub seed: String,
pub mesh: String,
pub planning_evidence: String,
pub goal: String,
pub deliverables: Vec<String>,
pub lanes: Vec<String>,
pub root_roles: Vec<String>,
pub child_lead_roles: Vec<String>,
pub planning_lead: String,
pub engineer_count: usize,
pub review_rejection_limit: usize,
pub fourth_rejection: String,
pub root_continuation: String,
pub exclusions: Vec<String>,
pub capacity: PlanCapacity,
pub nodes: Vec<PlanNode>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanCapacity {
pub logical_lane_limit: usize,
pub host_process_ceiling: usize,
pub project_spawn_max_parallel: usize,
pub plan_process_ceiling: usize,
pub parent_role_cap: usize,
pub run_budget: usize,
pub simultaneous_process_ceiling: usize,
pub per_lane_child_wave_ceiling: usize,
pub disk_min_mib: u64,
pub model_quota: usize,
pub backpressure: String,
pub cargo_targets: Vec<LaneBinding>,
pub conductors: Vec<LaneBinding>,
pub schedule: Vec<CapacityWave>,
pub scale_outcome: Option<String>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LaneBinding {
pub lane: String,
pub value: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CapacityWave {
pub lanes: Vec<String>,
pub process_slots: usize,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanNode {
pub id: String,
pub seed_deliverables: Vec<String>,
pub lane: String,
pub role: String,
pub work_kind: String,
pub outcome: String,
pub owns: Vec<String>,
pub forbidden: Vec<String>,
pub consumes: Vec<String>,
pub produces: Vec<String>,
pub depends_on: Vec<String>,
pub red: GateContract,
pub green: GateContract,
pub eval: EvalContract,
pub evidence: String,
pub review: ReviewContract,
pub failure_route: String,
pub rollback: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GateContract {
pub command: Vec<String>,
pub expects: String,
pub reason: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EvalContract {
pub command: Vec<String>,
pub threshold: Option<u32>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ReviewContract {
pub role: String,
pub predicate: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct VerifiedPlanSeed {
pub run: String,
pub relative_path: String,
pub mesh: String,
pub deliverables: Vec<String>,
pub outcomes: Vec<String>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanTopology {
pub schema: String,
pub run: String,
pub seed: String,
pub mesh: String,
pub planning_evidence: String,
pub goal: String,
pub deliverables: Vec<String>,
pub lanes: Vec<PlanLane>,
pub nodes: Vec<PlanNode>,
pub topological_order: Vec<String>,
pub capacity: PlanCapacity,
pub capacity_policy: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanLane {
pub id: String,
pub conductor: String,
pub cargo_target: String,
pub node_ids: Vec<String>,
pub deliverables: Vec<String>,
}
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
strum::AsRefStr,
strum::Display,
strum::EnumCount,
strum::EnumIs,
strum::EnumString,
strum::IntoStaticStr,
strum::VariantNames,
)]
#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
pub enum PathKind {
File,
Directory,
}
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
strum::AsRefStr,
strum::Display,
strum::EnumCount,
strum::EnumIs,
strum::EnumString,
strum::IntoStaticStr,
strum::VariantNames,
)]
#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
pub enum PathState {
Missing,
File,
Directory,
Symlink,
Other,
}
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
strum::AsRefStr,
strum::Display,
strum::EnumCount,
strum::EnumIs,
strum::EnumString,
strum::IntoStaticStr,
strum::VariantNames,
)]
#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
pub enum ProbeExpectation {
Modify,
Create,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PlanEnvironmentProbe {
Path {
path: String,
expectation: ProbeExpectation,
kind: PathKind,
},
Symbol {
path: String,
symbol: String,
expected_matches: usize,
},
Interface {
path: String,
schema: String,
version: String,
},
Command {
argv: Vec<String>,
expected_exit: i32,
semantic_marker: String,
},
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanProbeManifest {
pub schema: String,
pub worktree_identity: String,
pub baseline: String,
pub probes: Vec<PlanEnvironmentProbe>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct InterfaceObservation {
pub schema: String,
pub version: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CommandObservation {
pub exit: i32,
pub stdout: String,
pub stderr: String,
}
pub trait SourceProbe {
type Error: core::fmt::Display;
fn worktree_identity(&self) -> Result<String, Self::Error>;
fn baseline(&self) -> Result<String, Self::Error>;
fn path_state(&self, path: &str) -> Result<PathState, Self::Error>;
fn symbol_matches(&self, path: &str, symbol: &str) -> Result<usize, Self::Error>;
fn interface(&self, path: &str) -> Result<InterfaceObservation, Self::Error>;
fn run(&self, argv: &[String]) -> Result<CommandObservation, Self::Error>;
fn available_disk_mib(&self) -> Result<u64, Self::Error>;
fn model_quota(&self) -> Result<usize, Self::Error>;
fn host_process_ceiling(&self) -> Result<usize, Self::Error>;
fn project_spawn_max_parallel(&self) -> Result<usize, Self::Error>;
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlanCheckReport {
pub schema: String,
pub run: String,
pub worktree_identity: String,
pub baseline: String,
pub probe_count: usize,
pub available_disk_mib: u64,
pub model_quota: usize,
pub host_process_ceiling: usize,
pub project_spawn_max_parallel: usize,
}
#[derive(Clone, Debug, Eq, Error, PartialEq)]
pub enum PlanError {
#[error("plan parse error: {0}")]
Parse(String),
#[error("plan structure error: {0}")]
Structure(String),
#[error("plan environment error: {0}")]
Environment(String),
#[error("unknown plan lane `{0}`")]
UnknownLane(String),
}