mirror of
https://github.com/instructkr/claude-code.git
synced 2026-05-14 09:56:44 +00:00
omx(team): auto-checkpoint worker-1 [1]
This commit is contained in:
@@ -449,18 +449,19 @@ pub fn compute_event_fingerprint(
|
||||
status: &LaneEventStatus,
|
||||
data: Option<&serde_json::Value>,
|
||||
) -> String {
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
format!("{event:?}").hash(&mut hasher);
|
||||
format!("{status:?}").hash(&mut hasher);
|
||||
if let Some(d) = data {
|
||||
serde_json::to_string(d)
|
||||
.unwrap_or_default()
|
||||
.hash(&mut hasher);
|
||||
}
|
||||
format!("{:016x}", hasher.finish())
|
||||
let payload = serde_json::json!({
|
||||
"event": event,
|
||||
"status": status,
|
||||
"data": data,
|
||||
});
|
||||
let canonical = serde_json::to_vec(&payload).unwrap_or_default();
|
||||
let digest = Sha256::digest(canonical);
|
||||
digest[..8]
|
||||
.iter()
|
||||
.map(|byte| format!("{byte:02x}"))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Classification of event terminality for reconciliation.
|
||||
@@ -1045,6 +1046,7 @@ impl LaneEvent {
|
||||
emitted_at,
|
||||
)
|
||||
.with_optional_detail(detail)
|
||||
.with_terminal_fingerprint()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -1098,7 +1100,7 @@ impl LaneEvent {
|
||||
event =
|
||||
event.with_data(serde_json::to_value(subphase).expect("subphase should serialize"));
|
||||
}
|
||||
event
|
||||
event.with_terminal_fingerprint()
|
||||
}
|
||||
|
||||
/// Ship prepared — §4.44.5
|
||||
@@ -1170,6 +1172,21 @@ impl LaneEvent {
|
||||
#[must_use]
|
||||
pub fn with_data(mut self, data: Value) -> Self {
|
||||
self.data = Some(data);
|
||||
if is_terminal_event(self.event) {
|
||||
self = self.with_terminal_fingerprint();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn with_terminal_fingerprint(mut self) -> Self {
|
||||
if is_terminal_event(self.event) {
|
||||
self.metadata.event_fingerprint = Some(compute_event_fingerprint(
|
||||
&self.event,
|
||||
&self.status,
|
||||
self.data.as_ref(),
|
||||
));
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -1375,6 +1392,39 @@ mod tests {
|
||||
assert_eq!(round_trip.event, LaneEventName::ShipPushedMain);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convenience_terminal_events_attach_and_refresh_fingerprints() {
|
||||
let finished = LaneEvent::finished("2026-04-04T00:00:00Z", Some("done".to_string()));
|
||||
let initial_fingerprint = finished
|
||||
.metadata
|
||||
.event_fingerprint
|
||||
.clone()
|
||||
.expect("finished events should carry terminal fingerprint");
|
||||
|
||||
let with_payload = finished.with_data(json!({"result": "ok", "attempt": 1}));
|
||||
assert!(with_payload.metadata.event_fingerprint.is_some());
|
||||
assert_ne!(
|
||||
Some(initial_fingerprint),
|
||||
with_payload.metadata.event_fingerprint,
|
||||
"payload changes must refresh the actionable terminal fingerprint"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tool_style_finished_events_dedupe_after_payload_is_added() {
|
||||
let first = LaneEvent::finished("2026-04-04T00:00:00Z", Some("done".to_string()))
|
||||
.with_data(json!({"result": "ok"}));
|
||||
let duplicate = LaneEvent::finished("2026-04-04T00:00:01Z", Some("done again".to_string()))
|
||||
.with_data(json!({"result": "ok"}));
|
||||
|
||||
assert_eq!(
|
||||
first.metadata.event_fingerprint,
|
||||
duplicate.metadata.event_fingerprint
|
||||
);
|
||||
let deduped = dedupe_terminal_events(&[first, duplicate]);
|
||||
assert_eq!(deduped.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commit_events_can_carry_worktree_and_supersession_metadata() {
|
||||
let event = LaneEvent::commit_created(
|
||||
|
||||
Reference in New Issue
Block a user