//! Outputs an op produces — effects materialised in the substrate and
//! payload bytes that feed the witness signature.

use serde::{Deserialize, Serialize};

/// Single effect record — what the op asserts about authoritative state.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EffectRecord {
    /// Effect kind tag (`"Insert"`, `"Update"`, `"Delete"`).
    pub kind: String,
    /// Entity the effect targets.
    pub entity: String,
    /// Attribute names mutated.
    pub attrs: Vec<String>,
    /// FSM dimensions touched (empty for non-FSM effects).
    pub dimensions: Vec<String>,
}

/// Value the op body returns. Pure-data — no references to the runtime
/// context survive past the pipeline.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OpOutput {
    /// Effects to fold into the substrate AFTER the body returns.
    pub effects: Vec<EffectRecord>,
    /// Bytes to mix into the witness payload alongside `state_root`.
    /// Typically the canonical encoding of the op's body or a digest
    /// thereof; for noop ops this is empty.
    pub witness_payload: Vec<u8>,
}
