version: "1.0.0"
target_crate: forjar
bindings:
- contract: blake3-state-v1.yaml
equation: hash_string
module_path: "forjar::tripwire::hasher::hash_string"
function: hash_string
signature: "fn hash_string(s: &str) -> String"
status: implemented
notes: "Returns 'blake3:' || hex(BLAKE3(s))"
- contract: blake3-state-v1.yaml
equation: hash_file
module_path: "forjar::tripwire::hasher::hash_file"
function: hash_file
signature: "fn hash_file(path: &Path) -> Result<String, String>"
status: implemented
notes: "Streaming 64KB buffer for large files"
- contract: blake3-state-v1.yaml
equation: composite_hash
module_path: "forjar::tripwire::hasher::composite_hash"
function: composite_hash
signature: "fn composite_hash(components: &[&str]) -> String"
status: implemented
notes: "NUL-separated component concatenation"
- contract: dag-ordering-v1.yaml
equation: topological_sort
module_path: "forjar::core::resolver::build_execution_order"
function: build_execution_order
signature: "fn build_execution_order(config: &ForjarConfig) -> Result<Vec<String>, String>"
status: implemented
notes: "Kahn's algorithm with alphabetical tie-breaking"
- contract: dag-ordering-v1.yaml
equation: kahn_sort
module_path: "forjar::core::resolver::kahn_sort"
function: kahn_sort
signature: "fn kahn_sort(resource_ids: &[String], in_degree: &mut HashMap<String, usize>, adjacency: &mut HashMap<String, Vec<String>>) -> Vec<String>"
status: implemented
notes: "Private helper; tested via build_execution_order"
- contract: execution-safety-v1.yaml
equation: atomic_write
module_path: "forjar::core::state::save_lock"
function: save_lock
signature: "fn save_lock(state_dir: &Path, lock: &StateLock) -> Result<(), String>"
status: implemented
notes: "temp + rename pattern; creates parent dirs"
- contract: execution-safety-v1.yaml
equation: jidoka_stop
module_path: "forjar::core::executor::record_failure"
function: record_failure
signature: "fn record_failure(ctx: &mut RecordCtx, resource_id: &str, resource_type: &ResourceType, duration: f64, error: &str) -> bool"
status: implemented
notes: "Private helper; returns should_stop based on FailurePolicy"
- contract: recipe-determinism-v1.yaml
equation: expand_recipe
module_path: "forjar::core::recipe::expand_recipe"
function: expand_recipe
signature: "fn expand_recipe(recipe_id: &str, recipe_file: &RecipeFile, machine: &MachineTarget, provided_inputs: &HashMap<String, Value>, external_depends_on: &[String]) -> Result<IndexMap<String, Resource>, String>"
status: implemented
notes: "Namespaces resource IDs, propagates machine target"
- contract: recipe-determinism-v1.yaml
equation: validate_inputs
module_path: "forjar::core::recipe::validate_inputs"
function: validate_inputs
signature: "fn validate_inputs(recipe: &RecipeMetadata, provided: &HashMap<String, Value>) -> Result<HashMap<String, String>, String>"
status: implemented
notes: "Type-checks all 6 input types (string, int, bool, path, enum, list)"
- contract: recipe-determinism-v1.yaml
equation: validate_input_type
module_path: "forjar::core::recipe::validate_input_type"
function: validate_input_type
signature: "fn validate_input_type(name: &str, type_name: &str, value: &Value, decl: &RecipeInput) -> Result<String, String>"
status: implemented
notes: "Private helper; dispatches to type-specific validation"
- contract: idempotent-apply-v1.yaml
equation: plan_fixed_point
module_path: "forjar::core::planner::plan"
function: plan
signature: "fn plan(config: &ForjarConfig, execution_order: &[String], locks: &HashMap<String, StateLock>, tag_filter: Option<&str>) -> ExecutionPlan"
status: implemented
notes: "Counter-conservation debug_assert; second plan over converged locks yields zero changes"
- contract: idempotent-apply-v1.yaml
equation: hash_determinism
module_path: "forjar::core::planner::hash_desired_state"
function: hash_desired_state
signature: "fn hash_desired_state(resource: &Resource) -> String"
status: implemented
notes: "FJ-2200 determinism debug_assert_eq; stable field order, BLAKE3 over NUL-joined components"
- contract: idempotent-apply-v1.yaml
equation: noop_fixed_point
module_path: "forjar::core::planner::determine_present_action"
function: determine_present_action
signature: "fn determine_present_action(resource_id: &str, resource: &Resource, machine_name: &str, locks: &HashMap<String, StateLock>) -> PlanAction"
status: implemented
notes: "Private helper; FJ-2200 debug_assert enforces converged + matching hash → NoOp"
- contract: plan-apply-equivalence-v1.yaml
equation: plan_determinism
module_path: "forjar::core::planner::plan"
function: plan
signature: "fn plan(config: &ForjarConfig, execution_order: &[String], locks: &HashMap<String, StateLock>, tag_filter: Option<&str>) -> ExecutionPlan"
status: implemented
notes: "Pure function; forjar plan (src/cli/plan.rs) and forjar apply (executor::apply) share it"
- contract: plan-apply-equivalence-v1.yaml
equation: apply_executes_plan
module_path: "forjar::core::executor::apply"
function: apply
signature: "fn apply(cfg: &ApplyConfig) -> Result<Vec<ApplyResult>, String>"
status: implemented
notes: "Executor iterates plan.changes only; outcome-conservation debug_assert in apply_machine"
- contract: plan-apply-equivalence-v1.yaml
equation: noop_no_execution
module_path: "forjar::core::executor::apply_single_resource"
function: apply_single_resource
signature: "fn apply_single_resource(cfg: &ApplyConfig, change: &PlannedChange, machine: &Machine, ctx: &mut RecordCtx, converged_resources: &HashSet<String>) -> Result<ResourceOutcome, String>"
status: implemented
notes: "Private helper; planned NoOp without force/trigger short-circuits to Unchanged"
- contract: destroy-undo-roundtrip-v1.yaml
equation: snapshot_generation
module_path: "forjar::cli::generation::create_generation"
function: create_generation
signature: "fn create_generation(state_dir: &Path, config_path: Option<&Path>) -> Result<u32, String>"
status: implemented
notes: "FJ-1386; monotonic numbering, atomic current-symlink switch, debug_assert on current"
- contract: destroy-undo-roundtrip-v1.yaml
equation: restore_generation
module_path: "forjar::cli::generation::rollback_to_generation"
function: rollback_to_generation
signature: "fn rollback_to_generation(state_dir: &Path, generation: u32, yes: bool) -> Result<(), String>"
status: implemented
notes: "Restores snapshot then atomically re-points current; debug_assert on current"
- contract: destroy-undo-roundtrip-v1.yaml
equation: undo_roundtrip
module_path: "forjar::cli::undo::cmd_undo"
function: cmd_undo
signature: "fn cmd_undo(file: &Path, state_dir: &Path, generations: u32, machine_filter: Option<&str>, dry_run: bool, yes: bool) -> Result<(), String>"
status: implemented
notes: "FJ-2003; targets current − n, rejects impossible targets, re-applies to converge"
- contract: codegen-dispatch-v1.yaml
equation: check_script
module_path: "forjar::core::codegen::check_script"
function: check_script
signature: "fn check_script(resource: &Resource) -> Result<String, String>"
status: implemented
notes: "Dispatches to resource-specific check handlers"
- contract: codegen-dispatch-v1.yaml
equation: apply_script
module_path: "forjar::core::codegen::apply_script"
function: apply_script
signature: "fn apply_script(resource: &Resource) -> Result<String, String>"
status: implemented
notes: "Dispatches to resource-specific apply handlers"
- contract: codegen-dispatch-v1.yaml
equation: state_query_script
module_path: "forjar::core::codegen::state_query_script"
function: state_query_script
signature: "fn state_query_script(resource: &Resource) -> Result<String, String>"
status: implemented
notes: "Dispatches to resource-specific state query handlers"