//! The stable identity of an action a repeated failure is grouped under (G09).
//!
//! Grouping is by what the action *is* - operation, component revision, signature, workspace - so
//! two failures that share a cause share an identity, and the identity does not move when unrelated
//! fields of an observation do.
use sha2::{Digest, Sha256};
/// Generates a stable deterministic action identity from grouping keys.
#[must_use]
pub fn compute_action_identity(
operation: &str,
component_revision: &str,
signature: &str,
workspace: &str,
) -> String {
let mut hasher = Sha256::new();
// The operation is case-folded, the rest are not: this is the identity the durable records
// already carry, so the field forms are fixed.
let fields = [
operation.trim().to_lowercase(),
component_revision.trim().to_string(),
signature.trim().to_string(),
workspace.trim().to_string(),
];
for field in &fields {
let bytes = field.as_bytes();
hasher.update(format!("{}:", bytes.len()).as_bytes());
hasher.update(bytes);
hasher.update(b"\n");
}
format!("act-{}", hex::encode(&hasher.finalize()[..8]))
}