#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ProcessBoundaryKind {
EmitsEvents,
EmitsObjectRelations,
ImportsFormat,
ExportsFormat,
ClaimsConformance,
ClaimsReceipt,
ClaimsReplay,
ClaimsProcessMiningSupport,
}
impl ProcessBoundaryKind {
#[must_use]
pub const fn tag(self) -> &'static str {
match self {
ProcessBoundaryKind::EmitsEvents => "emits_events",
ProcessBoundaryKind::EmitsObjectRelations => "emits_object_relations",
ProcessBoundaryKind::ImportsFormat => "imports_format",
ProcessBoundaryKind::ExportsFormat => "exports_format",
ProcessBoundaryKind::ClaimsConformance => "claims_conformance",
ProcessBoundaryKind::ClaimsReceipt => "claims_receipt",
ProcessBoundaryKind::ClaimsReplay => "claims_replay",
ProcessBoundaryKind::ClaimsProcessMiningSupport => "claims_process_mining_support",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProcessBoundary {
pub kind: ProcessBoundaryKind,
pub name: String,
pub has_witness: bool,
pub has_round_trip_fixture: bool,
pub has_loss_policy: bool,
pub has_refusal_path: bool,
pub has_conformance_fields: bool,
pub has_receipt_shape: bool,
pub exports_raw_evidence: bool,
pub hidden_pm_growth: bool,
}
impl ProcessBoundary {
#[must_use]
pub fn fully_attested(kind: ProcessBoundaryKind, name: impl Into<String>) -> Self {
Self {
kind,
name: name.into(),
has_witness: true,
has_round_trip_fixture: true,
has_loss_policy: true,
has_refusal_path: true,
has_conformance_fields: true,
has_receipt_shape: true,
exports_raw_evidence: false,
hidden_pm_growth: false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum StrictViolation {
MissingWitness,
MissingRoundTripFixture,
MissingLossPolicy,
RawEvidenceExported,
MissingRefusalPath,
MissingConformanceFields,
MissingReceiptShape,
HiddenProcessMiningGrowth,
}
impl StrictViolation {
#[must_use]
pub const fn law(self) -> &'static str {
match self {
StrictViolation::MissingWitness => "MissingWitness",
StrictViolation::MissingRoundTripFixture => "MissingRoundTripFixture",
StrictViolation::MissingLossPolicy => "MissingLossPolicy",
StrictViolation::RawEvidenceExported => "RawEvidenceExported",
StrictViolation::MissingRefusalPath => "MissingRefusalPath",
StrictViolation::MissingConformanceFields => "MissingConformanceFields",
StrictViolation::MissingReceiptShape => "MissingReceiptShape",
StrictViolation::HiddenProcessMiningGrowth => "HiddenProcessMiningGrowth",
}
}
}
impl core::fmt::Display for StrictViolation {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "strict violation: {}", self.law())
}
}
pub trait StrictCheck {
fn check(&self) -> Result<(), Vec<StrictViolation>>;
}
impl StrictCheck for ProcessBoundary {
fn check(&self) -> Result<(), Vec<StrictViolation>> {
use ProcessBoundaryKind as K;
let mut v = Vec::new();
if self.hidden_pm_growth {
v.push(StrictViolation::HiddenProcessMiningGrowth);
}
if self.exports_raw_evidence {
v.push(StrictViolation::RawEvidenceExported);
}
let owes_witness = matches!(
self.kind,
K::EmitsEvents
| K::EmitsObjectRelations
| K::ImportsFormat
| K::ExportsFormat
| K::ClaimsReceipt
);
if owes_witness && !self.has_witness {
v.push(StrictViolation::MissingWitness);
}
if matches!(self.kind, K::ImportsFormat | K::ExportsFormat) && !self.has_round_trip_fixture
{
v.push(StrictViolation::MissingRoundTripFixture);
}
if matches!(self.kind, K::ExportsFormat) && !self.has_loss_policy {
v.push(StrictViolation::MissingLossPolicy);
}
if matches!(self.kind, K::ClaimsConformance) && !self.has_conformance_fields {
v.push(StrictViolation::MissingConformanceFields);
}
if matches!(self.kind, K::ClaimsReceipt) && !self.has_receipt_shape {
v.push(StrictViolation::MissingReceiptShape);
}
let owes_refusal = matches!(
self.kind,
K::ImportsFormat
| K::ExportsFormat
| K::ClaimsConformance
| K::ClaimsReceipt
| K::ClaimsReplay
| K::ClaimsProcessMiningSupport
);
if owes_refusal && !self.has_refusal_path {
v.push(StrictViolation::MissingRefusalPath);
}
if matches!(self.kind, K::ClaimsReplay | K::ClaimsProcessMiningSupport)
&& !self.hidden_pm_growth
{
v.push(StrictViolation::HiddenProcessMiningGrowth);
}
if v.is_empty() {
Ok(())
} else {
Err(v)
}
}
}