Accept legacy review return events
This commit is contained in:
@@ -775,6 +775,10 @@ fn hydrate_session(
|
|||||||
record.sequence
|
record.sequence
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
let legacy_unlinked_review_return = record.commitment_id.is_none()
|
||||||
|
&& !review_completed
|
||||||
|
&& commitment.state == CommitmentState::Active;
|
||||||
|
if !legacy_unlinked_review_return {
|
||||||
ensure_record_commitment(&record, &commitment.id)?;
|
ensure_record_commitment(&record, &commitment.id)?;
|
||||||
if !review_completed {
|
if !review_completed {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
@@ -789,6 +793,7 @@ fn hydrate_session(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2318,6 +2323,85 @@ mod tests {
|
|||||||
fs::remove_file(path).unwrap();
|
fs::remove_file(path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn replay_accepts_legacy_unlinked_review_to_planning() {
|
||||||
|
let path = temp_log_path("legacy-review-return");
|
||||||
|
let first_commitment_id = "commitment-legacy-first";
|
||||||
|
let second_commitment_id = "commitment-legacy-second";
|
||||||
|
{
|
||||||
|
let mut log = EventLog::open(&path).unwrap();
|
||||||
|
log.append_batch([
|
||||||
|
PendingEventRecord {
|
||||||
|
event_type: EventType::RuntimeTransition,
|
||||||
|
runtime_state: RuntimeState::Planning,
|
||||||
|
commitment_id: None,
|
||||||
|
payload_json: json!({
|
||||||
|
"schema_version": POLICY_SCHEMA_VERSION,
|
||||||
|
"action": "enter_planning",
|
||||||
|
"from": "locked",
|
||||||
|
"to": "planning",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
PendingEventRecord {
|
||||||
|
event_type: EventType::CommitmentCreated,
|
||||||
|
runtime_state: RuntimeState::Active,
|
||||||
|
commitment_id: Some(first_commitment_id.to_string()),
|
||||||
|
payload_json: commitment_payload(first_commitment_id, CommitmentState::Active),
|
||||||
|
},
|
||||||
|
PendingEventRecord {
|
||||||
|
event_type: EventType::PolicyApplied,
|
||||||
|
runtime_state: RuntimeState::Active,
|
||||||
|
commitment_id: Some(first_commitment_id.to_string()),
|
||||||
|
payload_json: policy_payload(first_commitment_id),
|
||||||
|
},
|
||||||
|
PendingEventRecord {
|
||||||
|
event_type: EventType::RuntimeTransition,
|
||||||
|
runtime_state: RuntimeState::Review,
|
||||||
|
commitment_id: Some(first_commitment_id.to_string()),
|
||||||
|
payload_json: json!({
|
||||||
|
"schema_version": POLICY_SCHEMA_VERSION,
|
||||||
|
"action": "complete_for_review",
|
||||||
|
"from": "active",
|
||||||
|
"to": "review",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
PendingEventRecord {
|
||||||
|
event_type: EventType::RuntimeTransition,
|
||||||
|
runtime_state: RuntimeState::Planning,
|
||||||
|
commitment_id: None,
|
||||||
|
payload_json: json!({
|
||||||
|
"schema_version": POLICY_SCHEMA_VERSION,
|
||||||
|
"action": "return_to_planning_after_review",
|
||||||
|
"from": "review",
|
||||||
|
"to": "planning",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
PendingEventRecord {
|
||||||
|
event_type: EventType::CommitmentCreated,
|
||||||
|
runtime_state: RuntimeState::Active,
|
||||||
|
commitment_id: Some(second_commitment_id.to_string()),
|
||||||
|
payload_json: commitment_payload(second_commitment_id, CommitmentState::Active),
|
||||||
|
},
|
||||||
|
PendingEventRecord {
|
||||||
|
event_type: EventType::PolicyApplied,
|
||||||
|
runtime_state: RuntimeState::Active,
|
||||||
|
commitment_id: Some(second_commitment_id.to_string()),
|
||||||
|
payload_json: policy_payload(second_commitment_id),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let reopened = SessionController::new(&path).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(reopened.runtime_state(), RuntimeState::Active);
|
||||||
|
assert_eq!(
|
||||||
|
reopened.active_commitment().unwrap().id,
|
||||||
|
second_commitment_id
|
||||||
|
);
|
||||||
|
fs::remove_file(path).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn replay_tolerates_review_completed_without_changing_runtime() {
|
fn replay_tolerates_review_completed_without_changing_runtime() {
|
||||||
let path = temp_log_path("review-completed-no-transition");
|
let path = temp_log_path("review-completed-no-transition");
|
||||||
|
|||||||
Reference in New Issue
Block a user