Skip to main content

mechanism_runtime/
lib.rs

1//! Typed mechanism/theory surface crate for schema publication and bounded fit evaluation.
2//!
3//! `mechanism-runtime` keeps the compatibility name, but its actual role is narrow:
4//! it publishes artifact families plus small helper evaluators and does not implement
5//! autonomous orchestration or promotion authority.
6//!
7//! ## Integration Points
8//!
9//! - **forge-pilot observe phase:** `governance_gate.rs` (`#[cfg(feature = "governance")]`) reads
10//!   mechanism bundle publication status, theory version advisory state, and fit run dispositions
11//!   from semantic-memory projections.
12//! - **forge-pilot act phase:** fit run dispositions (eligible for local review vs. blocked)
13//!   and simulation contract advisory flags constrain whether mechanism promotions proceed.
14//! - **verification-control:** theory refuter suite and rollout stability report case types
15//!   are affected; fit run blocking dispositions trigger verification cases.
16//! - **Stack Arena scenarios:** governed lane exercises governance observation of mechanism
17//!   bundle state and fit run evaluation dispositions.
18//!
19//! ## Artifact Families
20//!
21//! | Artifact | Schema Version | Owner |
22//! |----------|---------------|-------|
23//! | [`MechanismBundleV1`] | `mechanism_bundle_v1` | this crate |
24//! | [`TheoryVersionV1`] | `theory_version_v1` | this crate |
25//! | [`TheoryLibraryV1`] | `theory_library_v1` | this crate |
26//! | [`HypothesisLibraryV1`] | `hypothesis_library_v1` | this crate |
27//! | [`SimulationContractV1`] | `simulation_contract_v1` | this crate |
28//! | [`FitRunV1`] | `fit_run_v1` | this crate |
29//! | [`TheoryRefuterSuiteV1`] | `theory_refuter_suite_v1` | this crate |
30//! | [`RolloutStabilityReportV1`] | `rollout_stability_report_v1` | this crate |
31
32pub mod error;
33pub use error::*;
34
35use schemars::JsonSchema;
36use serde::{Deserialize, Serialize};
37use stack_ids::{
38    FitRunId, HypothesisLibraryId, MechanismBundleId, RolloutStabilityReportId,
39    SimulationContractId, SurfaceStatus, TheoryLibraryId, TheoryRefuterSuiteId, TheoryVersionId,
40};
41
42pub const MECHANISM_BUNDLE_V1_SCHEMA: &str = "mechanism_bundle_v1";
43pub const THEORY_VERSION_V1_SCHEMA: &str = "theory_version_v1";
44pub const THEORY_LIBRARY_V1_SCHEMA: &str = "theory_library_v1";
45pub const HYPOTHESIS_LIBRARY_V1_SCHEMA: &str = "hypothesis_library_v1";
46pub const SIMULATION_CONTRACT_V1_SCHEMA: &str = "simulation_contract_v1";
47pub const FIT_RUN_V1_SCHEMA: &str = "fit_run_v1";
48pub const THEORY_REFUTER_SUITE_V1_SCHEMA: &str = "theory_refuter_suite_v1";
49pub const ROLLOUT_STABILITY_REPORT_V1_SCHEMA: &str = "rollout_stability_report_v1";
50
51#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
52pub struct MechanismBundleV1 {
53    pub schema_version: String,
54    pub mechanism_bundle_id: MechanismBundleId,
55    pub mechanism_name: String,
56    pub canonical_owner: String,
57    pub publication_status: SurfaceStatus,
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
61pub struct TheoryVersionV1 {
62    pub schema_version: String,
63    pub theory_version_id: TheoryVersionId,
64    pub mechanism_bundle_id: MechanismBundleId,
65    pub theory_name: String,
66    pub semantic_version: String,
67    pub advisory_only: bool,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
71pub struct TheoryLibraryV1 {
72    pub schema_version: String,
73    pub theory_library_id: TheoryLibraryId,
74    #[serde(default)]
75    pub theory_version_ids: Vec<TheoryVersionId>,
76    pub canonical_owner: String,
77    pub publication_status: SurfaceStatus,
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
81pub struct HypothesisLibraryV1 {
82    pub schema_version: String,
83    pub hypothesis_library_id: HypothesisLibraryId,
84    #[serde(default)]
85    pub hypothesis_refs: Vec<String>,
86    pub publication_status: SurfaceStatus,
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
90pub struct SimulationContractV1 {
91    pub schema_version: String,
92    pub simulation_contract_id: SimulationContractId,
93    pub mechanism_bundle_id: MechanismBundleId,
94    pub target_outcome: String,
95    #[serde(default)]
96    pub required_inputs: Vec<String>,
97    pub advisory_only: bool,
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
101#[serde(rename_all = "snake_case")]
102pub enum FitDisposition {
103    AdvisoryFitOnly,
104    PromotionBlockedMissingRefuter,
105    PromotionBlockedFailingRefuter,
106    PromotionBlockedStabilityRisk,
107    EligibleForLocalReview,
108}
109
110#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
111pub struct FitRunV1 {
112    pub schema_version: String,
113    pub fit_run_id: FitRunId,
114    pub mechanism_bundle_id: MechanismBundleId,
115    pub theory_version_id: TheoryVersionId,
116    pub simulation_contract_id: SimulationContractId,
117    pub fit_score: f64,
118    pub disposition: FitDisposition,
119    pub advisory_only: bool,
120    pub degraded: bool,
121    pub refuter_ready: bool,
122    pub stability_clear: bool,
123    pub theory_refuter_suite_id: TheoryRefuterSuiteId,
124    pub rollout_stability_report_id: RolloutStabilityReportId,
125    #[serde(default)]
126    pub notes: Vec<String>,
127    pub generated_at: String,
128}
129
130#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
131pub struct TheoryRefuterSuiteV1 {
132    pub schema_version: String,
133    pub theory_refuter_suite_id: TheoryRefuterSuiteId,
134    pub theory_version_id: TheoryVersionId,
135    #[serde(default)]
136    pub required_refuters: Vec<String>,
137    #[serde(default)]
138    pub available_refuters: Vec<String>,
139    #[serde(default)]
140    pub failing_refuters: Vec<String>,
141    pub horizon_only: bool,
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
145pub struct RolloutStabilityReportV1 {
146    pub schema_version: String,
147    pub rollout_stability_report_id: RolloutStabilityReportId,
148    pub theory_version_id: TheoryVersionId,
149    pub invariance_summary: String,
150    pub advisory_only: bool,
151    pub locally_reviewable: bool,
152    #[serde(default)]
153    pub blocking_findings: Vec<String>,
154}
155
156pub fn evaluate_fit_run(
157    mechanism: &MechanismBundleV1,
158    theory: &TheoryVersionV1,
159    contract: &SimulationContractV1,
160    refuter_suite: &TheoryRefuterSuiteV1,
161    stability_report: &RolloutStabilityReportV1,
162    fit_score: f64,
163    generated_at: impl Into<String>,
164) -> FitRunV1 {
165    let missing_required_refuters = refuter_suite
166        .required_refuters
167        .iter()
168        .filter(|required| !refuter_suite.available_refuters.contains(required))
169        .cloned()
170        .collect::<Vec<_>>();
171    let refuter_ready = missing_required_refuters.is_empty()
172        && refuter_suite.failing_refuters.is_empty()
173        && !refuter_suite.horizon_only;
174    let stability_clear = !stability_report.advisory_only
175        && stability_report.locally_reviewable
176        && stability_report.blocking_findings.is_empty();
177
178    let disposition = if !refuter_ready && !refuter_suite.failing_refuters.is_empty() {
179        FitDisposition::PromotionBlockedFailingRefuter
180    } else if !refuter_ready {
181        FitDisposition::PromotionBlockedMissingRefuter
182    } else if !stability_clear {
183        FitDisposition::PromotionBlockedStabilityRisk
184    } else if fit_score >= 0.8 && !theory.advisory_only && !contract.advisory_only {
185        FitDisposition::EligibleForLocalReview
186    } else {
187        FitDisposition::AdvisoryFitOnly
188    };
189
190    let mut notes = Vec::new();
191    if !missing_required_refuters.is_empty() {
192        notes.push(format!(
193            "missing required refuters: {}",
194            missing_required_refuters.join(", ")
195        ));
196    }
197    if !refuter_suite.failing_refuters.is_empty() {
198        notes.push(format!(
199            "failing refuters remain visible: {}",
200            refuter_suite.failing_refuters.join(", ")
201        ));
202    }
203    if !stability_report.blocking_findings.is_empty() {
204        notes.push(format!(
205            "stability blockers: {}",
206            stability_report.blocking_findings.join(", ")
207        ));
208    }
209    if matches!(disposition, FitDisposition::EligibleForLocalReview) {
210        notes
211            .push("fit run is eligible for local review only; no authority is created here".into());
212    } else if notes.is_empty() {
213        notes.push("fit run remains advisory until typed refuter and stability gates clear".into());
214    }
215
216    FitRunV1 {
217        schema_version: FIT_RUN_V1_SCHEMA.into(),
218        fit_run_id: FitRunId::generate(),
219        mechanism_bundle_id: mechanism.mechanism_bundle_id.clone(),
220        theory_version_id: theory.theory_version_id.clone(),
221        simulation_contract_id: contract.simulation_contract_id.clone(),
222        fit_score,
223        disposition,
224        advisory_only: disposition != FitDisposition::EligibleForLocalReview,
225        degraded: disposition != FitDisposition::EligibleForLocalReview,
226        refuter_ready,
227        stability_clear,
228        theory_refuter_suite_id: refuter_suite.theory_refuter_suite_id.clone(),
229        rollout_stability_report_id: stability_report.rollout_stability_report_id.clone(),
230        notes,
231        generated_at: generated_at.into(),
232    }
233}