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
//! The `sentence-transformers` reference-vector accuracy gate for the default
//! embedding model (issue #3486 / #3493 P0, deflaked by #3711).
//!
//! Why: split out of `mod.rs`'s inline `mod tests` (issue #610 line-cap — that
//! file is at its grandfathered SLOC budget) so #3711's wrong-model diagnosis
//! could be added without growing it.
//! What: a CHILD module of `mod.rs`'s `mod tests`, deliberately NOT a sibling
//! of `provider_tests`. A sibling would be outside that module and would need
//! to duplicate `ENV_LOCK`/`EnvVarGuard` the way `provider_tests` does — and a
//! second lock does not serialise against the first, which is precisely the
//! env race #3711 fixes. As a child it inherits the parent's single lock and
//! guard through `use super::*`.
//! Test: this file.
use *;
/// Fixed sample used by [`default_model_matches_sentence_transformers_reference`].
///
/// Why: issue #3486 / #3493 P0 — the default model swap (INT8 →
/// `AllMiniLML6V2` fp32) must be verified against a genuine, independent
/// reference, not just "fastembed didn't error". These 5 texts and their
/// reference vectors were generated with a real
/// `sentence-transformers/all-MiniLM-L6-v2` CPU fp32 model (`device="cpu"`,
/// `normalize_embeddings=True`) — the same independent-library method the
/// #3486 CoreML/fp16 experiment's correctness gate used (there: 0.999999+
/// mean cosine for fp32/fp16 vs 0.9897 for INT8, across a 50-chunk sample).
const REFERENCE_TEXTS: = ;
include!;
/// Name `FastEmbedder::model_name()` reports for the fp32 production
/// default — the ONLY model whose accuracy
/// [`default_model_matches_sentence_transformers_reference`] is a valid
/// gate for (see `embedding_model_name`, issue #3530).
const REFERENCE_FP32_MODEL_NAME: &str = "all-MiniLM-L6-v2";
/// Minimum mean cosine similarity required between the default embedder
/// and `REFERENCE_VECTORS` by
/// [`default_model_matches_sentence_transformers_reference`].
///
/// Why this exact value (issue #3711): the threshold only has to land in the
/// gap between the two models that can plausibly be loaded. Compare them by
/// DEFICIT from a perfect match (`1 - cosine`), since that is what the
/// threshold actually budgets — this constant allows a deficit of 1e-3:
///
/// - fp32 `AllMiniLML6V2` — the production default this test guards —
/// measures 0.999999+ against the `sentence-transformers` reference, a
/// deficit of ~1e-6. The only variance a *correctly loaded* fp32 model
/// can contribute is float re-association across different
/// GEMM/reduction microkernels (ORT thread counts, AVX2 vs AVX-512,
/// different runners), which is ~1e-6 relative on a 6-layer MiniLM and
/// cannot compound into a visible cosine change. So the budget is ~1000x
/// larger than the drift it must tolerate.
/// - INT8 `AllMiniLML6V2Q` measures 0.9897 (see
/// `resolve_default_embedding_model`'s doc), a deficit of ~1.03e-2 —
/// ~10x larger than the budget, so it fails. The local reproduction for
/// #3711 was tighter still: 0.995703, a deficit of ~4.3e-3, only ~4x
/// over. That ~4x is the REAL margin on the wrong-model side, not the
/// comfortable gap an earlier draft of this comment claimed, and it is
/// precisely why the wrong-model discriminator in the test body is the
/// `model_name()` assertion rather than this number.
///
/// So: platform numeric variance cannot trip this threshold, and a wrong
/// quantization still fails it — but only by a single order of magnitude.
///
/// Why it is NOT loosened (issue #3711): the 0.990649 CI failure was not
/// fp32 drift. A value that low is unreachable by re-association and is
/// within sampling distance of INT8's 0.9897 — the test was measuring a
/// genuinely INT8 embedder and reporting it as an fp32 accuracy
/// regression. The defect was the missing wrong-model diagnosis (now two
/// guards in the test body), not the tolerance, so nudging this constant
/// would have deleted the test's entire diagnostic value while leaving
/// both causes in place. Any future failure of this assertion with
/// `REFERENCE_FP32_MODEL_NAME` confirmed loaded is a REAL fp32 accuracy
/// regression and must not be papered over here either.
const REFERENCE_MIN_MEAN_COSINE: f64 = 0.999;
/// Why: verifies the actual production default (`FastEmbedder::new()`,
/// which now resolves to `AllMiniLML6V2` fp32 per
/// `resolve_default_embedding_model`) produces embeddings numerically
/// consistent with a genuine, independent `sentence-transformers`
/// reference — not just "some vector came back" (issue #3486 / #3493 P0).
/// What: pins `TRUSTY_EMBEDDER_MODEL` unset under `ENV_LOCK`, embeds
/// [`REFERENCE_TEXTS`] with the default embedder, asserts the model that
/// actually loaded is [`REFERENCE_FP32_MODEL_NAME`], and only then asserts
/// mean cosine similarity against `REFERENCE_VECTORS` is
/// `>= REFERENCE_MIN_MEAN_COSINE`.
/// Test: this test. NOT `#[ignore]`d (issue #3493 P0 part 2 — this is the
/// correctness gate that would have caught the CoreML-default accuracy
/// regression had it been wired into CI; see `ci.yml`'s `test` job for
/// the fastembed-model pre-seed step that makes this safe to run on every
/// PR without HuggingFace-download flakiness).
///
/// Deflaked in issue #3711. Two independent paths let this test measure an
/// INT8 embedder while blaming fp32 accuracy, and both are now diagnosed
/// rather than tolerated:
/// 1. env race — `FastEmbedder::new()` reads `TRUSTY_EMBEDDER_MODEL`
/// inside `resolve_default_embedding_model`, and this test held no
/// `ENV_LOCK`, so the sibling
/// `resolve_default_embedding_model_int8_opt_in` (which sets that var
/// process-globally) could be mid-loop at the instant this test
/// resolved its model. Now serialised like every other env-touching
/// test in this module, which additionally covers the `TRUSTY_DEVICE`
/// write `with_cache_size` performs on its CPU-fallback path.
/// 2. silent INT8 substitution — `FastEmbedder::with_cache_size`'s
/// two-model robustness net loads `AllMiniLML6V2Q` when the fp32
/// primary fails to initialise (plausible on a disk- and
/// memory-tight CI runner), and nothing checked which model came
/// back. `model_name()` (issue #3530) is now asserted first, so this
/// surfaces as "the fp32 primary never loaded" instead of an
/// inscrutable cosine number.
///
/// A synchronous `#[test]` driving an explicit current-thread runtime,
/// rather than `#[tokio::test]`, is what lets this module's existing std
/// `ENV_LOCK` cover the whole construct-and-embed window without tripping
/// `clippy::await_holding_lock` or introducing a second, non-serialising
/// lock (the trap `provider_tests.rs` documents).