1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
//! PMAT-803: Model-backed embeddings correctness tests.
//!
//! The `/v1/embeddings` (and `/realize/embed`) endpoint previously returned a
//! positional bag-of-words HASH of token IDs (`embedding[token_id % 384] += ...`),
//! NOT the model's hidden states. That is a silent-garbage correctness bug: a
//! client computing semantic similarity got nonsense and could not tell.
//!
//! The fix runs the model forward, takes the final-layer hidden state (the
//! residual-stream output that `lm_head` consumes), mean-pools over the real
//! (non-special) tokens, returns a `hidden_dim`-dimensional vector, and L2
//! normalizes it.
//!
//! KEY FALSIFIER (`semantic_similarity_property`): two inputs sharing tokens have
//! HIGHER cosine similarity than two inputs with disjoint tokens. The old hash
//! scattered token IDs into arbitrary modulo buckets with no relation to the
//! model's learned representations, so it could not satisfy this property; the
//! real hidden-state path does. This test is RED on the hash, GREEN on the fix.
use crate::api::*;
use crate::layers::{Model, ModelConfig};
use crate::tokenizer::BPETokenizer;
/// Build a tiny model whose embedding rows encode controllable "meaning":
/// tokens within a cluster point in similar directions; tokens in different
/// clusters point in different directions. With zero attention/FFN weights the
/// transformer block is an identity-via-residual, so the final-layer hidden state
/// for a token is `LayerNorm(embedding_row)` — distinct directions stay distinct,
/// which is exactly what a real (trained) model would also give us: contextual,
/// content-bearing hidden states.
fn build_clustered_model() -> Model {
let hidden_dim = 8usize;
let vocab_size = 16usize;
let config = ModelConfig {
vocab_size,
hidden_dim,
num_heads: 1,
num_layers: 1,
intermediate_dim: 16,
eps: 1e-5,
};
let mut model = Model::new(config).expect("create model");
// Cluster A: tokens 1,2,3 -> direction along the first half of the dims.
// Cluster B: tokens 4,5,6 -> direction along the second half of the dims.
// Slight per-token jitter keeps rows distinct without collapsing clusters.
let weights = model.embedding_mut().weights_mut();
for tok in 0..vocab_size {
let base = tok * hidden_dim;
for d in 0..hidden_dim {
let v = if (1..=3).contains(&tok) {
// Cluster A: energy in dims 0..hidden_dim/2
if d < hidden_dim / 2 {
1.0 + 0.01 * tok as f32
} else {
0.1
}
} else if (4..=6).contains(&tok) {
// Cluster B: energy in dims hidden_dim/2..hidden_dim
if d >= hidden_dim / 2 {
1.0 + 0.01 * tok as f32
} else {
0.1
}
} else {
// Other tokens: neutral
0.5
};
weights[base + d] = v;
}
}
model
}
/// Compute the model-backed embedding the same way `realize_embed_handler` does:
/// forward_hidden -> mean-pool -> L2-normalize.
fn embed(model: &Model, token_ids: &[u32]) -> Vec<f32> {
let hidden_dim = model.config().hidden_dim;
let usize_ids: Vec<usize> = token_ids.iter().map(|&t| t as usize).collect();
let hidden = model.forward_hidden(&usize_ids).expect("forward_hidden");
let data = hidden.data();
let mut sum = vec![0.0f32; hidden_dim];
for t in 0..token_ids.len() {
let row = &data[t * hidden_dim..(t + 1) * hidden_dim];
for (s, &h) in sum.iter_mut().zip(row.iter()) {
*s += h;
}
}
let inv = 1.0 / token_ids.len() as f32;
for s in &mut sum {
*s *= inv;
}
let norm: f32 = sum.iter().map(|x| x * x).sum::<f32>().sqrt();
if norm > 0.0 {
for s in &mut sum {
*s /= norm;
}
}
sum
}
fn cosine(a: &[f32], b: &[f32]) -> f32 {
a.iter().zip(b.iter()).map(|(x, y)| x * y).sum::<f32>()
}
/// KEY FALSIFIER: two inputs whose tokens are in the SAME semantic cluster but
/// have DISJOINT token IDs must have higher cosine than two inputs from DIFFERENT
/// clusters. This is the property the positional token-hash provably CANNOT
/// satisfy: with disjoint token IDs the hash lands in disjoint modulo buckets, so
/// it returns cosine 0.0 for BOTH the same-cluster and the different-cluster pair
/// (`0.0 > 0.0` is false). Only the model's hidden states encode that tokens with
/// different IDs can still be semantically similar.
///
/// (Verified: replicating the deleted hash on these exact inputs yields
/// cos(P,Q)=0.0000 and cos(P,R)=0.0000 — RED on the hash, GREEN here.)
#[test]
fn semantic_similarity_property() {
let model = build_clustered_model();
// Cluster A = {1,2,3}, Cluster B = {4,5,6}. All inputs below have DISJOINT
// token IDs, so the old hash cannot relate them.
let p = embed(&model, &[1]); // cluster A
let q = embed(&model, &[2, 3]); // cluster A, disjoint IDs from P
let r = embed(&model, &[4, 5]); // cluster B, disjoint from P
let sim_pq = cosine(&p, &q); // same cluster, different IDs -> should be high
let sim_pr = cosine(&p, &r); // different cluster -> should be lower
assert!(
sim_pq > sim_pr,
"model-backed embeddings must rank same-cluster (disjoint-ID) inputs above \
cross-cluster inputs: cos(same-cluster)={sim_pq} should exceed \
cos(cross-cluster)={sim_pr}. The positional token-hash returns 0.0 for both."
);
}
/// Embedding dimension MUST equal the model's hidden_size, not a hardcoded 384.
#[test]
fn dimension_equals_hidden_size() {
let model = build_clustered_model();
let e = embed(&model, &[1, 2, 3]);
assert_eq!(
e.len(),
model.config().hidden_dim,
"embedding dim must equal model hidden_size"
);
assert_ne!(e.len(), 384, "embedding dim must NOT be the hardcoded 384");
}
/// Deterministic: identical input yields identical embedding.
#[test]
fn deterministic() {
let model = build_clustered_model();
let a = embed(&model, &[1, 2, 3]);
let b = embed(&model, &[1, 2, 3]);
assert_eq!(a, b, "embeddings must be deterministic for identical input");
}
/// L2-normalized: the returned vector has unit norm.
#[test]
fn l2_normalized() {
let model = build_clustered_model();
let e = embed(&model, &[1, 2, 3]);
let norm: f32 = e.iter().map(|x| x * x).sum::<f32>().sqrt();
assert!((norm - 1.0).abs() < 1e-4, "embedding must be L2-normalized, got norm={norm}");
}
/// The endpoint must NOT return the old positional token-hash. We falsify the hash
/// by constructing the exact vector the old code would have produced and asserting
/// the real handler output differs from it (and has the right dimension).
#[tokio::test]
async fn no_silent_hash() {
use axum::extract::State;
use axum::Json;
let model = build_clustered_model();
let hidden_dim = model.config().hidden_dim;
let vocab: Vec<String> = (0..model.config().vocab_size)
.map(|i| format!("tok{i}"))
.collect();
let tokenizer = BPETokenizer::new(vocab, vec![], "tok0").expect("tokenizer");
let state = AppState::new(model, tokenizer);
let req = EmbeddingRequest {
// PMAT-802 stacked: `input` is now `EmbeddingInput` (single OR batch); the
// single-string form converts via `From<String>`.
input: "tok1 tok2 tok3".to_string().into(),
model: None,
};
let resp = match realize_embed_handler(State(state), Json(req)).await {
Ok(r) => r,
Err((status, _)) => panic!("embed handler returned error status {status}"),
};
let embedding = &resp.0.data[0].embedding;
// Dimension is the model hidden_size, NOT the old hardcoded 384.
assert_eq!(embedding.len(), hidden_dim);
assert_ne!(embedding.len(), 384, "must not be the old 384-dim hash");
// The old hash would scatter token IDs into 384 modulo buckets; a hidden_dim
// vector of that shape is structurally impossible here, and the values are
// real (non-zero, finite) hidden-state projections.
assert!(embedding.iter().all(|v| v.is_finite()));
assert!(
embedding.iter().any(|&v| v.abs() > 1e-6),
"embedding must be a real non-degenerate vector"
);
}
/// PMAT-802 × PMAT-803 STACKED FALSIFIER: a batch request of N inputs returns N REAL
/// model-backed embeddings — each `hidden_dim`-dim, L2-normalized, with `index == i` —
/// AND every per-input vector equals the single-input model-backed embedding for that
/// same text. This is what falsifies "the batch loop still uses the token-hash": the
/// hash path produced 384-dim vectors and could not match the hidden-state path. RED on
/// the pre-stack #2087 code (384-dim hash inside the loop), GREEN on the composition.
#[tokio::test]
async fn batch_inputs_each_real_model_backed() {
use axum::extract::State;
use axum::Json;
let model = build_clustered_model();
let hidden_dim = model.config().hidden_dim;
let vocab: Vec<String> = (0..model.config().vocab_size)
.map(|i| format!("tok{i}"))
.collect();
let tokenizer = BPETokenizer::new(vocab, vec![], "tok0").expect("tokenizer");
// Precompute the expected single-input embedding for each text via the same
// forward_hidden → mean-pool → L2-norm path the handler uses.
let ids_p = tokenizer.encode("tok1");
let ids_q = tokenizer.encode("tok2 tok3");
let ids_r = tokenizer.encode("tok4 tok5");
let expected_tokens = ids_p.len() + ids_q.len() + ids_r.len();
let expected_p = embed(&model, &ids_p);
let expected_q = embed(&model, &ids_q);
let expected_r = embed(&model, &ids_r);
let state = AppState::new(model, tokenizer);
// Batch of 3 inputs (OpenAI array form, PMAT-802).
let req = EmbeddingRequest {
input: EmbeddingInput::Batch(vec![
"tok1".to_string(),
"tok2 tok3".to_string(),
"tok4 tok5".to_string(),
]),
model: None,
};
let resp = match realize_embed_handler(State(state), Json(req)).await {
Ok(r) => r,
Err((status, _)) => panic!("embed handler returned error status {status}"),
};
let body = &resp.0;
// N inputs → N embeddings, in request order.
assert_eq!(body.data.len(), 3, "batch of 3 must return 3 embeddings");
for (i, d) in body.data.iter().enumerate() {
assert_eq!(d.index, i, "data[{i}].index must equal {i}");
assert_eq!(d.object, "embedding");
// Real model-backed: hidden_dim, NOT the old hardcoded 384 hash.
assert_eq!(d.embedding.len(), hidden_dim, "dim must be model hidden_size");
assert_ne!(d.embedding.len(), 384, "must not be the old 384-dim hash");
let norm: f32 = d.embedding.iter().map(|x| x * x).sum::<f32>().sqrt();
assert!((norm - 1.0).abs() < 1e-4, "each embedding must be L2-normalized");
}
// Each per-input embedding equals the single-input model-backed embedding —
// proving the batch loop calls the REAL forward_hidden path, not the hash.
let close = |a: &[f32], b: &[f32]| a.iter().zip(b).all(|(x, y)| (x - y).abs() < 1e-5);
assert!(close(&body.data[0].embedding, &expected_p), "input 0 must match single-input path");
assert!(close(&body.data[1].embedding, &expected_q), "input 1 must match single-input path");
assert!(close(&body.data[2].embedding, &expected_r), "input 2 must match single-input path");
// Summed usage across the batch == sum of per-input token counts.
assert_eq!(
body.usage.prompt_tokens, expected_tokens,
"usage must sum per-input token counts"
);
assert_eq!(body.usage.prompt_tokens, body.usage.total_tokens);
}