Skip to main content

entrenar/models/
llama_370m.rs

1#![allow(clippy::doc_overindented_list_items)]
2//! # Llama 370M Sovereign (albor) — Architectural Scaffold
3//!
4//! Compile-time-frozen configuration for the SHIP-TWO-001 MODEL-2 "albor"
5//! 370M Python code-completion model.
6//!
7//! **Canonical contract:** `contracts/model-families/llama-370m-sovereign-v1.yaml`
8//! **Contract version:** 1.0.0
9//! **Contract ID:**      C-LLAMA-370M-SOVEREIGN
10//!
11//! ## Purpose
12//!
13//! This module is a **scaffold only** — it does NOT implement forward/backward.
14//! Its sole job is to lift the architectural constants from the YAML contract
15//! into Rust's type system so that recipe/artifact drift (the MODEL-1 v2 QLoRA
16//! divergence class of bug) is caught at compile time, not at eval time.
17//!
18//! ## Invariants (mirrored from the YAML contract)
19//!
20//! - **INV-ARCH-370M-001**  Parameter count ∈ [366M, 374M] (370M ± 1%).
21//!                          Verified at runtime by `estimated_param_count()`
22//!                          and by `apr inspect` on trained artifacts.
23//! - **INV-ARCH-370M-002**  `num_heads * head_dim == hidden_dim` (16 * 64 == 1024).
24//!                          Compile-time asserted in [`Llama370MConfig::validate`].
25//! - **INV-ARCH-370M-003**  `num_kv_heads` divides `num_heads` evenly (GQA).
26//!                          Compile-time asserted in [`Llama370MConfig::validate`].
27//! - **INV-ARCH-370M-004**  `tied_embeddings == true` — lm_head shares storage
28//!                          with token_embd. Compile-time enforced via the
29//!                          `TIED_EMBEDDINGS` const.
30//! - **INV-ARCH-370M-005**  `rope_theta == 10000.0` exactly (Llama-1 convention).
31//!                          Compile-time enforced as a `const f32`.
32//! - **INV-ARCH-370M-006**  `vocab_size == 50_257` and matches the paired
33//!                          tokenizer-bpe-v1 contract. Tokenizer coupling
34//!                          cannot be checked at compile time — runtime
35//!                          `debug_assert_eq!` at model load.
36//! - **INV-ARCH-370M-007**  SwiGLU activation: distinct `gate_proj` and
37//!                          `up_proj` tensors. Enforced at checkpoint load
38//!                          time (runtime) by the APR loader.
39//! - **INV-ARCH-370M-008**  `has_bias == false` on every linear projection.
40//!                          Compile-time enforced via the `HAS_BIAS` const.
41//! - **INV-ARCH-370M-009**  Row-major APR layout (LAYOUT-001). Embedding
42//!                          shape `[vocab_size, hidden_dim]`, NOT reversed.
43//!                          Enforced by `aprender::format::layout_contract`
44//!                          at load time (runtime — tensor data is not
45//!                          available to the type system).
46//!
47//! ## Design Notes
48//!
49//! Rust 1.79+ supports `const` panics, so every machine-checkable invariant
50//! lives inside [`Llama370MConfig::validate`], a `const fn` that compiles
51//! down to nothing if all invariants hold and refuses to compile otherwise
52//! (via `const _: () = Llama370MConfig::validate();`).
53//!
54//! The `HiddenDim<N>`, `NumHeads<N>`, etc. PhantomData newtypes exist so
55//! that downstream code (forward/backward, to be written later) can be
56//! parameterized on the exact dimensions — making it a compile error to,
57//! for instance, pass a `HiddenDim<768>` activation into a 1024-dim
58//! projection.
59//!
60//! This module intentionally does NOT:
61//!   - implement forward/backward;
62//!   - allocate tensors;
63//!   - export anything to `aprender-train`'s public API
64//!     (re-exports are a follow-up PR).
65
66#![allow(dead_code)] // scaffold — forward/backward not yet implemented
67
68use std::marker::PhantomData;
69
70// ─────────────────────────────────────────────────────────────
71// Compile-time shape newtypes (Poka-Yoke)
72// ─────────────────────────────────────────────────────────────
73//
74// These zero-sized types let downstream code be generic on exact
75// dimensions. Mixing, e.g., a HiddenDim<1024> with a HiddenDim<768>
76// is a compile error, not a runtime shape mismatch.
77
78/// Hidden dimension (model width) as a compile-time constant.
79#[derive(Debug, Clone, Copy, Default)]
80pub struct HiddenDim<const N: usize>(PhantomData<()>);
81
82impl<const N: usize> HiddenDim<N> {
83    pub const VALUE: usize = N;
84    pub const fn new() -> Self {
85        Self(PhantomData)
86    }
87}
88
89/// Number of attention heads.
90#[derive(Debug, Clone, Copy, Default)]
91pub struct NumHeads<const N: usize>(PhantomData<()>);
92
93impl<const N: usize> NumHeads<N> {
94    pub const VALUE: usize = N;
95    pub const fn new() -> Self {
96        Self(PhantomData)
97    }
98}
99
100/// Number of KV heads (GQA).
101#[derive(Debug, Clone, Copy, Default)]
102pub struct NumKvHeads<const N: usize>(PhantomData<()>);
103
104impl<const N: usize> NumKvHeads<N> {
105    pub const VALUE: usize = N;
106    pub const fn new() -> Self {
107        Self(PhantomData)
108    }
109}
110
111/// Per-head dimension (hidden_dim / num_heads).
112#[derive(Debug, Clone, Copy, Default)]
113pub struct HeadDim<const N: usize>(PhantomData<()>);
114
115impl<const N: usize> HeadDim<N> {
116    pub const VALUE: usize = N;
117    pub const fn new() -> Self {
118        Self(PhantomData)
119    }
120}
121
122/// Intermediate (FFN) dimension.
123#[derive(Debug, Clone, Copy, Default)]
124pub struct IntermediateDim<const N: usize>(PhantomData<()>);
125
126impl<const N: usize> IntermediateDim<N> {
127    pub const VALUE: usize = N;
128    pub const fn new() -> Self {
129        Self(PhantomData)
130    }
131}
132
133/// Number of transformer blocks.
134#[derive(Debug, Clone, Copy, Default)]
135pub struct NumLayers<const N: usize>(PhantomData<()>);
136
137impl<const N: usize> NumLayers<N> {
138    pub const VALUE: usize = N;
139    pub const fn new() -> Self {
140        Self(PhantomData)
141    }
142}
143
144/// Vocabulary size.
145#[derive(Debug, Clone, Copy, Default)]
146pub struct VocabSize<const N: usize>(PhantomData<()>);
147
148impl<const N: usize> VocabSize<N> {
149    pub const VALUE: usize = N;
150    pub const fn new() -> Self {
151        Self(PhantomData)
152    }
153}
154
155// ─────────────────────────────────────────────────────────────
156// Llama370MConfig — frozen architectural constants
157// ─────────────────────────────────────────────────────────────
158//
159// All fields are `pub const` and byte-identical to
160// contracts/model-families/llama-370m-sovereign-v1.yaml §architecture
161// and §constraints.
162
163/// Architectural configuration for the albor 370M sovereign model.
164///
165/// Every constant here is pinned to a specific value in the YAML contract.
166/// Changing any of these values requires bumping the contract to v1.1.0
167/// and re-running the `GATE-ARCH-370M-*` gates.
168pub struct Llama370MConfig;
169
170impl Llama370MConfig {
171    // ── Architecture ──
172    /// Total parameter count (nominal). See `estimated_param_count()` for
173    /// the runtime-checkable figure under INV-ARCH-370M-001.
174    pub const PARAMETERS_NOMINAL: usize = 370_000_000;
175
176    /// Lower bound on param count (INV-ARCH-370M-001).
177    pub const PARAMETERS_MIN: usize = 366_000_000;
178
179    /// Upper bound on param count (INV-ARCH-370M-001).
180    pub const PARAMETERS_MAX: usize = 374_000_000;
181
182    pub const HIDDEN_DIM: usize = 1024;
183    pub const NUM_LAYERS: usize = 24;
184    pub const NUM_HEADS: usize = 16;
185    pub const NUM_KV_HEADS: usize = 4; // GQA: heads / 4
186    pub const HEAD_DIM: usize = 64; // hidden_dim / num_heads
187    pub const INTERMEDIATE_DIM: usize = 2816; // ~2.75 * hidden
188    pub const VOCAB_SIZE: usize = 50_257;
189    pub const MAX_POSITION_EMBEDDINGS: usize = 4096;
190
191    /// RoPE base frequency — Llama-1 convention (INV-ARCH-370M-005).
192    pub const ROPE_THETA: f32 = 10_000.0;
193
194    /// RMSNorm epsilon.
195    pub const RMS_NORM_EPS: f32 = 1.0e-5;
196
197    // ── Constraints ──
198    pub const TIED_EMBEDDINGS: bool = true; // INV-ARCH-370M-004
199    pub const HAS_BIAS: bool = false; // INV-ARCH-370M-008
200
201    /// Compile-time verification of every machine-checkable invariant.
202    ///
203    /// Each `assert!` here becomes a hard compile error (via Rust 1.79+
204    /// `const` panics) if the invariant is violated. Any change to the
205    /// constants above that breaks one of these invariants will fail to
206    /// compile — by design.
207    ///
208    /// Invariants encoded here (in order):
209    ///   INV-ARCH-370M-002  num_heads * head_dim == hidden_dim
210    ///   INV-ARCH-370M-003  num_kv_heads divides num_heads
211    ///   INV-ARCH-370M-004  tied_embeddings == true
212    ///   INV-ARCH-370M-005  rope_theta == 10000.0
213    ///   INV-ARCH-370M-006  vocab_size == 50_257
214    ///   INV-ARCH-370M-008  has_bias == false
215    ///
216    /// Invariants NOT encodable at compile time (documented as runtime
217    /// `debug_assert!` at load sites):
218    ///   INV-ARCH-370M-001  param count ∈ [366M, 374M] — depends on the
219    ///                      actual allocated tensors; checked by
220    ///                      `estimated_param_count()` and by `apr inspect`.
221    ///   INV-ARCH-370M-007  SwiGLU gate_proj/up_proj both present and
222    ///                      distinct — depends on the on-disk checkpoint
223    ///                      tensor table; checked by the APR loader.
224    ///   INV-ARCH-370M-009  row-major [vocab_size, hidden_dim] layout —
225    ///                      depends on tensor shape metadata in the
226    ///                      loaded artifact; checked by
227    ///                      `aprender::format::layout_contract`.
228    pub const fn validate() {
229        // INV-ARCH-370M-002
230        assert!(
231            Self::NUM_HEADS * Self::HEAD_DIM == Self::HIDDEN_DIM,
232            "INV-ARCH-370M-002 violated: num_heads * head_dim != hidden_dim",
233        );
234
235        // INV-ARCH-370M-003
236        assert!(
237            Self::NUM_KV_HEADS > 0 && Self::NUM_HEADS % Self::NUM_KV_HEADS == 0,
238            "INV-ARCH-370M-003 violated: num_kv_heads does not divide num_heads",
239        );
240
241        // INV-ARCH-370M-004
242        assert!(
243            Self::TIED_EMBEDDINGS,
244            "INV-ARCH-370M-004 violated: tied_embeddings must be true for 370M",
245        );
246
247        // INV-ARCH-370M-005 — f32 equality is legal in const context
248        // and is exactly what the contract requires (byte-equal literal).
249        assert!(
250            Self::ROPE_THETA == 10_000.0_f32,
251            "INV-ARCH-370M-005 violated: rope_theta must be exactly 10000.0",
252        );
253
254        // INV-ARCH-370M-006
255        assert!(
256            Self::VOCAB_SIZE == 50_257,
257            "INV-ARCH-370M-006 violated: vocab_size must equal 50_257",
258        );
259
260        // INV-ARCH-370M-008
261        assert!(
262            !Self::HAS_BIAS,
263            "INV-ARCH-370M-008 violated: has_bias must be false (Llama convention)",
264        );
265
266        // Sanity: head_dim consistency (free-tier check, also implied
267        // by INV-ARCH-370M-002 above).
268        assert!(
269            Self::HIDDEN_DIM / Self::NUM_HEADS == Self::HEAD_DIM,
270            "hidden_dim / num_heads != head_dim — config internally inconsistent",
271        );
272
273        // Sanity: max_position_embeddings is a positive multiple of 2.
274        assert!(
275            Self::MAX_POSITION_EMBEDDINGS > 0 && Self::MAX_POSITION_EMBEDDINGS % 2 == 0,
276            "max_position_embeddings must be a positive even integer for RoPE",
277        );
278    }
279}
280
281// Drive `validate()` at crate-compile time. If any `assert!` inside
282// `validate()` fails, the crate fails to build.
283#[allow(clippy::let_unit_value)]
284const _: () = Llama370MConfig::validate();
285
286// ─────────────────────────────────────────────────────────────
287// Parameter count estimator (INV-ARCH-370M-001 runtime check)
288// ─────────────────────────────────────────────────────────────
289
290/// Estimate the total parameter count for the albor 370M config using
291/// the **nominal (untied)** counting convention.
292///
293/// The contract's INV-ARCH-370M-001 band [366M, 374M] corresponds to the
294/// HuggingFace-style reported figure, which counts `lm_head.weight` as
295/// a distinct matrix even though — per INV-ARCH-370M-004 — storage is
296/// shared with `model.embed_tokens.weight`. This mirrors how Llama
297/// families are reported in the literature (e.g., "TinyLlama-1.1B" is
298/// counted with untied lm_head even when tied).
299///
300/// For the actual on-disk param count reported by `apr inspect`
301/// (with tying applied), use [`estimated_stored_param_count`].
302///
303/// Formula (untied — contract reporting convention):
304///
305/// ```text
306/// embedding:           vocab * hidden
307/// lm_head:             vocab * hidden   (tied storage, but counted here)
308/// per transformer layer:
309///   attention q_proj:  (num_heads    * head_dim) * hidden
310///   attention k_proj:  (num_kv_heads * head_dim) * hidden
311///   attention v_proj:  (num_kv_heads * head_dim) * hidden
312///   attention o_proj:  hidden * (num_heads * head_dim)
313///   mlp gate_proj:     intermediate * hidden
314///   mlp up_proj:       intermediate * hidden
315///   mlp down_proj:     hidden * intermediate
316///   input_layernorm:   hidden
317///   post_attn_layernorm: hidden
318/// final rmsnorm:       hidden
319/// ```
320#[must_use]
321pub const fn estimated_param_count() -> usize {
322    // Untied: add the lm_head bookkeeping on top of the stored count.
323    estimated_stored_param_count() + (Llama370MConfig::VOCAB_SIZE * Llama370MConfig::HIDDEN_DIM)
324}
325
326/// Estimate the **stored** parameter count (what `apr inspect` sees on
327/// disk for a tied-embedding checkpoint). This is ~51.2M lower than the
328/// nominal figure because `lm_head.weight` is aliased to
329/// `model.embed_tokens.weight` (INV-ARCH-370M-004).
330#[must_use]
331pub const fn estimated_stored_param_count() -> usize {
332    let h = Llama370MConfig::HIDDEN_DIM;
333    let l = Llama370MConfig::NUM_LAYERS;
334    let v = Llama370MConfig::VOCAB_SIZE;
335    let i = Llama370MConfig::INTERMEDIATE_DIM;
336    let nh = Llama370MConfig::NUM_HEADS;
337    let nkv = Llama370MConfig::NUM_KV_HEADS;
338    let hd = Llama370MConfig::HEAD_DIM;
339
340    // Embedding (tied with lm_head — counted once).
341    let embedding = v * h;
342
343    // Attention: q_proj + k_proj + v_proj + o_proj
344    let q = h * (nh * hd);
345    let k = h * (nkv * hd);
346    let vv = h * (nkv * hd);
347    let o = (nh * hd) * h;
348    let attn = q + k + vv + o;
349
350    // MLP (SwiGLU): gate_proj + up_proj + down_proj
351    let mlp = (h * i) + (h * i) + (i * h);
352
353    // Two RMSNorm weights per layer (input_layernorm, post_attention_layernorm).
354    let norms = 2 * h;
355
356    let per_layer = attn + mlp + norms;
357
358    // Final model.norm.weight.
359    let final_norm = h;
360
361    embedding + l * per_layer + final_norm
362}
363
364/// Pure helper that enforces GATE-ARCH-370M-011 / INV-ARCH-370M-006:
365/// the tokenizer's vocabulary size MUST exactly match the model's
366/// `vocab_size` before pretraining dispatches. Returns `Ok(())` when
367/// they match, `Err(String)` with a machine-diffable message when they
368/// do not. The caller is expected to surface the error to the user
369/// and abort the dispatch before any forward pass.
370pub fn assert_tokenizer_vocab_matches_model(
371    tokenizer_vocab_size: usize,
372    model_vocab_size: usize,
373) -> Result<(), String> {
374    if tokenizer_vocab_size == model_vocab_size {
375        return Ok(());
376    }
377    Err(format!(
378        "GATE-ARCH-370M-011 (INV-ARCH-370M-006) violated: \
379         tokenizer vocab_size ({tokenizer_vocab_size}) != model vocab_size \
380         ({model_vocab_size}). See contracts/model-families/llama-370m-sovereign-v1.yaml \
381         and contracts/tokenizer-bpe-v1.yaml — retrain the tokenizer or amend both contracts \
382         in lockstep before resuming pretraining."
383    ))
384}
385
386/// Polymorphic-path variant of [`assert_tokenizer_vocab_matches_model`] that
387/// allows `tokenizer_vocab_size <= model_vocab_size` (per
388/// `apr-pretrain-arch-polymorphic-v1` v1.3.0 §qwen_tokenizer_vocab_compatibility,
389/// SPEC-SHIP-TWO-001 §55). When fine-tuning from an HF-distributed
390/// pretrained checkpoint (Qwen2.5 / Llama2 / Mistral), `tokenizer.json`
391/// commonly materializes fewer string-token entries than the model's
392/// declared `vocab_size` declares. The gap is reserved/special slots
393/// (e.g., `<|reserved_271|>`...) that the lm_head + embedding layers
394/// have weights for but no tokenizer string maps to. Strict equality
395/// (the §24/§25 from-scratch baseline invariant) is too strict for
396/// these models; the relaxed bound preserves the OOB-safety property:
397///
398/// **Safety argument**: tokenizer.encode(text) → ids ∈ [0, tokenizer_vocab).
399/// Embedding/lm_head layers are sized for [0, model_vocab). When
400/// tokenizer_vocab ≤ model_vocab, every encoded id is in-bounds; the
401/// reserved high-id slots are never indexed at training time. When
402/// tokenizer_vocab > model_vocab, the encoder could emit ids ≥ model_vocab
403/// → N-09 OOB → silent garbage gradients → fail-fast.
404///
405/// Returns `Ok(())` when bound holds, `Err(String)` with a machine-diffable
406/// message when violated.
407pub fn assert_tokenizer_vocab_within_model_bound(
408    tokenizer_vocab_size: usize,
409    model_vocab_size: usize,
410) -> Result<(), String> {
411    if tokenizer_vocab_size <= model_vocab_size {
412        return Ok(());
413    }
414    Err(format!(
415        "GATE-ARCH-370M-011 (INV-ARCH-370M-006-RELAXED) violated: \
416         tokenizer vocab_size ({tokenizer_vocab_size}) > model vocab_size \
417         ({model_vocab_size}). See contracts/apr-pretrain-arch-polymorphic-v1.yaml \
418         §qwen_tokenizer_vocab_compatibility — for HF-distributed pretrained \
419         checkpoints, tokenizer_vocab MUST be <= model_vocab (reserved-slot \
420         tolerance); a tokenizer with MORE strings than the model expects \
421         would emit OOB ids → N-09 escape → silent garbage gradients."
422    ))
423}
424
425// ─────────────────────────────────────────────────────────────
426// FALSIFY-SHIP-017 / AC-SHIP2-007 / GATE-ARCH-370M-005
427// ─────────────────────────────────────────────────────────────
428
429/// Number of held-out prompts required by AC-SHIP2-007 / FALSIFY-SHIP-017
430/// (spec §6 Model 2: "`apr run` produces syntactically valid Python on
431/// 100 held-out prompts").
432pub const AC_SHIP2_007_HELDOUT_PROMPT_COUNT: usize = 100;
433
434/// Tolerance: `≤ 1` completion out of the 100 held-out prompts may fail
435/// to yield a Python-AST-parseable non-trivial statement prefix.
436/// Anything `≥ 2` is a ship-blocking FAIL per FALSIFY-SHIP-017.
437pub const AC_SHIP2_007_MAX_TOLERATED_SYNTAX_ERRORS: usize = 1;
438
439/// Ship-017 verdict — the pure algorithmic result of evaluating whether
440/// a 100-prompt Python-AST-parse sweep meets AC-SHIP2-007.
441#[derive(Debug, Clone, Copy, PartialEq, Eq)]
442pub enum Ship017Verdict {
443    /// `syntax_errors ≤ AC_SHIP2_007_MAX_TOLERATED_SYNTAX_ERRORS`.
444    Pass,
445    /// `syntax_errors ≥ 2` on the 100-prompt sweep.
446    Fail,
447}
448
449/// Pure threshold function for FALSIFY-SHIP-017 (AC-SHIP2-007).
450///
451/// Given `syntax_errors` — the count of held-out completions (out of
452/// `AC_SHIP2_007_HELDOUT_PROMPT_COUNT`) that failed to yield a
453/// Python-AST-parseable non-trivial statement prefix — returns the
454/// FALSIFY-SHIP-017 verdict under the rule:
455///
456///   errors ≤ 1 → Pass   (tolerate one flaky completion)
457///   errors ≥ 2 → Fail   (ship-blocker)
458///
459/// This is the algorithm-level discharge of GATE-ARCH-370M-005: the
460/// threshold itself is proven correct at `cargo test` time; full
461/// discharge (a real 100-prompt `apr run` harness against a trained
462/// 370M .apr) remains PENDING on pretraining compute-dispatch
463/// (AC-SHIP2-003/004). Fixture swap is data-only once a trained
464/// artifact exists — no harness rewrite required.
465pub const fn verdict_from_syntax_error_count(syntax_errors: usize) -> Ship017Verdict {
466    if syntax_errors <= AC_SHIP2_007_MAX_TOLERATED_SYNTAX_ERRORS {
467        Ship017Verdict::Pass
468    } else {
469        Ship017Verdict::Fail
470    }
471}
472
473// ─────────────────────────────────────────────────────────────
474// FALSIFY-SHIP-020 (AC-SHIP2-010): decode-throughput threshold
475// ─────────────────────────────────────────────────────────────
476
477/// Minimum `apr run` median decode throughput, in tokens/second, on the
478/// SHIP-TWO-001 reference hardware (RTX 4090). Source of truth:
479/// `contracts/model-families/llama-370m-sovereign-v1.yaml`
480/// GATE-ARCH-370M-006 and the SHIP-TWO-001 falsification table
481/// (FALSIFY-SHIP-020).
482pub const AC_SHIP2_010_MIN_DECODE_TPS_RTX4090: f32 = 100.0;
483
484/// Verdict for GATE-ARCH-370M-006 / FALSIFY-SHIP-020: does the measured
485/// `apr bench` median decode throughput meet the ship-gate threshold?
486#[derive(Debug, Clone, Copy, PartialEq, Eq)]
487pub enum Ship020Verdict {
488    /// Measured tok/s ≥ [`AC_SHIP2_010_MIN_DECODE_TPS_RTX4090`].
489    Pass,
490    /// Measured tok/s < [`AC_SHIP2_010_MIN_DECODE_TPS_RTX4090`] (ship-blocker).
491    Fail,
492}
493
494/// Pure threshold function implementing FALSIFY-SHIP-020: a measured
495/// median decode throughput of `measured_tps` tokens/second passes the
496/// ship-gate iff it is finite AND ≥ [`AC_SHIP2_010_MIN_DECODE_TPS_RTX4090`].
497///
498/// Non-finite inputs (NaN, ±∞) are conservatively classified as
499/// `Fail`: a benchmark run that could not produce a well-defined
500/// finite median is always ill-formed and must never be allowed to
501/// silently green the ship-gate.
502///
503/// This is the same decision-rule-vs-harness separation used by
504/// FALSIFY-SHIP-017 (syntax-error count). The compute-heavy part
505/// (`apr bench --median` on a real trained 370M .apr) is deferred to
506/// AC-SHIP2-003/004 compute-dispatch; the decision rule itself is
507/// proven today at unit-test time.
508#[must_use]
509pub fn verdict_from_decode_tps(measured_tps: f32) -> Ship020Verdict {
510    if !(measured_tps.is_finite()) {
511        return Ship020Verdict::Fail;
512    }
513    if measured_tps >= AC_SHIP2_010_MIN_DECODE_TPS_RTX4090 {
514        Ship020Verdict::Pass
515    } else {
516        Ship020Verdict::Fail
517    }
518}
519
520// ─────────────────────────────────────────────────────────────
521// AC-SHIP2-008 / FALSIFY-SHIP-018 — HumanEval pass@1 threshold
522// ─────────────────────────────────────────────────────────────
523//
524// Spec §5.2 AC-SHIP2-008 states: `apr eval --benchmark humaneval`
525// must report pass@1 ≥ 30.0% for the trained 370M `.apr` artifact.
526// The decision rule is a pure (correct, total) → pct comparison;
527// the compute-heavy harness (164 HumanEval tasks × `apr run` ×
528// greedy sampling) is fixture-swappable once a trained artifact
529// exists. Landing the threshold function today discharges
530// GATE-ARCH-370M-007 at PARTIAL_ALGORITHM_LEVEL and catches any
531// future drift in the 30.0 floor at `cargo test` time — before a
532// single HumanEval task is dispatched.
533
534/// Contract-frozen floor for AC-SHIP2-008: HumanEval pass@1 must
535/// reach **30.0%** on the trained 370M artifact. The numeric floor
536/// mirrors `contracts/model-families/llama-370m-sovereign-v1.yaml`
537/// GATE-ARCH-370M-007 rule body and spec §5.2 AC-SHIP2-008.
538pub const AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT: f32 = 30.0;
539
540/// Binary verdict emitted by [`verdict_from_pass_at_1`].
541#[derive(Debug, Clone, Copy, PartialEq, Eq)]
542pub enum Ship018Verdict {
543    /// `correct / total * 100 ≥ threshold_pct` and inputs are well-formed.
544    Pass,
545    /// Any of: ratio < threshold, `total == 0`, non-finite threshold.
546    Fail,
547}
548
549/// Decision function for AC-SHIP2-008 / FALSIFY-SHIP-018.
550///
551/// Returns [`Ship018Verdict::Pass`] iff `correct / total * 100`
552/// is ≥ `threshold_pct`. Conservative-Fail guards:
553///
554///   - `total == 0` → Fail (avoid division-by-zero; an empty run
555///     cannot satisfy a positive threshold).
556///   - `correct > total` → Fail (nonsensical input; a real
557///     harness can never report more passes than attempts).
558///   - `!threshold_pct.is_finite()` → Fail (NaN / ±∞ contract
559///     drift — no real contract floor can be non-finite).
560///
561/// Stored per-ULP ratio comparisons use f32 arithmetic to keep the
562/// verdict a pure function of its inputs with no harness state.
563#[must_use]
564pub fn verdict_from_pass_at_1(correct: usize, total: usize, threshold_pct: f32) -> Ship018Verdict {
565    if total == 0 {
566        return Ship018Verdict::Fail;
567    }
568    if correct > total {
569        return Ship018Verdict::Fail;
570    }
571    if !threshold_pct.is_finite() {
572        return Ship018Verdict::Fail;
573    }
574    // Safe: correct ≤ total ≤ usize::MAX; f32 cast preserves ordering
575    // within the humaneval range (total ≤ 164 for canonical HumanEval).
576    let ratio_pct = (correct as f32 / total as f32) * 100.0_f32;
577    if ratio_pct >= threshold_pct {
578        Ship018Verdict::Pass
579    } else {
580        Ship018Verdict::Fail
581    }
582}
583
584// ─────────────────────────────────────────────────────────────
585// FALSIFY-SHIP-016 / AC-SHIP2-006 / GATE-ARCH-370M-008 — apr qa aggregate
586// ─────────────────────────────────────────────────────────────
587
588/// Number of canonical `apr qa` gates composing AC-SHIP2-006 /
589/// FALSIFY-SHIP-016. The spec row AC-SHIP2-006 reads
590/// "`apr qa <model>.apr` — all 8 gates PASS" and the matching
591/// FALSIFY row names the decision rule as "any gate FAIL" →
592/// Fail. The 8 canonical gates (matching `QaConfig::skip_*` in
593/// `crates/apr-cli/src/commands/qa.rs`) are:
594///   1. golden_output      — correctness gate (GH-202 regression)
595///   2. throughput         — tok/s ≥ configured floor
596///   3. ollama_parity      — speedup vs Ollama baseline
597///   4. gpu_vs_cpu_speedup — GPU ≥ 2× CPU (F-PERF-042)
598///   5. tensor_contract    — layout/dtype/shape validation
599///   6. cross_format_parity — argmax(GGUF) == argmax(SafeTensors)
600///   7. ptx_parity         — batched GPU kernels vs scalar refs
601///   8. probar             — property-based tests
602///
603/// Contract-drift guard: any change to this number must be matched
604/// in lockstep across the contract, spec, and CLI qa handler.
605pub const AC_SHIP2_006_REQUIRED_QA_GATE_COUNT: usize = 8;
606
607/// Ternary verdict for FALSIFY-SHIP-016 / GATE-ARCH-370M-008.
608/// `Pass` iff every one of the 8 canonical `apr qa` gates passed.
609/// `Fail` otherwise (any single gate failure, or wrong gate count).
610#[derive(Debug, Clone, Copy, PartialEq, Eq)]
611pub enum Ship016Verdict {
612    Pass,
613    Fail,
614}
615
616/// Algorithm-level verdict rule for FALSIFY-SHIP-016 / GATE-ARCH-370M-008
617/// / AC-SHIP2-006: `apr qa <model>.apr` is an aggregate-AND over the
618/// 8 canonical QA gates. Verdict is `Pass` iff **exactly 8** gate
619/// results were supplied **and every one passed**. Any shorter/longer
620/// slice is a contract-drift Fail; any single `false` entry is a
621/// ship-blocking Fail. This proves the decision rule without running
622/// the compute-heavy gates themselves; the harness (realizar, cuda,
623/// tokenizer, corpus) is fixture-swappable once a real trained 370M
624/// .apr exists. Spec §7 row FALSIFY-SHIP-016 ("any gate FAIL") is
625/// the counter-example this fn is built to classify.
626#[must_use]
627pub fn verdict_from_qa_gates(gate_results: &[bool]) -> Ship016Verdict {
628    if gate_results.len() != AC_SHIP2_006_REQUIRED_QA_GATE_COUNT {
629        return Ship016Verdict::Fail;
630    }
631    if gate_results.iter().all(|&passed| passed) {
632        Ship016Verdict::Pass
633    } else {
634        Ship016Verdict::Fail
635    }
636}
637
638// ─────────────────────────────────────────────────────────────
639// FALSIFY-SHIP-013 / AC-SHIP2-003 / GATE-ARCH-370M-013 — val CE loss floor
640// ─────────────────────────────────────────────────────────────
641//
642// AC-SHIP2-003 (spec §5.2) states: "`entrenar` pretraining loop reaches
643// target loss (CE ≤ 2.2 on val)". The decision rule is a pure single-
644// number f32 threshold check on a measured cross-entropy value. Cross-
645// entropy is non-negative by definition (H(p,q) ≥ 0 for all probability
646// distributions p,q), so the admissible input domain is `[0.0, +∞)`; any
647// negative measurement indicates a broken loss harness (sign flip,
648// log-domain underflow, subtract instead of add) and must Fail closed.
649//
650// This PARTIAL_ALGORITHM_LEVEL discharge binds the decision rule only.
651// The compute-heavy half — an actual `apr pretrain --validate` loop
652// producing a live val CE from MODEL-2 training — remains blocked on
653// AC-SHIP2-003 compute-dispatch. The decision rule itself (what number
654// constitutes a Pass) is proven today at `cargo test` time via the
655// mutation survey below.
656
657/// Maximum acceptable cross-entropy loss on the validation set for
658/// MODEL-2 (albor 370M Sovereign) at the end of pretraining. Spec §5.2
659/// AC-SHIP2-003: "CE ≤ 2.2 on val". A measured val CE strictly above
660/// 2.2 is a ship-blocker (training did not converge well enough for
661/// the 370M target to hit its HumanEval / syntax-parse downstream
662/// gates). Pinned here so any contract drift in either direction
663/// (loosening to 2.5, hardening to 2.0) is caught at compile+test
664/// time, not at a production training run.
665///
666/// f32-exact: `2.2` is representable in IEEE-754 binary32 as the
667/// closest-round value `0x400CCCCD` = 2.20000004768371582...; the
668/// ULP-above neighbour is strictly greater and is used as the
669/// sharpest Fail counter-example in the mutation survey.
670pub const AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS: f32 = 2.2;
671
672/// Binary verdict for FALSIFY-SHIP-013 / AC-SHIP2-003 /
673/// GATE-ARCH-370M-013. `Pass` iff the measured val CE is finite AND
674/// non-negative AND at or below [`AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS`].
675/// `Fail` otherwise (including every non-finite value: NaN, +∞, -∞,
676/// and every negative value, which is a harness-bug domain violation
677/// since H(p,q) ≥ 0 by definition).
678#[derive(Debug, Clone, Copy, PartialEq, Eq)]
679pub enum Ship013Verdict {
680    /// Measured val CE ∈ `[0.0, AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS]`.
681    Pass,
682    /// Measured val CE > ceiling, or non-finite, or negative (domain
683    /// violation — a real cross-entropy can never be < 0).
684    Fail,
685}
686
687/// Algorithm-level verdict rule for FALSIFY-SHIP-013 / AC-SHIP2-003 /
688/// GATE-ARCH-370M-013: a single f32 threshold check against the MODEL-2
689/// val-CE ceiling. Returns [`Ship013Verdict::Fail`] conservatively for
690/// any non-finite input (NaN, +∞, -∞) AND for any negative input (CE
691/// is ≥ 0 by definition — a negative value means the loss harness is
692/// broken, which must never be silently promoted to a Pass).
693///
694/// The full discharge (live `apr pretrain --validate` loop producing
695/// a real MODEL-2 val CE on RTX 4090 ≤ 2.2) remains blocked on
696/// AC-SHIP2-003 compute-dispatch.
697#[must_use]
698pub const fn verdict_from_val_ce_loss(measured_ce: f32) -> Ship013Verdict {
699    if !measured_ce.is_finite() {
700        return Ship013Verdict::Fail;
701    }
702    if measured_ce < 0.0 {
703        // Cross-entropy is non-negative by definition; a negative
704        // measurement is a harness bug, not a "better than zero" Pass.
705        return Ship013Verdict::Fail;
706    }
707    if measured_ce <= AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS {
708        Ship013Verdict::Pass
709    } else {
710        Ship013Verdict::Fail
711    }
712}
713
714// ─────────────────────────────────────────────────────────────
715// FALSIFY-SHIP-014 / AC-SHIP2-004 / GATE-ARCH-370M-014 — training-budget floor
716// ─────────────────────────────────────────────────────────────
717//
718// AC-SHIP2-004 (spec §5.2) states: "Training on RTX 4090 completes
719// within 21 days (hardware budget)". The decision rule is a pure
720// single-number u32 threshold check on measured wall-clock days. u32
721// naturally rules out negative values (no need for an explicit domain
722// guard); the only extrema to cover are the boundary (21), the
723// immediate neighbours (20 / 22), and the saturation point u32::MAX.
724// Zero days is a trivial Pass (under budget).
725//
726// This PARTIAL_ALGORITHM_LEVEL discharge binds the decision rule only.
727// The compute-heavy half — an actual wall-clock measurement of a real
728// 370M pretraining run on RTX 4090 → ≤ 21 days — remains blocked on
729// AC-SHIP2-004 compute-dispatch. The decision rule itself (what
730// duration constitutes a Pass) is proven today at `cargo test` time
731// via the mutation survey below.
732
733/// Maximum acceptable wall-clock training duration, in integer days,
734/// for MODEL-2 (albor 370M Sovereign) on the SHIP-TWO-001 reference
735/// RTX 4090 host. Spec §5.2 AC-SHIP2-004: "Training on RTX 4090
736/// completes within 21 days (hardware budget)". A measured duration
737/// strictly above 21 days is a ship-blocker (the hardware budget
738/// overflowed and a 2× H100 week-3 escape hatch from Spec §9 Risk #4
739/// is required). Pinned here so any contract drift in either
740/// direction (extending to 30, compressing to 14) is caught at
741/// compile+test time, not mid-pretraining.
742pub const AC_SHIP2_004_MAX_TRAINING_DURATION_DAYS: u32 = 21;
743
744/// Binary verdict for FALSIFY-SHIP-014 / AC-SHIP2-004 /
745/// GATE-ARCH-370M-014. `Pass` iff the measured wall-clock training
746/// duration in days is at or below
747/// [`AC_SHIP2_004_MAX_TRAINING_DURATION_DAYS`]. `Fail` otherwise.
748#[derive(Debug, Clone, Copy, PartialEq, Eq)]
749pub enum Ship014Verdict {
750    /// Measured training duration ≤ `AC_SHIP2_004_MAX_TRAINING_DURATION_DAYS`.
751    Pass,
752    /// Measured training duration > ceiling (ship-blocker per Spec §9
753    /// Risk #4).
754    Fail,
755}
756
757/// Algorithm-level verdict rule for FALSIFY-SHIP-014 / AC-SHIP2-004 /
758/// GATE-ARCH-370M-014: a single u32 threshold check against the
759/// MODEL-2 hardware-budget ceiling. Unlike the f32 ship gates
760/// (SHIP-007, SHIP-013, SHIP-020), u32 automatically rules out
761/// negatives (no domain guard needed) and has no non-finite states;
762/// the only interesting counter-examples are the boundary (21), the
763/// immediate neighbours (20 / 22), and u32::MAX.
764///
765/// Zero days is Pass (trivially under-budget, e.g. a cached artifact
766/// or a same-day re-run). The full discharge (live wall-clock
767/// measurement of MODEL-2 pretraining on RTX 4090 ≤ 21 days) remains
768/// blocked on AC-SHIP2-004 compute-dispatch.
769#[must_use]
770pub const fn verdict_from_training_duration_days(measured_days: u32) -> Ship014Verdict {
771    if measured_days <= AC_SHIP2_004_MAX_TRAINING_DURATION_DAYS {
772        Ship014Verdict::Pass
773    } else {
774        Ship014Verdict::Fail
775    }
776}
777
778// ─────────────────────────────────────────────────────────────
779// Unit tests
780// ─────────────────────────────────────────────────────────────
781
782#[cfg(test)]
783mod tests {
784    use super::*;
785
786    /// INV-ARCH-370M-002/003/004/005/006/008 — byte-equality with contract.
787    #[test]
788    fn config_matches_contract_values() {
789        // §architecture
790        assert_eq!(Llama370MConfig::HIDDEN_DIM, 1024);
791        assert_eq!(Llama370MConfig::NUM_LAYERS, 24);
792        assert_eq!(Llama370MConfig::NUM_HEADS, 16);
793        assert_eq!(Llama370MConfig::NUM_KV_HEADS, 4);
794        assert_eq!(Llama370MConfig::HEAD_DIM, 64);
795        assert_eq!(Llama370MConfig::INTERMEDIATE_DIM, 2816);
796        assert_eq!(Llama370MConfig::VOCAB_SIZE, 50_257);
797        assert_eq!(Llama370MConfig::MAX_POSITION_EMBEDDINGS, 4096);
798        assert!((Llama370MConfig::ROPE_THETA - 10_000.0_f32).abs() < 1e-6);
799        assert!((Llama370MConfig::RMS_NORM_EPS - 1.0e-5_f32).abs() < 1e-9);
800
801        // §constraints
802        assert!(Llama370MConfig::TIED_EMBEDDINGS);
803        assert!(!Llama370MConfig::HAS_BIAS);
804
805        // Derived: INV-ARCH-370M-002 & 003
806        assert_eq!(
807            Llama370MConfig::NUM_HEADS * Llama370MConfig::HEAD_DIM,
808            Llama370MConfig::HIDDEN_DIM,
809        );
810        assert_eq!(Llama370MConfig::NUM_HEADS % Llama370MConfig::NUM_KV_HEADS, 0);
811    }
812
813    /// GATE-ARCH-370M-011 / INV-ARCH-370M-006 — pure vocab-parity helper
814    /// MUST reject any mismatch between tokenizer vocab_size and model
815    /// vocab_size, and MUST accept equal values. The real-compute MODEL-2
816    /// dispatch at commit 29607ed33 surfaced this when a tokenizer at
817    /// vocab=50_257 was paired with a model pinned at VOCAB_SIZE=50_000;
818    /// the N-09 OOB escape masked the mismatch → garbage gradients.
819    /// Task #131 bumped VOCAB_SIZE to 50_257 (Option A); the counter-example
820    /// value below now exercises the opposite drift (a tokenizer one token
821    /// short of contract) so the helper is still exercised on real mismatch.
822    #[test]
823    fn falsify_gate_arch_370m_011_helper_rejects_mismatch() {
824        assert!(assert_tokenizer_vocab_matches_model(
825            Llama370MConfig::VOCAB_SIZE,
826            Llama370MConfig::VOCAB_SIZE,
827        )
828        .is_ok());
829
830        let mismatch = Llama370MConfig::VOCAB_SIZE - 1;
831        let err = assert_tokenizer_vocab_matches_model(mismatch, Llama370MConfig::VOCAB_SIZE)
832            .expect_err("mismatch must return Err");
833        assert!(
834            err.contains("GATE-ARCH-370M-011")
835                && err.contains(&mismatch.to_string())
836                && err.contains(&Llama370MConfig::VOCAB_SIZE.to_string()),
837            "error must name the gate and both vocab sizes for forensics, got: {err}",
838        );
839
840        assert!(assert_tokenizer_vocab_matches_model(0, 1).is_err());
841        assert!(assert_tokenizer_vocab_matches_model(
842            Llama370MConfig::VOCAB_SIZE + 1,
843            Llama370MConfig::VOCAB_SIZE
844        )
845        .is_err());
846    }
847
848    /// FALSIFY-APR-PRETRAIN-ARCH-009 (§55) — relaxed-bound helper accepts
849    /// `tokenizer_vocab <= model_vocab` for the polymorphic init path.
850    /// Discharges the §55 finding: HF-distributed Qwen2.5-Coder-0.5B
851    /// materializes 151643 BPE entries + 22 added = 151665 effective
852    /// strings, but config.json declares `vocab_size = 151936` (271
853    /// reserved slots). The relaxed bound preserves OOB safety while
854    /// admitting the standard HF reserved-slot pattern.
855    #[test]
856    fn falsify_apr_pretrain_arch_009_relaxed_bound_accepts_qwen_reserved_slots() {
857        // The exact §55 LIVE smoke shape: 151665 ≤ 151936 must pass.
858        const QWEN_BPE_PLUS_ADDED: usize = 151_665;
859        const QWEN_DECLARED_VOCAB: usize = 151_936;
860        assert!(
861            assert_tokenizer_vocab_within_model_bound(
862                QWEN_BPE_PLUS_ADDED,
863                QWEN_DECLARED_VOCAB
864            )
865            .is_ok(),
866            "FALSIFY-APR-PRETRAIN-ARCH-009: tokenizer 151665 ≤ model 151936 MUST pass relaxed bound \
867             (HF reserved-slot tolerance)"
868        );
869
870        // BPE-only count (without --include-added-tokens): 151643 ≤ 151936 must also pass.
871        const QWEN_BPE_ONLY: usize = 151_643;
872        assert!(
873            assert_tokenizer_vocab_within_model_bound(QWEN_BPE_ONLY, QWEN_DECLARED_VOCAB).is_ok()
874        );
875
876        // Equality remains acceptable (Llama370M-from-scratch case).
877        assert!(assert_tokenizer_vocab_within_model_bound(
878            Llama370MConfig::VOCAB_SIZE,
879            Llama370MConfig::VOCAB_SIZE
880        )
881        .is_ok());
882    }
883
884    /// FALSIFY-APR-PRETRAIN-ARCH-010 (§55) — relaxed-bound helper REJECTS
885    /// `tokenizer_vocab > model_vocab`. This is the OOB-safety guard:
886    /// a tokenizer producing ids ≥ model_vocab would silently corrupt
887    /// embedding lookup. Strict-greater MUST fail-fast.
888    #[test]
889    fn falsify_apr_pretrain_arch_010_relaxed_bound_rejects_oversized_tokenizer() {
890        const QWEN_DECLARED_VOCAB: usize = 151_936;
891        let oversized = QWEN_DECLARED_VOCAB + 1;
892        let err = assert_tokenizer_vocab_within_model_bound(oversized, QWEN_DECLARED_VOCAB)
893            .expect_err("FALSIFY-APR-PRETRAIN-ARCH-010: tokenizer > model MUST fail-fast");
894        assert!(
895            err.contains("RELAXED") && err.contains("OOB"),
896            "error must cite the relaxed-mode invariant + OOB risk: {err}"
897        );
898        assert!(
899            err.contains(&oversized.to_string()) && err.contains(&QWEN_DECLARED_VOCAB.to_string()),
900            "error must name both sizes for forensics: {err}"
901        );
902    }
903
904    /// INV-ARCH-370M-001 — estimated param count within [366M, 374M].
905    ///
906    /// Recomputes the canonical transformer param formula and asserts the
907    /// answer lies in the ±1% band the contract permits for the final
908    /// trained artifact.
909    #[test]
910    fn estimated_param_count_within_contract_band() {
911        let p = estimated_param_count();
912        let stored = estimated_stored_param_count();
913
914        // Sanity printout for debugging drift.
915        eprintln!("albor-370m nominal param count = {p} ({} M)", p / 1_000_000,);
916        eprintln!(
917            "albor-370m stored  param count = {stored} ({} M, lm_head tied)",
918            stored / 1_000_000,
919        );
920
921        // INV-ARCH-370M-001 — nominal ±1% band.
922        assert!(
923            p >= Llama370MConfig::PARAMETERS_MIN,
924            "nominal param count {p} below INV-ARCH-370M-001 floor (366M)",
925        );
926        assert!(
927            p <= Llama370MConfig::PARAMETERS_MAX,
928            "nominal param count {p} above INV-ARCH-370M-001 ceiling (374M)",
929        );
930
931        // Tighter ±5% sanity band around the 370M nominal figure, per
932        // this scaffold's unit-test requirements.
933        let nominal = Llama370MConfig::PARAMETERS_NOMINAL as f64;
934        let pct = (p as f64 - nominal).abs() / nominal;
935        assert!(
936            pct < 0.05,
937            "nominal param count {p} differs from 370M by {:.2}% (> 5%)",
938            pct * 100.0,
939        );
940
941        // Tying must reduce storage by exactly one vocab*hidden matrix.
942        assert_eq!(
943            p - stored,
944            Llama370MConfig::VOCAB_SIZE * Llama370MConfig::HIDDEN_DIM,
945            "tying accounting mismatch",
946        );
947    }
948
949    /// Sanity: the compile-time `validate()` matches the runtime check.
950    #[test]
951    fn validate_is_a_noop_at_runtime() {
952        // If `validate()` compiled, it's already been proven to not panic
953        // (the `const _: () = ...;` at module scope forced evaluation at
954        // compile time). Calling it again at runtime is a free
955        // defence-in-depth assertion.
956        Llama370MConfig::validate();
957    }
958
959    /// Shape newtypes are zero-sized and usable in generic contexts.
960    #[test]
961    fn shape_newtypes_compile_and_roundtrip() {
962        type Hidden = HiddenDim<{ Llama370MConfig::HIDDEN_DIM }>;
963        type Heads = NumHeads<{ Llama370MConfig::NUM_HEADS }>;
964        type KvHeads = NumKvHeads<{ Llama370MConfig::NUM_KV_HEADS }>;
965        type Head = HeadDim<{ Llama370MConfig::HEAD_DIM }>;
966        type Inter = IntermediateDim<{ Llama370MConfig::INTERMEDIATE_DIM }>;
967        type Layers = NumLayers<{ Llama370MConfig::NUM_LAYERS }>;
968        type Vocab = VocabSize<{ Llama370MConfig::VOCAB_SIZE }>;
969
970        assert_eq!(Hidden::VALUE, 1024);
971        assert_eq!(Heads::VALUE, 16);
972        assert_eq!(KvHeads::VALUE, 4);
973        assert_eq!(Head::VALUE, 64);
974        assert_eq!(Inter::VALUE, 2816);
975        assert_eq!(Layers::VALUE, 24);
976        assert_eq!(Vocab::VALUE, 50_257);
977
978        // Zero-sized: all shape newtypes cost nothing at runtime.
979        assert_eq!(std::mem::size_of::<Hidden>(), 0);
980        assert_eq!(std::mem::size_of::<Heads>(), 0);
981    }
982
983    // ========================================================================
984    // C-LLAMA-370M-SOVEREIGN / AC-SHIP2-001 / FALSIFY-SHIP-011
985    // ========================================================================
986
987    /// The sovereign contract YAML embedded at compile time so the test
988    /// binary has a byte-frozen copy — any edit to the file is caught
989    /// by the next test run, not discovered post-publish.
990    const SOVEREIGN_CONTRACT_YAML: &str =
991        include_str!("../../../../contracts/model-families/llama-370m-sovereign-v1.yaml");
992
993    /// GATE-ARCH-370M-001 / INV-ARCH-370M-002..008: every architectural
994    /// constant declared in `contracts/model-families/llama-370m-sovereign-v1.yaml`
995    /// matches the Rust scaffold `Llama370MConfig::*` const byte-equally.
996    ///
997    /// Discharges FALSIFY-SHIP-011 (AC-SHIP2-001): architecture registered
998    /// in a llama-family contract entry whose dimensions validate against
999    /// `contracts/model-families/_schema.yaml` AND match the compile-time
1000    /// Rust config that the training loop will actually consume. Binds the
1001    /// YAML contract and the Rust scaffold: if either drifts without the
1002    /// other, this test fails — catching the MODEL-1 QLoRA class of
1003    /// recipe/artifact drift at `cargo test` time, before a single step
1004    /// of pretraining compute runs.
1005    #[test]
1006    fn falsify_ship_011_rust_scaffold_matches_yaml_contract() {
1007        let doc: serde_yaml::Value = serde_yaml::from_str(SOVEREIGN_CONTRACT_YAML)
1008            .expect("llama-370m-sovereign-v1.yaml must parse as YAML");
1009
1010        // Contract identity — must be the right contract.
1011        assert_eq!(
1012            doc["contract_id"].as_str(),
1013            Some("C-LLAMA-370M-SOVEREIGN"),
1014            "wrong contract loaded — check include_str! path",
1015        );
1016        assert_eq!(doc["family"].as_str(), Some("llama"));
1017        assert_eq!(doc["size_variant"].as_str(), Some("370m"));
1018
1019        // Architectural dimensions (INV-ARCH-370M-002, -003, -005, -006).
1020        let arch = &doc["architecture"];
1021        assert_eq!(
1022            arch["hidden_dim"].as_u64().map(|v| v as usize),
1023            Some(Llama370MConfig::HIDDEN_DIM),
1024            "YAML architecture.hidden_dim drifted from Rust const",
1025        );
1026        assert_eq!(
1027            arch["num_layers"].as_u64().map(|v| v as usize),
1028            Some(Llama370MConfig::NUM_LAYERS),
1029        );
1030        assert_eq!(
1031            arch["num_heads"].as_u64().map(|v| v as usize),
1032            Some(Llama370MConfig::NUM_HEADS),
1033        );
1034        assert_eq!(
1035            arch["num_kv_heads"].as_u64().map(|v| v as usize),
1036            Some(Llama370MConfig::NUM_KV_HEADS),
1037        );
1038        assert_eq!(arch["head_dim"].as_u64().map(|v| v as usize), Some(Llama370MConfig::HEAD_DIM),);
1039        assert_eq!(
1040            arch["intermediate_dim"].as_u64().map(|v| v as usize),
1041            Some(Llama370MConfig::INTERMEDIATE_DIM),
1042        );
1043        assert_eq!(
1044            arch["vocab_size"].as_u64().map(|v| v as usize),
1045            Some(Llama370MConfig::VOCAB_SIZE),
1046        );
1047        assert_eq!(
1048            arch["max_position_embeddings"].as_u64().map(|v| v as usize),
1049            Some(Llama370MConfig::MAX_POSITION_EMBEDDINGS),
1050        );
1051        let rope_theta = arch["rope_theta"].as_f64().expect("rope_theta must be a float");
1052        assert!(
1053            (rope_theta - f64::from(Llama370MConfig::ROPE_THETA)).abs() < 1e-6,
1054            "YAML rope_theta {rope_theta} != Rust const {}",
1055            Llama370MConfig::ROPE_THETA,
1056        );
1057
1058        // Constraints (INV-ARCH-370M-004, -008).
1059        let constraints = &doc["constraints"];
1060        assert_eq!(
1061            constraints["tied_embeddings"].as_bool(),
1062            Some(Llama370MConfig::TIED_EMBEDDINGS),
1063        );
1064        assert_eq!(constraints["has_bias"].as_bool(), Some(Llama370MConfig::HAS_BIAS),);
1065        assert_eq!(constraints["attention_type"].as_str(), Some("gqa"));
1066        assert_eq!(constraints["activation"].as_str(), Some("silu"));
1067        assert_eq!(constraints["norm_type"].as_str(), Some("rmsnorm"));
1068        assert_eq!(constraints["positional_encoding"].as_str(), Some("rope"));
1069        assert_eq!(constraints["mlp_type"].as_str(), Some("swiglu"));
1070    }
1071
1072    /// GATE-ARCH-370M-001 (gate status): once FALSIFY-SHIP-011 is
1073    /// discharged, the sovereign contract MUST declare status ACTIVE —
1074    /// a PROPOSED gate cannot be a ship-blocker.
1075    #[test]
1076    fn falsify_ship_011_sovereign_contract_is_active() {
1077        let doc: serde_yaml::Value =
1078            serde_yaml::from_str(SOVEREIGN_CONTRACT_YAML).expect("parse sovereign contract");
1079        assert_eq!(
1080            doc["status"].as_str(),
1081            Some("ACTIVE"),
1082            "C-LLAMA-370M-SOVEREIGN must be ACTIVE once FALSIFY-SHIP-011 \
1083             discharges — PROPOSED contracts cannot gate a ship",
1084        );
1085    }
1086
1087    // ========================================================================
1088    // GATE-ARCH-370M-004 / AC-SHIP2-009 / FALSIFY-SHIP-019
1089    // ========================================================================
1090
1091    /// Enumerate every APR tensor name the 370M architecture produces.
1092    ///
1093    /// Returns `(name, expected_shape)` pairs. Ordering mirrors the
1094    /// canonical GGUF/APR dump order: embedding → per-layer tensors
1095    /// (24 layers × 9 tensors) → final norm. `lm_head.weight` shares
1096    /// storage with `model.embed_tokens.weight` per INV-ARCH-370M-004
1097    /// (tied), but the layout contract records it as a separate entry
1098    /// because the kernel path needs a named row-major [vocab, hidden]
1099    /// reference at decode time.
1100    fn enumerate_370m_apr_tensors() -> Vec<(String, Vec<usize>)> {
1101        let h = Llama370MConfig::HIDDEN_DIM;
1102        let v = Llama370MConfig::VOCAB_SIZE;
1103        let i = Llama370MConfig::INTERMEDIATE_DIM;
1104        let nh = Llama370MConfig::NUM_HEADS;
1105        let nkv = Llama370MConfig::NUM_KV_HEADS;
1106        let hd = Llama370MConfig::HEAD_DIM;
1107        let layers = Llama370MConfig::NUM_LAYERS;
1108
1109        let mut out: Vec<(String, Vec<usize>)> = Vec::with_capacity(3 + 9 * layers);
1110        out.push(("model.embed_tokens.weight".into(), vec![v, h]));
1111        out.push(("lm_head.weight".into(), vec![v, h]));
1112        for n in 0..layers {
1113            out.push((format!("model.layers.{n}.self_attn.q_proj.weight"), vec![nh * hd, h]));
1114            out.push((format!("model.layers.{n}.self_attn.k_proj.weight"), vec![nkv * hd, h]));
1115            out.push((format!("model.layers.{n}.self_attn.v_proj.weight"), vec![nkv * hd, h]));
1116            out.push((format!("model.layers.{n}.self_attn.o_proj.weight"), vec![h, nh * hd]));
1117            out.push((format!("model.layers.{n}.mlp.gate_proj.weight"), vec![i, h]));
1118            out.push((format!("model.layers.{n}.mlp.up_proj.weight"), vec![i, h]));
1119            out.push((format!("model.layers.{n}.mlp.down_proj.weight"), vec![h, i]));
1120            out.push((format!("model.layers.{n}.input_layernorm.weight"), vec![h]));
1121            out.push((format!("model.layers.{n}.post_attention_layernorm.weight"), vec![h]));
1122        }
1123        out.push(("model.norm.weight".into(), vec![h]));
1124        out
1125    }
1126
1127    /// FALSIFY-SHIP-019 (AC-SHIP2-009) — algorithm-level PARTIAL proof
1128    /// that every APR tensor the 370M architecture produces is covered
1129    /// by `aprender::format::layout_contract` (the authoritative
1130    /// row-major validator reused by every GGUF↔APR export site, per
1131    /// spec §9 Risk #2 mitigation).
1132    ///
1133    /// This test proves three things without needing a trained model:
1134    ///   1. **Coverage:** every 370M tensor name normalises to a
1135    ///      contract entry — no unknown-tensor silent-skip gap.
1136    ///   2. **Row-major ordering:** every 2D tensor's enumerated shape
1137    ///      is `[out_dim, in_dim]` (the row-major APR layout mandated
1138    ///      by INV-ARCH-370M-009 and by LAYOUT-001). Specifically
1139    ///      `lm_head.weight` is `[vocab, hidden]`, never reversed —
1140    ///      GH-202 root cause.
1141    ///   3. **Critical-tensor enforcement:** `validate_apr_shape` on
1142    ///      `lm_head.weight` accepts `[vocab, hidden]` AND rejects
1143    ///      `[hidden, vocab]`, proving the validator actively catches
1144    ///      the GH-202 class of layout bug.
1145    ///
1146    /// **Discharge:** `evidence_discharged_by` on GATE-ARCH-370M-004;
1147    /// full discharge blocks on real trained 370M artifact (need the
1148    /// GGUF export path to actually invoke `validate_apr_shape` on
1149    /// real tensor bytes, which requires a trained `.apr`).
1150    #[test]
1151    fn falsify_ship_019_layout_contract_covers_every_370m_tensor() {
1152        use aprender::format::layout_contract::LayoutContract;
1153        let contract = LayoutContract::new();
1154        let tensors = enumerate_370m_apr_tensors();
1155
1156        // Invariant 1: the enumerator produces exactly the expected number
1157        // of APR entries for a 24-layer 370M Llama (1 embedding + 1 lm_head
1158        // + 9 per-layer + 1 final norm).
1159        assert_eq!(
1160            tensors.len(),
1161            3 + 9 * Llama370MConfig::NUM_LAYERS,
1162            "370M enumerator produced wrong tensor count — scaffold drift",
1163        );
1164
1165        // Invariant 2: coverage — every enumerated name resolves to a
1166        // TensorContract entry. Pattern-normalisation collapses
1167        // `model.layers.<n>.*` to `model.layers.{n}.*`.
1168        for (name, _) in &tensors {
1169            assert!(
1170                contract.get_apr_contract(name).is_some(),
1171                "370M tensor `{name}` has no layout_contract entry — \
1172                 LAYOUT-001 coverage gap (every tensor in this model must \
1173                 pattern-match a TensorContract or GGUF export layout will \
1174                 silently skip it)",
1175            );
1176        }
1177
1178        // Invariant 3: row-major ordering — every 2D tensor enumerated
1179        // above has shape `[out_dim, in_dim]`. The ordering is the whole
1180        // point of LAYOUT-001 (see layout_contract.rs §Key Principles).
1181        // Spot-check the pinned invariants rather than re-parsing the
1182        // formula strings.
1183        let lm = tensors
1184            .iter()
1185            .find(|(n, _)| n == "lm_head.weight")
1186            .expect("lm_head must be enumerated");
1187        assert_eq!(
1188            lm.1,
1189            vec![Llama370MConfig::VOCAB_SIZE, Llama370MConfig::HIDDEN_DIM],
1190            "lm_head.weight must be row-major [vocab, hidden] — GH-202 \
1191             root cause; reversed `[hidden, vocab]` produces [PAD] garbage",
1192        );
1193        let embed = tensors
1194            .iter()
1195            .find(|(n, _)| n == "model.embed_tokens.weight")
1196            .expect("embed_tokens must be enumerated");
1197        assert_eq!(
1198            embed.1,
1199            vec![Llama370MConfig::VOCAB_SIZE, Llama370MConfig::HIDDEN_DIM],
1200            "embed_tokens.weight must be row-major [vocab, hidden]",
1201        );
1202        // GQA: K/V projections are 4× smaller on the out_dim axis vs Q/O.
1203        let k0 = tensors
1204            .iter()
1205            .find(|(n, _)| n == "model.layers.0.self_attn.k_proj.weight")
1206            .expect("k_proj layer 0 must be enumerated");
1207        assert_eq!(
1208            k0.1,
1209            vec![
1210                Llama370MConfig::NUM_KV_HEADS * Llama370MConfig::HEAD_DIM,
1211                Llama370MConfig::HIDDEN_DIM,
1212            ],
1213            "k_proj must be row-major [kv_heads*head_dim, hidden] — GQA",
1214        );
1215        let q0 = tensors
1216            .iter()
1217            .find(|(n, _)| n == "model.layers.0.self_attn.q_proj.weight")
1218            .expect("q_proj layer 0 must be enumerated");
1219        assert_eq!(
1220            q0.1,
1221            vec![
1222                Llama370MConfig::NUM_HEADS * Llama370MConfig::HEAD_DIM,
1223                Llama370MConfig::HIDDEN_DIM,
1224            ],
1225            "q_proj must be row-major [heads*head_dim, hidden]",
1226        );
1227
1228        // Invariant 4: `validate_apr_shape` actively enforces the critical
1229        // tensor. Correct shape passes, reversed shape fails — the
1230        // validator must catch the GH-202 class of bug, not just
1231        // silently accept.
1232        contract
1233            .validate_apr_shape(
1234                "lm_head.weight",
1235                &[Llama370MConfig::VOCAB_SIZE, Llama370MConfig::HIDDEN_DIM],
1236                Llama370MConfig::VOCAB_SIZE,
1237                Llama370MConfig::HIDDEN_DIM,
1238            )
1239            .expect("correct [vocab, hidden] lm_head must validate");
1240        let bad = contract.validate_apr_shape(
1241            "lm_head.weight",
1242            &[Llama370MConfig::HIDDEN_DIM, Llama370MConfig::VOCAB_SIZE],
1243            Llama370MConfig::VOCAB_SIZE,
1244            Llama370MConfig::HIDDEN_DIM,
1245        );
1246        assert!(
1247            bad.is_err(),
1248            "reversed [hidden, vocab] lm_head MUST be rejected by the \
1249             layout contract — this is GH-202 regression protection",
1250        );
1251    }
1252
1253    /// GATE-ARCH-370M-004 wiring check: once FALSIFY-SHIP-019 has an
1254    /// algorithm-level PARTIAL discharge, the sovereign contract YAML
1255    /// MUST record `discharge_status: PARTIAL_ALGORITHM_LEVEL` +
1256    /// `evidence_discharged_by` + `full_discharge_blocks_on` on
1257    /// GATE-ARCH-370M-004. Any edit that drops those fields fails this
1258    /// test before the artifact ships.
1259    #[test]
1260    fn falsify_ship_019_gate_arch_370m_004_has_partial_discharge_marker() {
1261        let doc: serde_yaml::Value =
1262            serde_yaml::from_str(SOVEREIGN_CONTRACT_YAML).expect("parse sovereign contract");
1263        let gates =
1264            doc["gates"].as_sequence().expect("gates must be a sequence in sovereign contract");
1265        let gate = gates
1266            .iter()
1267            .find(|g| g["id"].as_str() == Some("GATE-ARCH-370M-004"))
1268            .expect("GATE-ARCH-370M-004 must exist in sovereign contract");
1269
1270        assert_eq!(
1271            gate["falsification_id"].as_str(),
1272            Some("FALSIFY-SHIP-019"),
1273            "GATE-ARCH-370M-004 must bind FALSIFY-SHIP-019",
1274        );
1275        assert_eq!(
1276            gate["binds_to"].as_str(),
1277            Some("AC-SHIP2-009"),
1278            "GATE-ARCH-370M-004 must bind AC-SHIP2-009",
1279        );
1280        assert_eq!(
1281            gate["discharge_status"].as_str(),
1282            Some("PARTIAL_ALGORITHM_LEVEL"),
1283            "GATE-ARCH-370M-004 must advertise PARTIAL_ALGORITHM_LEVEL \
1284             (full discharge blocks on real trained 370M .apr)",
1285        );
1286        let evidence = gate["evidence_discharged_by"]
1287            .as_sequence()
1288            .expect("GATE-ARCH-370M-004 must have evidence_discharged_by");
1289        assert!(
1290            !evidence.is_empty(),
1291            "GATE-ARCH-370M-004 evidence_discharged_by must list \
1292             at least one test function or artifact",
1293        );
1294        assert!(
1295            gate["full_discharge_blocks_on"].as_str().is_some(),
1296            "PARTIAL gate must document full_discharge_blocks_on",
1297        );
1298        assert_eq!(
1299            gate["ship_blocking"].as_bool(),
1300            Some(true),
1301            "GATE-ARCH-370M-004 must advertise ship_blocking:true — the \
1302             gate's `verdict:pass` alone is insufficient green while \
1303             discharge_status == PARTIAL_ALGORITHM_LEVEL",
1304        );
1305    }
1306
1307    // ========================================================================
1308    // GATE-ARCH-370M-005 / AC-SHIP2-007 / FALSIFY-SHIP-017
1309    // ========================================================================
1310
1311    /// FALSIFY-SHIP-017 (AC-SHIP2-007) — algorithm-level proof of the
1312    /// Python-AST-parse threshold function.
1313    ///
1314    /// The full-discharge harness (100 held-out prompts × `apr run` ×
1315    /// Python AST parse) blocks on a real trained 370M .apr. But the
1316    /// *decision rule* — "≥ 2 syntax errors on 100 prompts is a
1317    /// ship-blocker, ≤ 1 tolerated" — is a pure integer threshold and
1318    /// can be proven correct today. Any edit to `verdict_from_syntax_error_count`
1319    /// that widens the tolerance (or flips the boundary) is caught here
1320    /// before the artifact ships.
1321    ///
1322    /// Covers four invariants:
1323    ///   1. **Zero errors** → Pass (the trivial unanimous-parse case).
1324    ///   2. **Exactly-one error** → Pass (the tolerance boundary; matches
1325    ///      the EX-06 harness' `tolerate ≤ 1 SyntaxError` rule and
1326    ///      spec-§6 FALSIFY-SHIP-017 wording `tolerate ≤1`).
1327    ///   3. **Exactly-two errors** → Fail (the ship-blocker boundary;
1328    ///      FALSIFY-SHIP-017 says `≥ 2 SyntaxError`).
1329    ///   4. **Monotonicity** — raising the error count can only worsen
1330    ///      the verdict (Pass → Fail is one-way). This rules out any
1331    ///      future threshold edit that accidentally promotes a high
1332    ///      error count back to Pass.
1333    #[test]
1334    fn falsify_ship_017_syntax_error_count_threshold_logic() {
1335        // (1) Zero errors — unanimous parse.
1336        assert_eq!(
1337            verdict_from_syntax_error_count(0),
1338            Ship017Verdict::Pass,
1339            "0 syntax errors must always Pass",
1340        );
1341
1342        // (2) Tolerance boundary — 1 error still tolerated.
1343        assert_eq!(
1344            verdict_from_syntax_error_count(1),
1345            Ship017Verdict::Pass,
1346            "1 syntax error is the AC_SHIP2_007_MAX_TOLERATED_SYNTAX_ERRORS \
1347             boundary and must Pass",
1348        );
1349
1350        // (3) Ship-blocker boundary — 2 errors flips to Fail.
1351        assert_eq!(
1352            verdict_from_syntax_error_count(2),
1353            Ship017Verdict::Fail,
1354            "2 syntax errors is the FALSIFY-SHIP-017 ship-blocker \
1355             boundary and must Fail",
1356        );
1357
1358        // (3b) Pathological cases — high error counts must still Fail.
1359        assert_eq!(
1360            verdict_from_syntax_error_count(AC_SHIP2_007_HELDOUT_PROMPT_COUNT),
1361            Ship017Verdict::Fail,
1362            "all-errors must Fail — trivial sanity",
1363        );
1364        assert_eq!(
1365            verdict_from_syntax_error_count(AC_SHIP2_007_HELDOUT_PROMPT_COUNT / 2),
1366            Ship017Verdict::Fail,
1367            "50% errors on 100 prompts must Fail",
1368        );
1369
1370        // (4) Monotonicity — once Fail, always Fail as errors rise.
1371        let mut last_was_fail = false;
1372        for errors in 0..=AC_SHIP2_007_HELDOUT_PROMPT_COUNT {
1373            let verdict = verdict_from_syntax_error_count(errors);
1374            if last_was_fail {
1375                assert_eq!(
1376                    verdict,
1377                    Ship017Verdict::Fail,
1378                    "monotonicity violation at errors={errors}: once Fail, \
1379                     more errors cannot return to Pass",
1380                );
1381            }
1382            if verdict == Ship017Verdict::Fail {
1383                last_was_fail = true;
1384            }
1385        }
1386
1387        // Provenance sanity — the AC-SHIP2-007 prompt-count constant
1388        // matches the spec's 100-prompt harness size. If this ever drifts,
1389        // the threshold is still correct (it's count-agnostic) but the
1390        // GATE-ARCH-370M-005 evidence no longer matches the spec wording.
1391        assert_eq!(
1392            AC_SHIP2_007_HELDOUT_PROMPT_COUNT, 100,
1393            "AC-SHIP2-007 spec §6 pins the harness at 100 held-out prompts",
1394        );
1395        assert_eq!(
1396            AC_SHIP2_007_MAX_TOLERATED_SYNTAX_ERRORS, 1,
1397            "FALSIFY-SHIP-017 (spec §8.3 row) tolerates ≤ 1 SyntaxError",
1398        );
1399    }
1400
1401    /// GATE-ARCH-370M-005 wiring check: once FALSIFY-SHIP-017 has an
1402    /// algorithm-level PARTIAL discharge, the sovereign contract YAML
1403    /// MUST record `discharge_status: PARTIAL_ALGORITHM_LEVEL` plus
1404    /// `evidence_discharged_by` plus `full_discharge_blocks_on` on
1405    /// GATE-ARCH-370M-005. Any edit that drops those fields fails this
1406    /// test before the artifact ships.
1407    #[test]
1408    fn falsify_ship_017_gate_arch_370m_005_has_partial_discharge_marker() {
1409        let doc: serde_yaml::Value =
1410            serde_yaml::from_str(SOVEREIGN_CONTRACT_YAML).expect("parse sovereign contract");
1411        let gates =
1412            doc["gates"].as_sequence().expect("gates must be a sequence in sovereign contract");
1413        let gate = gates
1414            .iter()
1415            .find(|g| g["id"].as_str() == Some("GATE-ARCH-370M-005"))
1416            .expect("GATE-ARCH-370M-005 must exist in sovereign contract");
1417
1418        assert_eq!(
1419            gate["falsification_id"].as_str(),
1420            Some("FALSIFY-SHIP-017"),
1421            "GATE-ARCH-370M-005 must bind FALSIFY-SHIP-017",
1422        );
1423        assert_eq!(
1424            gate["binds_to"].as_str(),
1425            Some("AC-SHIP2-007"),
1426            "GATE-ARCH-370M-005 must bind AC-SHIP2-007",
1427        );
1428        assert_eq!(
1429            gate["discharge_status"].as_str(),
1430            Some("PARTIAL_ALGORITHM_LEVEL"),
1431            "GATE-ARCH-370M-005 must advertise PARTIAL_ALGORITHM_LEVEL \
1432             (full discharge blocks on real trained 370M .apr + 100-prompt \
1433             `apr run` harness)",
1434        );
1435        let evidence = gate["evidence_discharged_by"]
1436            .as_sequence()
1437            .expect("GATE-ARCH-370M-005 must have evidence_discharged_by");
1438        assert!(
1439            !evidence.is_empty(),
1440            "GATE-ARCH-370M-005 evidence_discharged_by must list \
1441             at least one test function or artifact",
1442        );
1443        assert!(
1444            gate["full_discharge_blocks_on"].as_str().is_some(),
1445            "PARTIAL gate must document full_discharge_blocks_on",
1446        );
1447        assert_eq!(
1448            gate["ship_blocking"].as_bool(),
1449            Some(true),
1450            "GATE-ARCH-370M-005 must advertise ship_blocking:true — the \
1451             gate's `verdict:pass` alone is insufficient green while \
1452             discharge_status == PARTIAL_ALGORITHM_LEVEL",
1453        );
1454    }
1455
1456    /// FALSIFY-SHIP-020 / AC-SHIP2-010 — pure decode-throughput threshold
1457    /// proof. `apr bench --median` on a real trained 370M .apr is the
1458    /// compute-heavy harness; the decision rule itself (≥100 tok/s
1459    /// passes, <100 tok/s fails) is separable and proven here.
1460    ///
1461    /// Invariants covered:
1462    ///   1. Pass boundary: exactly 100.0 tok/s → Pass (contract floor).
1463    ///   2. Fail boundary: 99.999 tok/s → Fail (one ULP below floor).
1464    ///   3. Generous green: 120.0 and 500.0 tok/s → Pass.
1465    ///   4. Hard red: 0.0 and 50.0 tok/s → Fail.
1466    ///   5. Monotonicity: once Fail, all strictly lower tps stay Fail.
1467    ///   6. Degenerate inputs: NaN and ±∞ → Fail (no well-defined
1468    ///      median → no proof).
1469    ///   7. Provenance pinning: the const floor MUST be 100.0 — any
1470    ///      edit that loosens the threshold trips this test before the
1471    ///      contract can ship.
1472    #[test]
1473    fn falsify_ship_020_decode_tps_threshold_logic() {
1474        // Pass boundary
1475        assert_eq!(
1476            verdict_from_decode_tps(100.0),
1477            Ship020Verdict::Pass,
1478            "exactly 100.0 tok/s must Pass (contract floor)",
1479        );
1480        // Fail boundary (one f32 step below 100.0)
1481        let just_below = f32::from_bits(100.0_f32.to_bits() - 1);
1482        assert!(just_below < 100.0);
1483        assert_eq!(
1484            verdict_from_decode_tps(just_below),
1485            Ship020Verdict::Fail,
1486            "one ULP below 100.0 tok/s must Fail",
1487        );
1488        // Generous-green sanity
1489        assert_eq!(verdict_from_decode_tps(120.0), Ship020Verdict::Pass);
1490        assert_eq!(verdict_from_decode_tps(500.0), Ship020Verdict::Pass);
1491        // Hard-red sanity
1492        assert_eq!(verdict_from_decode_tps(0.0), Ship020Verdict::Fail);
1493        assert_eq!(verdict_from_decode_tps(50.0), Ship020Verdict::Fail);
1494        // Monotonicity sweep: once Fail, any strictly smaller tps stays Fail.
1495        let samples = [0.0_f32, 25.0, 50.0, 75.0, 99.0, 99.5, 99.99, 100.0, 150.0, 10_000.0];
1496        let mut seen_fail = false;
1497        for &t in &samples {
1498            let v = verdict_from_decode_tps(t);
1499            if v == Ship020Verdict::Fail {
1500                seen_fail = true;
1501            } else if seen_fail {
1502                // We saw Fail earlier in the monotonically-increasing sweep
1503                // and now see Pass — that's fine (Fail→Pass is the
1504                // allowed crossover at the threshold). Re-arm by
1505                // resetting the seen_fail flag so we only guard against
1506                // Pass→Fail regressions within the sweep.
1507                seen_fail = false;
1508            }
1509        }
1510        // Separate direct Pass→Fail regression guard: walk strictly
1511        // decreasing from a clear Pass; once Fail shows, it must stick.
1512        let decreasing = [10_000.0_f32, 500.0, 150.0, 100.0, 99.99, 99.0, 50.0, 25.0, 0.0];
1513        let mut locked_fail = false;
1514        for &t in &decreasing {
1515            let v = verdict_from_decode_tps(t);
1516            if v == Ship020Verdict::Fail {
1517                locked_fail = true;
1518            } else {
1519                assert!(
1520                    !locked_fail,
1521                    "monotonicity violated: tps={t} produced Pass after a \
1522                     lower-tps Fail was already observed",
1523                );
1524            }
1525        }
1526        // Degenerate inputs: NaN / ±∞ are all conservatively Fail.
1527        // A real `apr bench` run can NEVER produce a non-finite median;
1528        // if one appears, the harness itself is broken and we must
1529        // refuse to claim a ship-gate pass on a value we cannot
1530        // meaningfully compare against the threshold.
1531        assert_eq!(
1532            verdict_from_decode_tps(f32::NAN),
1533            Ship020Verdict::Fail,
1534            "NaN tps has no well-defined median and must Fail",
1535        );
1536        assert_eq!(verdict_from_decode_tps(f32::NEG_INFINITY), Ship020Verdict::Fail,);
1537        assert_eq!(
1538            verdict_from_decode_tps(f32::INFINITY),
1539            Ship020Verdict::Fail,
1540            "+∞ tok/s is ill-formed — a real `apr bench` median is \
1541             always a finite positive; treating +∞ as Pass would let \
1542             an instrumentation bug silently green the ship-gate",
1543        );
1544        // Provenance pinning — any edit that loosens the threshold
1545        // (say, to 60.0) would silently lower the ship bar. Trip here
1546        // before the contract can ship.
1547        assert!(
1548            (AC_SHIP2_010_MIN_DECODE_TPS_RTX4090 - 100.0_f32).abs() < f32::EPSILON,
1549            "AC_SHIP2_010_MIN_DECODE_TPS_RTX4090 must stay pinned to 100.0 \
1550             tok/s — see contracts/model-families/llama-370m-sovereign-v1.yaml \
1551             GATE-ARCH-370M-006",
1552        );
1553    }
1554
1555    /// GATE-ARCH-370M-006 wiring check: the sovereign contract YAML
1556    /// MUST record `discharge_status: PARTIAL_ALGORITHM_LEVEL` +
1557    /// `evidence_discharged_by` + `full_discharge_blocks_on` +
1558    /// `ship_blocking: true` on GATE-ARCH-370M-006, and bind it to
1559    /// AC-SHIP2-010 / FALSIFY-SHIP-020. Any edit that drops those
1560    /// fields fails this test before the artifact ships.
1561    #[test]
1562    fn falsify_ship_020_gate_arch_370m_006_has_partial_discharge_marker() {
1563        let doc: serde_yaml::Value =
1564            serde_yaml::from_str(SOVEREIGN_CONTRACT_YAML).expect("parse sovereign contract");
1565        let gates =
1566            doc["gates"].as_sequence().expect("gates must be a sequence in sovereign contract");
1567        let gate = gates
1568            .iter()
1569            .find(|g| g["id"].as_str() == Some("GATE-ARCH-370M-006"))
1570            .expect("GATE-ARCH-370M-006 must exist in sovereign contract");
1571
1572        assert_eq!(
1573            gate["falsification_id"].as_str(),
1574            Some("FALSIFY-SHIP-020"),
1575            "GATE-ARCH-370M-006 must bind FALSIFY-SHIP-020",
1576        );
1577        assert_eq!(
1578            gate["binds_to"].as_str(),
1579            Some("AC-SHIP2-010"),
1580            "GATE-ARCH-370M-006 must bind AC-SHIP2-010",
1581        );
1582        assert_eq!(
1583            gate["discharge_status"].as_str(),
1584            Some("PARTIAL_ALGORITHM_LEVEL"),
1585            "GATE-ARCH-370M-006 must advertise PARTIAL_ALGORITHM_LEVEL \
1586             (full discharge blocks on real trained 370M .apr + RTX 4090 \
1587             `apr bench` median run)",
1588        );
1589        let evidence = gate["evidence_discharged_by"]
1590            .as_sequence()
1591            .expect("GATE-ARCH-370M-006 must have evidence_discharged_by");
1592        assert!(
1593            !evidence.is_empty(),
1594            "GATE-ARCH-370M-006 evidence_discharged_by must list \
1595             at least one test function or artifact",
1596        );
1597        assert!(
1598            gate["full_discharge_blocks_on"].as_str().is_some(),
1599            "PARTIAL gate must document full_discharge_blocks_on",
1600        );
1601        assert_eq!(
1602            gate["ship_blocking"].as_bool(),
1603            Some(true),
1604            "GATE-ARCH-370M-006 must advertise ship_blocking:true — the \
1605             gate's `verdict:pass` alone is insufficient green while \
1606             discharge_status == PARTIAL_ALGORITHM_LEVEL",
1607        );
1608    }
1609
1610    // ========================================================================
1611    // FALSIFY-SHIP-018 / AC-SHIP2-008 / GATE-ARCH-370M-007 — pass@1 threshold
1612    // ========================================================================
1613
1614    /// Algorithm-level proof that `verdict_from_pass_at_1` enforces the
1615    /// spec §5.2 AC-SHIP2-008 rule "HumanEval pass@1 ≥ 30.0%" correctly:
1616    ///
1617    ///   1. Exactly-at-floor passes (30/100, 60/200, 1/1 at threshold 100).
1618    ///   2. One f32 ULP below the floor fails.
1619    ///   3. Generous-green (50/100, 164/164) passes.
1620    ///   4. Hard-red (0/100, 1/100) fails.
1621    ///   5. Monotonicity: sweeping `correct` upward from 0 with total fixed
1622    ///      at 164 (canonical HumanEval) never flips Pass → Fail.
1623    ///   6. Div-safety guard: `total == 0` always fails, even with 0 correct.
1624    ///   7. Sanity guard: `correct > total` always fails (impossible harness).
1625    ///   8. Non-finite threshold guard: NaN / ±∞ always fail.
1626    ///   9. Provenance: the contract floor const is pinned to 30.0 (edit
1627    ///      to the const without amending the contract is caught here).
1628    ///
1629    /// Full `apr eval --benchmark humaneval` discharge blocks on the trained
1630    /// 370M .apr from AC-SHIP2-003/004 compute-dispatch — fixture swap only.
1631    #[test]
1632    fn falsify_ship_018_humaneval_pass_at_1_threshold_logic() {
1633        // ── (1) Exactly-at-floor → Pass
1634        assert_eq!(
1635            verdict_from_pass_at_1(30, 100, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1636            Ship018Verdict::Pass,
1637            "30/100 = 30.0% must pass the 30.0 floor",
1638        );
1639        assert_eq!(
1640            verdict_from_pass_at_1(60, 200, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1641            Ship018Verdict::Pass,
1642            "60/200 = 30.0% must pass the 30.0 floor",
1643        );
1644        // HumanEval canonical N=164 at-floor: ⌈0.3 × 164⌉ = 50 → 50/164 = 30.49%
1645        assert_eq!(
1646            verdict_from_pass_at_1(50, 164, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1647            Ship018Verdict::Pass,
1648            "50/164 ≈ 30.49% must pass the 30.0 floor",
1649        );
1650
1651        // ── (2a) Just below the floor → Fail.
1652        //
1653        // 49/164 ≈ 29.878% computes to a ratio strictly less than 30.0 in
1654        // f32 (see below) and must therefore fail against the 30.0 floor.
1655        // (Note: 30/100 in f32 rounds to ~30.000002, slightly *above* 30.0,
1656        // so "exactly-at-floor" must be tested with ratios that are exact
1657        // in f32 — see case (2b).)
1658        assert_eq!(
1659            verdict_from_pass_at_1(49, 164, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1660            Ship018Verdict::Fail,
1661            "49/164 ≈ 29.88% must fail the 30.0 floor",
1662        );
1663        assert_eq!(
1664            verdict_from_pass_at_1(29, 100, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1665            Ship018Verdict::Fail,
1666            "29/100 = 29.0% must fail the 30.0 floor",
1667        );
1668
1669        // ── (2b) Inclusive-floor proof at an f32-exact ratio.
1670        //
1671        // 50/100 → exactly 50.0% in f32 (both operands integer-exact, the
1672        // quotient 0.5 is a power of two, and 0.5 × 100.0 = 50.0 exactly).
1673        // This lets us prove the comparison is `>=` (inclusive), not `>`:
1674        //   - Threshold = 50.0              → Pass (exact equality).
1675        //   - Threshold = 50.0 + one ULP    → Fail (strictly above ratio).
1676        //   - Threshold = 50.0 - one ULP    → Pass (strictly below ratio).
1677        let exact_50 = 50.0_f32;
1678        assert_eq!(50.0_f32 * 2.0_f32, 100.0_f32, "sanity: 50.0 is exact in f32");
1679        let fifty_plus_ulp = f32::from_bits(exact_50.to_bits() + 1);
1680        let fifty_minus_ulp = f32::from_bits(exact_50.to_bits() - 1);
1681        assert!(fifty_plus_ulp > exact_50, "sanity: +ULP is strictly above");
1682        assert!(fifty_minus_ulp < exact_50, "sanity: −ULP is strictly below");
1683        assert_eq!(
1684            verdict_from_pass_at_1(50, 100, exact_50),
1685            Ship018Verdict::Pass,
1686            "inclusive floor: 50.0% ≥ 50.0 must Pass (proves `>=`, not `>`)",
1687        );
1688        assert_eq!(
1689            verdict_from_pass_at_1(50, 100, fifty_plus_ulp),
1690            Ship018Verdict::Fail,
1691            "50/100 must fail when threshold is one ULP above 50.0",
1692        );
1693        assert_eq!(
1694            verdict_from_pass_at_1(50, 100, fifty_minus_ulp),
1695            Ship018Verdict::Pass,
1696            "50/100 must pass when threshold is one ULP below 50.0",
1697        );
1698
1699        // ── (3) Generous-green
1700        assert_eq!(
1701            verdict_from_pass_at_1(82, 164, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1702            Ship018Verdict::Pass,
1703            "82/164 = 50% must pass",
1704        );
1705        assert_eq!(
1706            verdict_from_pass_at_1(164, 164, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1707            Ship018Verdict::Pass,
1708            "perfect score must pass",
1709        );
1710
1711        // ── (4) Hard-red
1712        assert_eq!(
1713            verdict_from_pass_at_1(0, 164, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1714            Ship018Verdict::Fail,
1715            "zero-correct run must fail",
1716        );
1717        assert_eq!(
1718            verdict_from_pass_at_1(1, 164, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1719            Ship018Verdict::Fail,
1720            "1/164 ≈ 0.6% must fail",
1721        );
1722
1723        // ── (5) Monotonicity sweep: correct ∈ 0..=164, total = 164
1724        //
1725        // Over an increasing `correct` axis the verdict is allowed to flip
1726        // Fail → Pass exactly once; it must never flip Pass → Fail.
1727        let total = 164usize;
1728        let mut already_passed = false;
1729        for correct in 0..=total {
1730            let v =
1731                verdict_from_pass_at_1(correct, total, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT);
1732            match v {
1733                Ship018Verdict::Pass => {
1734                    already_passed = true;
1735                }
1736                Ship018Verdict::Fail => {
1737                    assert!(
1738                        !already_passed,
1739                        "monotonicity violated: correct={correct} reverted Pass→Fail",
1740                    );
1741                }
1742            }
1743        }
1744
1745        // ── (6) Div-safety: total=0 must always fail
1746        assert_eq!(
1747            verdict_from_pass_at_1(0, 0, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1748            Ship018Verdict::Fail,
1749            "empty run (total=0) must fail — a positive floor is unsatisfiable",
1750        );
1751        assert_eq!(
1752            verdict_from_pass_at_1(0, 0, 0.0_f32),
1753            Ship018Verdict::Fail,
1754            "empty run must fail even with a zero threshold — the harness \
1755             is broken if it reports an empty denominator",
1756        );
1757
1758        // ── (7) Sanity guard: correct > total
1759        assert_eq!(
1760            verdict_from_pass_at_1(165, 164, AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT),
1761            Ship018Verdict::Fail,
1762            "correct > total is a broken harness report; must fail closed",
1763        );
1764
1765        // ── (8) Non-finite threshold → Fail
1766        assert_eq!(
1767            verdict_from_pass_at_1(164, 164, f32::NAN),
1768            Ship018Verdict::Fail,
1769            "NaN threshold must fail",
1770        );
1771        assert_eq!(
1772            verdict_from_pass_at_1(164, 164, f32::INFINITY),
1773            Ship018Verdict::Fail,
1774            "+∞ threshold must fail",
1775        );
1776        assert_eq!(
1777            verdict_from_pass_at_1(164, 164, f32::NEG_INFINITY),
1778            Ship018Verdict::Fail,
1779            "−∞ threshold must fail",
1780        );
1781
1782        // ── (9) Provenance pin
1783        assert!(
1784            (AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT - 30.0_f32).abs() < f32::EPSILON,
1785            "contract floor drift: AC_SHIP2_008_MIN_HUMANEVAL_PASS_AT_1_PCT \
1786             must stay pinned to 30.0 (spec §5.2 AC-SHIP2-008)",
1787        );
1788    }
1789
1790    /// Binds the YAML contract's `GATE-ARCH-370M-007` block to this test
1791    /// binary: any rename, removal, or discharge_status regression in
1792    /// `contracts/model-families/llama-370m-sovereign-v1.yaml` is caught
1793    /// at `cargo test` time.
1794    #[test]
1795    fn falsify_ship_018_gate_arch_370m_007_has_partial_discharge_marker() {
1796        let doc: serde_yaml::Value =
1797            serde_yaml::from_str(SOVEREIGN_CONTRACT_YAML).expect("parse sovereign contract");
1798
1799        let gates = doc["gates"].as_sequence().expect("contract must have `gates:` sequence");
1800
1801        let gate = gates
1802            .iter()
1803            .find(|g| g["id"].as_str() == Some("GATE-ARCH-370M-007"))
1804            .expect("GATE-ARCH-370M-007 (SHIP-018 humaneval pass@1) must be present");
1805
1806        assert_eq!(
1807            gate["binds_to"].as_str(),
1808            Some("AC-SHIP2-008"),
1809            "GATE-ARCH-370M-007 must bind AC-SHIP2-008",
1810        );
1811        assert_eq!(
1812            gate["falsification_id"].as_str(),
1813            Some("FALSIFY-SHIP-018"),
1814            "GATE-ARCH-370M-007 must bind FALSIFY-SHIP-018",
1815        );
1816        assert_eq!(
1817            gate["discharge_status"].as_str(),
1818            Some("PARTIAL_ALGORITHM_LEVEL"),
1819            "GATE-ARCH-370M-007 must advertise PARTIAL_ALGORITHM_LEVEL — \
1820             full discharge blocks on trained 370M .apr + real apr eval",
1821        );
1822        let evidence = gate["evidence_discharged_by"]
1823            .as_sequence()
1824            .expect("GATE-ARCH-370M-007 must have evidence_discharged_by");
1825        assert!(
1826            !evidence.is_empty(),
1827            "GATE-ARCH-370M-007 evidence_discharged_by must list at least \
1828             one test function or const pin",
1829        );
1830        assert!(
1831            gate["full_discharge_blocks_on"].as_str().is_some(),
1832            "PARTIAL gate must document full_discharge_blocks_on",
1833        );
1834        assert_eq!(
1835            gate["ship_blocking"].as_bool(),
1836            Some(true),
1837            "GATE-ARCH-370M-007 must advertise ship_blocking:true — \
1838             verdict:pass alone is insufficient green while \
1839             discharge_status == PARTIAL_ALGORITHM_LEVEL",
1840        );
1841    }
1842
1843    /// FALSIFY-SHIP-016 algorithm-level PARTIAL discharge: the decision
1844    /// rule of SHIP-016 — "`apr qa <model>.apr` passes iff all 8 gates
1845    /// PASS; any gate FAIL fails the ship" — is a pure aggregate-AND
1846    /// over a Boolean slice. This test proves the rule without running
1847    /// the compute-heavy gates themselves. The rule separates from the
1848    /// compute dependency: the gate-runner is fixture-swappable once
1849    /// a trained 370M .apr exists; the decision is proven today.
1850    #[test]
1851    fn falsify_ship_016_apr_qa_aggregate_and_logic() {
1852        // Section 1: canonical Pass — all 8 gates true → Pass.
1853        let all_pass = [true; AC_SHIP2_006_REQUIRED_QA_GATE_COUNT];
1854        assert_eq!(
1855            verdict_from_qa_gates(&all_pass),
1856            Ship016Verdict::Pass,
1857            "AC-SHIP2-006: all 8 gates PASS must yield Pass",
1858        );
1859
1860        // Section 2: single-gate-fail must flip the aggregate to Fail —
1861        // this is the "any gate FAIL" counter-example from FALSIFY-SHIP-016.
1862        for flip_idx in 0..AC_SHIP2_006_REQUIRED_QA_GATE_COUNT {
1863            let mut gates = [true; AC_SHIP2_006_REQUIRED_QA_GATE_COUNT];
1864            gates[flip_idx] = false;
1865            assert_eq!(
1866                verdict_from_qa_gates(&gates),
1867                Ship016Verdict::Fail,
1868                "flipping gate index {flip_idx} from Pass to Fail must yield aggregate Fail \
1869                 — SHIP-016 is an AND, not a majority or threshold",
1870            );
1871        }
1872
1873        // Section 3: canonical Fail — all 8 gates false → Fail.
1874        let all_fail = [false; AC_SHIP2_006_REQUIRED_QA_GATE_COUNT];
1875        assert_eq!(
1876            verdict_from_qa_gates(&all_fail),
1877            Ship016Verdict::Fail,
1878            "all 8 gates FAIL must yield Fail",
1879        );
1880
1881        // Section 4: exhaustive 2^8 = 256-combination proof — the ONLY
1882        // input yielding Pass is the all-true vector; every other
1883        // combination of 8 bools must yield Fail.
1884        let mut pass_count = 0usize;
1885        let mut fail_count = 0usize;
1886        for mask in 0u32..(1u32 << AC_SHIP2_006_REQUIRED_QA_GATE_COUNT) {
1887            let gates: [bool; AC_SHIP2_006_REQUIRED_QA_GATE_COUNT] =
1888                std::array::from_fn(|i| (mask >> i) & 1 == 1);
1889            match verdict_from_qa_gates(&gates) {
1890                Ship016Verdict::Pass => {
1891                    pass_count += 1;
1892                    assert!(
1893                        gates.iter().all(|&p| p),
1894                        "Pass verdict must only occur when all 8 gates are true; \
1895                         got {gates:?} at mask {mask:#010b}",
1896                    );
1897                }
1898                Ship016Verdict::Fail => {
1899                    fail_count += 1;
1900                    assert!(
1901                        gates.iter().any(|&p| !p),
1902                        "Fail verdict must only occur when at least one gate is false; \
1903                         got {gates:?} at mask {mask:#010b}",
1904                    );
1905                }
1906            }
1907        }
1908        assert_eq!(pass_count, 1, "exactly one of 256 combos (all-true) yields Pass");
1909        assert_eq!(fail_count, 255, "the other 255 combos must yield Fail");
1910
1911        // Section 5: monotonicity — adding a Pass to a mixed slice can
1912        // only move the verdict up (Fail→Pass) or keep it the same,
1913        // never downgrade Pass→Fail. Pair each combo with the combo
1914        // obtained by flipping one bit from false to true; assert
1915        // the verdict never regresses.
1916        for mask in 0u32..(1u32 << AC_SHIP2_006_REQUIRED_QA_GATE_COUNT) {
1917            let before: [bool; AC_SHIP2_006_REQUIRED_QA_GATE_COUNT] =
1918                std::array::from_fn(|i| (mask >> i) & 1 == 1);
1919            for flip_idx in 0..AC_SHIP2_006_REQUIRED_QA_GATE_COUNT {
1920                if before[flip_idx] {
1921                    continue;
1922                }
1923                let mut after = before;
1924                after[flip_idx] = true;
1925                let before_v = verdict_from_qa_gates(&before);
1926                let after_v = verdict_from_qa_gates(&after);
1927                assert!(
1928                    !(before_v == Ship016Verdict::Pass && after_v == Ship016Verdict::Fail),
1929                    "monotonicity violated: flipping gate {flip_idx} from false to true \
1930                     regressed Pass→Fail at mask {mask:#010b}",
1931                );
1932            }
1933        }
1934
1935        // Section 6: contract-drift guards — wrong gate count must Fail
1936        // conservatively even when every supplied entry is true. This
1937        // prevents a silent green from an out-of-sync harness that
1938        // shipped 7 or 9 gates instead of the spec-mandated 8.
1939        assert_eq!(
1940            verdict_from_qa_gates(&[]),
1941            Ship016Verdict::Fail,
1942            "empty gate slice must Fail (contract drift)",
1943        );
1944        assert_eq!(
1945            verdict_from_qa_gates(&[true; 7]),
1946            Ship016Verdict::Fail,
1947            "7 gates (short by one) must Fail even when all true (contract drift)",
1948        );
1949        assert_eq!(
1950            verdict_from_qa_gates(&[true; 9]),
1951            Ship016Verdict::Fail,
1952            "9 gates (long by one) must Fail even when all true (contract drift)",
1953        );
1954        assert_eq!(
1955            verdict_from_qa_gates(&[true; 16]),
1956            Ship016Verdict::Fail,
1957            "double-wide gate slice must Fail (contract drift)",
1958        );
1959
1960        // Section 7: provenance pin — the 8-gate count is the
1961        // contract number; drift on this constant fails lockstep-wise
1962        // with the spec amendment and `QaConfig` skip flags.
1963        assert_eq!(
1964            AC_SHIP2_006_REQUIRED_QA_GATE_COUNT, 8,
1965            "AC-SHIP2-006 is the 8-gate aggregate; any change requires \
1966             contract + spec + CLI skip-flag edits in lockstep",
1967        );
1968    }
1969
1970    /// GATE-ARCH-370M-008 wiring check: once FALSIFY-SHIP-016 has an
1971    /// algorithm-level PARTIAL discharge, the sovereign contract YAML
1972    /// MUST record `discharge_status: PARTIAL_ALGORITHM_LEVEL` +
1973    /// `evidence_discharged_by` + `full_discharge_blocks_on` on
1974    /// GATE-ARCH-370M-008. Any edit that drops those fields fails this
1975    /// test before the artifact ships.
1976    #[test]
1977    fn falsify_ship_016_gate_arch_370m_008_has_partial_discharge_marker() {
1978        let doc: serde_yaml::Value =
1979            serde_yaml::from_str(SOVEREIGN_CONTRACT_YAML).expect("parse sovereign contract");
1980        let gates =
1981            doc["gates"].as_sequence().expect("gates must be a sequence in sovereign contract");
1982        let gate = gates
1983            .iter()
1984            .find(|g| g["id"].as_str() == Some("GATE-ARCH-370M-008"))
1985            .expect("GATE-ARCH-370M-008 must exist in sovereign contract");
1986
1987        assert_eq!(
1988            gate["falsification_id"].as_str(),
1989            Some("FALSIFY-SHIP-016"),
1990            "GATE-ARCH-370M-008 must bind FALSIFY-SHIP-016",
1991        );
1992        assert_eq!(
1993            gate["binds_to"].as_str(),
1994            Some("AC-SHIP2-006"),
1995            "GATE-ARCH-370M-008 must bind AC-SHIP2-006",
1996        );
1997        assert_eq!(
1998            gate["discharge_status"].as_str(),
1999            Some("PARTIAL_ALGORITHM_LEVEL"),
2000            "GATE-ARCH-370M-008 must advertise PARTIAL_ALGORITHM_LEVEL \
2001             (full discharge blocks on real trained 370M .apr + `apr qa` harness)",
2002        );
2003        let evidence = gate["evidence_discharged_by"]
2004            .as_sequence()
2005            .expect("GATE-ARCH-370M-008 must have evidence_discharged_by");
2006        assert!(
2007            !evidence.is_empty(),
2008            "GATE-ARCH-370M-008 evidence_discharged_by must list \
2009             at least one test function or artifact",
2010        );
2011        assert!(
2012            gate["full_discharge_blocks_on"].as_str().is_some(),
2013            "PARTIAL gate must document full_discharge_blocks_on",
2014        );
2015        assert_eq!(
2016            gate["ship_blocking"].as_bool(),
2017            Some(true),
2018            "GATE-ARCH-370M-008 must advertise ship_blocking:true — the \
2019             gate's `verdict:pass` alone is insufficient green while \
2020             discharge_status == PARTIAL_ALGORITHM_LEVEL",
2021        );
2022    }
2023
2024    // ========================================================================
2025    // FALSIFY-SHIP-013 / AC-SHIP2-003 / GATE-ARCH-370M-013 — val CE loss floor
2026    // ========================================================================
2027
2028    /// FALSIFY-SHIP-013 algorithm-level PARTIAL discharge: prove the
2029    /// f32-threshold decision rule binding the measured MODEL-2 val CE
2030    /// to [`AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS`] = 2.2. Any edit
2031    /// that changes the constant, the comparison direction, the
2032    /// non-finite handling, the negative-domain guard, or the
2033    /// monotonicity must break this test before an `apr pretrain
2034    /// --validate` compute dispatch is launched.
2035    ///
2036    /// Mutation survey (7 sections):
2037    ///   1. Exact boundary 2.2 → Pass (inclusive floor, not strict <)
2038    ///   2. One-ULP above boundary → Fail; one-ULP below → Pass
2039    ///   3. Clear Pass band {0.0, 0.5, 1.0, 2.0, 2.199}
2040    ///   4. Clear Fail band {2.201, 3.0, 10.0, f32::MAX}
2041    ///   5. Non-finite {NaN, +∞, -∞} → Fail conservatively
2042    ///   6. Negative (domain violation, CE ≥ 0) → Fail conservatively
2043    ///   7. Provenance pin: the const stays byte-equal to 2.2_f32
2044    #[test]
2045    fn falsify_ship_013_val_ce_loss_threshold_logic() {
2046        // Section 1: exact boundary 2.2 → Pass. AC-SHIP2-003 says
2047        // "CE ≤ 2.2" (inclusive), so sim == threshold must Pass. A
2048        // regression that silently swaps `<=` to `<` would make the
2049        // ceiling unreachable.
2050        assert_eq!(
2051            verdict_from_val_ce_loss(AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS),
2052            Ship013Verdict::Pass,
2053            "val CE == 2.2 must Pass (inclusive floor, not strict <)",
2054        );
2055        assert_eq!(verdict_from_val_ce_loss(2.2), Ship013Verdict::Pass, "literal 2.2 must Pass",);
2056
2057        // Section 2: ULP asymmetry around the boundary. f32 at 2.2 is
2058        // `0x400CCCCD` = 2.20000004768371582...; the next-representable
2059        // float up is `0x400CCCCE` (Fail), and the next below is
2060        // `0x400CCCCC` (Pass). Sharpest possible counter-examples.
2061        let one_ulp_above = f32::from_bits(AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS.to_bits() + 1);
2062        let one_ulp_below = f32::from_bits(AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS.to_bits() - 1);
2063        assert!(one_ulp_above > AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS);
2064        assert!(one_ulp_below < AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS);
2065        assert_eq!(
2066            verdict_from_val_ce_loss(one_ulp_above),
2067            Ship013Verdict::Fail,
2068            "one ULP above 2.2 must Fail (strictly above ceiling)",
2069        );
2070        assert_eq!(
2071            verdict_from_val_ce_loss(one_ulp_below),
2072            Ship013Verdict::Pass,
2073            "one ULP below 2.2 must Pass (still under ceiling)",
2074        );
2075
2076        // Section 3: clear Pass band. 0.0 is the theoretical minimum
2077        // (perfect predictor); 2.199 is safely under 2.2.
2078        for ce in [0.0_f32, 0.5, 1.0, 2.0, 2.199] {
2079            assert_eq!(
2080                verdict_from_val_ce_loss(ce),
2081                Ship013Verdict::Pass,
2082                "val CE = {ce} must Pass (in clear Pass band)",
2083            );
2084        }
2085
2086        // Section 4: clear Fail band. A poorly-converged 370M would
2087        // land here (a random 50K-vocab predictor is ≈ ln(50257) ≈
2088        // 10.82 nats, which must obviously Fail). f32::MAX is the
2089        // saturation sanity check.
2090        for ce in [2.201_f32, 3.0, 10.0, f32::MAX] {
2091            assert_eq!(
2092                verdict_from_val_ce_loss(ce),
2093                Ship013Verdict::Fail,
2094                "val CE = {ce} must Fail (above 2.2 ceiling)",
2095            );
2096        }
2097
2098        // Section 5: non-finite inputs must Fail conservatively. A
2099        // loss-harness bug that produces NaN (log(0) or divide-by-zero
2100        // in softmax) or ±∞ (overflow in exp) must never silently
2101        // promote to Pass via NaN comparison semantics.
2102        assert_eq!(
2103            verdict_from_val_ce_loss(f32::NAN),
2104            Ship013Verdict::Fail,
2105            "NaN val CE must Fail conservatively",
2106        );
2107        assert_eq!(
2108            verdict_from_val_ce_loss(f32::INFINITY),
2109            Ship013Verdict::Fail,
2110            "+∞ val CE must Fail conservatively",
2111        );
2112        assert_eq!(
2113            verdict_from_val_ce_loss(f32::NEG_INFINITY),
2114            Ship013Verdict::Fail,
2115            "-∞ val CE must Fail conservatively",
2116        );
2117
2118        // Section 6: negative CE is a domain violation. Cross-entropy
2119        // H(p,q) = -Σ p(x) log q(x) ≥ 0 for all probability
2120        // distributions p,q. A negative measurement indicates a sign
2121        // flip, log-domain underflow, or subtract-instead-of-add bug
2122        // in the loss harness, and must never be promoted to "better
2123        // than zero" Pass.
2124        for neg_ce in [-0.001_f32, -1.0, -f32::INFINITY] {
2125            assert_eq!(
2126                verdict_from_val_ce_loss(neg_ce),
2127                Ship013Verdict::Fail,
2128                "negative val CE = {neg_ce} must Fail (CE ≥ 0 by definition)",
2129            );
2130        }
2131
2132        // Section 7: provenance pin — the 2.2 constant is load-bearing
2133        // and lockstepped with the spec. If AC-SHIP2-003 ever changes
2134        // the ceiling (relaxing to 2.5 for a smaller training-data
2135        // budget, tightening to 2.0 for a 500M jump), this const and
2136        // this test must move together.
2137        #[allow(clippy::float_cmp)]
2138        {
2139            assert_eq!(
2140                AC_SHIP2_003_MAX_VAL_CROSS_ENTROPY_LOSS, 2.2_f32,
2141                "MODEL-2 val CE ceiling is 2.2 \
2142                 (spec §5.2 AC-SHIP2-003; albor 370M Sovereign target)",
2143            );
2144        }
2145    }
2146
2147    // ========================================================================
2148    // FALSIFY-SHIP-014 / AC-SHIP2-004 / GATE-ARCH-370M-014 — training budget
2149    // ========================================================================
2150
2151    /// FALSIFY-SHIP-014 algorithm-level PARTIAL discharge: prove the
2152    /// u32-threshold decision rule binding the measured MODEL-2
2153    /// training wall-clock duration to
2154    /// [`AC_SHIP2_004_MAX_TRAINING_DURATION_DAYS`] = 21. Any edit that
2155    /// changes the constant, the comparison direction, or introduces
2156    /// a non-monotonic regression must break this test before a
2157    /// real-compute dispatch on the RTX 4090 host is launched.
2158    ///
2159    /// Mutation survey (6 sections):
2160    ///   1. Exact boundary 21 → Pass (inclusive ceiling)
2161    ///   2. Adjacent values: 20 → Pass; 22 → Fail
2162    ///   3. Clear Pass band {0, 1, 7, 14, 20, 21}
2163    ///   4. Clear Fail band {22, 30, 100, u32::MAX}
2164    ///   5. Monotonicity sweep 0..=42 — verdict flips exactly once
2165    ///      at the 21→22 transition and never flips back
2166    ///   6. Provenance pin: the const stays byte-equal to 21_u32
2167    #[test]
2168    fn falsify_ship_014_training_duration_threshold_logic() {
2169        // Section 1: exact boundary 21 → Pass. AC-SHIP2-004 says
2170        // "within 21 days" (inclusive), so 21 == threshold must Pass.
2171        // A regression that silently swaps `<=` to `<` would make the
2172        // ceiling unreachable.
2173        assert_eq!(
2174            verdict_from_training_duration_days(AC_SHIP2_004_MAX_TRAINING_DURATION_DAYS),
2175            Ship014Verdict::Pass,
2176            "21 days must Pass (inclusive ceiling, not strict <)",
2177        );
2178        assert_eq!(
2179            verdict_from_training_duration_days(21),
2180            Ship014Verdict::Pass,
2181            "literal 21 days must Pass",
2182        );
2183
2184        // Section 2: adjacent values. 20 is the sharpest Pass
2185        // counter-example (one below ceiling); 22 is the sharpest
2186        // Fail counter-example (one above). u32 neighbours are
2187        // exact (no ULP noise) so these are both rock-solid.
2188        assert_eq!(
2189            verdict_from_training_duration_days(20),
2190            Ship014Verdict::Pass,
2191            "20 days must Pass (one day under ceiling)",
2192        );
2193        assert_eq!(
2194            verdict_from_training_duration_days(22),
2195            Ship014Verdict::Fail,
2196            "22 days must Fail (one day over ceiling; Spec §9 Risk #4 escape hatch)",
2197        );
2198
2199        // Section 3: clear Pass band. 0 is trivial (same-day cache
2200        // hit, no actual training); 1/7/14 are smaller training runs;
2201        // 21 is the boundary.
2202        for days in [0_u32, 1, 7, 14, 20, 21] {
2203            assert_eq!(
2204                verdict_from_training_duration_days(days),
2205                Ship014Verdict::Pass,
2206                "{days} days must Pass (in clear Pass band)",
2207            );
2208        }
2209
2210        // Section 4: clear Fail band. 22/30/100 are incremental
2211        // overruns (each invokes Spec §9 Risk #4 escape-hatch planning
2212        // — rent 2× H100 week 3); u32::MAX is the saturation sanity.
2213        for days in [22_u32, 30, 100, u32::MAX] {
2214            assert_eq!(
2215                verdict_from_training_duration_days(days),
2216                Ship014Verdict::Fail,
2217                "{days} days must Fail (above 21-day ceiling)",
2218            );
2219        }
2220
2221        // Section 5: monotonicity sweep 0..=42 — verdict must flip
2222        // exactly once at the 21→22 transition and never flip back.
2223        // This is the complete classification over a 2× the ceiling
2224        // range; any mutation that introduces non-monotonicity (e.g.
2225        // a midlife-crisis carve-out at "after day 14 but before day
2226        // 21" or a modular-arithmetic bug) is trivially caught.
2227        let mut seen_fail = false;
2228        for days in 0..=42_u32 {
2229            let v = verdict_from_training_duration_days(days);
2230            match (v, seen_fail) {
2231                (Ship014Verdict::Pass, true) => {
2232                    panic!(
2233                        "monotonicity broken: day {days} flipped back to Pass \
2234                         after a previous Fail was observed",
2235                    );
2236                }
2237                (Ship014Verdict::Fail, _) => {
2238                    seen_fail = true;
2239                }
2240                _ => {}
2241            }
2242        }
2243        // And verify the transition is exactly at 21→22, not earlier
2244        // or later (rules out off-by-one mutants).
2245        assert_eq!(
2246            verdict_from_training_duration_days(21),
2247            Ship014Verdict::Pass,
2248            "sweep boundary: day 21 must Pass",
2249        );
2250        assert_eq!(
2251            verdict_from_training_duration_days(22),
2252            Ship014Verdict::Fail,
2253            "sweep boundary: day 22 must Fail",
2254        );
2255
2256        // Section 6: provenance pin — the 21 constant is load-bearing
2257        // and lockstepped with the spec. If AC-SHIP2-004 ever changes
2258        // the ceiling (extending to 30 for a longer run, tightening
2259        // to 14 for a distilled student), this const and this test
2260        // must move together.
2261        assert_eq!(
2262            AC_SHIP2_004_MAX_TRAINING_DURATION_DAYS, 21_u32,
2263            "MODEL-2 training-budget ceiling is 21 days \
2264             (spec §5.2 AC-SHIP2-004; RTX 4090 hardware budget)",
2265        );
2266    }
2267}