1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#![cfg(feature = "discovery")]
// THE WORKED WHOLE (COVERAGE.md §1/§6): the discover-then-conform collapse,
// witnessed as a real type-gated transition — NOT prose.
//
// Contribution claim (van der Aalst's terms): classical conformance is two
// artifacts — mine a model (discovery), then replay the log against it
// (conformance). Here the event log and the conformance certificate are the SAME
// object, because admission (the conformance gate) and the receipt (the log) are
// one type-enforced transition (Shape B). This file proves the fusion is real:
//
// emit events → admit() [OCEL court + chain/continuity certify] → AdmittedReceipt
// │
// discover_from_admitted(&AdmittedReceipt) ──────────┘
//
// `discover_from_admitted` takes `&AdmittedReceipt`. The ONLY constructor of
// AdmittedReceipt is `admission::admit`, which runs both courts. So discovery is
// COMPILE-TIME GATED on admission: a receipt that did not pass conformance has no
// path to discovery. The receipt mined IS the certificate that proved conformance.
//
// Failing-when-fake: if admit() were a fiat cast (T-1), a forged receipt would
// reach AdmittedReceipt and then discovery — but the forged-receipt test below
// proves it is REFUSED and never yields an AdmittedReceipt to mine.
use affidavit::admission::admit;
use affidavit::chain::{recompute_chain, ChainAssembler, FORMAT_VERSION};
use affidavit::discovery::discover_from_admitted;
use affidavit::ocel::{build_event, object_ref, SeqCounter};
use affidavit::types::{Blake3Hash, OperationEvent, Receipt};
fn honest_receipt(activities: &[&str]) -> Receipt {
let mut asm = ChainAssembler::new();
let mut counter = SeqCounter::new();
for a in activities {
let ev = build_event(
*a,
vec![object_ref("o", "artifact")],
a.as_bytes(),
&mut counter,
)
.expect("build event");
asm.append(ev).expect("append");
}
asm.finalize()
}
#[test]
fn the_admitted_receipt_is_both_log_and_certificate() {
// 1. Build + admit: the receipt passes the OCEL court AND the chain/continuity
// certify pipeline, yielding an AdmittedReceipt (the certificate).
let receipt = honest_receipt(&["create", "transform", "release"]);
let admitted = admit(receipt).expect("honest receipt is admitted by both courts");
// 2. Discover FROM the admitted value: the SAME object that proved conformance
// is now mined as the event log. One artifact, both roles (Shape B).
let model = discover_from_admitted(&admitted);
// The discovered model reflects the receipt's events — discovery really ran on
// the certificate, not on a placeholder.
assert!(
model.contains("create"),
"model mined from the certificate names its activities: {model}"
);
assert!(
model.contains("release"),
"model mined from the certificate names its activities: {model}"
);
}
#[test]
fn discovery_is_type_gated_on_admission_a_forgery_never_reaches_it() {
// A chain-consistent but structurally-forged receipt (seq starts at 5).
let forged_event = OperationEvent {
id: "evt-5".to_string(),
seq: 5, // continuity violation
event_type: "create".to_string(),
objects: vec![object_ref("o", "artifact")],
payload_commitment: Blake3Hash::from_bytes(b"x"),
};
let chain_hash = recompute_chain(std::slice::from_ref(&forged_event)).expect("chain");
// External crates cannot call Receipt::sealed (crate-private). Reach a Receipt
// through the deserialize path, exactly as a real attacker's file would — the
// chain_hash matches, so it survives deserialization but is structurally forged.
let forged: Receipt = serde_json::from_value(serde_json::json!({
"format_version": FORMAT_VERSION,
"events": [forged_event],
"chain_hash": chain_hash,
}))
.expect("chain-consistent receipt deserializes");
// admit() REFUSES it — so there is NO AdmittedReceipt to hand to discovery.
// discover_from_admitted CANNOT be called on `forged`: it does not type-check
// (forged is a Receipt, not an AdmittedReceipt). The refusal is the proof the
// gate is real and not a fiat cast.
let result = admit(forged);
assert!(
result.is_err(),
"a forged receipt must be refused — there is no admitted value for discovery to consume"
);
// (Statically: `discover_from_admitted(&forged)` would be a compile error —
// `&Receipt` is not `&AdmittedReceipt`. Admission is a type precondition.)
}