Skip to main content

vyre_conform/pipeline/certify/
accessors.rs

1//! Read-only accessors for sealed conformance certificate types.
2
3use std::collections::BTreeMap;
4
5use super::{
6    Certificate, CertificateLevels, CertificateStrength, ConformanceLevel, CoverageMetrics,
7    EngineResult, EngineStatus, OpOutcome, OpResult, TrackReport, Violation,
8};
9use crate::spec::law::LawViolation;
10use crate::spec::types::ParityFailure;
11
12impl Violation {
13    /// Create a structured conformance violation.
14    #[must_use]
15    #[inline]
16    pub(crate) fn new(
17        op_id: String,
18        law: String,
19        backend: String,
20        reference_output: Vec<u8>,
21        backend_output: Vec<u8>,
22        message: String,
23    ) -> Self {
24        Self {
25            op_id,
26            law,
27            backend,
28            reference_output,
29            backend_output,
30            message,
31        }
32    }
33
34    /// Operation identifier being certified when the violation occurred.
35    #[must_use]
36    #[inline]
37    pub fn op_id(&self) -> &str {
38        &self.op_id
39    }
40
41    /// Algebraic law or conformance rule that was violated.
42    #[must_use]
43    #[inline]
44    pub fn law(&self) -> &str {
45        &self.law
46    }
47
48    /// Backend identifier that produced the violating output.
49    #[must_use]
50    #[inline]
51    pub fn backend(&self) -> &str {
52        &self.backend
53    }
54
55    /// CPU reference bytes for the failing case.
56    #[must_use]
57    #[inline]
58    pub fn reference_output(&self) -> &[u8] {
59        &self.reference_output
60    }
61
62    /// Backend output bytes for the failing case.
63    #[must_use]
64    #[inline]
65    pub fn backend_output(&self) -> &[u8] {
66        &self.backend_output
67    }
68
69    /// Actionable remediation message.
70    #[must_use]
71    #[inline]
72    pub fn message(&self) -> &str {
73        &self.message
74    }
75}
76
77impl Certificate {
78    #[must_use]
79    #[inline]
80    pub(crate) fn new(
81        backend_name: String,
82        backend_version: String,
83        spec_version: u32,
84        level: CertificateLevels,
85        timestamp: String,
86        monotonic_sequence: u64,
87        strength: CertificateStrength,
88        witness_count: u64,
89        witness_count_by_op: BTreeMap<String, u64>,
90        proof_status: String,
91        integer_track: TrackReport,
92        float_track: Option<TrackReport>,
93        approximate_track: Option<TrackReport>,
94        ops: Vec<OpResult>,
95        unsupported_ops: Vec<String>,
96        engines: Vec<EngineResult>,
97        registry_hash: [u8; 32],
98        coverage: CoverageMetrics,
99    ) -> Self {
100        let certificate_hash = certificate_hash_for(
101            &backend_name,
102            &backend_version,
103            spec_version,
104            &timestamp,
105            monotonic_sequence,
106            &registry_hash,
107        );
108        Self {
109            backend_name,
110            backend_version,
111            spec_version,
112            level,
113            timestamp,
114            monotonic_sequence,
115            certificate_hash,
116            strength,
117            witness_count,
118            witness_count_by_op,
119            proof_status,
120            integer_track,
121            float_track,
122            approximate_track,
123            ops,
124            unsupported_ops,
125            engines,
126            registry_hash,
127            coverage,
128        }
129    }
130
131    /// Stable certificate identifier.
132    #[must_use]
133    #[inline]
134    pub fn id(&self) -> &[u8; 32] {
135        &self.certificate_hash
136    }
137
138    /// Backend identifier that produced this certificate.
139    #[must_use]
140    #[inline]
141    pub fn backend_id(&self) -> &str {
142        &self.backend_name
143    }
144
145    /// Spec registry hash covered by this certificate.
146    #[must_use]
147    #[inline]
148    pub fn spec_hash(&self) -> &[u8; 32] {
149        &self.registry_hash
150    }
151
152    /// Deterministic certificate digest.
153    #[must_use]
154    #[inline]
155    pub fn cert_hash(&self) -> &[u8; 32] {
156        &self.certificate_hash
157    }
158
159    /// Backend implementation name that produced this certificate.
160    #[must_use]
161    #[inline]
162    pub fn backend_name(&self) -> &str {
163        &self.backend_name
164    }
165
166    /// Backend implementation version that produced this certificate.
167    #[must_use]
168    #[inline]
169    pub fn backend_version(&self) -> &str {
170        &self.backend_version
171    }
172
173    /// Highest operation spec version included in this certificate run.
174    #[must_use]
175    #[inline]
176    pub fn spec_version(&self) -> u32 {
177        self.spec_version
178    }
179
180    /// Claimed conformance levels after all operation, law, and engine gates.
181    #[must_use]
182    #[inline]
183    pub fn level(&self) -> CertificateLevels {
184        self.level
185    }
186
187    /// UTC issuance timestamp for this certificate.
188    #[must_use]
189    #[inline]
190    pub fn timestamp(&self) -> &str {
191        &self.timestamp
192    }
193
194    /// Process-local monotonic issuance sequence.
195    #[must_use]
196    #[inline]
197    pub fn monotonic_sequence(&self) -> u64 {
198        self.monotonic_sequence
199    }
200
201    /// Deterministic certificate digest.
202    #[must_use]
203    #[inline]
204    pub fn certificate_hash(&self) -> &[u8; 32] {
205        &self.certificate_hash
206    }
207
208    /// Requested certificate strength for this run.
209    #[must_use]
210    #[inline]
211    pub fn strength(&self) -> CertificateStrength {
212        self.strength
213    }
214
215    /// Declared witness budget for the requested certificate strength.
216    #[must_use]
217    #[inline]
218    pub fn witness_count(&self) -> u64 {
219        self.witness_count
220    }
221
222    /// Actual per-operation law witness counts retained in the certificate.
223    #[must_use]
224    #[inline]
225    pub fn witness_count_by_op(&self) -> &BTreeMap<String, u64> {
226        &self.witness_count_by_op
227    }
228
229    /// Human-readable proof status derived from the certificate strength.
230    #[must_use]
231    #[inline]
232    pub fn proof_status(&self) -> &str {
233        &self.proof_status
234    }
235
236    /// Integer-track certification report.
237    #[must_use]
238    #[inline]
239    pub fn integer_track(&self) -> &TrackReport {
240        &self.integer_track
241    }
242
243    /// Float-track certification report when float operations were present.
244    #[must_use]
245    #[inline]
246    pub fn float_track(&self) -> &Option<TrackReport> {
247        &self.float_track
248    }
249
250    /// Approximate-track certification report when approximate operations were present.
251    #[must_use]
252    #[inline]
253    pub fn approximate_track(&self) -> &Option<TrackReport> {
254        &self.approximate_track
255    }
256
257    /// Per-operation certification results.
258    #[must_use]
259    #[inline]
260    pub fn ops(&self) -> &[OpResult] {
261        &self.ops
262    }
263
264    /// Operation identifiers that the backend explicitly reported unsupported.
265    #[must_use]
266    #[inline]
267    pub fn unsupported_ops(&self) -> &[String] {
268        &self.unsupported_ops
269    }
270
271    /// Engine invariant harness results that gate claimed certificate levels.
272    #[must_use]
273    #[inline]
274    pub fn engines(&self) -> &[EngineResult] {
275        &self.engines
276    }
277
278    /// Blake3 registry fingerprint for the exact certified operation specs.
279    #[must_use]
280    #[inline]
281    pub fn registry_hash(&self) -> &[u8; 32] {
282        &self.registry_hash
283    }
284
285    /// Aggregate operation and law coverage metrics.
286    #[must_use]
287    #[inline]
288    pub fn coverage(&self) -> &CoverageMetrics {
289        &self.coverage
290    }
291}
292
293impl OpResult {
294    /// Operation identifier for this result.
295    #[must_use]
296    #[inline]
297    pub fn id(&self) -> &str {
298        &self.id
299    }
300
301    /// Operation archetype used for track reporting.
302    #[must_use]
303    #[inline]
304    pub fn archetype(&self) -> &str {
305        &self.archetype
306    }
307
308    /// Final per-operation outcome.
309    #[must_use]
310    #[inline]
311    pub fn outcome(&self) -> OpOutcome {
312        self.outcome
313    }
314
315    /// Whether every generated parity case matched the CPU reference.
316    #[must_use]
317    #[inline]
318    pub fn parity_passed(&self) -> bool {
319        self.parity_passed
320    }
321
322    /// Declared laws verified with at least one executed case and no violation.
323    #[must_use]
324    #[inline]
325    pub fn laws_verified(&self) -> &[String] {
326        &self.laws_verified
327    }
328
329    /// Concrete law violations recorded for this operation.
330    #[must_use]
331    #[inline]
332    pub fn laws_failed(&self) -> &[LawViolation] {
333        &self.laws_failed
334    }
335
336    /// Retained parity failures for forensic replay.
337    #[must_use]
338    #[inline]
339    pub fn parity_failures(&self) -> &[ParityFailure] {
340        &self.parity_failures
341    }
342
343    /// Total parity and law cases evaluated for this operation.
344    #[must_use]
345    #[inline]
346    pub fn cases_tested(&self) -> u64 {
347        self.cases_tested
348    }
349
350    /// Actual law witness cases tested for this operation, capped by strength.
351    #[must_use]
352    #[inline]
353    pub fn witness_count(&self) -> u64 {
354        self.witness_count
355    }
356}
357
358impl TrackReport {
359    /// Claimed conformance level for this track, or none if any gate failed.
360    #[must_use]
361    #[inline]
362    pub fn level(&self) -> Option<ConformanceLevel> {
363        self.level
364    }
365
366    /// Operation results included in this track.
367    #[must_use]
368    #[inline]
369    pub fn ops(&self) -> &[OpResult] {
370        &self.ops
371    }
372
373    /// Unsupported operation identifiers included in this track.
374    #[must_use]
375    #[inline]
376    pub fn unsupported_ops(&self) -> &[String] {
377        &self.unsupported_ops
378    }
379
380    /// Track-local coverage metrics.
381    #[must_use]
382    #[inline]
383    pub fn coverage(&self) -> &CoverageMetrics {
384        &self.coverage
385    }
386}
387
388impl EngineResult {
389    /// Engine harness identifier.
390    #[must_use]
391    #[inline]
392    pub fn id(&self) -> &str {
393        &self.id
394    }
395
396    /// Aggregate pass/fail status for this engine harness.
397    #[must_use]
398    #[inline]
399    pub fn status(&self) -> EngineStatus {
400        self.status
401    }
402
403    /// Engine invariants verified by this harness.
404    #[must_use]
405    #[inline]
406    pub fn invariants_verified(&self) -> &[String] {
407        &self.invariants_verified
408    }
409
410    /// Engine invariant failure diagnostics.
411    #[must_use]
412    #[inline]
413    pub fn invariants_failed(&self) -> &[String] {
414        &self.invariants_failed
415    }
416
417    /// Number of invariant cases evaluated by this harness.
418    #[must_use]
419    #[inline]
420    pub fn cases_tested(&self) -> u64 {
421        self.cases_tested
422    }
423}
424
425fn certificate_hash_for(
426    backend_name: &str,
427    backend_version: &str,
428    spec_version: u32,
429    timestamp: &str,
430    monotonic_sequence: u64,
431    registry_hash: &[u8; 32],
432) -> [u8; 32] {
433    let mut hasher = blake3::Hasher::new();
434    hasher.update(b"vyre-conform.certificate.v1");
435    hash_bytes(&mut hasher, backend_name.as_bytes());
436    hash_bytes(&mut hasher, backend_version.as_bytes());
437    hasher.update(&spec_version.to_le_bytes());
438    hash_bytes(&mut hasher, timestamp.as_bytes());
439    hasher.update(&monotonic_sequence.to_le_bytes());
440    hasher.update(registry_hash);
441    *hasher.finalize().as_bytes()
442}
443
444fn hash_bytes(hasher: &mut blake3::Hasher, bytes: &[u8]) {
445    hasher.update(&(bytes.len() as u64).to_le_bytes());
446    hasher.update(bytes);
447}