KeiSeiKit-1.0/_primitives/_rust/kei-replay/src/diff.rs
Parfii-bot 0be354a920 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

73 lines
2.4 KiB
Rust

//! Diff — compare two DNAs facet-by-facet.
//!
//! Pure parser + comparator. No I/O, no ledger lookup. Callers that want
//! the composed-body text diff can run `replay` on each DNA first and diff
//! the resulting `composed_prompt` themselves.
use anyhow::{anyhow, Result};
use kei_agent_runtime::dna::Dna;
/// Diff report between two DNA strings.
#[derive(Debug, Clone)]
pub struct DnaDiff {
pub left: Dna,
pub right: Dna,
pub role_changed: bool,
pub caps_changed: bool,
pub scope_changed: bool,
pub body_changed: bool,
pub nonce_changed: bool,
}
impl DnaDiff {
/// `true` when every facet is identical (same composition, same nonce).
pub fn is_identical(&self) -> bool {
!(self.role_changed
|| self.caps_changed
|| self.scope_changed
|| self.body_changed
|| self.nonce_changed)
}
/// `true` when the two DNAs would re-compose to the same prompt body
/// (nonce difference allowed — nonces are per-invocation salt).
pub fn is_same_composition(&self) -> bool {
!(self.role_changed || self.caps_changed || self.scope_changed || self.body_changed)
}
/// Human-readable multi-line report.
pub fn render(&self) -> String {
let mut out = Vec::with_capacity(7);
out.push(format!("left : {}", self.left.render()));
out.push(format!("right: {}", self.right.render()));
out.push(format!("role : {}", flag(self.role_changed)));
out.push(format!("caps : {}", flag(self.caps_changed)));
out.push(format!("scope : {}", flag(self.scope_changed)));
out.push(format!("body : {}", flag(self.body_changed)));
out.push(format!("nonce : {}", flag(self.nonce_changed)));
out.join("\n")
}
}
fn flag(changed: bool) -> &'static str {
if changed {
"CHANGED"
} else {
"same"
}
}
/// Parse both DNAs and emit the facet-level diff.
pub fn diff(left: &str, right: &str) -> Result<DnaDiff> {
let l = Dna::parse(left).map_err(|e| anyhow!("invalid left DNA: {e}"))?;
let r = Dna::parse(right).map_err(|e| anyhow!("invalid right DNA: {e}"))?;
Ok(DnaDiff {
role_changed: l.role != r.role,
caps_changed: l.caps_bitmap != r.caps_bitmap,
scope_changed: l.scope_hash != r.scope_hash,
body_changed: l.body_hash != r.body_hash,
nonce_changed: l.nonce != r.nonce,
left: l,
right: r,
})
}