From 5c40d4e778b31433f3e01e10d8d3a6b346653a3c Mon Sep 17 00:00:00 2001 From: bellman Date: Thu, 14 May 2026 18:26:49 +0900 Subject: [PATCH] omx(team): auto-checkpoint worker-3 [4] --- rust/crates/runtime/src/green_contract.rs | 254 +++++++++++++++++- rust/crates/runtime/src/policy_engine.rs | 49 +++- .../crates/runtime/tests/integration_tests.rs | 10 +- 3 files changed, 304 insertions(+), 9 deletions(-) diff --git a/rust/crates/runtime/src/green_contract.rs b/rust/crates/runtime/src/green_contract.rs index d65ce912..33cfd8c9 100644 --- a/rust/crates/runtime/src/green_contract.rs +++ b/rust/crates/runtime/src/green_contract.rs @@ -30,12 +30,33 @@ impl std::fmt::Display for GreenLevel { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct GreenContract { pub required_level: GreenLevel, + pub require_test_command_provenance: bool, + pub require_base_branch_freshness: bool, + pub require_recovery_attempt_context: bool, + pub block_known_flakes: bool, } impl GreenContract { #[must_use] pub fn new(required_level: GreenLevel) -> Self { - Self { required_level } + Self { + required_level, + require_test_command_provenance: false, + require_base_branch_freshness: false, + require_recovery_attempt_context: false, + block_known_flakes: false, + } + } + + #[must_use] + pub fn merge_ready(required_level: GreenLevel) -> Self { + Self { + required_level, + require_test_command_provenance: true, + require_base_branch_freshness: true, + require_recovery_attempt_context: true, + block_known_flakes: true, + } } #[must_use] @@ -52,12 +73,164 @@ impl GreenContract { } } + #[must_use] + pub fn evaluate_evidence(&self, evidence: &GreenEvidence) -> GreenEvidenceOutcome { + let mut missing = Vec::new(); + let mut blocking_flakes = Vec::new(); + + if evidence.observed_level < self.required_level { + missing.push(GreenContractRequirement::RequiredLevel); + } + + if self.require_test_command_provenance && !evidence.has_passing_test_command() { + missing.push(GreenContractRequirement::TestCommandProvenance); + } + + if self.require_base_branch_freshness && !evidence.base_branch_fresh { + missing.push(GreenContractRequirement::BaseBranchFreshness); + } + + if self.require_recovery_attempt_context && !evidence.recovery_attempt_context_recorded { + missing.push(GreenContractRequirement::RecoveryAttemptContext); + } + + if self.block_known_flakes { + blocking_flakes = evidence + .known_flakes + .iter() + .filter(|flake| flake.blocks_green) + .cloned() + .collect(); + } + + if missing.is_empty() && blocking_flakes.is_empty() { + GreenEvidenceOutcome::Satisfied { + required_level: self.required_level, + observed_level: evidence.observed_level, + } + } else { + GreenEvidenceOutcome::Unsatisfied { + required_level: self.required_level, + observed_level: evidence.observed_level, + missing, + blocking_flakes, + } + } + } + #[must_use] pub fn is_satisfied_by(self, observed_level: GreenLevel) -> bool { observed_level >= self.required_level } } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct GreenEvidence { + pub observed_level: GreenLevel, + pub test_commands: Vec, + pub base_branch_fresh: bool, + pub known_flakes: Vec, + pub recovery_attempt_context_recorded: bool, +} + +impl GreenEvidence { + #[must_use] + pub fn new(observed_level: GreenLevel) -> Self { + Self { + observed_level, + test_commands: Vec::new(), + base_branch_fresh: false, + known_flakes: Vec::new(), + recovery_attempt_context_recorded: false, + } + } + + #[must_use] + pub fn with_test_command(mut self, command: impl Into, exit_code: i32) -> Self { + self.test_commands.push(TestCommandProvenance { + command: command.into(), + exit_code, + }); + self + } + + #[must_use] + pub fn with_base_branch_fresh(mut self, is_fresh: bool) -> Self { + self.base_branch_fresh = is_fresh; + self + } + + #[must_use] + pub fn with_known_flake(mut self, test_name: impl Into, blocks_green: bool) -> Self { + self.known_flakes.push(KnownFlake { + test_name: test_name.into(), + blocks_green, + }); + self + } + + #[must_use] + pub fn with_recovery_attempt_context(mut self, recorded: bool) -> Self { + self.recovery_attempt_context_recorded = recorded; + self + } + + #[must_use] + pub fn has_passing_test_command(&self) -> bool { + self.test_commands.iter().any(TestCommandProvenance::passed) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct TestCommandProvenance { + pub command: String, + pub exit_code: i32, +} + +impl TestCommandProvenance { + #[must_use] + pub fn passed(&self) -> bool { + self.exit_code == 0 && !self.command.trim().is_empty() + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct KnownFlake { + pub test_name: String, + pub blocks_green: bool, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum GreenContractRequirement { + RequiredLevel, + TestCommandProvenance, + BaseBranchFreshness, + RecoveryAttemptContext, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "outcome", rename_all = "snake_case")] +pub enum GreenEvidenceOutcome { + Satisfied { + required_level: GreenLevel, + observed_level: GreenLevel, + }, + Unsatisfied { + required_level: GreenLevel, + observed_level: GreenLevel, + missing: Vec, + blocking_flakes: Vec, + }, +} + +impl GreenEvidenceOutcome { + #[must_use] + pub fn is_satisfied(&self) -> bool { + matches!(self, Self::Satisfied { .. }) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "outcome", rename_all = "snake_case")] pub enum GreenContractOutcome { @@ -149,4 +322,83 @@ mod tests { } ); } + #[test] + fn merge_ready_contract_requires_provenance_beyond_test_level() { + // given + let contract = GreenContract::merge_ready(GreenLevel::Workspace); + let evidence = GreenEvidence::new(GreenLevel::Workspace) + .with_test_command("cargo test --manifest-path rust/Cargo.toml", 0); + + // when + let outcome = contract.evaluate_evidence(&evidence); + + // then + assert_eq!( + outcome, + GreenEvidenceOutcome::Unsatisfied { + required_level: GreenLevel::Workspace, + observed_level: GreenLevel::Workspace, + missing: vec![ + GreenContractRequirement::BaseBranchFreshness, + GreenContractRequirement::RecoveryAttemptContext, + ], + blocking_flakes: vec![], + } + ); + assert!(!outcome.is_satisfied()); + } + + #[test] + fn merge_ready_contract_accepts_complete_test_provenance_context() { + // given + let contract = GreenContract::merge_ready(GreenLevel::Workspace); + let evidence = GreenEvidence::new(GreenLevel::MergeReady) + .with_test_command("cargo test --manifest-path rust/Cargo.toml", 0) + .with_base_branch_fresh(true) + .with_recovery_attempt_context(true); + + // when + let outcome = contract.evaluate_evidence(&evidence); + + // then + assert_eq!( + outcome, + GreenEvidenceOutcome::Satisfied { + required_level: GreenLevel::Workspace, + observed_level: GreenLevel::MergeReady, + } + ); + } + + #[test] + fn known_blocking_flake_prevents_green_contract_satisfaction() { + // given + let contract = GreenContract::merge_ready(GreenLevel::Workspace); + let evidence = GreenEvidence::new(GreenLevel::MergeReady) + .with_test_command("cargo test --manifest-path rust/Cargo.toml", 0) + .with_base_branch_fresh(true) + .with_recovery_attempt_context(true) + .with_known_flake( + "session_lifecycle_prefers_running_process_over_idle_shell", + true, + ); + + // when + let outcome = contract.evaluate_evidence(&evidence); + + // then + assert_eq!( + outcome, + GreenEvidenceOutcome::Unsatisfied { + required_level: GreenLevel::Workspace, + observed_level: GreenLevel::MergeReady, + missing: vec![], + blocking_flakes: vec![KnownFlake { + test_name: "session_lifecycle_prefers_running_process_over_idle_shell" + .to_string(), + blocks_green: true, + }], + } + ); + } } diff --git a/rust/crates/runtime/src/policy_engine.rs b/rust/crates/runtime/src/policy_engine.rs index 0403853c..f96c0feb 100644 --- a/rust/crates/runtime/src/policy_engine.rs +++ b/rust/crates/runtime/src/policy_engine.rs @@ -58,7 +58,9 @@ impl PolicyCondition { Self::Or(conditions) => conditions .iter() .any(|condition| condition.matches(context)), - Self::GreenAt { level } => context.green_level >= *level, + Self::GreenAt { level } => { + context.green_contract_satisfied && context.green_level >= *level + } Self::StaleBranch => context.branch_freshness >= STALE_BRANCH_THRESHOLD, Self::StartupBlocked => context.blocker == LaneBlocker::Startup, Self::LaneCompleted => context.completed, @@ -134,6 +136,7 @@ pub enum DiffScope { pub struct LaneContext { pub lane_id: String, pub green_level: GreenLevel, + pub green_contract_satisfied: bool, pub branch_freshness: Duration, pub blocker: LaneBlocker, pub review_status: ReviewStatus, @@ -156,6 +159,7 @@ impl LaneContext { Self { lane_id: lane_id.into(), green_level, + green_contract_satisfied: false, branch_freshness, blocker, review_status, @@ -171,6 +175,7 @@ impl LaneContext { Self { lane_id: lane_id.into(), green_level: 0, + green_contract_satisfied: false, branch_freshness: Duration::from_secs(0), blocker: LaneBlocker::None, review_status: ReviewStatus::Pending, @@ -179,6 +184,12 @@ impl LaneContext { reconciled: true, } } + + #[must_use] + pub fn with_green_contract_satisfied(mut self, satisfied: bool) -> Self { + self.green_contract_satisfied = satisfied; + self + } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -257,7 +268,8 @@ mod tests { ReviewStatus::Approved, DiffScope::Scoped, false, - ); + ) + .with_green_contract_satisfied(true); // when let actions = engine.evaluate(&context); @@ -266,6 +278,36 @@ mod tests { assert_eq!(actions, vec![PolicyAction::MergeToDev]); } + #[test] + fn merge_rule_blocks_when_green_tests_lack_contract_provenance() { + // given + let engine = PolicyEngine::new(vec![PolicyRule::new( + "merge-to-dev", + PolicyCondition::And(vec![ + PolicyCondition::GreenAt { level: 2 }, + PolicyCondition::ScopedDiff, + PolicyCondition::ReviewPassed, + ]), + PolicyAction::MergeToDev, + 20, + )]); + let context = LaneContext::new( + "lane-7", + 3, + Duration::from_secs(5), + LaneBlocker::None, + ReviewStatus::Approved, + DiffScope::Scoped, + false, + ); + + // when + let actions = engine.evaluate(&context); + + // then + assert!(actions.is_empty()); + } + #[test] fn stale_branch_rule_fires_at_threshold() { // given @@ -468,7 +510,8 @@ mod tests { ReviewStatus::Pending, DiffScope::Full, false, - ); + ) + .with_green_contract_satisfied(true); // when let actions = engine.evaluate(&context); diff --git a/rust/crates/runtime/tests/integration_tests.rs b/rust/crates/runtime/tests/integration_tests.rs index 0bf1442d..c92b3948 100644 --- a/rust/crates/runtime/tests/integration_tests.rs +++ b/rust/crates/runtime/tests/integration_tests.rs @@ -96,9 +96,7 @@ fn green_contract_unsatisfied_blocks_merge() { false, ); - // This is a conceptual test — we need a way to express "requires workspace green" - // Currently LaneContext has raw green_level: u8, not a contract - // For now we just verify the policy condition works + // The context has a test level but lacks the full green contract, so merge stays blocked. let engine = PolicyEngine::new(vec![PolicyRule::new( "workspace-green-required", PolicyCondition::GreenAt { level: 3 }, // GreenLevel::Workspace @@ -267,7 +265,8 @@ fn fresh_approved_lane_gets_merge_action() { ReviewStatus::Approved, DiffScope::Scoped, false, - ); + ) + .with_green_contract_satisfied(true); let engine = PolicyEngine::new(vec![PolicyRule::new( "merge-if-green-approved-not-stale", @@ -357,7 +356,8 @@ fn worker_provider_failure_flows_through_recovery_to_policy() { ReviewStatus::Approved, DiffScope::Scoped, false, - ); + ) + .with_green_contract_satisfied(true); let policy_engine = PolicyEngine::new(vec![ // Rule: if recovered from failure + green + approved -> merge