affidavit 26.6.22

Provenance Layer — receipt assembly and certification (verify a witness against a format standard; never decide honesty).
// Reference witness: OCPQ query-scope kinds and pm4py interop shapes/filters are
// constructed as exhaustive censuses (COVERAGE.md §2 — OCPQ + pm4py interop
// vocabulary).
//
//   • OcpqScopeKind — the object-centric process query scope kinds.
//   • Pm4pyShape    — the pm4py artifact shapes the interop grammar recognises.
//   • FilterShape   — the pm4py filter dimensions.

use wasm4pm_compat::interop::{FilterShape as F, Pm4pyShape as S};
use wasm4pm_compat::ocpq::OcpqScopeKind as Scope;

#[test]
fn ocpq_scope_kinds_are_constructed() {
    let all = [Scope::Open, Scope::Closed, Scope::SingleType];
    // No-wildcard binding-strategy category: a new OcpqScopeKind variant breaks
    // compilation here (exhaustive match, no `_` arm).
    fn category(s: Scope) -> &'static str {
        match s {
            Scope::Open => "unbounded",
            Scope::Closed => "declared-set",
            Scope::SingleType => "singleton",
        }
    }
    let cats: std::collections::BTreeSet<&str> = all.iter().copied().map(category).collect();
    assert_eq!(cats.len(), 3, "three OCPQ scope binding strategies");
}

#[test]
fn pm4py_shapes_are_constructed() {
    let all = [
        S::EventLog,
        S::ObjectCentricLog,
        S::PetriNet,
        S::ProcessTree,
        S::Bpmn,
        S::DirectlyFollowsGraph,
        S::Declare,
    ];
    // Route through the real `tag()` method — genuinely exercised, not tautological.
    assert!(
        all.iter().all(|s| !s.tag().is_empty()),
        "every shape has a non-empty tag"
    );
    assert_eq!(
        S::ObjectCentricLog.tag(),
        "ocel",
        "object-centric-log tag anchor"
    );
    let tags: std::collections::BTreeSet<&str> = all.iter().map(|s| s.tag()).collect();
    assert_eq!(tags.len(), 7, "seven distinct pm4py shape tags");
    // The object-centric shapes are distinguished from flat ones (the interop
    // grammar's convergence/divergence guard depends on this classification).
    assert!(S::ObjectCentricLog.is_object_centric());
    assert!(!S::EventLog.is_object_centric());
}

#[test]
fn pm4py_filter_shapes_are_constructed() {
    // NOTE: FilterShape is `#[non_exhaustive]` — the crate reserves the right to
    // add dimensions, so this census covers the 5 CURRENTLY-KNOWN variants, not a
    // closed set (the wildcard below is required by non_exhaustive, and is an
    // honest acknowledgement that completeness here is open, not compile-proven).
    let all = [
        F::Activity,
        F::Timeframe,
        F::Variant,
        F::Attribute,
        F::ObjectType,
    ];
    fn label(f: F) -> &'static str {
        match f {
            F::Activity => "activity",
            F::Timeframe => "timeframe",
            F::Variant => "variant",
            F::Attribute => "attribute",
            F::ObjectType => "object-type",
            _ => "unknown-future-dimension",
        }
    }
    let s: std::collections::BTreeSet<&str> = all.iter().copied().map(label).collect();
    assert_eq!(s.len(), 5, "five currently-known pm4py filter dimensions");
}