open-standards/jouleclaw/jouleclaw-rs/crates/jouleclaw-loader-gguf/tests/pre_tokenize.rs
Transaction Science 8f9a42e4d4 jouleclaw Phase 2: cascade + loader-gguf + pack + history + wire
Five crates ported / designed. All 235 tests pass; 0 errors;
0 warnings outside the loader-gguf NEON-intrinsics module (suppressed
with a documented #![allow(unsafe_op_in_unsafe_fn)] — proper fix is
wrapping each intrinsic call in unsafe { }, tracked as kernel-quality
maintenance, not standards work).

jouleclaw-cascade
  Ported from pattern-lang/joule-cascade (~7044 LOC, 17 files).
  L0 (Cache), tier dispatch, 7-axis Synthesis coordinate router, cost
  model, calibration ledger (in-memory + disk), history, verification,
  body + body_safety policy gates, active-entity tracking, l2_service
  trait surface. Two tests that depended on joule-l1's lawful-primitive
  impl (which requires pattern-lang's pattern-core + cortex-ir +
  synthesizer — OpenIE IP) were removed; the L1 trait surface lives
  here and consumers plug their own lawful lexicon in.

jouleclaw-loader-gguf
  Ported from pattern-lang/joule-loader-gguf (~11605 LOC, 17 files).
  GGUF v3 parser with mmap, Llama and Gemma / Gemma 4 decoders,
  Q4_0 / Q5_K / Q8_0 / Q8_0 grouped quants, in-place KV cache,
  matmul_q8_0 with NEON intrinsics on Apple Silicon, safetensors
  reader, tokenizer + Gemma tokenizer, sample, dequant.

jouleclaw-pack (NEW)
  The .jc.toml sidecar — JouleClaw's standard-defining contribution.
  A model on disk (GGUF / safetensors / MLX) tells you tensor shapes
  and quant schemes. It does NOT tell you what one forward pass
  actually costs in joules on real hardware. The .jc.toml is a
  declared-cost contract that travels with the model:

    - per-tensor precision (FP16/BF16/FP8/INT8/NVFP4/NF4/Q4_K/...)
    - page-alignment status (mmap-zero-copy possible? on which UMA?)
    - measured J/op on a reference hardware matrix with explicit
      Provenance (HwShunt / ModelBased / Estimator)
    - drift_factor tolerance per measurement; the runtime trips
      PackError::CostDrift when measured > declared * drift_factor
      and down-weights the backend in subsequent auction rounds

  Without a declared-cost contract, "energy-optimized inference" is
  marketing. With one, it is an engineering claim any third party
  can verify against the published reference-hardware corpus.

  5 lib tests pass. ModelFormat, Precision, Alignment, MeasurementOp,
  Pack, TensorContract, Measurement, hash_model(), verify_measurement().

jouleclaw-history
  Ported from pattern-lang/joule-history (~2026 LOC, 6 files).
  Persistent resolution history: disk + in-memory + tiered
  (hot/warm/cold) + semantic. One Rust-2024 edition fix in
  tiered.rs (binding-mode pattern: |(_, &seq)| seq -> |(_, seq)| *seq).

jouleclaw-wire
  Ported from pattern-lang/joule-wire (~1129 LOC, 2 files).
  L4 wire tier — the remote frontier escape hatch. RPC client +
  transport, invoked only when the local cascade returns Unresolvable.

Phase 3 next: HAL from efficient-genai, backend-{apple,reference,
cuda,metal,rocm,vulkan}, runtime (port joule-runtime — chat/embed/
generate/streaming/PLD/drafter — needs backends to compile).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-26 11:55:46 -04:00

151 lines
4.5 KiB
Rust

//! Tests for the GPT-2 / Llama 3 regex pre-tokenizer.
//!
//! This is the canonical pre-tokenization step that splits text into
//! chunks before BPE merge application. The regex is:
//!
//! 'reign|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+
//!
//! Matching behavior:
//! - Contractions ('s, 't, 're, 've, 'm, 'll, 'd) are their own chunks
//! - Letter runs, optionally preceded by a single space
//! - Number runs, optionally preceded by a single space
//! - Punctuation/symbol runs, optionally preceded by a single space
//! - Whitespace runs
//!
//! This produces tokenizations that match HuggingFace tokenizers for
//! Llama 3 / Mistral / Qwen / GPT-style models.
use jouleclaw_loader_gguf::tokenizer::pre_tokenize_gpt2;
#[test]
fn splits_simple_words_with_leading_space() {
let chunks = pre_tokenize_gpt2("hello world");
assert_eq!(chunks, vec!["hello", " world"]);
}
#[test]
fn first_word_has_no_leading_space() {
let chunks = pre_tokenize_gpt2("the quick brown fox");
assert_eq!(chunks, vec!["the", " quick", " brown", " fox"]);
}
#[test]
fn splits_contractions() {
// "don't" → "don", "'t"
let chunks = pre_tokenize_gpt2("don't");
assert_eq!(chunks, vec!["don", "'t"]);
}
#[test]
fn handles_all_canonical_contractions() {
for (input, expected_apos) in &[
("he's", "'s"),
("don't", "'t"),
("they're", "'re"),
("we've", "'ve"),
("I'm", "'m"),
("we'll", "'ll"),
("I'd", "'d"),
] {
let chunks = pre_tokenize_gpt2(input);
assert!(chunks.iter().any(|c| c == expected_apos),
"input {:?} should produce a {:?} chunk; got {:?}",
input, expected_apos, chunks);
}
}
#[test]
fn splits_punctuation_from_words() {
let chunks = pre_tokenize_gpt2("hello, world.");
// "hello" + "," + " world" + "."
assert_eq!(chunks, vec!["hello", ",", " world", "."]);
}
#[test]
fn splits_numbers_from_letters() {
let chunks = pre_tokenize_gpt2("foo 42 bar");
assert_eq!(chunks, vec!["foo", " 42", " bar"]);
}
#[test]
fn keeps_whitespace_runs() {
// Double-space should produce one chunk for the leading space + word,
// and capture the extra space somewhere.
let chunks = pre_tokenize_gpt2("a b");
// Expected: "a", " ", " b" (or similar — whitespace handling has edges)
// Just verify reassembly is correct.
let recovered: String = chunks.concat();
assert_eq!(recovered, "a b",
"pre-tokenization should be byte-exact reversible by concatenation");
}
#[test]
fn empty_input_produces_no_chunks() {
let chunks = pre_tokenize_gpt2("");
assert!(chunks.is_empty());
}
#[test]
fn single_word_produces_one_chunk() {
let chunks = pre_tokenize_gpt2("hello");
assert_eq!(chunks, vec!["hello"]);
}
#[test]
fn whitespace_only_input() {
let chunks = pre_tokenize_gpt2(" ");
// Three spaces — should be one whitespace run.
let recovered: String = chunks.concat();
assert_eq!(recovered, " ");
}
#[test]
fn handles_newlines_as_whitespace() {
let chunks = pre_tokenize_gpt2("a\nb");
let recovered: String = chunks.concat();
assert_eq!(recovered, "a\nb");
}
#[test]
fn unicode_letters_are_letter_chunks() {
// German umlauts, Greek, Cyrillic — all \p{L}.
let chunks = pre_tokenize_gpt2("café αβγ привет");
let recovered: String = chunks.concat();
assert_eq!(recovered, "café αβγ привет");
// Each language should be one chunk after a space.
assert!(chunks.iter().any(|c| c == "café"));
assert!(chunks.iter().any(|c| c == " αβγ"));
assert!(chunks.iter().any(|c| c == " привет"));
}
#[test]
fn pre_tokenization_is_byte_reversible() {
// Across a variety of inputs, concatenating chunks should reproduce
// the original input exactly. This is the defining property of a
// proper pre-tokenizer.
for input in &[
"hello world",
"I don't know.",
"She said, \"hi!\"",
"x = 42; y = x + 1;",
"café au lait",
"What about 100% sure?",
"multi\nline\ntext",
] {
let chunks = pre_tokenize_gpt2(input);
let recovered: String = chunks.concat();
assert_eq!(&recovered, input,
"round-trip failed for {:?}: chunks={:?}, recovered={:?}",
input, chunks, recovered);
}
}
#[test]
fn determinism() {
let input = "The quick brown fox jumps over the lazy dog.";
let c1 = pre_tokenize_gpt2(input);
let c2 = pre_tokenize_gpt2(input);
let c3 = pre_tokenize_gpt2(input);
assert_eq!(c1, c2);
assert_eq!(c2, c3);
}