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}