Skip to main content

u280_evidence_oracle/
sealed_result.rs

1//! Receipt-bound, typed revalidation of a completed Phase-B oracle result.
2
3use super::{
4    DEFAULT_KERNEL, MAXIMUM_BATCH, MAXIMUM_P95_CAPTURE_CYCLES_EXACT,
5    MINIMUM_SIGNATURES_PER_SECOND_EXACT, OracleOutcome, PERFORMANCE_CLOCK_BOUND_HZ,
6    PHASE_B_ORACLE_RECEIPT_SCHEMA, PHASE_B_TYPED_RESULT_CONTRACT, PHASE_B_TYPED_RESULT_SCHEMA,
7    PROFILE, REQUEST_KIND, REQUIRED_PERFORMANCE_BATCH, REQUIRED_PERFORMANCE_SAMPLES,
8    RESULT_EVIDENCE_BOUNDARY, RESULT_KIND, SUMMARY_BYTES, SampleSpec, SampleValidationState,
9    advance_reservation_chain, expected_layout, output_poison, validate_coordination_hardware,
10    validate_coordination_records, validate_hardware_identity, validate_reservation,
11    validate_results, validate_results_statistics, validate_run_metadata, validate_sample_contract,
12    validate_transport_contract,
13};
14use crate::archive::{
15    ArchiveSnapshot, FileRecord, StrictExternalFile, StrictResultFile, StrictResultSnapshot,
16    TypedTransportPolicy, is_lower_hex, open_strict_external_file, open_strict_typed_result,
17    open_verified_file_exact, read_verified_small_exact, sha256_bytes,
18    verify_transport_archive_again_exact, verify_typed_transport_archive,
19};
20use crate::model::{
21    OracleRequest, ReservationReceipt, ResultsEnvelope, RunMetadata, TransportContract,
22    parse_canonical_json, parse_strict_json,
23};
24use anyhow::{Context, Result, bail, ensure};
25use hashsigs_reference::{
26    FUSED_OUTPUT_BYTES, HashSigsSha256GenericV1, MessageDigest, PrivateSeed, SIGNATURE_BYTES,
27    Sha256GenericWots,
28};
29use serde::{Deserialize, Serialize};
30use sha2::{Digest as _, Sha256};
31use std::collections::{BTreeMap, BTreeSet, HashSet};
32use std::path::{Component, Path, PathBuf};
33
34const RECEIPT_KIND: &str = "hashsigs_phase_b_rust_oracle_receipt";
35const COMPLETED_RESULT_KIND: &str = "completed_comparison";
36const MAXIMUM_CREATION_RECEIPT_BYTES: usize = 64 * 1024;
37const MAXIMUM_RESULT_REQUESTS: usize = 8_192;
38const MAXIMUM_RESULT_JOBS: u64 = 1_048_576;
39const MAXIMUM_JOB_TRANSCRIPT_BYTES: u64 = 512 * 1024 * 1024;
40const JOB_READ_BUFFER_BYTES: usize = 64 * 1024;
41const MAXIMUM_JOB_LINE_BYTES: usize = 4 * 1024;
42const MINIMUM_JOB_LINE_BYTES: u64 = 256;
43const INPUT_BYTES_PER_JOB: u64 = 64;
44const OUTPUT_SLOT_BYTES: u64 = 4_096;
45const OUTPUT_VALID_BYTES: u64 = 2_208;
46const OUTPUT_VALID_BYTES_USIZE: usize = 2_208;
47const OUTPUT_SLOT_BYTES_USIZE: usize = 4_096;
48const OUTPUT_PADDING_BYTES: u64 = 1_888;
49const EXPECTED_PRODUCER: &str = "independent Rust Sha256GenericWots oracle";
50const EXPECTED_PINNED_COMMIT: &str = "2d315dd4168804b7cbc51c51a1bf7ca27bf74140";
51const TYPED_TRANSPORT_ROOT_BUDGET: u64 = 128 * 1024 * 1024;
52const TYPED_TRANSPORT_SAMPLE_METADATA_BUDGET: u64 = 512 * 1024;
53const TYPED_TRANSPORT_SAMPLE_JSON_BYTES: u64 = 1024 * 1024;
54const MAXIMUM_TYPED_PERFORMANCE_SAMPLES: usize = 1_000_000;
55
56#[derive(Debug, Eq, PartialEq)]
57struct VerifiedMarker;
58
59/// Descriptor-retained capture of the exact oracle creation receipt.
60///
61/// The capture is created only by [`open_verified_oracle_receipt_capture`]. It
62/// retains the absolute parent, basename, file descriptor, exact byte count,
63/// and SHA-256 so final result revalidation cannot silently substitute a
64/// caller-owned byte slice.
65///
66/// It cannot be constructed externally:
67///
68/// ```compile_fail
69/// use u280_evidence_oracle::VerifiedOracleReceiptCapture;
70/// let _forged = VerifiedOracleReceiptCapture {};
71/// ```
72///
73/// It is deliberately non-`Clone` and non-deserializable:
74///
75/// ```compile_fail
76/// use u280_evidence_oracle::VerifiedOracleReceiptCapture;
77/// fn require_clone<T: Clone>() {}
78/// require_clone::<VerifiedOracleReceiptCapture>();
79/// ```
80///
81/// ```compile_fail
82/// use serde::de::DeserializeOwned;
83/// use u280_evidence_oracle::VerifiedOracleReceiptCapture;
84/// fn require_deserialize<T: DeserializeOwned>() {}
85/// require_deserialize::<VerifiedOracleReceiptCapture>();
86/// ```
87#[derive(Debug)]
88pub struct VerifiedOracleReceiptCapture {
89    retained: StrictExternalFile,
90    exact_bytes: Vec<u8>,
91    _marker: VerifiedMarker,
92}
93
94impl VerifiedOracleReceiptCapture {
95    /// Exact canonical absolute capture path.
96    #[must_use]
97    pub fn path(&self) -> &Path {
98        self.retained.path()
99    }
100
101    /// Exact receipt byte count, including the terminal newline.
102    #[must_use]
103    pub fn byte_count(&self) -> u64 {
104        self.retained.record().bytes
105    }
106
107    /// SHA-256 of the exact receipt bytes, including the terminal newline.
108    #[must_use]
109    pub fn sha256(&self) -> &str {
110        &self.retained.record().sha256
111    }
112
113    /// Revalidates the retained receipt descriptor and its absolute pathname.
114    ///
115    /// # Errors
116    ///
117    /// Returns an error if the parent, path, metadata, byte count, or content
118    /// digest changed since capture.
119    pub fn revalidate(&self) -> Result<()> {
120        self.retained.revalidate()
121    }
122
123    fn exact_bytes(&self) -> &[u8] {
124        &self.exact_bytes
125    }
126}
127
128/// One immutable file or manifest binding recovered from the sealed result.
129///
130/// The private marker and fields prevent external construction. In particular,
131/// this external doctest must not compile:
132///
133/// ```compile_fail
134/// use u280_evidence_oracle::VerifiedResultArtifactBinding;
135/// let _forged = VerifiedResultArtifactBinding {
136///     file: "SHA256SUMS".to_owned(),
137///     bytes: 1,
138///     sha256: "00".repeat(32),
139/// };
140/// ```
141///
142/// This proof fragment is not deserializable:
143///
144/// ```compile_fail
145/// use serde::de::DeserializeOwned;
146/// use u280_evidence_oracle::VerifiedResultArtifactBinding;
147/// fn require_deserialize<T: DeserializeOwned>() {}
148/// require_deserialize::<VerifiedResultArtifactBinding>();
149/// ```
150///
151/// It is also deliberately non-`Clone`:
152///
153/// ```compile_fail
154/// use u280_evidence_oracle::VerifiedResultArtifactBinding;
155/// fn require_clone<T: Clone>() {}
156/// require_clone::<VerifiedResultArtifactBinding>();
157/// ```
158#[derive(Debug, Eq, PartialEq)]
159pub struct VerifiedResultArtifactBinding {
160    file: String,
161    bytes: u64,
162    sha256: String,
163    _marker: VerifiedMarker,
164}
165
166impl VerifiedResultArtifactBinding {
167    /// Exact producer-owned filename.
168    #[must_use]
169    pub fn file(&self) -> &str {
170        &self.file
171    }
172
173    /// Exact byte count.
174    #[must_use]
175    pub fn bytes(&self) -> u64 {
176        self.bytes
177    }
178
179    /// Lowercase SHA-256 digest.
180    #[must_use]
181    pub fn sha256(&self) -> &str {
182        &self.sha256
183    }
184}
185
186/// One input or output artifact retained for a verified request.
187///
188/// This type has no public constructor:
189///
190/// ```compile_fail
191/// use u280_evidence_oracle::VerifiedRequestArtifactBinding;
192/// let _forged = VerifiedRequestArtifactBinding {
193///     file: "input.bin".to_owned(),
194///     logical_bytes: 64,
195///     stored_bytes: 64,
196///     sha256: "00".repeat(32),
197/// };
198/// ```
199///
200/// It is not deserializable:
201///
202/// ```compile_fail
203/// use serde::de::DeserializeOwned;
204/// use u280_evidence_oracle::VerifiedRequestArtifactBinding;
205/// fn require_deserialize<T: DeserializeOwned>() {}
206/// require_deserialize::<VerifiedRequestArtifactBinding>();
207/// ```
208///
209/// It is not cloneable:
210///
211/// ```compile_fail
212/// use u280_evidence_oracle::VerifiedRequestArtifactBinding;
213/// fn require_clone<T: Clone>() {}
214/// require_clone::<VerifiedRequestArtifactBinding>();
215/// ```
216#[derive(Debug, Eq, PartialEq)]
217pub struct VerifiedRequestArtifactBinding {
218    file: String,
219    logical_bytes: u64,
220    stored_bytes: u64,
221    sha256: String,
222    _marker: VerifiedMarker,
223}
224
225impl VerifiedRequestArtifactBinding {
226    /// Request-local artifact filename.
227    #[must_use]
228    pub fn file(&self) -> &str {
229        &self.file
230    }
231
232    /// Logical byte count authenticated by the original request.
233    #[must_use]
234    pub fn logical_bytes(&self) -> u64 {
235        self.logical_bytes
236    }
237
238    /// Stored byte count authenticated by the original request.
239    #[must_use]
240    pub fn stored_bytes(&self) -> u64 {
241        self.stored_bytes
242    }
243
244    /// Lowercase artifact SHA-256 digest.
245    #[must_use]
246    pub fn sha256(&self) -> &str {
247        &self.sha256
248    }
249}
250
251/// The routed hardware image binding recovered from one oracle request.
252///
253/// This external construction must not compile:
254///
255/// ```compile_fail
256/// use u280_evidence_oracle::VerifiedXclbinBinding;
257/// let _forged = VerifiedXclbinBinding {
258///     path: "forged.xclbin".to_owned(),
259///     bytes: 1,
260///     sha256: "00".repeat(32),
261/// };
262/// ```
263///
264/// It is not deserializable:
265///
266/// ```compile_fail
267/// use serde::de::DeserializeOwned;
268/// use u280_evidence_oracle::VerifiedXclbinBinding;
269/// fn require_deserialize<T: DeserializeOwned>() {}
270/// require_deserialize::<VerifiedXclbinBinding>();
271/// ```
272///
273/// It is not cloneable:
274///
275/// ```compile_fail
276/// use u280_evidence_oracle::VerifiedXclbinBinding;
277/// fn require_clone<T: Clone>() {}
278/// require_clone::<VerifiedXclbinBinding>();
279/// ```
280#[derive(Debug, Eq, PartialEq)]
281pub struct VerifiedXclbinBinding {
282    path: String,
283    bytes: u64,
284    sha256: String,
285    _marker: VerifiedMarker,
286}
287
288impl VerifiedXclbinBinding {
289    /// Exact absolute path captured by the transport producer.
290    #[must_use]
291    pub fn path(&self) -> &str {
292        &self.path
293    }
294
295    /// Exact xclbin byte count.
296    #[must_use]
297    pub fn bytes(&self) -> u64 {
298        self.bytes
299    }
300
301    /// Lowercase xclbin SHA-256 digest.
302    #[must_use]
303    pub fn sha256(&self) -> &str {
304        &self.sha256
305    }
306}
307
308/// Exact XRT build identity recovered from the retained native-XRT reports.
309///
310/// The fields are private, the type has no public constructor, and it is
311/// deliberately neither cloneable nor deserializable.
312#[derive(Debug, Eq, PartialEq)]
313pub struct VerifiedXrtBuildIdentity {
314    version: String,
315    branch: String,
316    hash: String,
317    build_date: String,
318    _marker: VerifiedMarker,
319}
320
321impl VerifiedXrtBuildIdentity {
322    /// Exact XRT version string.
323    #[must_use]
324    pub fn version(&self) -> &str {
325        &self.version
326    }
327
328    /// Exact XRT branch string.
329    #[must_use]
330    pub fn branch(&self) -> &str {
331        &self.branch
332    }
333
334    /// Canonical lowercase XRT build hash.
335    #[must_use]
336    pub fn hash(&self) -> &str {
337        &self.hash
338    }
339
340    /// Exact XRT build timestamp.
341    #[must_use]
342    pub fn build_date(&self) -> &str {
343        &self.build_date
344    }
345}
346
347/// Exact programmed xclbin identity from the continuous pre/post card capture.
348#[derive(Debug, Eq, PartialEq)]
349pub struct VerifiedHardwareXclbinIdentity {
350    path: String,
351    bytes: u64,
352    sha256: String,
353    uuid: String,
354    interface_uuid: String,
355    deployment_platform: String,
356    fpga_part: String,
357    target: String,
358    _marker: VerifiedMarker,
359}
360
361impl VerifiedHardwareXclbinIdentity {
362    /// Exact absolute xclbin path recorded by the card runner.
363    #[must_use]
364    pub fn path(&self) -> &str {
365        &self.path
366    }
367
368    /// Exact xclbin byte count.
369    #[must_use]
370    pub fn bytes(&self) -> u64 {
371        self.bytes
372    }
373
374    /// Exact lowercase xclbin SHA-256.
375    #[must_use]
376    pub fn sha256(&self) -> &str {
377        &self.sha256
378    }
379
380    /// Exact loaded xclbin UUID.
381    #[must_use]
382    pub fn uuid(&self) -> &str {
383        &self.uuid
384    }
385
386    /// Exact shell interface UUID declared by the xclbin.
387    #[must_use]
388    pub fn interface_uuid(&self) -> &str {
389        &self.interface_uuid
390    }
391
392    /// Exact deployment-platform/XSA name carried by the xclbin.
393    #[must_use]
394    pub fn deployment_platform(&self) -> &str {
395        &self.deployment_platform
396    }
397
398    /// Exact FPGA part carried by the xclbin identity.
399    #[must_use]
400    pub fn fpga_part(&self) -> &str {
401        &self.fpga_part
402    }
403
404    /// Exact xclbin target (`hw` for this contract).
405    #[must_use]
406    pub fn target(&self) -> &str {
407        &self.target
408    }
409}
410
411/// Strict, continuous physical-card identity recovered from the transport.
412///
413/// A value is created only after re-running the existing pre-load, post-load,
414/// and post-run native-XRT continuity checks, including the raw platform and
415/// host reports. It is not a route seal and does not prove current card
416/// ownership.
417///
418/// ```compile_fail
419/// use serde::de::DeserializeOwned;
420/// use u280_evidence_oracle::VerifiedHardwareCardIdentity;
421/// fn require_deserialize<T: DeserializeOwned>() {}
422/// require_deserialize::<VerifiedHardwareCardIdentity>();
423/// ```
424///
425/// ```compile_fail
426/// use u280_evidence_oracle::VerifiedHardwareCardIdentity;
427/// fn require_clone<T: Clone>() {}
428/// require_clone::<VerifiedHardwareCardIdentity>();
429/// ```
430#[derive(Debug, Eq, PartialEq)]
431pub struct VerifiedHardwareCardIdentity {
432    device_index: u64,
433    bdf: String,
434    device_name: String,
435    xmc_serial_number: String,
436    shell_vbnv: String,
437    logic_uuid: String,
438    interface_uuid: String,
439    fpga_part: String,
440    xrt_build: VerifiedXrtBuildIdentity,
441    xclbin: VerifiedHardwareXclbinIdentity,
442    _marker: VerifiedMarker,
443}
444
445impl VerifiedHardwareCardIdentity {
446    /// Exact XRT device index used by the run.
447    #[must_use]
448    pub fn device_index(&self) -> u64 {
449        self.device_index
450    }
451
452    /// Canonical physical `PCIe` BDF.
453    #[must_use]
454    pub fn bdf(&self) -> &str {
455        &self.bdf
456    }
457
458    /// Exact XRT device/shell name.
459    #[must_use]
460    pub fn device_name(&self) -> &str {
461        &self.device_name
462    }
463
464    /// Exact XMC serial number.
465    #[must_use]
466    pub fn xmc_serial_number(&self) -> &str {
467        &self.xmc_serial_number
468    }
469
470    /// Exact U280 shell VBNV.
471    #[must_use]
472    pub fn shell_vbnv(&self) -> &str {
473        &self.shell_vbnv
474    }
475
476    /// Exact shell logic UUID.
477    #[must_use]
478    pub fn logic_uuid(&self) -> &str {
479        &self.logic_uuid
480    }
481
482    /// Exact shell interface UUID.
483    #[must_use]
484    pub fn interface_uuid(&self) -> &str {
485        &self.interface_uuid
486    }
487
488    /// Exact FPGA part reported continuously by the card capture.
489    #[must_use]
490    pub fn fpga_part(&self) -> &str {
491        &self.fpga_part
492    }
493
494    /// Strict XRT build identity.
495    #[must_use]
496    pub fn xrt_build(&self) -> &VerifiedXrtBuildIdentity {
497        &self.xrt_build
498    }
499
500    /// Strict programmed xclbin identity.
501    #[must_use]
502    pub fn xclbin(&self) -> &VerifiedHardwareXclbinIdentity {
503        &self.xclbin
504    }
505}
506
507/// Routed-clock evidence binding declared consistently by the transport.
508///
509/// The evidence file itself is outside the transport archive. A later route
510/// join must match this exact path/length/digest to accepted route evidence.
511#[derive(Debug, Eq, PartialEq)]
512pub struct VerifiedRoutedClockEvidenceBinding {
513    path: String,
514    bytes: u64,
515    sha256: String,
516    _marker: VerifiedMarker,
517}
518
519impl VerifiedRoutedClockEvidenceBinding {
520    /// Exact evidence path captured by the card runner.
521    #[must_use]
522    pub fn path(&self) -> &str {
523        &self.path
524    }
525
526    /// Exact declared evidence byte count.
527    #[must_use]
528    pub fn bytes(&self) -> u64 {
529        self.bytes
530    }
531
532    /// Exact declared evidence SHA-256.
533    #[must_use]
534    pub fn sha256(&self) -> &str {
535        &self.sha256
536    }
537}
538
539/// Exact clock fields shared by metadata, results, and every request.
540#[derive(Debug, Eq, PartialEq)]
541pub struct VerifiedClockObservation {
542    requested_clock_hz_metadata: Option<u64>,
543    declared_routed_hz: Option<u64>,
544    routed_clock_evidence: Option<VerifiedRoutedClockEvidenceBinding>,
545    supports_hardware_rate_claim: bool,
546    _marker: VerifiedMarker,
547}
548
549impl VerifiedClockObservation {
550    /// Requested clock metadata, which never substitutes for route evidence.
551    #[must_use]
552    pub fn requested_clock_hz_metadata(&self) -> Option<u64> {
553        self.requested_clock_hz_metadata
554    }
555
556    /// Routed clock declared by the transport, before an accepted route join.
557    #[must_use]
558    pub fn declared_routed_hz(&self) -> Option<u64> {
559        self.declared_routed_hz
560    }
561
562    /// Exact declared route-evidence binding, if present.
563    #[must_use]
564    pub fn routed_clock_evidence(&self) -> Option<&VerifiedRoutedClockEvidenceBinding> {
565        self.routed_clock_evidence.as_ref()
566    }
567
568    /// Whether the transport consistently declared a hardware-rate claim.
569    #[must_use]
570    pub fn supports_hardware_rate_claim(&self) -> bool {
571        self.supports_hardware_rate_claim
572    }
573}
574
575/// One independently re-parsed raw timing/summary/diagnostic observation.
576///
577/// `capture_core_interval_cycles` is the raw numerator spanning `batch - 1`
578/// inter-result intervals. `whole_kernel_nanoseconds` is the raw elapsed
579/// numerator spanning `batch` results. The final promoter must consume these
580/// observations through the enclosing opaque guard, not accept caller-created
581/// lookalike samples.
582///
583/// ```compile_fail
584/// use u280_evidence_oracle::VerifiedPerformanceSample;
585/// let _forged = VerifiedPerformanceSample {};
586/// ```
587///
588/// ```compile_fail
589/// use serde::de::DeserializeOwned;
590/// use u280_evidence_oracle::VerifiedPerformanceSample;
591/// fn require_deserialize<T: DeserializeOwned>() {}
592/// require_deserialize::<VerifiedPerformanceSample>();
593/// ```
594///
595/// ```compile_fail
596/// use u280_evidence_oracle::VerifiedPerformanceSample;
597/// fn require_clone<T: Clone>() {}
598/// require_clone::<VerifiedPerformanceSample>();
599/// ```
600#[derive(Debug, Eq, PartialEq)]
601pub struct VerifiedPerformanceSample {
602    sample: String,
603    phase: String,
604    sample_index: usize,
605    batch: u32,
606    capture_core_interval_cycles: u64,
607    memory_retirement_interval_cycles: u64,
608    whole_kernel_nanoseconds: u64,
609    _marker: VerifiedMarker,
610}
611
612impl VerifiedPerformanceSample {
613    /// Canonical transport sample path.
614    #[must_use]
615    pub fn sample(&self) -> &str {
616        &self.sample
617    }
618
619    /// Launch phase (`warmup` or `measured`).
620    #[must_use]
621    pub fn phase(&self) -> &str {
622        &self.phase
623    }
624
625    /// Zero-based sample index within its batch and phase.
626    #[must_use]
627    pub fn sample_index(&self) -> usize {
628        self.sample_index
629    }
630
631    /// Exact launch batch.
632    #[must_use]
633    pub fn batch(&self) -> u32 {
634        self.batch
635    }
636
637    /// Raw capture/core span in cycles over `batch - 1` intervals.
638    #[must_use]
639    pub fn capture_core_interval_cycles(&self) -> u64 {
640        self.capture_core_interval_cycles
641    }
642
643    /// Raw memory-retirement span in cycles over `batch - 1` intervals.
644    #[must_use]
645    pub fn memory_retirement_interval_cycles(&self) -> u64 {
646        self.memory_retirement_interval_cycles
647    }
648
649    /// Raw whole-kernel elapsed time in nanoseconds over `batch` results.
650    #[must_use]
651    pub fn whole_kernel_nanoseconds(&self) -> u64 {
652        self.whole_kernel_nanoseconds
653    }
654
655    /// Whether this sample belongs to the required p95 population.
656    #[must_use]
657    pub fn is_required_performance_population(&self) -> bool {
658        self.batch == REQUIRED_PERFORMANCE_BATCH && self.phase == "measured"
659    }
660}
661
662/// Exact integer performance observations derived from retained raw samples.
663///
664/// The raw p95 numerators and denominators deliberately match the promoter
665/// core's `PerformanceAssessment` interface. Every decision is made with
666/// cross-multiplied `u128` arithmetic; no floating-point value can pass or fail
667/// a threshold here.
668///
669/// ```compile_fail
670/// use serde::de::DeserializeOwned;
671/// use u280_evidence_oracle::VerifiedPerformanceObservations;
672/// fn require_deserialize<T: DeserializeOwned>() {}
673/// require_deserialize::<VerifiedPerformanceObservations>();
674/// ```
675///
676/// ```compile_fail
677/// use u280_evidence_oracle::VerifiedPerformanceObservations;
678/// fn require_clone<T: Clone>() {}
679/// require_clone::<VerifiedPerformanceObservations>();
680/// ```
681#[derive(Debug, Eq, PartialEq)]
682pub struct VerifiedPerformanceObservations {
683    required_batch: u32,
684    minimum_measured_samples: usize,
685    required_batch_requested: bool,
686    observed_measured_samples: usize,
687    p95_rank: Option<usize>,
688    p95_capture_interval_cycles: Option<u64>,
689    capture_results_denominator: u32,
690    p95_whole_kernel_nanoseconds: Option<u64>,
691    whole_kernel_results_denominator: u32,
692    clock: VerifiedClockObservation,
693    samples: Vec<VerifiedPerformanceSample>,
694    _marker: VerifiedMarker,
695}
696
697impl VerifiedPerformanceObservations {
698    /// Required performance batch (`16_384`).
699    #[must_use]
700    pub fn required_batch(&self) -> u32 {
701        self.required_batch
702    }
703
704    /// Minimum measured population (`30`).
705    #[must_use]
706    pub fn minimum_measured_samples(&self) -> usize {
707        self.minimum_measured_samples
708    }
709
710    /// Exact arithmetic normalization clock (`250_000_000 Hz`).
711    #[must_use]
712    pub fn normalized_clock_hz(&self) -> u64 {
713        PERFORMANCE_CLOCK_BOUND_HZ
714    }
715
716    /// Exact minimum sustained rate (`500_000 signatures/s`).
717    #[must_use]
718    pub fn minimum_signatures_per_second(&self) -> u64 {
719        MINIMUM_SIGNATURES_PER_SECOND_EXACT
720    }
721
722    /// Exact maximum p95 capture/core cost (`500 cycles/result`).
723    #[must_use]
724    pub fn maximum_capture_cycles_per_result(&self) -> u64 {
725        MAXIMUM_P95_CAPTURE_CYCLES_EXACT
726    }
727
728    /// Whether the required batch was requested by the retained run.
729    #[must_use]
730    pub fn required_batch_requested(&self) -> bool {
731        self.required_batch_requested
732    }
733
734    /// Exact number of measured samples in the required batch.
735    #[must_use]
736    pub fn observed_measured_samples(&self) -> usize {
737        self.observed_measured_samples
738    }
739
740    /// Whether the minimum measured population is present.
741    #[must_use]
742    pub(crate) fn sample_count_requirement_met(&self) -> bool {
743        self.observed_measured_samples >= self.minimum_measured_samples
744    }
745
746    /// One-based nearest-rank p95 position within the measured population.
747    #[must_use]
748    pub fn p95_rank(&self) -> Option<usize> {
749        self.p95_rank
750    }
751
752    /// Raw p95 capture/core numerator in cycles.
753    #[must_use]
754    pub fn p95_capture_interval_cycles(&self) -> Option<u64> {
755        self.p95_capture_interval_cycles
756    }
757
758    /// Inter-result denominator for the capture/core numerator.
759    #[must_use]
760    pub fn capture_results_denominator(&self) -> u32 {
761        self.capture_results_denominator
762    }
763
764    /// Raw p95 whole-kernel elapsed numerator in nanoseconds.
765    #[must_use]
766    pub fn p95_whole_kernel_nanoseconds(&self) -> Option<u64> {
767        self.p95_whole_kernel_nanoseconds
768    }
769
770    /// Result-count denominator for the whole-kernel numerator.
771    #[must_use]
772    pub fn whole_kernel_results_denominator(&self) -> u32 {
773        self.whole_kernel_results_denominator
774    }
775
776    /// Exact shared clock observation.
777    #[must_use]
778    pub fn clock(&self) -> &VerifiedClockObservation {
779        &self.clock
780    }
781
782    /// Exact `p95 <= 500 cycles/result` decision.
783    #[must_use]
784    pub(crate) fn capture_cycles_threshold_met(&self) -> bool {
785        exact_capture_cycles_threshold_met(self.p95_capture_interval_cycles)
786    }
787
788    /// Exact normalized-250-MHz `>= 500_000 signatures/s` decision.
789    #[must_use]
790    pub(crate) fn normalized_250mhz_rate_threshold_met(&self) -> bool {
791        exact_capture_rate_threshold_met(
792            PERFORMANCE_CLOCK_BOUND_HZ,
793            self.p95_capture_interval_cycles,
794        )
795    }
796
797    /// Exact declared-routed-clock `>= 500_000 signatures/s` decision.
798    #[must_use]
799    pub(crate) fn declared_routed_rate_threshold_met(&self) -> bool {
800        self.clock.supports_hardware_rate_claim
801            && self.clock.routed_clock_evidence.is_some()
802            && self.clock.declared_routed_hz.is_some_and(|clock_hz| {
803                exact_capture_rate_threshold_met(clock_hz, self.p95_capture_interval_cycles)
804            })
805    }
806
807    /// Exact whole-kernel-elapsed `>= 500_000 signatures/s` decision.
808    #[must_use]
809    pub(crate) fn whole_kernel_rate_threshold_met(&self) -> bool {
810        exact_whole_kernel_rate_threshold_met(self.p95_whole_kernel_nanoseconds)
811    }
812
813    /// Whether the full required population and routed-clock inputs exist.
814    #[must_use]
815    pub(crate) fn threshold_observations_complete(&self) -> bool {
816        self.required_batch_requested
817            && self.sample_count_requirement_met()
818            && self.p95_capture_interval_cycles.is_some()
819            && self.p95_whole_kernel_nanoseconds.is_some()
820            && self.clock.declared_routed_hz.is_some()
821            && self.clock.routed_clock_evidence.is_some()
822            && self.clock.supports_hardware_rate_claim
823    }
824
825    /// Pre-route-join conjunction of the complete population and exact costs.
826    ///
827    /// This decision is deliberately non-promotable: the routed-clock evidence
828    /// binding is declared by the transport but its external bytes have not yet
829    /// been joined to an accepted route seal. The final promoter must repeat
830    /// these exact comparisons while performing that join.
831    #[must_use]
832    pub(crate) fn pre_route_join_performance_thresholds_met(&self) -> bool {
833        self.threshold_observations_complete()
834            && self.capture_cycles_threshold_met()
835            && self.normalized_250mhz_rate_threshold_met()
836            && self.declared_routed_rate_threshold_met()
837            && self.whole_kernel_rate_threshold_met()
838    }
839
840    /// Every independently parsed sample, including warmups and controls.
841    #[must_use]
842    pub fn samples(&self) -> &[VerifiedPerformanceSample] {
843        &self.samples
844    }
845}
846
847/// Semantically revalidated fields for one complete oracle request.
848///
849/// Its private fields and seal prevent external struct construction:
850///
851/// ```compile_fail
852/// use u280_evidence_oracle::VerifiedResultRequest;
853/// let _forged = VerifiedResultRequest {};
854/// ```
855///
856/// This type is deliberately not deserializable by callers:
857///
858/// ```compile_fail
859/// use serde::de::DeserializeOwned;
860/// use u280_evidence_oracle::VerifiedResultRequest;
861/// fn require_deserialize<T: DeserializeOwned>() {}
862/// require_deserialize::<VerifiedResultRequest>();
863/// ```
864///
865/// It is also deliberately non-`Clone`:
866///
867/// ```compile_fail
868/// use u280_evidence_oracle::VerifiedResultRequest;
869/// fn require_clone<T: Clone>() {}
870/// require_clone::<VerifiedResultRequest>();
871/// ```
872#[derive(Debug, Eq, PartialEq)]
873pub struct VerifiedResultRequest {
874    sample: String,
875    phase: String,
876    sample_index: usize,
877    request_sha256: String,
878    run_id: String,
879    coordination_intent: VerifiedResultArtifactBinding,
880    coordination_burn: VerifiedResultArtifactBinding,
881    coordination_receipt: VerifiedResultArtifactBinding,
882    batch: u32,
883    nonce_hex: String,
884    reservation_record_sha256: String,
885    xclbin: VerifiedXclbinBinding,
886    hardware_identity_pre_run: VerifiedResultArtifactBinding,
887    input: VerifiedRequestArtifactBinding,
888    output: VerifiedRequestArtifactBinding,
889    jobs: u32,
890    matched_jobs: u32,
891    mismatched_jobs: u32,
892    padding_valid: bool,
893    cryptographic_oracle_valid: bool,
894    _marker: VerifiedMarker,
895}
896
897impl VerifiedResultRequest {
898    /// Canonical sample path inside the retained transport archive.
899    #[must_use]
900    pub fn sample(&self) -> &str {
901        &self.sample
902    }
903
904    /// Launch phase (`warmup` or `measured`).
905    #[must_use]
906    pub fn phase(&self) -> &str {
907        &self.phase
908    }
909
910    /// Zero-based sample index within the batch and phase.
911    #[must_use]
912    pub fn sample_index(&self) -> usize {
913        self.sample_index
914    }
915
916    /// SHA-256 of the request's exact `oracle-request.json` bytes.
917    #[must_use]
918    pub fn request_sha256(&self) -> &str {
919        &self.request_sha256
920    }
921
922    /// Coordination run identifier checked against the result-wide run.
923    #[must_use]
924    pub fn run_id(&self) -> &str {
925        &self.run_id
926    }
927
928    /// Request-local intent binding checked against the result-wide root.
929    #[must_use]
930    pub fn coordination_intent(&self) -> &VerifiedResultArtifactBinding {
931        &self.coordination_intent
932    }
933
934    /// Request-local authorization-burn binding.
935    #[must_use]
936    pub fn coordination_burn(&self) -> &VerifiedResultArtifactBinding {
937        &self.coordination_burn
938    }
939
940    /// Request-local post-lock coordination receipt binding.
941    #[must_use]
942    pub fn coordination_receipt(&self) -> &VerifiedResultArtifactBinding {
943        &self.coordination_receipt
944    }
945
946    /// Requested jobs in this launch.
947    #[must_use]
948    pub fn batch(&self) -> u32 {
949        self.batch
950    }
951
952    /// Canonical request nonce.
953    #[must_use]
954    pub fn nonce_hex(&self) -> &str {
955        &self.nonce_hex
956    }
957
958    /// Reservation-record SHA-256 bound by the request.
959    #[must_use]
960    pub fn reservation_record_sha256(&self) -> &str {
961        &self.reservation_record_sha256
962    }
963
964    /// Exact hardware xclbin binding.
965    #[must_use]
966    pub fn xclbin(&self) -> &VerifiedXclbinBinding {
967        &self.xclbin
968    }
969
970    /// Exact pre-run native-XRT identity binding.
971    #[must_use]
972    pub fn hardware_identity_pre_run(&self) -> &VerifiedResultArtifactBinding {
973        &self.hardware_identity_pre_run
974    }
975
976    /// Request-authenticated input artifact binding.
977    #[must_use]
978    pub fn input(&self) -> &VerifiedRequestArtifactBinding {
979        &self.input
980    }
981
982    /// Request-authenticated full output-allocation binding.
983    #[must_use]
984    pub fn output(&self) -> &VerifiedRequestArtifactBinding {
985        &self.output
986    }
987
988    /// Complete job count represented by the transcript.
989    #[must_use]
990    pub fn jobs(&self) -> u32 {
991        self.jobs
992    }
993
994    /// Transcript jobs whose expected and observed digests match.
995    #[must_use]
996    pub fn matched_jobs(&self) -> u32 {
997        self.matched_jobs
998    }
999
1000    /// Transcript jobs whose expected and observed digests differ.
1001    #[must_use]
1002    pub fn mismatched_jobs(&self) -> u32 {
1003        self.mismatched_jobs
1004    }
1005
1006    /// Whether every reserved output byte retained its required poison value.
1007    #[must_use]
1008    pub fn padding_valid(&self) -> bool {
1009        self.padding_valid
1010    }
1011
1012    /// Recomputed conjunction of complete payload and padding validity.
1013    #[must_use]
1014    pub fn cryptographic_oracle_valid(&self) -> bool {
1015        self.cryptographic_oracle_valid
1016    }
1017}
1018
1019/// Opaque, descriptor-retaining view of a receipt-bound Phase-B oracle result.
1020///
1021/// It cannot be constructed or deserialized externally, and it intentionally
1022/// does not implement `Clone`:
1023///
1024/// ```compile_fail
1025/// use u280_evidence_oracle::VerifiedSealedResult;
1026/// let _forged = VerifiedSealedResult {};
1027/// ```
1028///
1029/// ```compile_fail
1030/// use serde::de::DeserializeOwned;
1031/// use u280_evidence_oracle::VerifiedSealedResult;
1032/// fn require_deserialize<T: DeserializeOwned>() {}
1033/// require_deserialize::<VerifiedSealedResult>();
1034/// ```
1035///
1036/// ```compile_fail
1037/// use u280_evidence_oracle::VerifiedSealedResult;
1038/// fn require_clone<T: Clone>() {}
1039/// require_clone::<VerifiedSealedResult>();
1040/// ```
1041///
1042/// The returned values describe historical evidence. Keep this guard alive and
1043/// call [`Self::revalidate`] immediately before the promoter publishes its own
1044/// sealed result. That call uses the same retained result and transport root
1045/// descriptors; path-only snapshots are not substituted.
1046#[derive(Debug)]
1047pub struct VerifiedSealedResult {
1048    transport_manifest: VerifiedResultArtifactBinding,
1049    final_hardware_identity: VerifiedResultArtifactBinding,
1050    hardware_card_identity: VerifiedHardwareCardIdentity,
1051    performance: VerifiedPerformanceObservations,
1052    run_id: String,
1053    coordination_intent: VerifiedResultArtifactBinding,
1054    coordination_burn: VerifiedResultArtifactBinding,
1055    coordination_receipt: VerifiedResultArtifactBinding,
1056    samples: usize,
1057    jobs: u64,
1058    matched_jobs: u64,
1059    mismatched_jobs: u64,
1060    all_padding_valid: bool,
1061    cryptographic_oracle_valid: bool,
1062    requests: Vec<VerifiedResultRequest>,
1063    result_directory: PathBuf,
1064    result_manifest: VerifiedResultArtifactBinding,
1065    creation_receipt: VerifiedOracleReceiptCapture,
1066    result_snapshot: StrictResultSnapshot,
1067    transport_snapshot: ArchiveSnapshot,
1068    _marker: VerifiedMarker,
1069}
1070
1071impl VerifiedSealedResult {
1072    /// Fixed cryptographic profile accepted by this typed verifier.
1073    #[must_use]
1074    pub fn profile(&self) -> &'static str {
1075        PROFILE
1076    }
1077
1078    /// Canonical retained transport root.
1079    #[must_use]
1080    pub fn transport_root(&self) -> &Path {
1081        &self.transport_snapshot.root
1082    }
1083
1084    /// Exact transport `SHA256SUMS` binding validated by the original oracle.
1085    #[must_use]
1086    pub fn transport_manifest(&self) -> &VerifiedResultArtifactBinding {
1087        &self.transport_manifest
1088    }
1089
1090    /// Exact final native-XRT hardware identity binding.
1091    #[must_use]
1092    pub fn final_hardware_identity(&self) -> &VerifiedResultArtifactBinding {
1093        &self.final_hardware_identity
1094    }
1095
1096    /// Strict card and programmed-image identity proof.
1097    #[must_use]
1098    pub fn hardware_card_identity(&self) -> &VerifiedHardwareCardIdentity {
1099        &self.hardware_card_identity
1100    }
1101
1102    /// Independently parsed exact performance observations.
1103    #[must_use]
1104    pub fn performance(&self) -> &VerifiedPerformanceObservations {
1105        &self.performance
1106    }
1107
1108    /// Final hardware promotion remains the later route/card combiner's job.
1109    #[must_use]
1110    pub fn hardware_completion_promotable(&self) -> bool {
1111        false
1112    }
1113
1114    /// Coordination run identifier shared by every request.
1115    #[must_use]
1116    pub fn run_id(&self) -> &str {
1117        &self.run_id
1118    }
1119
1120    /// Result-wide coordination intent root.
1121    #[must_use]
1122    pub fn coordination_intent(&self) -> &VerifiedResultArtifactBinding {
1123        &self.coordination_intent
1124    }
1125
1126    /// Result-wide durable authorization-burn root.
1127    #[must_use]
1128    pub fn coordination_burn(&self) -> &VerifiedResultArtifactBinding {
1129        &self.coordination_burn
1130    }
1131
1132    /// Result-wide post-lock coordination receipt root.
1133    #[must_use]
1134    pub fn coordination_receipt(&self) -> &VerifiedResultArtifactBinding {
1135        &self.coordination_receipt
1136    }
1137
1138    /// Number of complete request samples.
1139    #[must_use]
1140    pub fn samples(&self) -> usize {
1141        self.samples
1142    }
1143
1144    /// Number of transcript jobs across all samples.
1145    #[must_use]
1146    pub fn jobs(&self) -> u64 {
1147        self.jobs
1148    }
1149
1150    /// Number of matching transcript jobs.
1151    #[must_use]
1152    pub fn matched_jobs(&self) -> u64 {
1153        self.matched_jobs
1154    }
1155
1156    /// Number of mismatching transcript jobs.
1157    #[must_use]
1158    pub fn mismatched_jobs(&self) -> u64 {
1159        self.mismatched_jobs
1160    }
1161
1162    /// Conjunction of every request's padding decision.
1163    #[must_use]
1164    pub fn all_padding_valid(&self) -> bool {
1165        self.all_padding_valid
1166    }
1167
1168    /// Recomputed complete cryptographic decision.
1169    #[must_use]
1170    pub fn cryptographic_oracle_valid(&self) -> bool {
1171        self.cryptographic_oracle_valid
1172    }
1173
1174    /// Revalidated request-level joins and decisions.
1175    #[must_use]
1176    pub fn requests(&self) -> &[VerifiedResultRequest] {
1177        &self.requests
1178    }
1179
1180    /// Canonical result directory bound by the exact creation receipt.
1181    #[must_use]
1182    pub fn result_directory(&self) -> &Path {
1183        &self.result_directory
1184    }
1185
1186    /// Result directory's exact `SHA256SUMS` creation-time binding.
1187    #[must_use]
1188    pub fn result_manifest(&self) -> &VerifiedResultArtifactBinding {
1189        &self.result_manifest
1190    }
1191
1192    /// Descriptor-retained exact creation receipt.
1193    #[must_use]
1194    pub fn creation_receipt(&self) -> &VerifiedOracleReceiptCapture {
1195        &self.creation_receipt
1196    }
1197
1198    /// Revalidates the complete result and transport through their originally
1199    /// retained roots.
1200    ///
1201    /// # Errors
1202    ///
1203    /// Returns an error if either absolute root path identity, tree, manifest,
1204    /// or any covered file changed since this guard was created.
1205    ///
1206    /// No filesystem API can prevent the owner from changing a path after
1207    /// this method returns. A promoter must therefore publish the receipt and
1208    /// both manifest identities, not claim that either path remains immutable.
1209    pub fn revalidate(&self) -> Result<()> {
1210        self.creation_receipt.revalidate()?;
1211        self.result_snapshot.revalidate()?;
1212        verify_transport_archive_again_exact(&self.transport_snapshot)?;
1213        self.creation_receipt.revalidate()?;
1214        Ok(())
1215    }
1216}
1217
1218#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1219#[serde(deny_unknown_fields)]
1220struct SealedBinding {
1221    file: String,
1222    bytes: u64,
1223    sha256: String,
1224}
1225
1226#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1227#[serde(deny_unknown_fields)]
1228struct SealedRequestArtifactBinding {
1229    file: String,
1230    logical_bytes: u64,
1231    stored_bytes: u64,
1232    sha256: String,
1233}
1234
1235#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1236#[serde(deny_unknown_fields)]
1237struct SealedXclbinBinding {
1238    path: String,
1239    bytes: u64,
1240    sha256: String,
1241}
1242
1243#[derive(Clone, Debug, Deserialize, Serialize)]
1244#[serde(deny_unknown_fields)]
1245struct SealedRequest {
1246    sample: String,
1247    phase: String,
1248    sample_index: usize,
1249    request_sha256: String,
1250    run_id: String,
1251    coordination_intent: SealedBinding,
1252    coordination_burn: SealedBinding,
1253    coordination_receipt: SealedBinding,
1254    batch: u32,
1255    nonce_hex: String,
1256    reservation_record_sha256: String,
1257    xclbin: SealedXclbinBinding,
1258    hardware_identity_pre_run: SealedBinding,
1259    input: SealedRequestArtifactBinding,
1260    output: SealedRequestArtifactBinding,
1261    jobs: u32,
1262    matched_jobs: u32,
1263    padding_valid: bool,
1264    cryptographic_oracle_valid: bool,
1265}
1266
1267// These booleans are distinct fields in the sealed canonical JSON contract;
1268// replacing them with enums would change its wire representation.
1269#[allow(clippy::struct_excessive_bools)]
1270#[derive(Clone, Debug, Deserialize, Serialize)]
1271#[serde(deny_unknown_fields)]
1272struct SealedSummary {
1273    schema: u64,
1274    kind: String,
1275    verifier_contract: String,
1276    profile: String,
1277    producer: String,
1278    pinned_hashsigs_rs_commit: String,
1279    transport_manifest: SealedBinding,
1280    run_id: String,
1281    coordination_intent: SealedBinding,
1282    coordination_burn: SealedBinding,
1283    coordination_receipt: SealedBinding,
1284    final_hardware_identity: SealedBinding,
1285    worker_threads: usize,
1286    sample_count: usize,
1287    total_jobs: u64,
1288    matched_jobs: u64,
1289    mismatched_jobs: u64,
1290    all_padding_valid: bool,
1291    requests: Vec<SealedRequest>,
1292    cryptographic_oracle_valid: bool,
1293    card_identity_promotable: bool,
1294    performance_promotable: bool,
1295    hardware_completion_promotable: bool,
1296    evidence_boundary: String,
1297}
1298
1299#[derive(Clone, Debug, Deserialize, Serialize)]
1300#[serde(deny_unknown_fields)]
1301struct SealedJob {
1302    schema: u64,
1303    sample: String,
1304    job_index: u32,
1305    input_sha256: String,
1306    expected_sha256: String,
1307    observed_sha256: String,
1308    r#match: bool,
1309}
1310
1311// These booleans are distinct fields in the canonical creation receipt;
1312// replacing them with enums would break receipt compatibility.
1313#[allow(clippy::struct_excessive_bools)]
1314#[derive(Clone, Debug, Deserialize, Serialize)]
1315#[serde(deny_unknown_fields)]
1316struct CompletedReceipt {
1317    schema: u64,
1318    kind: String,
1319    result_kind: String,
1320    result_schema: u64,
1321    typed_verifier_contract: String,
1322    result_directory: String,
1323    manifest: SealedBinding,
1324    structural_validation_valid: bool,
1325    cryptographic_oracle_valid: bool,
1326    card_identity_promotable: bool,
1327    performance_promotable: bool,
1328    hardware_completion_promotable: bool,
1329    samples: usize,
1330    jobs: u64,
1331}
1332
1333#[derive(Clone, Copy, Debug)]
1334struct TranscriptCount {
1335    jobs: u32,
1336    matched_jobs: u32,
1337    padding_valid: bool,
1338}
1339
1340struct VerifiedValues {
1341    transport_manifest: VerifiedResultArtifactBinding,
1342    final_hardware_identity: VerifiedResultArtifactBinding,
1343    run_id: String,
1344    coordination_intent: VerifiedResultArtifactBinding,
1345    coordination_burn: VerifiedResultArtifactBinding,
1346    coordination_receipt: VerifiedResultArtifactBinding,
1347    samples: usize,
1348    jobs: u64,
1349    matched_jobs: u64,
1350    mismatched_jobs: u64,
1351    all_padding_valid: bool,
1352    cryptographic_oracle_valid: bool,
1353    requests: Vec<VerifiedResultRequest>,
1354}
1355
1356struct VerifiedTransportEvidence {
1357    hardware_card_identity: VerifiedHardwareCardIdentity,
1358    performance: VerifiedPerformanceObservations,
1359}
1360
1361#[derive(Debug, Eq, PartialEq)]
1362struct ExactPerformanceDecision {
1363    required_batch_requested: bool,
1364    observed_measured_samples: usize,
1365    p95_rank: Option<usize>,
1366    p95_capture_interval_cycles: Option<u64>,
1367    p95_whole_kernel_nanoseconds: Option<u64>,
1368}
1369
1370/// Serializes the exact canonical schema-2 creation-receipt line.
1371///
1372/// The returned string excludes the terminal newline; the CLI adds exactly one
1373/// newline when it writes the line to stdout. Callers that retain the receipt
1374/// as bytes must retain that newline as well.
1375///
1376/// # Errors
1377///
1378/// Returns an error if the canonical result path is not UTF-8 or the outcome's
1379/// manifest binding is noncanonical.
1380pub fn completed_result_receipt_line(outcome: &OracleOutcome) -> Result<String> {
1381    let result_directory = outcome
1382        .result_directory
1383        .to_str()
1384        .context("result directory is not valid UTF-8")?;
1385    ensure!(
1386        is_nonzero_lower_hex(&outcome.result_manifest_sha256, 64)
1387            && outcome.result_manifest_bytes > 0,
1388        "result manifest binding is not canonical"
1389    );
1390    let receipt = CompletedReceipt {
1391        schema: PHASE_B_ORACLE_RECEIPT_SCHEMA,
1392        kind: RECEIPT_KIND.to_owned(),
1393        result_kind: COMPLETED_RESULT_KIND.to_owned(),
1394        result_schema: PHASE_B_TYPED_RESULT_SCHEMA,
1395        typed_verifier_contract: PHASE_B_TYPED_RESULT_CONTRACT.to_owned(),
1396        result_directory: result_directory.to_owned(),
1397        manifest: SealedBinding {
1398            file: "SHA256SUMS".to_owned(),
1399            bytes: outcome.result_manifest_bytes,
1400            sha256: outcome.result_manifest_sha256.clone(),
1401        },
1402        structural_validation_valid: true,
1403        cryptographic_oracle_valid: outcome.cryptographic_oracle_valid,
1404        card_identity_promotable: false,
1405        performance_promotable: false,
1406        hardware_completion_promotable: false,
1407        samples: outcome.samples,
1408        jobs: outcome.jobs,
1409    };
1410    serde_json::to_string(&receipt).context("cannot serialize strict result receipt")
1411}
1412
1413/// Securely opens and validates one exact schema-2 creation-receipt capture.
1414///
1415/// The file must be a bounded, nonempty, singly linked regular file beneath an
1416/// absolute symlink-free parent path. Its canonical bytes are parsed before the
1417/// descriptor-backed capture is returned.
1418///
1419/// # Errors
1420///
1421/// Returns an error for an insecure path or file type, a malformed receipt, an
1422/// unsupported receipt contract, or any open/read/revalidation race.
1423pub fn open_verified_oracle_receipt_capture(path: &Path) -> Result<VerifiedOracleReceiptCapture> {
1424    let maximum_bytes = u64::try_from(MAXIMUM_CREATION_RECEIPT_BYTES)
1425        .context("creation-receipt bound exceeds u64")?;
1426    let (retained, exact_bytes) =
1427        open_strict_external_file(path, maximum_bytes, "oracle creation receipt")?;
1428    let receipt: CompletedReceipt = parse_canonical_json(&exact_bytes, "creation receipt")?;
1429    validate_receipt_header(&receipt)?;
1430    ensure!(
1431        canonical_absolute_path(Path::new(&receipt.result_directory)),
1432        "creation receipt result path is not absolute and canonical"
1433    );
1434    let capture = VerifiedOracleReceiptCapture {
1435        retained,
1436        exact_bytes,
1437        _marker: VerifiedMarker,
1438    };
1439    capture.revalidate()?;
1440    Ok(capture)
1441}
1442
1443/// Revalidates a completed Phase-B result from its descriptor-retained receipt.
1444///
1445/// The receipt must be the exact canonical schema-2 line emitted by the oracle,
1446/// including its sole trailing newline. This API takes no caller-supplied result
1447/// path, manifest digest, summary JSON, or decision. It reads those bindings
1448/// from the receipt and descriptor-rooted sealed directory. The separate
1449/// `transport_root` argument names the original producer archive whose exact
1450/// manifest is bound by the result.
1451///
1452/// # Evidence boundary
1453///
1454/// A successful return binds the descriptor-retained receipt capture, joins
1455/// the result to the retained transport manifest, re-runs the strict native-XRT
1456/// card-identity chain, derives sample order from that transport, independently
1457/// parses every timing/summary/diagnostic record, and recomputes every job
1458/// digest and padding byte. Required-batch p95 performance is exposed only as
1459/// exact integer observations; its pre-route threshold assessment stays
1460/// internal.
1461/// The receipt is an external creation-time anchor, not a signature: its
1462/// custodian must preserve its descriptor-backed path and exact bytes. This
1463/// API does not join an accepted route seal, authenticate the external
1464/// routed-clock evidence file, prove
1465/// current card ownership, establish ledger honesty or journal nonrollback, or
1466/// prevent cross-archive replay. The final promoter must still keep a durable
1467/// global seen-set and combine the separate accepted-route evidence.
1468///
1469/// The returned guard describes historical evidence until
1470/// [`VerifiedSealedResult::revalidate`] succeeds immediately before promoter
1471/// publication.
1472///
1473/// The receipt capture is consumed and cannot be replayed into a second guard:
1474///
1475/// ```compile_fail
1476/// use std::path::Path;
1477/// use u280_evidence_oracle::{
1478///     VerifiedOracleReceiptCapture, verify_typed_sealed_result,
1479/// };
1480/// fn cannot_reuse(capture: VerifiedOracleReceiptCapture, transport: &Path) {
1481///     let _first = verify_typed_sealed_result(capture, transport);
1482///     let _second = verify_typed_sealed_result(capture, transport);
1483/// }
1484/// ```
1485///
1486/// # Errors
1487///
1488/// Returns an error for a noncanonical or mismatched receipt, any filesystem or
1489/// manifest mismatch in either archive, a noncanonical/extended result record,
1490/// an unbounded or incomplete transcript, an original-request/artifact/job
1491/// splice, inconsistent decisions, or a premature promotion flag.
1492pub fn verify_typed_sealed_result(
1493    creation_receipt: VerifiedOracleReceiptCapture,
1494    transport_root: &Path,
1495) -> Result<VerifiedSealedResult> {
1496    creation_receipt.revalidate()?;
1497    let receipt: CompletedReceipt = {
1498        let exact_bytes = creation_receipt.exact_bytes();
1499        ensure!(
1500            exact_bytes.len() <= MAXIMUM_CREATION_RECEIPT_BYTES,
1501            "creation receipt exceeds its strict size limit"
1502        );
1503        parse_canonical_json(exact_bytes, "creation receipt")?
1504    };
1505    validate_receipt_header(&receipt)?;
1506
1507    let requested_root = Path::new(&receipt.result_directory);
1508    ensure!(
1509        canonical_absolute_path(requested_root),
1510        "creation receipt result path is not absolute and canonical"
1511    );
1512    let header = open_strict_typed_result(requested_root)?;
1513    ensure!(
1514        header.root() == requested_root,
1515        "creation receipt result path is not the canonical descriptor-rooted path"
1516    );
1517    let receipt_manifest = FileRecord {
1518        bytes: receipt.manifest.bytes,
1519        sha256: receipt.manifest.sha256.clone(),
1520    };
1521    ensure!(
1522        header.manifest() == &receipt_manifest,
1523        "result manifest differs from the exact creation receipt"
1524    );
1525
1526    let summary_bytes = header.read_summary()?;
1527    let summary: SealedSummary = parse_canonical_json(&summary_bytes, "summary.json")?;
1528    let expected_jobs = validate_summary_header(&summary)?;
1529    let transcript_maximum = validate_transcript_size(header.jobs_bytes(), expected_jobs)?;
1530    let result_snapshot = header.verify_jobs(transcript_maximum)?;
1531
1532    let transport_policy = typed_transport_policy(&summary, expected_jobs)?;
1533    let transport_snapshot = verify_typed_transport_archive(transport_root, transport_policy)?;
1534    validate_transport_manifest_and_roots(&transport_snapshot, &summary)?;
1535    let transport_evidence =
1536        validate_typed_hardware_and_performance(&transport_snapshot, &summary)?;
1537    let transcript_counts =
1538        validate_transport_join(&result_snapshot, &transport_snapshot, &summary)?;
1539    let values = validate_summary_decisions(summary, &transcript_counts)?;
1540    validate_receipt_result_join(&receipt, &values)?;
1541
1542    creation_receipt.revalidate()?;
1543    result_snapshot.revalidate()?;
1544    verify_transport_archive_again_exact(&transport_snapshot)?;
1545    creation_receipt.revalidate()?;
1546    let result_directory = result_snapshot.root.clone();
1547    Ok(VerifiedSealedResult {
1548        transport_manifest: values.transport_manifest,
1549        final_hardware_identity: values.final_hardware_identity,
1550        hardware_card_identity: transport_evidence.hardware_card_identity,
1551        performance: transport_evidence.performance,
1552        run_id: values.run_id,
1553        coordination_intent: values.coordination_intent,
1554        coordination_burn: values.coordination_burn,
1555        coordination_receipt: values.coordination_receipt,
1556        samples: values.samples,
1557        jobs: values.jobs,
1558        matched_jobs: values.matched_jobs,
1559        mismatched_jobs: values.mismatched_jobs,
1560        all_padding_valid: values.all_padding_valid,
1561        cryptographic_oracle_valid: values.cryptographic_oracle_valid,
1562        requests: values.requests,
1563        result_directory,
1564        result_manifest: verified_binding(&receipt.manifest),
1565        creation_receipt,
1566        result_snapshot,
1567        transport_snapshot,
1568        _marker: VerifiedMarker,
1569    })
1570}
1571
1572fn validate_receipt_header(receipt: &CompletedReceipt) -> Result<()> {
1573    ensure!(
1574        receipt.schema == PHASE_B_ORACLE_RECEIPT_SCHEMA,
1575        "creation receipt schema must be {PHASE_B_ORACLE_RECEIPT_SCHEMA}"
1576    );
1577    ensure!(
1578        receipt.kind == RECEIPT_KIND,
1579        "creation receipt kind changed"
1580    );
1581    ensure!(
1582        receipt.result_kind == COMPLETED_RESULT_KIND,
1583        "creation receipt is not a completed comparison"
1584    );
1585    ensure!(
1586        receipt.result_schema == PHASE_B_TYPED_RESULT_SCHEMA,
1587        "creation receipt result schema must be {PHASE_B_TYPED_RESULT_SCHEMA}"
1588    );
1589    ensure!(
1590        receipt.typed_verifier_contract == PHASE_B_TYPED_RESULT_CONTRACT,
1591        "creation receipt typed-verifier contract changed"
1592    );
1593    validate_binding(&receipt.manifest, "SHA256SUMS", "creation receipt manifest")?;
1594    ensure!(
1595        receipt.structural_validation_valid,
1596        "creation receipt structural decision is false"
1597    );
1598    ensure!(
1599        !receipt.card_identity_promotable
1600            && !receipt.performance_promotable
1601            && !receipt.hardware_completion_promotable,
1602        "creation receipt makes a premature promotion claim"
1603    );
1604    ensure!(
1605        receipt.samples > 0 && receipt.samples <= MAXIMUM_RESULT_REQUESTS,
1606        "creation receipt sample count exceeds the verifier policy"
1607    );
1608    ensure!(
1609        receipt.jobs <= MAXIMUM_RESULT_JOBS,
1610        "creation receipt job count exceeds the verifier policy"
1611    );
1612    Ok(())
1613}
1614
1615fn validate_summary_header(summary: &SealedSummary) -> Result<u64> {
1616    ensure!(
1617        summary.schema == PHASE_B_TYPED_RESULT_SCHEMA,
1618        "typed result schema must be {PHASE_B_TYPED_RESULT_SCHEMA}"
1619    );
1620    ensure!(summary.kind == RESULT_KIND, "typed result kind changed");
1621    ensure!(
1622        summary.verifier_contract == PHASE_B_TYPED_RESULT_CONTRACT,
1623        "typed result verifier contract changed"
1624    );
1625    ensure!(summary.profile == PROFILE, "typed result profile changed");
1626    ensure!(
1627        summary.producer == EXPECTED_PRODUCER,
1628        "typed result producer changed"
1629    );
1630    ensure!(
1631        summary.pinned_hashsigs_rs_commit == EXPECTED_PINNED_COMMIT,
1632        "typed result HashSigsRS pin changed"
1633    );
1634    validate_binding(
1635        &summary.transport_manifest,
1636        "SHA256SUMS",
1637        "transport manifest",
1638    )?;
1639    validate_binding(
1640        &summary.coordination_intent,
1641        "coordination-intent.json",
1642        "coordination intent",
1643    )?;
1644    validate_binding(
1645        &summary.coordination_burn,
1646        "coordination-burn.json",
1647        "coordination burn",
1648    )?;
1649    validate_binding(
1650        &summary.coordination_receipt,
1651        "coordination-receipt.json",
1652        "coordination receipt",
1653    )?;
1654    validate_binding(
1655        &summary.final_hardware_identity,
1656        "hardware-identity.json",
1657        "final hardware identity",
1658    )?;
1659    ensure!(
1660        is_nonzero_lower_hex(&summary.run_id, 32),
1661        "typed result run id is not canonical"
1662    );
1663    ensure!(
1664        (1..=256).contains(&summary.worker_threads),
1665        "typed result worker count is invalid"
1666    );
1667    ensure!(
1668        summary.sample_count > 0
1669            && summary.sample_count <= MAXIMUM_RESULT_REQUESTS
1670            && summary.sample_count == summary.requests.len(),
1671        "typed result sample count differs from its bounded complete request set"
1672    );
1673    ensure!(
1674        !summary.card_identity_promotable
1675            && !summary.performance_promotable
1676            && !summary.hardware_completion_promotable,
1677        "typed result makes a premature promotion claim"
1678    );
1679    ensure!(
1680        summary.evidence_boundary == RESULT_EVIDENCE_BOUNDARY,
1681        "typed result evidence boundary changed"
1682    );
1683
1684    let mut expected_jobs = 0_u64;
1685    let mut seen_samples = HashSet::new();
1686    let mut seen_requests = HashSet::new();
1687    let mut seen_nonces = HashSet::new();
1688    let mut seen_reservations = HashSet::new();
1689    for request in &summary.requests {
1690        validate_request_shape(request, summary)?;
1691        ensure!(
1692            seen_samples.insert(request.sample.as_str()),
1693            "typed result repeats a request sample"
1694        );
1695        ensure!(
1696            seen_requests.insert(request.request_sha256.as_str())
1697                && seen_nonces.insert(request.nonce_hex.as_str())
1698                && seen_reservations.insert(request.reservation_record_sha256.as_str()),
1699            "typed result repeats a request, nonce, or reservation"
1700        );
1701        ensure!(
1702            request.jobs == request.batch,
1703            "request job count differs from its batch"
1704        );
1705        expected_jobs = expected_jobs
1706            .checked_add(u64::from(request.jobs))
1707            .context("typed result total job count overflow")?;
1708    }
1709    ensure!(
1710        expected_jobs == summary.total_jobs,
1711        "typed result total jobs differ from its complete request set"
1712    );
1713    ensure!(
1714        expected_jobs <= MAXIMUM_RESULT_JOBS,
1715        "typed result job count exceeds the verifier policy"
1716    );
1717    Ok(expected_jobs)
1718}
1719
1720fn validate_transcript_size(bytes: u64, expected_jobs: u64) -> Result<u64> {
1721    if expected_jobs == 0 {
1722        ensure!(bytes == 0, "zero-job result has a nonempty transcript");
1723        return Ok(0);
1724    }
1725    let schema_maximum = expected_jobs
1726        .checked_mul(u64::try_from(MAXIMUM_JOB_LINE_BYTES).expect("line limit fits u64"))
1727        .context("job transcript schema bound overflow")?;
1728    let schema_minimum = expected_jobs
1729        .checked_mul(MINIMUM_JOB_LINE_BYTES)
1730        .context("job transcript minimum bound overflow")?;
1731    ensure!(
1732        bytes >= schema_minimum,
1733        "job transcript is too small for its schema-derived job count"
1734    );
1735    ensure!(
1736        bytes <= schema_maximum && bytes <= MAXIMUM_JOB_TRANSCRIPT_BYTES,
1737        "job transcript exceeds its schema-derived or absolute byte policy"
1738    );
1739    Ok(schema_maximum.min(MAXIMUM_JOB_TRANSCRIPT_BYTES))
1740}
1741
1742fn typed_transport_policy(
1743    summary: &SealedSummary,
1744    expected_jobs: u64,
1745) -> Result<TypedTransportPolicy> {
1746    ensure!(
1747        expected_jobs == summary.total_jobs,
1748        "typed transport policy job count changed"
1749    );
1750    let mut files = BTreeMap::new();
1751    let mut directories = BTreeSet::from(["samples".to_owned()]);
1752    for (path, maximum) in [
1753        ("coordination-burn.json", 64 * 1024),
1754        ("coordination-intent.json", 64 * 1024),
1755        ("coordination-receipt.json", 64 * 1024),
1756        ("hardware-identity-pre-run.json", 16 * 1024 * 1024),
1757        ("hardware-identity.json", 16 * 1024 * 1024),
1758        ("results.json", 16 * 1024 * 1024),
1759        ("run-metadata.json", 16 * 1024 * 1024),
1760        ("xrt-host.json", 64 * 1024),
1761        ("xrt-platform-post-run.json", 4 * 1024 * 1024),
1762        ("xrt-platform-pre-load.json", 4 * 1024 * 1024),
1763    ] {
1764        files.insert(path.to_owned(), maximum);
1765    }
1766
1767    let mut artifact_bytes = 0_u64;
1768    for request in &summary.requests {
1769        let (batch_directory, _) = request
1770            .sample
1771            .rsplit_once('/')
1772            .context("typed result sample path has no batch directory")?;
1773        directories.insert(batch_directory.to_owned());
1774        directories.insert(request.sample.clone());
1775        for (file, maximum) in [
1776            ("diagnostics.json", TYPED_TRANSPORT_SAMPLE_JSON_BYTES),
1777            ("input.bin", request.input.stored_bytes),
1778            ("oracle-request.json", TYPED_TRANSPORT_SAMPLE_JSON_BYTES),
1779            ("oracle-request.sha256", 256),
1780            ("output.bin", request.output.stored_bytes),
1781            ("reservation.json", TYPED_TRANSPORT_SAMPLE_JSON_BYTES),
1782            ("summary-decoded.json", TYPED_TRANSPORT_SAMPLE_JSON_BYTES),
1783            ("summary.bin", SUMMARY_BYTES),
1784            ("timing.json", TYPED_TRANSPORT_SAMPLE_JSON_BYTES),
1785            ("transport.json", TYPED_TRANSPORT_SAMPLE_JSON_BYTES),
1786            ("validation.json", TYPED_TRANSPORT_SAMPLE_JSON_BYTES),
1787        ] {
1788            let path = format!("{}/{file}", request.sample);
1789            ensure!(
1790                files.insert(path, maximum).is_none(),
1791                "typed transport policy repeats a sample file"
1792            );
1793        }
1794        artifact_bytes = artifact_bytes
1795            .checked_add(request.input.stored_bytes)
1796            .and_then(|bytes| bytes.checked_add(request.output.stored_bytes))
1797            .and_then(|bytes| bytes.checked_add(SUMMARY_BYTES))
1798            .context("typed transport artifact budget overflow")?;
1799    }
1800    let metadata_budget = u64::try_from(summary.sample_count)
1801        .context("typed transport sample count exceeds u64")?
1802        .checked_mul(TYPED_TRANSPORT_SAMPLE_METADATA_BUDGET)
1803        .context("typed transport metadata budget overflow")?;
1804    let maximum_total_bytes = TYPED_TRANSPORT_ROOT_BUDGET
1805        .checked_add(artifact_bytes)
1806        .and_then(|bytes| bytes.checked_add(metadata_budget))
1807        .context("typed transport aggregate policy overflow")?;
1808    Ok(TypedTransportPolicy {
1809        files,
1810        directories,
1811        maximum_total_bytes,
1812    })
1813}
1814
1815fn validate_transport_manifest_and_roots(
1816    transport: &ArchiveSnapshot,
1817    summary: &SealedSummary,
1818) -> Result<()> {
1819    ensure!(
1820        summary.transport_manifest.file == "SHA256SUMS"
1821            && summary.transport_manifest.bytes == transport.manifest.bytes
1822            && summary.transport_manifest.sha256 == transport.manifest.sha256,
1823        "typed result transport manifest differs from the original transport"
1824    );
1825    for (binding, path, label) in [
1826        (
1827            &summary.coordination_intent,
1828            "coordination-intent.json",
1829            "coordination intent",
1830        ),
1831        (
1832            &summary.coordination_burn,
1833            "coordination-burn.json",
1834            "coordination burn",
1835        ),
1836        (
1837            &summary.coordination_receipt,
1838            "coordination-receipt.json",
1839            "coordination receipt",
1840        ),
1841        (
1842            &summary.final_hardware_identity,
1843            "hardware-identity.json",
1844            "final hardware identity",
1845        ),
1846    ] {
1847        let record = transport
1848            .files
1849            .get(path)
1850            .with_context(|| format!("transport manifest omits {path}"))?;
1851        ensure!(
1852            binding.file == path
1853                && binding.bytes == record.bytes
1854                && binding.sha256 == record.sha256,
1855            "typed result {label} differs from the original transport"
1856        );
1857    }
1858    Ok(())
1859}
1860
1861fn validate_typed_hardware_and_performance(
1862    transport: &ArchiveSnapshot,
1863    summary: &SealedSummary,
1864) -> Result<VerifiedTransportEvidence> {
1865    // Re-run the original oracle's complete coordination, native-XRT identity,
1866    // and results-envelope validation over the retained transport descriptors.
1867    // The typed result summary is not trusted as a substitute for these files.
1868    let coordination = validate_coordination_records(transport)?;
1869    let metadata: RunMetadata = parse_typed_transport_json(transport, "run-metadata.json")?;
1870    validate_run_metadata(&metadata, &coordination)?;
1871    ensure!(
1872        metadata.run_id == summary.run_id,
1873        "strict hardware/performance revalidation crossed coordination runs"
1874    );
1875    let hardware = validate_hardware_identity(transport, &metadata)?;
1876    validate_coordination_hardware(&coordination, &hardware)?;
1877    let results: ResultsEnvelope = parse_typed_transport_json(transport, "results.json")?;
1878    validate_results(&results, &metadata, &hardware.final_record, &coordination)?;
1879
1880    // Parse every launch again through the original strict request, timing,
1881    // diagnostics, summary, and reservation validators. Only measured samples
1882    // feed percentile arithmetic, but warmups and controls must also validate.
1883    // expected_layout fixes every unique batch/phase/index path from metadata,
1884    // while validate_results fixes each measured count to that same metadata;
1885    // the population cannot be padded with arbitrary duplicate samples.
1886    let samples = expected_layout(transport, &metadata)?;
1887    ensure!(
1888        samples.len() == summary.requests.len(),
1889        "strict hardware/performance sample set differs from the typed result"
1890    );
1891    let mut validation_state = SampleValidationState {
1892        metadata: &metadata,
1893        pre_run_identity_record: &hardware.pre_run_record,
1894        coordination: &coordination,
1895        reservation_ids: HashSet::new(),
1896        nonces: HashSet::new(),
1897        reservation_chain: None,
1898    };
1899    let mut measured_metrics = Vec::new();
1900    let mut observations = Vec::with_capacity(samples.len());
1901    for sample in &samples {
1902        let validated = validate_sample_contract(transport, sample, &mut validation_state)?;
1903        let metrics = validated.metrics;
1904        ensure!(
1905            metrics.batch == sample.batch,
1906            "strict sample metrics changed batch identity"
1907        );
1908        if sample.phase == "measured" {
1909            measured_metrics.push(metrics);
1910        }
1911        observations.push(VerifiedPerformanceSample {
1912            sample: sample.relative.clone(),
1913            phase: sample.phase.to_owned(),
1914            sample_index: sample.index,
1915            batch: sample.batch,
1916            capture_core_interval_cycles: metrics.capture_span,
1917            memory_retirement_interval_cycles: metrics.memory_span,
1918            whole_kernel_nanoseconds: metrics.kernel_nanoseconds,
1919            _marker: VerifiedMarker,
1920        });
1921    }
1922    // This preserves compatibility with the producer's human-readable float
1923    // report. It is only a sealed-record consistency check: the typed proof's
1924    // pass/fail observations below use the raw integer numerators exclusively.
1925    validate_results_statistics(&results, &metadata, &measured_metrics)?;
1926
1927    Ok(VerifiedTransportEvidence {
1928        hardware_card_identity: verified_hardware_card_identity(&hardware),
1929        performance: verified_performance_observations(&metadata, observations)?,
1930    })
1931}
1932
1933fn verified_hardware_card_identity(
1934    hardware: &super::ValidatedHardwareIdentity,
1935) -> VerifiedHardwareCardIdentity {
1936    let identity = &hardware.pre_run;
1937    VerifiedHardwareCardIdentity {
1938        device_index: identity.device.index,
1939        bdf: identity.device.bdf.clone(),
1940        device_name: identity.device.name.clone(),
1941        xmc_serial_number: identity.platform.xmc_serial_number.clone(),
1942        shell_vbnv: identity.platform.shell_vbnv.clone(),
1943        logic_uuid: identity.platform.logic_uuid.clone(),
1944        interface_uuid: identity.device.interface_uuid.clone(),
1945        fpga_part: identity.platform.fpga_part.clone(),
1946        xrt_build: VerifiedXrtBuildIdentity {
1947            version: identity.xrt_build.version.clone(),
1948            branch: identity.xrt_build.branch.clone(),
1949            hash: identity.xrt_build.hash.clone(),
1950            build_date: identity.xrt_build.build_date.clone(),
1951            _marker: VerifiedMarker,
1952        },
1953        xclbin: VerifiedHardwareXclbinIdentity {
1954            path: identity.xclbin.path.clone(),
1955            bytes: identity.xclbin.digest.bytes,
1956            sha256: identity.xclbin.digest.sha256.clone(),
1957            uuid: identity.xclbin.uuid.clone(),
1958            interface_uuid: identity.xclbin.interface_uuid.clone(),
1959            deployment_platform: identity.xclbin.xsa_name.clone(),
1960            fpga_part: identity.xclbin.fpga_part.clone(),
1961            target: identity.xclbin.target.clone(),
1962            _marker: VerifiedMarker,
1963        },
1964        _marker: VerifiedMarker,
1965    }
1966}
1967
1968fn verified_clock_observation(metadata: &RunMetadata) -> VerifiedClockObservation {
1969    let routed_clock_evidence = metadata
1970        .clock
1971        .routed_clock_evidence
1972        .as_ref()
1973        .map(|evidence| VerifiedRoutedClockEvidenceBinding {
1974            path: evidence.path.clone(),
1975            bytes: evidence.digest.bytes,
1976            sha256: evidence.digest.sha256.clone(),
1977            _marker: VerifiedMarker,
1978        });
1979    VerifiedClockObservation {
1980        requested_clock_hz_metadata: metadata.clock.requested_clock_hz_metadata,
1981        declared_routed_hz: metadata.clock.routed_clock_hz,
1982        routed_clock_evidence,
1983        supports_hardware_rate_claim: metadata.clock.supports_hardware_rate_claim,
1984        _marker: VerifiedMarker,
1985    }
1986}
1987
1988fn verified_performance_observations(
1989    metadata: &RunMetadata,
1990    samples: Vec<VerifiedPerformanceSample>,
1991) -> Result<VerifiedPerformanceObservations> {
1992    let decision = exact_performance_decision(
1993        metadata.batches.contains(&REQUIRED_PERFORMANCE_BATCH),
1994        &samples,
1995    )?;
1996    let observations = VerifiedPerformanceObservations {
1997        required_batch: REQUIRED_PERFORMANCE_BATCH,
1998        minimum_measured_samples: REQUIRED_PERFORMANCE_SAMPLES,
1999        required_batch_requested: decision.required_batch_requested,
2000        observed_measured_samples: decision.observed_measured_samples,
2001        p95_rank: decision.p95_rank,
2002        p95_capture_interval_cycles: decision.p95_capture_interval_cycles,
2003        capture_results_denominator: REQUIRED_PERFORMANCE_BATCH - 1,
2004        p95_whole_kernel_nanoseconds: decision.p95_whole_kernel_nanoseconds,
2005        whole_kernel_results_denominator: REQUIRED_PERFORMANCE_BATCH,
2006        clock: verified_clock_observation(metadata),
2007        samples,
2008        _marker: VerifiedMarker,
2009    };
2010    // This provisional comparison is intentionally consumed only inside the
2011    // typed verifier. Public callers receive the exact observations; a later
2012    // route combiner must independently join accepted route evidence before it
2013    // can make a performance or hardware-completion claim.
2014    let _pre_route_only = observations.pre_route_join_performance_thresholds_met();
2015    Ok(observations)
2016}
2017
2018fn exact_performance_decision(
2019    required_batch_requested: bool,
2020    samples: &[VerifiedPerformanceSample],
2021) -> Result<ExactPerformanceDecision> {
2022    let measured = samples
2023        .iter()
2024        .filter(|sample| sample.is_required_performance_population())
2025        .collect::<Vec<_>>();
2026    ensure!(
2027        measured.len() <= MAXIMUM_TYPED_PERFORMANCE_SAMPLES,
2028        "typed performance population exceeds its strict memory bound"
2029    );
2030    ensure!(
2031        measured.iter().all(|sample| {
2032            sample.capture_core_interval_cycles > 0 && sample.whole_kernel_nanoseconds > 0
2033        }),
2034        "typed performance population contains a zero raw cost"
2035    );
2036    let capture = measured
2037        .iter()
2038        .map(|sample| sample.capture_core_interval_cycles)
2039        .collect::<Vec<_>>();
2040    let whole = measured
2041        .iter()
2042        .map(|sample| sample.whole_kernel_nanoseconds)
2043        .collect::<Vec<_>>();
2044    let (p95_rank, p95_capture_interval_cycles) = exact_nearest_rank_p95(capture)?;
2045    let (_, p95_whole_kernel_nanoseconds) = exact_nearest_rank_p95(whole)?;
2046    let observed_measured_samples = measured.len();
2047
2048    Ok(ExactPerformanceDecision {
2049        required_batch_requested,
2050        observed_measured_samples,
2051        p95_rank,
2052        p95_capture_interval_cycles,
2053        p95_whole_kernel_nanoseconds,
2054    })
2055}
2056
2057fn exact_capture_cycles_threshold_met(p95_capture_interval_cycles: Option<u64>) -> bool {
2058    let capture_denominator = u128::from(REQUIRED_PERFORMANCE_BATCH - 1);
2059    p95_capture_interval_cycles.is_some_and(|cycles| {
2060        u128::from(cycles) <= u128::from(MAXIMUM_P95_CAPTURE_CYCLES_EXACT) * capture_denominator
2061    })
2062}
2063
2064fn exact_capture_rate_threshold_met(
2065    clock_hz: u64,
2066    p95_capture_interval_cycles: Option<u64>,
2067) -> bool {
2068    let capture_denominator = u128::from(REQUIRED_PERFORMANCE_BATCH - 1);
2069    let minimum_rate = u128::from(MINIMUM_SIGNATURES_PER_SECOND_EXACT);
2070    p95_capture_interval_cycles.is_some_and(|cycles| {
2071        u128::from(clock_hz) * capture_denominator >= minimum_rate * u128::from(cycles)
2072    })
2073}
2074
2075fn exact_whole_kernel_rate_threshold_met(p95_whole_kernel_nanoseconds: Option<u64>) -> bool {
2076    let whole_denominator = u128::from(REQUIRED_PERFORMANCE_BATCH);
2077    let minimum_rate = u128::from(MINIMUM_SIGNATURES_PER_SECOND_EXACT);
2078    p95_whole_kernel_nanoseconds.is_some_and(|nanoseconds| {
2079        1_000_000_000_u128 * whole_denominator >= minimum_rate * u128::from(nanoseconds)
2080    })
2081}
2082
2083fn exact_nearest_rank_p95(mut values: Vec<u64>) -> Result<(Option<usize>, Option<u64>)> {
2084    if values.is_empty() {
2085        return Ok((None, None));
2086    }
2087    ensure!(
2088        values.len() <= MAXIMUM_TYPED_PERFORMANCE_SAMPLES,
2089        "typed p95 population exceeds its strict memory bound"
2090    );
2091    values.sort_unstable();
2092    let rank = values
2093        .len()
2094        .checked_mul(95)
2095        .context("typed p95 rank overflow")?
2096        .div_ceil(100);
2097    let value = values
2098        .get(rank.checked_sub(1).context("typed p95 rank underflow")?)
2099        .copied()
2100        .context("typed p95 rank exceeds its population")?;
2101    Ok((Some(rank), Some(value)))
2102}
2103
2104struct TranscriptReader<'a> {
2105    file: &'a StrictResultFile,
2106    offset: u64,
2107}
2108
2109impl<'a> TranscriptReader<'a> {
2110    fn new(file: &'a StrictResultFile) -> Self {
2111        Self { file, offset: 0 }
2112    }
2113
2114    fn next_line(&mut self) -> Result<Option<Vec<u8>>> {
2115        if self.offset == self.file.bytes() {
2116            return Ok(None);
2117        }
2118        let mut line = Vec::new();
2119        while self.offset < self.file.bytes() {
2120            let remaining = self.file.bytes() - self.offset;
2121            let capacity = MAXIMUM_JOB_LINE_BYTES
2122                .checked_add(1)
2123                .and_then(|limit| limit.checked_sub(line.len()))
2124                .context("job transcript line length overflow")?;
2125            ensure!(
2126                capacity > 0,
2127                "job transcript line exceeds its strict size limit"
2128            );
2129            let amount = usize::try_from(
2130                remaining
2131                    .min(u64::try_from(capacity).expect("line capacity fits u64"))
2132                    .min(u64::try_from(JOB_READ_BUFFER_BYTES).expect("buffer size fits u64")),
2133            )
2134            .expect("bounded transcript read fits usize");
2135            let mut chunk = vec![0_u8; amount];
2136            self.file.read_exact_at(&mut chunk, self.offset)?;
2137            if let Some(position) = chunk.iter().position(|byte| *byte == b'\n') {
2138                let used = position + 1;
2139                line.extend_from_slice(&chunk[..used]);
2140                self.offset = self
2141                    .offset
2142                    .checked_add(u64::try_from(used).expect("line length fits u64"))
2143                    .context("job transcript offset overflow")?;
2144                ensure!(
2145                    line.len() <= MAXIMUM_JOB_LINE_BYTES,
2146                    "job transcript line exceeds its strict size limit"
2147                );
2148                return Ok(Some(line));
2149            }
2150            line.extend_from_slice(&chunk);
2151            self.offset = self
2152                .offset
2153                .checked_add(u64::try_from(amount).expect("chunk length fits u64"))
2154                .context("job transcript offset overflow")?;
2155            ensure!(
2156                line.len() <= MAXIMUM_JOB_LINE_BYTES,
2157                "job transcript line exceeds its strict size limit"
2158            );
2159        }
2160        bail!("job transcript has a truncated final line")
2161    }
2162}
2163
2164fn parse_typed_transport_json<T>(transport: &ArchiveSnapshot, path: &str) -> Result<T>
2165where
2166    T: serde::de::DeserializeOwned,
2167{
2168    let maximum = transport
2169        .files
2170        .get(path)
2171        .with_context(|| format!("typed transport manifest omits {path}"))?
2172        .bytes;
2173    let bytes = read_verified_small_exact(transport, path, maximum)?;
2174    parse_strict_json(&bytes, path)
2175}
2176
2177// Keep the fail-closed cross-artifact join linear so validation order and
2178// descriptor finalization remain directly auditable.
2179#[allow(clippy::too_many_lines)]
2180fn validate_transport_join(
2181    result: &StrictResultSnapshot,
2182    transport: &ArchiveSnapshot,
2183    summary: &SealedSummary,
2184) -> Result<Vec<TranscriptCount>> {
2185    let metadata: RunMetadata = parse_typed_transport_json(transport, "run-metadata.json")?;
2186    validate_transport_metadata_shape(&metadata, summary)?;
2187    let samples = expected_layout(transport, &metadata)?;
2188    ensure!(
2189        samples.len() == summary.requests.len(),
2190        "transport sample set differs from the typed result request set"
2191    );
2192    let jobs_file = result.file("jobs.jsonl")?;
2193    let mut transcript = TranscriptReader::new(jobs_file);
2194    let mut unique_private_seeds = HashSet::new();
2195    let mut reservation_ids = HashSet::new();
2196    let mut reservation_nonces = HashSet::new();
2197    let mut reservation_chain = None;
2198    let mut counts = Vec::with_capacity(samples.len());
2199    let oracle = Sha256GenericWots::new();
2200
2201    for (sample, sealed) in samples.iter().zip(&summary.requests) {
2202        ensure!(
2203            sealed.sample == sample.relative
2204                && sealed.batch == sample.batch
2205                && sealed.phase == sample.phase
2206                && sealed.sample_index == sample.index,
2207            "typed result sample order or identity differs from the retained transport"
2208        );
2209        let request_path = format!("{}/oracle-request.json", sample.relative);
2210        let request_bytes =
2211            read_verified_small_exact(transport, &request_path, TYPED_TRANSPORT_SAMPLE_JSON_BYTES)?;
2212        let request_sha256 = sha256_bytes(&request_bytes);
2213        ensure!(
2214            request_sha256 == sealed.request_sha256,
2215            "typed result request digest differs from the retained transport"
2216        );
2217        let request: OracleRequest = parse_strict_json(&request_bytes, &request_path)?;
2218        validate_transport_request(transport, &metadata, sample, sealed, &request)?;
2219        let sidecar_path = format!("{}/oracle-request.sha256", sample.relative);
2220        let sidecar = read_verified_small_exact(transport, &sidecar_path, 256)?;
2221        ensure!(
2222            sidecar == format!("{request_sha256}  oracle-request.json\n").as_bytes(),
2223            "transport oracle-request sidecar differs from the exact request"
2224        );
2225        let reservation_path = format!("{}/reservation.json", sample.relative);
2226        let reservation_bytes = read_verified_small_exact(
2227            transport,
2228            &reservation_path,
2229            TYPED_TRANSPORT_SAMPLE_JSON_BYTES,
2230        )?;
2231        let reservation: ReservationReceipt =
2232            parse_strict_json(&reservation_bytes, &reservation_path)?;
2233        validate_reservation(&reservation, &reservation_bytes, &request)?;
2234        advance_reservation_chain(&mut reservation_chain, &reservation)?;
2235        ensure!(
2236            reservation_ids.insert(reservation.reservation_id)
2237                && reservation_nonces.insert(reservation.nonce),
2238            "retained transport repeats a reservation identity or nonce"
2239        );
2240        let transport_contract_path = format!("{}/transport.json", sample.relative);
2241        let transport_contract: TransportContract =
2242            parse_typed_transport_json(transport, &transport_contract_path)?;
2243        validate_transport_contract(&transport_contract, &request)?;
2244
2245        let input_path = format!("{}/input.bin", sample.relative);
2246        let output_path = format!("{}/output.bin", sample.relative);
2247        let input = open_verified_file_exact(transport, &input_path)?;
2248        let output = open_verified_file_exact(transport, &output_path)?;
2249        let mut count = TranscriptCount {
2250            jobs: 0,
2251            matched_jobs: 0,
2252            padding_valid: true,
2253        };
2254        if sample.batch == 0 {
2255            let mut sentinel = [0_u8; OUTPUT_SLOT_BYTES_USIZE];
2256            output.read_exact_at(&mut sentinel, 0)?;
2257            count.padding_valid = sentinel.iter().enumerate().all(|(offset, byte)| {
2258                *byte == output_poison(u64::try_from(offset).expect("slot offset fits u64"))
2259            });
2260        }
2261        for job_index in 0..sample.batch {
2262            let line = transcript
2263                .next_line()?
2264                .context("job transcript omits one or more transport-owned jobs")?;
2265            let job: SealedJob = parse_canonical_json(&line, "jobs.jsonl line")?;
2266            ensure!(
2267                job.schema == 1 && job.sample == sample.relative && job.job_index == job_index,
2268                "job transcript is missing, duplicated, reordered, or relabeled"
2269            );
2270            for (digest, label) in [
2271                (&job.input_sha256, "job input"),
2272                (&job.expected_sha256, "job expected payload"),
2273                (&job.observed_sha256, "job observed payload"),
2274            ] {
2275                ensure!(
2276                    is_nonzero_lower_hex(digest, 64),
2277                    "{label} SHA-256 is not canonical"
2278                );
2279            }
2280            let computation = recompute_transport_job(
2281                oracle,
2282                &input,
2283                &output,
2284                job_index,
2285                &mut unique_private_seeds,
2286            )?;
2287            ensure!(
2288                job.input_sha256 == computation.input_sha256,
2289                "job input digest differs from retained transport input bytes"
2290            );
2291            ensure!(
2292                job.expected_sha256 == computation.expected_sha256,
2293                "job expected digest differs from independent WOTS recomputation"
2294            );
2295            ensure!(
2296                job.observed_sha256 == computation.observed_sha256,
2297                "job observed digest differs from retained transport output bytes"
2298            );
2299            ensure!(
2300                job.r#match == computation.payload_match
2301                    && job.r#match == (job.expected_sha256 == job.observed_sha256),
2302                "job match decision differs from independent transport evidence"
2303            );
2304            count.jobs = count.jobs.checked_add(1).context("job count overflow")?;
2305            if computation.payload_match {
2306                count.matched_jobs = count
2307                    .matched_jobs
2308                    .checked_add(1)
2309                    .context("matched job count overflow")?;
2310            }
2311            count.padding_valid &= computation.padding_valid;
2312        }
2313        input.finish()?;
2314        output.finish()?;
2315        counts.push(count);
2316    }
2317    ensure!(
2318        transcript.next_line()?.is_none(),
2319        "job transcript contains an extra transport-unowned job"
2320    );
2321    jobs_file.finish()?;
2322    Ok(counts)
2323}
2324
2325fn validate_transport_metadata_shape(
2326    metadata: &RunMetadata,
2327    summary: &SealedSummary,
2328) -> Result<()> {
2329    ensure!(
2330        metadata.schema == 2,
2331        "transport run metadata schema must be 2"
2332    );
2333    ensure!(
2334        metadata.runner == "phase_b_hbm",
2335        "transport is not a Phase-B HBM run"
2336    );
2337    ensure!(
2338        metadata.kernel_name == DEFAULT_KERNEL
2339            && metadata.measured_runs_per_batch > 0
2340            && metadata.cryptographic_control == "Rust/RHDL kernel only"
2341            && metadata.output_oracle == "external Rust oracle required",
2342        "transport metadata execution/oracle contract changed"
2343    );
2344    ensure!(
2345        metadata.run_id == summary.run_id,
2346        "transport metadata and typed result name different runs"
2347    );
2348    ensure!(
2349        root_binding_matches(&metadata.coordination_intent, &summary.coordination_intent)
2350            && root_binding_matches(&metadata.coordination_burn, &summary.coordination_burn)
2351            && root_binding_matches(
2352                &metadata.coordination_receipt,
2353                &summary.coordination_receipt,
2354            ),
2355        "transport metadata coordination roots differ from the typed result"
2356    );
2357    ensure!(
2358        !metadata.batches.is_empty() && metadata.batches.len() <= MAXIMUM_RESULT_REQUESTS,
2359        "transport batch set exceeds the typed verifier policy"
2360    );
2361    let samples_per_batch = metadata
2362        .warmups_per_batch
2363        .checked_add(metadata.measured_runs_per_batch)
2364        .context("transport samples-per-batch overflow")?;
2365    let sample_count = metadata
2366        .batches
2367        .len()
2368        .checked_mul(samples_per_batch)
2369        .context("transport sample count overflow")?;
2370    ensure!(
2371        sample_count > 0
2372            && sample_count <= MAXIMUM_RESULT_REQUESTS
2373            && sample_count == summary.sample_count,
2374        "transport-derived sample count differs from the bounded typed result"
2375    );
2376    let mut batches = HashSet::new();
2377    for batch in &metadata.batches {
2378        ensure!(
2379            *batch <= MAXIMUM_BATCH && batches.insert(*batch),
2380            "transport metadata has an invalid or repeated batch"
2381        );
2382    }
2383    Ok(())
2384}
2385
2386// This linear validation mirrors the canonical request contract and preserves
2387// the audit-visible order of its fail-closed checks.
2388#[allow(clippy::too_many_lines)]
2389fn validate_transport_request(
2390    transport: &ArchiveSnapshot,
2391    metadata: &RunMetadata,
2392    sample: &SampleSpec,
2393    sealed: &SealedRequest,
2394    request: &OracleRequest,
2395) -> Result<()> {
2396    ensure!(
2397        request.schema == 2,
2398        "transport oracle request schema must be 2"
2399    );
2400    ensure!(
2401        request.kind == REQUEST_KIND,
2402        "transport oracle request kind changed"
2403    );
2404    ensure!(
2405        request.profile == PROFILE,
2406        "transport oracle request profile changed"
2407    );
2408    ensure!(
2409        request.run_id == sealed.run_id && request.run_id == metadata.run_id,
2410        "typed result request differs from the transport coordination run"
2411    );
2412    ensure!(
2413        root_binding_matches(&request.coordination_intent, &sealed.coordination_intent)
2414            && root_binding_matches(&request.coordination_burn, &sealed.coordination_burn)
2415            && root_binding_matches(&request.coordination_receipt, &sealed.coordination_receipt,),
2416        "typed result request coordination roots differ from the original request"
2417    );
2418    ensure!(
2419        request.batch == sample.batch && request.batch == sealed.batch,
2420        "typed result request batch differs from the transport-owned sample"
2421    );
2422    ensure!(
2423        is_lower_hex(&request.nonce_hex, 16)
2424            && u64::from_str_radix(&request.nonce_hex, 16)? == request.nonce_u64
2425            && request.nonce_hex == sealed.nonce_hex,
2426        "typed result nonce differs from the original request"
2427    );
2428    ensure!(
2429        request.reservation_record_sha256 == sealed.reservation_record_sha256,
2430        "typed result reservation digest differs from the original request"
2431    );
2432    ensure!(
2433        request.xclbin.path == sealed.xclbin.path
2434            && request.xclbin.bytes == sealed.xclbin.bytes
2435            && request.xclbin.sha256 == sealed.xclbin.sha256
2436            && request.xclbin.path == metadata.xclbin.path
2437            && request.xclbin.bytes == metadata.xclbin.digest.bytes
2438            && request.xclbin.sha256 == metadata.xclbin.digest.sha256,
2439        "typed result xclbin differs from the transport request or metadata"
2440    );
2441    ensure!(
2442        request.clock == metadata.clock,
2443        "transport request clock binding differs from run metadata"
2444    );
2445    ensure!(
2446        root_binding_matches(
2447            &request.hardware_identity_pre_run,
2448            &sealed.hardware_identity_pre_run,
2449        ),
2450        "typed result pre-run identity differs from the original request"
2451    );
2452    let pre_run_record = transport
2453        .files
2454        .get("hardware-identity-pre-run.json")
2455        .context("transport manifest omits hardware-identity-pre-run.json")?;
2456    ensure!(
2457        request.hardware_identity_pre_run.archive_root_file == "hardware-identity-pre-run.json"
2458            && request.hardware_identity_pre_run.bytes == pre_run_record.bytes
2459            && request.hardware_identity_pre_run.sha256 == pre_run_record.sha256,
2460        "original request pre-run identity differs from the transport manifest"
2461    );
2462
2463    let logical_input = u64::from(sample.batch)
2464        .checked_mul(INPUT_BYTES_PER_JOB)
2465        .context("transport input geometry overflow")?;
2466    let logical_output = u64::from(sample.batch)
2467        .checked_mul(OUTPUT_SLOT_BYTES)
2468        .context("transport output geometry overflow")?;
2469    let stored_output = if sample.batch == 0 {
2470        OUTPUT_SLOT_BYTES
2471    } else {
2472        logical_output
2473    };
2474    validate_transport_artifact_join(
2475        transport,
2476        sample,
2477        &request.artifacts.input,
2478        &sealed.input,
2479        "input.bin",
2480        logical_input,
2481    )?;
2482    validate_transport_artifact_join(
2483        transport,
2484        sample,
2485        &request.artifacts.full_output_allocation,
2486        &sealed.output,
2487        "output.bin",
2488        stored_output,
2489    )?;
2490    validate_transport_request_artifact(
2491        transport,
2492        sample,
2493        &request.artifacts.summary,
2494        "summary.bin",
2495        SUMMARY_BYTES,
2496    )?;
2497    for (artifact, file) in [
2498        (&request.artifacts.diagnostic_registers, "diagnostics.json"),
2499        (
2500            &request.artifacts.untimed_transport_validation,
2501            "validation.json",
2502        ),
2503        (&request.artifacts.timing, "timing.json"),
2504        (&request.artifacts.transport_contract, "transport.json"),
2505    ] {
2506        let path = format!("{}/{file}", sample.relative);
2507        let bytes = transport
2508            .files
2509            .get(&path)
2510            .with_context(|| format!("transport manifest omits {path}"))?
2511            .bytes;
2512        validate_transport_request_artifact(transport, sample, artifact, file, bytes)?;
2513    }
2514    ensure!(
2515        request.output_contract.slot_bytes == OUTPUT_SLOT_BYTES
2516            && request.output_contract.valid_bytes_per_job == OUTPUT_VALID_BYTES
2517            && request.output_contract.padding_bytes_per_job == OUTPUT_PADDING_BYTES
2518            && request.output_contract.requested_output_slot_bytes == logical_output
2519            && request.output_contract.full_output_allocation_bytes == stored_output,
2520        "transport request output contract has the wrong geometry"
2521    );
2522    ensure!(
2523        request.cryptographic_oracle_valid.is_none() && !request.hardware_completion_promotable,
2524        "transport request contains a premature oracle or promotion decision"
2525    );
2526    let must_bind = request
2527        .required_oracle_result
2528        .must_bind
2529        .iter()
2530        .map(String::as_str)
2531        .collect::<Vec<_>>();
2532    ensure!(
2533        request.required_oracle_result.producer == "independent Rust oracle"
2534            && must_bind.len() == 7
2535            && must_bind[0] == "oracle-request.json sha256"
2536            && must_bind[1] == "coordination-intent.json sha256"
2537            && must_bind[2] == "coordination-burn.json sha256"
2538            && must_bind[3] == "coordination-receipt.json sha256"
2539            && must_bind[4] == "hardware-identity-pre-run.json sha256"
2540            && must_bind[5] == "top-level SHA256SUMS sha256"
2541            && must_bind[6] == "every input/output job"
2542            && request
2543                .required_oracle_result
2544                .must_not_mutate_transport_archive,
2545        "transport request required-oracle contract changed"
2546    );
2547    Ok(())
2548}
2549
2550fn root_binding_matches(
2551    original: &crate::model::RootArtifactBinding,
2552    sealed: &SealedBinding,
2553) -> bool {
2554    original.archive_root_file == sealed.file
2555        && original.bytes == sealed.bytes
2556        && original.sha256 == sealed.sha256
2557}
2558
2559fn validate_transport_artifact_join(
2560    transport: &ArchiveSnapshot,
2561    sample: &SampleSpec,
2562    original: &crate::model::ArtifactBinding,
2563    sealed: &SealedRequestArtifactBinding,
2564    expected_file: &str,
2565    expected_bytes: u64,
2566) -> Result<()> {
2567    ensure!(
2568        original.file == expected_file
2569            && original.logical_bytes == expected_bytes
2570            && original.stored_bytes == expected_bytes
2571            && sealed.file == original.file
2572            && sealed.logical_bytes == original.logical_bytes
2573            && sealed.stored_bytes == original.stored_bytes
2574            && sealed.sha256 == original.sha256,
2575        "typed result {expected_file} binding differs from the original request"
2576    );
2577    let path = format!("{}/{expected_file}", sample.relative);
2578    let record = transport
2579        .files
2580        .get(&path)
2581        .with_context(|| format!("transport manifest omits {path}"))?;
2582    ensure!(
2583        record.bytes == original.stored_bytes && record.sha256 == original.sha256,
2584        "original request {expected_file} differs from the transport manifest"
2585    );
2586    Ok(())
2587}
2588
2589fn validate_transport_request_artifact(
2590    transport: &ArchiveSnapshot,
2591    sample: &SampleSpec,
2592    original: &crate::model::ArtifactBinding,
2593    expected_file: &str,
2594    expected_bytes: u64,
2595) -> Result<()> {
2596    ensure!(
2597        original.file == expected_file
2598            && original.logical_bytes == expected_bytes
2599            && original.stored_bytes == expected_bytes,
2600        "original request {expected_file} has invalid geometry"
2601    );
2602    let path = format!("{}/{expected_file}", sample.relative);
2603    let record = transport
2604        .files
2605        .get(&path)
2606        .with_context(|| format!("transport manifest omits {path}"))?;
2607    ensure!(
2608        record.bytes == original.stored_bytes && record.sha256 == original.sha256,
2609        "original request {expected_file} differs from the transport manifest"
2610    );
2611    Ok(())
2612}
2613
2614struct JobRecomputation {
2615    input_sha256: String,
2616    expected_sha256: String,
2617    observed_sha256: String,
2618    payload_match: bool,
2619    padding_valid: bool,
2620}
2621
2622fn recompute_transport_job(
2623    oracle: Sha256GenericWots,
2624    input_file: &StrictResultFile,
2625    output_file: &StrictResultFile,
2626    job_index: u32,
2627    unique_private_seeds: &mut HashSet<[u8; 32]>,
2628) -> Result<JobRecomputation> {
2629    let job_offset = u64::from(job_index);
2630    let mut input = [0_u8; 64];
2631    let mut output = [0_u8; OUTPUT_SLOT_BYTES_USIZE];
2632    input_file.read_exact_at(
2633        &mut input,
2634        job_offset
2635            .checked_mul(INPUT_BYTES_PER_JOB)
2636            .context("transport input offset overflow")?,
2637    )?;
2638    output_file.read_exact_at(
2639        &mut output,
2640        job_offset
2641            .checked_mul(OUTPUT_SLOT_BYTES)
2642            .context("transport output offset overflow")?,
2643    )?;
2644    let private_seed: [u8; 32] = input[..32].try_into().expect("fixed seed span");
2645    let message: [u8; 32] = input[32..].try_into().expect("fixed message span");
2646    let seed_sha256: [u8; 32] = Sha256::digest(private_seed).into();
2647    ensure!(
2648        unique_private_seeds.insert(seed_sha256),
2649        "retained transport repeats a one-time private seed"
2650    );
2651    let fused = oracle.sign_and_public_key_from_private_seed(
2652        PrivateSeed::<HashSigsSha256GenericV1>::new(private_seed),
2653        &MessageDigest::new(message),
2654    );
2655    let signature = fused.signature.to_bytes();
2656    let public_key = fused.public_key.to_bytes();
2657    let mut expected = [0_u8; FUSED_OUTPUT_BYTES];
2658    expected[..SIGNATURE_BYTES].copy_from_slice(&signature);
2659    expected[SIGNATURE_BYTES..].copy_from_slice(&public_key);
2660    let observed = &output[..OUTPUT_VALID_BYTES_USIZE];
2661    let payload_match = observed == expected.as_slice();
2662    let padding_valid =
2663        output[OUTPUT_VALID_BYTES_USIZE..]
2664            .iter()
2665            .enumerate()
2666            .all(|(padding_index, byte)| {
2667                let global = job_offset
2668                    .checked_mul(OUTPUT_SLOT_BYTES)
2669                    .and_then(|offset| offset.checked_add(OUTPUT_VALID_BYTES))
2670                    .and_then(|offset| {
2671                        offset.checked_add(
2672                            u64::try_from(padding_index).expect("padding offset fits u64"),
2673                        )
2674                    })
2675                    .expect("validated output geometry fits u64");
2676                *byte == output_poison(global)
2677            });
2678    let result = JobRecomputation {
2679        input_sha256: crate::archive::hex_lower(&Sha256::digest(input)),
2680        expected_sha256: crate::archive::hex_lower(&Sha256::digest(expected)),
2681        observed_sha256: crate::archive::hex_lower(&Sha256::digest(observed)),
2682        payload_match,
2683        padding_valid,
2684    };
2685    input.fill(0);
2686    output.fill(0);
2687    Ok(result)
2688}
2689
2690// Keep each derived decision adjacent to its fail-closed consistency check so
2691// the aggregate validation sequence remains directly auditable.
2692#[allow(clippy::too_many_lines)]
2693fn validate_summary_decisions(
2694    summary: SealedSummary,
2695    transcript_counts: &[TranscriptCount],
2696) -> Result<VerifiedValues> {
2697    ensure!(
2698        transcript_counts.len() == summary.requests.len(),
2699        "job transcript request cardinality changed"
2700    );
2701    let mut total_jobs = 0_u64;
2702    let mut total_matched = 0_u64;
2703    let mut all_padding_valid = true;
2704    let mut common_pre_run = None;
2705    let mut common_xclbin = None;
2706    let mut verified_requests = Vec::with_capacity(summary.requests.len());
2707
2708    for (request, transcript) in summary.requests.iter().zip(transcript_counts) {
2709        ensure!(
2710            transcript.jobs == request.jobs,
2711            "request job count differs from its complete transcript"
2712        );
2713        ensure!(
2714            request.matched_jobs == transcript.matched_jobs,
2715            "request matched-job count differs from its transcript"
2716        );
2717        ensure!(
2718            request.padding_valid == transcript.padding_valid,
2719            "request padding decision differs from retained transport bytes"
2720        );
2721        let mismatched_jobs = request
2722            .jobs
2723            .checked_sub(request.matched_jobs)
2724            .context("request matched-job count exceeds jobs")?;
2725        let cryptographic_oracle_valid = mismatched_jobs == 0 && transcript.padding_valid;
2726        ensure!(
2727            request.cryptographic_oracle_valid == cryptographic_oracle_valid,
2728            "request cryptographic decision differs from payload/padding evidence"
2729        );
2730        if let Some(binding) = &common_pre_run {
2731            ensure!(
2732                binding == &request.hardware_identity_pre_run,
2733                "requests bind different pre-run hardware identities"
2734            );
2735        } else {
2736            common_pre_run = Some(request.hardware_identity_pre_run.clone());
2737        }
2738        if let Some(binding) = &common_xclbin {
2739            ensure!(
2740                binding == &request.xclbin,
2741                "requests bind different hardware xclbins"
2742            );
2743        } else {
2744            common_xclbin = Some(request.xclbin.clone());
2745        }
2746        total_jobs = total_jobs
2747            .checked_add(u64::from(request.jobs))
2748            .context("typed result total job count overflow")?;
2749        total_matched = total_matched
2750            .checked_add(u64::from(request.matched_jobs))
2751            .context("typed result matched job count overflow")?;
2752        all_padding_valid &= transcript.padding_valid;
2753        verified_requests.push(VerifiedResultRequest {
2754            sample: request.sample.clone(),
2755            phase: request.phase.clone(),
2756            sample_index: request.sample_index,
2757            request_sha256: request.request_sha256.clone(),
2758            run_id: request.run_id.clone(),
2759            coordination_intent: verified_binding(&request.coordination_intent),
2760            coordination_burn: verified_binding(&request.coordination_burn),
2761            coordination_receipt: verified_binding(&request.coordination_receipt),
2762            batch: request.batch,
2763            nonce_hex: request.nonce_hex.clone(),
2764            reservation_record_sha256: request.reservation_record_sha256.clone(),
2765            xclbin: verified_xclbin(&request.xclbin),
2766            hardware_identity_pre_run: verified_binding(&request.hardware_identity_pre_run),
2767            input: verified_request_artifact(&request.input),
2768            output: verified_request_artifact(&request.output),
2769            jobs: request.jobs,
2770            matched_jobs: request.matched_jobs,
2771            mismatched_jobs,
2772            padding_valid: transcript.padding_valid,
2773            cryptographic_oracle_valid,
2774            _marker: VerifiedMarker,
2775        });
2776    }
2777
2778    let mismatched_jobs = total_jobs
2779        .checked_sub(total_matched)
2780        .context("typed result matched-job count exceeds jobs")?;
2781    let cryptographic_oracle_valid = mismatched_jobs == 0 && all_padding_valid;
2782    ensure!(
2783        summary.total_jobs == total_jobs
2784            && summary.matched_jobs == total_matched
2785            && summary.mismatched_jobs == mismatched_jobs,
2786        "typed result aggregate job counters differ from the complete request set"
2787    );
2788    ensure!(
2789        summary.all_padding_valid == all_padding_valid,
2790        "typed result aggregate padding decision differs from its requests"
2791    );
2792    ensure!(
2793        summary.cryptographic_oracle_valid == cryptographic_oracle_valid,
2794        "typed result aggregate cryptographic decision is inconsistent"
2795    );
2796
2797    Ok(VerifiedValues {
2798        transport_manifest: verified_binding(&summary.transport_manifest),
2799        final_hardware_identity: verified_binding(&summary.final_hardware_identity),
2800        run_id: summary.run_id,
2801        coordination_intent: verified_binding(&summary.coordination_intent),
2802        coordination_burn: verified_binding(&summary.coordination_burn),
2803        coordination_receipt: verified_binding(&summary.coordination_receipt),
2804        samples: summary.sample_count,
2805        jobs: total_jobs,
2806        matched_jobs: total_matched,
2807        mismatched_jobs,
2808        all_padding_valid,
2809        cryptographic_oracle_valid,
2810        requests: verified_requests,
2811    })
2812}
2813
2814fn validate_receipt_result_join(receipt: &CompletedReceipt, values: &VerifiedValues) -> Result<()> {
2815    ensure!(
2816        receipt.samples == values.samples && receipt.jobs == values.jobs,
2817        "creation receipt sample/job totals differ from the typed result"
2818    );
2819    ensure!(
2820        receipt.cryptographic_oracle_valid == values.cryptographic_oracle_valid,
2821        "creation receipt cryptographic decision differs from the typed result"
2822    );
2823    Ok(())
2824}
2825
2826fn validate_request_shape(request: &SealedRequest, summary: &SealedSummary) -> Result<()> {
2827    // Batch zero is the producer's poison-sentinel cryptographic control. It
2828    // carries no job/performance observation and every promotion flag remains
2829    // false; validate_request_artifact_geometry enforces its sole 4 KiB slot.
2830    ensure!(
2831        request.batch <= MAXIMUM_BATCH,
2832        "typed result request batch exceeds the shell ABI"
2833    );
2834    ensure!(
2835        matches!(request.phase.as_str(), "warmup" | "measured"),
2836        "typed result request phase is invalid"
2837    );
2838    let expected_sample = format!(
2839        "samples/batch-{:05}/{}-{:03}",
2840        request.batch, request.phase, request.sample_index
2841    );
2842    ensure!(
2843        request.sample == expected_sample,
2844        "typed result request sample path is noncanonical"
2845    );
2846    ensure!(
2847        is_nonzero_lower_hex(&request.request_sha256, 64),
2848        "typed result request SHA-256 is not canonical"
2849    );
2850    ensure!(
2851        request.run_id == summary.run_id,
2852        "typed result request crosses coordination runs"
2853    );
2854    ensure!(
2855        request.coordination_intent == summary.coordination_intent
2856            && request.coordination_burn == summary.coordination_burn
2857            && request.coordination_receipt == summary.coordination_receipt,
2858        "typed result request coordination roots differ from the result"
2859    );
2860    ensure!(
2861        is_lower_hex(&request.nonce_hex, 16),
2862        "typed result request nonce is not canonical"
2863    );
2864    ensure!(
2865        is_nonzero_lower_hex(&request.reservation_record_sha256, 64),
2866        "typed result request reservation SHA-256 is not canonical"
2867    );
2868    validate_binding(
2869        &request.hardware_identity_pre_run,
2870        "hardware-identity-pre-run.json",
2871        "request pre-run hardware identity",
2872    )?;
2873    validate_xclbin(&request.xclbin)?;
2874    validate_request_artifact_geometry(request)?;
2875    Ok(())
2876}
2877
2878fn validate_request_artifact_geometry(request: &SealedRequest) -> Result<()> {
2879    let input_bytes = u64::from(request.batch)
2880        .checked_mul(INPUT_BYTES_PER_JOB)
2881        .context("typed result input geometry overflow")?;
2882    let logical_output = u64::from(request.batch)
2883        .checked_mul(OUTPUT_SLOT_BYTES)
2884        .context("typed result output geometry overflow")?;
2885    let output_bytes = if request.batch == 0 {
2886        OUTPUT_SLOT_BYTES
2887    } else {
2888        logical_output
2889    };
2890    validate_request_artifact(&request.input, "input.bin", input_bytes, input_bytes)?;
2891    validate_request_artifact(&request.output, "output.bin", output_bytes, output_bytes)?;
2892    Ok(())
2893}
2894
2895fn validate_request_artifact(
2896    binding: &SealedRequestArtifactBinding,
2897    file: &str,
2898    logical_bytes: u64,
2899    stored_bytes: u64,
2900) -> Result<()> {
2901    ensure!(
2902        binding.file == file,
2903        "request artifact names the wrong file"
2904    );
2905    ensure!(
2906        binding.logical_bytes == logical_bytes && binding.stored_bytes == stored_bytes,
2907        "request artifact geometry differs from its batch"
2908    );
2909    ensure!(
2910        is_nonzero_lower_hex(&binding.sha256, 64),
2911        "request artifact SHA-256 is not canonical"
2912    );
2913    Ok(())
2914}
2915
2916fn validate_xclbin(binding: &SealedXclbinBinding) -> Result<()> {
2917    ensure!(
2918        canonical_absolute_path(Path::new(&binding.path)),
2919        "typed result xclbin path is not absolute and canonical"
2920    );
2921    ensure!(binding.bytes > 0, "typed result xclbin is empty");
2922    ensure!(
2923        is_nonzero_lower_hex(&binding.sha256, 64),
2924        "typed result xclbin SHA-256 is not canonical"
2925    );
2926    Ok(())
2927}
2928
2929fn validate_binding(binding: &SealedBinding, file: &str, label: &str) -> Result<()> {
2930    ensure!(binding.file == file, "{label} names the wrong file");
2931    ensure!(binding.bytes > 0, "{label} byte count must be positive");
2932    ensure!(
2933        is_nonzero_lower_hex(&binding.sha256, 64),
2934        "{label} SHA-256 is not canonical"
2935    );
2936    Ok(())
2937}
2938
2939fn verified_binding(binding: &SealedBinding) -> VerifiedResultArtifactBinding {
2940    VerifiedResultArtifactBinding {
2941        file: binding.file.clone(),
2942        bytes: binding.bytes,
2943        sha256: binding.sha256.clone(),
2944        _marker: VerifiedMarker,
2945    }
2946}
2947
2948fn verified_request_artifact(
2949    binding: &SealedRequestArtifactBinding,
2950) -> VerifiedRequestArtifactBinding {
2951    VerifiedRequestArtifactBinding {
2952        file: binding.file.clone(),
2953        logical_bytes: binding.logical_bytes,
2954        stored_bytes: binding.stored_bytes,
2955        sha256: binding.sha256.clone(),
2956        _marker: VerifiedMarker,
2957    }
2958}
2959
2960fn verified_xclbin(binding: &SealedXclbinBinding) -> VerifiedXclbinBinding {
2961    VerifiedXclbinBinding {
2962        path: binding.path.clone(),
2963        bytes: binding.bytes,
2964        sha256: binding.sha256.clone(),
2965        _marker: VerifiedMarker,
2966    }
2967}
2968
2969fn canonical_absolute_path(path: &Path) -> bool {
2970    path.is_absolute()
2971        && path
2972            .components()
2973            .all(|component| !matches!(component, Component::CurDir | Component::ParentDir))
2974        && path.to_str().is_some_and(|text| {
2975            !text.ends_with('/') && !text.contains("//") && !text.contains('\0')
2976        })
2977}
2978
2979fn is_nonzero_lower_hex(value: &str, width: usize) -> bool {
2980    is_lower_hex(value, width) && value.bytes().any(|byte| byte != b'0')
2981}
2982
2983#[cfg(test)]
2984mod exact_performance_tests {
2985    use super::{
2986        REQUIRED_PERFORMANCE_BATCH, VerifiedMarker, VerifiedPerformanceSample,
2987        exact_capture_cycles_threshold_met, exact_capture_rate_threshold_met,
2988        exact_performance_decision, exact_whole_kernel_rate_threshold_met,
2989    };
2990
2991    const CAPTURE_BOUNDARY: u64 = 500 * 16_383;
2992    const WHOLE_KERNEL_BOUNDARY: u64 = 2_000 * 16_384;
2993
2994    fn sample(
2995        index: usize,
2996        phase: &str,
2997        batch: u32,
2998        capture_core_interval_cycles: u64,
2999        whole_kernel_nanoseconds: u64,
3000    ) -> VerifiedPerformanceSample {
3001        VerifiedPerformanceSample {
3002            sample: format!("samples/batch-{batch:05}/{phase}-{index:03}"),
3003            phase: phase.to_owned(),
3004            sample_index: index,
3005            batch,
3006            capture_core_interval_cycles,
3007            memory_retirement_interval_cycles: capture_core_interval_cycles,
3008            whole_kernel_nanoseconds,
3009            _marker: VerifiedMarker,
3010        }
3011    }
3012
3013    fn population(count: usize, capture: u64, whole: u64) -> Vec<VerifiedPerformanceSample> {
3014        (0..count)
3015            .map(|index| {
3016                sample(
3017                    index,
3018                    "measured",
3019                    REQUIRED_PERFORMANCE_BATCH,
3020                    capture,
3021                    whole,
3022                )
3023            })
3024            .collect()
3025    }
3026
3027    #[test]
3028    fn exact_boundary_matches_the_promoter_core_contract() {
3029        let samples = population(30, CAPTURE_BOUNDARY, WHOLE_KERNEL_BOUNDARY);
3030        let decision = exact_performance_decision(true, &samples).unwrap();
3031        assert_eq!(decision.p95_rank, Some(29));
3032        assert_eq!(decision.p95_capture_interval_cycles, Some(CAPTURE_BOUNDARY));
3033        assert_eq!(
3034            decision.p95_whole_kernel_nanoseconds,
3035            Some(WHOLE_KERNEL_BOUNDARY)
3036        );
3037        assert!(exact_capture_cycles_threshold_met(
3038            decision.p95_capture_interval_cycles
3039        ));
3040        assert!(exact_capture_rate_threshold_met(
3041            250_000_000,
3042            decision.p95_capture_interval_cycles
3043        ));
3044        assert!(exact_whole_kernel_rate_threshold_met(
3045            decision.p95_whole_kernel_nanoseconds
3046        ));
3047    }
3048
3049    #[test]
3050    fn one_raw_unit_beyond_each_boundary_fails_without_rounding() {
3051        let slow_capture = population(30, CAPTURE_BOUNDARY + 1, WHOLE_KERNEL_BOUNDARY);
3052        let capture = exact_performance_decision(true, &slow_capture).unwrap();
3053        assert!(!exact_capture_cycles_threshold_met(
3054            capture.p95_capture_interval_cycles
3055        ));
3056        assert!(!exact_capture_rate_threshold_met(
3057            250_000_000,
3058            capture.p95_capture_interval_cycles
3059        ));
3060        assert!(exact_whole_kernel_rate_threshold_met(
3061            capture.p95_whole_kernel_nanoseconds
3062        ));
3063
3064        let slow_whole = population(30, CAPTURE_BOUNDARY, WHOLE_KERNEL_BOUNDARY + 1);
3065        let whole = exact_performance_decision(true, &slow_whole).unwrap();
3066        assert!(exact_capture_cycles_threshold_met(
3067            whole.p95_capture_interval_cycles
3068        ));
3069        assert!(!exact_whole_kernel_rate_threshold_met(
3070            whole.p95_whole_kernel_nanoseconds
3071        ));
3072
3073        let routed_below_baseline = population(30, CAPTURE_BOUNDARY, WHOLE_KERNEL_BOUNDARY);
3074        let routed = exact_performance_decision(true, &routed_below_baseline).unwrap();
3075        assert!(exact_capture_rate_threshold_met(
3076            250_000_000,
3077            routed.p95_capture_interval_cycles
3078        ));
3079        assert!(!exact_capture_rate_threshold_met(
3080            249_999_999,
3081            routed.p95_capture_interval_cycles
3082        ));
3083    }
3084
3085    #[test]
3086    fn nearest_rank_p95_is_the_conservative_twenty_ninth_of_thirty() {
3087        let mut samples = population(28, 1, 1);
3088        samples.push(sample(28, "measured", REQUIRED_PERFORMANCE_BATCH, 100, 200));
3089        samples.push(sample(
3090            29,
3091            "measured",
3092            REQUIRED_PERFORMANCE_BATCH,
3093            1_000,
3094            2_000,
3095        ));
3096        let decision = exact_performance_decision(true, &samples).unwrap();
3097        assert_eq!(decision.p95_rank, Some(29));
3098        assert_eq!(decision.p95_capture_interval_cycles, Some(100));
3099        assert_eq!(decision.p95_whole_kernel_nanoseconds, Some(200));
3100    }
3101
3102    #[test]
3103    fn warmups_and_other_batches_cannot_complete_the_population() {
3104        let mut insufficient = population(29, CAPTURE_BOUNDARY, WHOLE_KERNEL_BOUNDARY);
3105        insufficient.push(sample(
3106            0,
3107            "warmup",
3108            REQUIRED_PERFORMANCE_BATCH,
3109            CAPTURE_BOUNDARY,
3110            WHOLE_KERNEL_BOUNDARY,
3111        ));
3112        insufficient.push(sample(0, "measured", 65, 1, 1));
3113        let count = exact_performance_decision(true, &insufficient).unwrap();
3114        assert_eq!(count.observed_measured_samples, 29);
3115        assert!(count.required_batch_requested);
3116
3117        let complete_population = population(30, CAPTURE_BOUNDARY, WHOLE_KERNEL_BOUNDARY);
3118        let no_route = exact_performance_decision(true, &complete_population).unwrap();
3119        assert_eq!(no_route.observed_measured_samples, 30);
3120        assert!(exact_capture_cycles_threshold_met(
3121            no_route.p95_capture_interval_cycles
3122        ));
3123        assert!(exact_capture_rate_threshold_met(
3124            250_000_000,
3125            no_route.p95_capture_interval_cycles
3126        ));
3127        assert!(exact_whole_kernel_rate_threshold_met(
3128            no_route.p95_whole_kernel_nanoseconds
3129        ));
3130    }
3131}