measure: claim 24 unflooring is +4 (NOT-SHOWN); asymmetric embedding prefixes are -5 (discarded)

Measured on the 75-query extended gold set (iteration 8's held-out extension)
against the certified stack baseline results-stack-ext.json, on the embedded
corpus. Three runs of the candidate, zero drift.

A. CLAIM 24 WITHOUT THE THRESHOLD - net +4, NOT-SHOWN, kept in the tree.
   fixed  : q14, q25 (in-sample paraphrase), q43, q52, q63, q67 (held-out)
   broken : q15 (paraphrase), q28 (associative)
   8 discordant, McNemar exact p = 0.2891, floor is 6.
   heldout_paraphrase 16.7% -> 30.0%, paraphrase 61.5% -> 69.2%.
   Every regression guard held: exact_rare 6/6, phrase 7/7, nonsense 10/10,
   superseded 2/3. Latency FLAT: p50 641 -> 632 ms.
   The in-sample half (+q14 +q25 -q15 -q28 = 0) was already on record in
   iteration 7's cmp-nogate.json, so only the held-out +4 is new.

B. ASYMMETRIC TASK PREFIXES ON THE EMBEDDER - net -5, REVERTED in this commit.
   Rationale was sound and the prediction was wrong, which is why it was worth
   measuring: nomic-embed-text is an asymmetric retrieval encoder and this file
   embedded query and document bare on both sides. Prefixing does exactly what
   the model card implies for the far-away cases - it rescued q42 (gold at
   GLOBAL COSINE RANK 25,564) and q39 - but it re-ranks the whole space and
   broke more than it fixed:
   fixed  : q24, q39, q42
   broken : q18, q19, q22, q31, q43, q44, q52, q63
   heldout_paraphrase 30.0% -> 23.3%, paraphrase 69.2% -> 53.8%.
   The corpus and the reproducer are kept (embed-corpus-prefixed.py,
   snapshot-pre-repair-20260806-embedded-prefixed.json) so nobody re-runs it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tim Lingo
2026-08-07 17:45:05 -05:00
parent 9790d9342d
commit 9717a4eeaf
6 changed files with 5646 additions and 31 deletions
@@ -1,6 +1,6 @@
{
"baseline": "stack-ext",
"candidate": "unfloor-ext",
"candidate": "unfloor-clean",
"n_shared_queries": 75,
"fixed_by_candidate": [
"q14",
@@ -96,9 +96,9 @@
"mrr@10": 0.32437728937728944,
"nonsense_clean": "10/10",
"superseded_outranks": "2/3",
"latency_ms_p50": 993.0,
"latency_ms_p95": 1544.7,
"latency_ms_max": 1809.0,
"latency_ms_p50": 632.5,
"latency_ms_p95": 992.5,
"latency_ms_max": 1177.8,
"errors": 0,
"by_category": {
"associative": {
@@ -0,0 +1,158 @@
{
"baseline": "unfloor-clean",
"candidate": "semsub",
"n_shared_queries": 75,
"fixed_by_candidate": [
"q24",
"q39",
"q42"
],
"broken_by_candidate": [
"q18",
"q19",
"q22",
"q31",
"q43",
"q44",
"q52",
"q63"
],
"discordant": 11,
"net_queries": -5,
"mcnemar_exact_p": 0.2265625,
"min_detectable_swing_queries": 6,
"observed_run_to_run_drift_queries": 0,
"noise_floor_queries": 6,
"verdict": "no measurable difference",
"baseline_aggregate": {
"n_queries": 75,
"n_scored": 65,
"hit@5": 0.5384615384615384,
"recall@5": 0.44907176157176154,
"recall@10": 0.5380300255300255,
"precision@5": 0.13230769230769232,
"mrr@10": 0.32437728937728944,
"nonsense_clean": "10/10",
"superseded_outranks": "2/3",
"latency_ms_p50": 632.5,
"latency_ms_p95": 992.5,
"latency_ms_max": 1177.8,
"errors": 0,
"by_category": {
"associative": {
"n": 6,
"hit@5": 0.5,
"recall@5": 0.07575757575757576,
"recall@10": 0.13636363636363635,
"mrr@10": 0.23214285714285712
},
"exact_rare": {
"n": 6,
"hit@5": 1.0,
"recall@5": 1.0,
"recall@10": 1.0,
"mrr@10": 1.0
},
"heldout_paraphrase": {
"n": 30,
"hit@5": 0.3,
"recall@5": 0.3,
"recall@10": 0.4,
"mrr@10": 0.11638888888888889
},
"nonsense": {
"n": 10,
"clean": 10,
"avg_false_positives": 0.0
},
"paraphrase": {
"n": 13,
"hit@5": 0.6923076923076923,
"recall@5": 0.6923076923076923,
"recall@10": 0.7692307692307693,
"mrr@10": 0.29423076923076924
},
"phrase": {
"n": 7,
"hit@5": 1.0,
"recall@5": 0.5335884353741497,
"recall@10": 0.5933956916099773,
"mrr@10": 0.8214285714285714
},
"superseded": {
"n": 3,
"hit@5": 0.3333333333333333,
"recall@5": 0.3333333333333333,
"recall@10": 0.6666666666666666,
"mrr@10": 0.20833333333333334,
"outranks": 2
}
}
},
"candidate_aggregate": {
"n_queries": 75,
"n_scored": 65,
"hit@5": 0.46153846153846156,
"recall@5": 0.3889430014430015,
"recall@10": 0.4887681762681762,
"precision@5": 0.12307692307692313,
"mrr@10": 0.30181318681318675,
"nonsense_clean": "10/10",
"superseded_outranks": "2/3",
"latency_ms_p50": 634.4,
"latency_ms_p95": 988.3,
"latency_ms_max": 1184.5,
"errors": 0,
"by_category": {
"associative": {
"n": 6,
"hit@5": 0.3333333333333333,
"recall@5": 0.06060606060606061,
"recall@10": 0.12121212121212122,
"mrr@10": 0.19047619047619047
},
"exact_rare": {
"n": 6,
"hit@5": 1.0,
"recall@5": 1.0,
"recall@10": 1.0,
"mrr@10": 1.0
},
"heldout_paraphrase": {
"n": 30,
"hit@5": 0.23333333333333334,
"recall@5": 0.23333333333333334,
"recall@10": 0.3,
"mrr@10": 0.08925925925925927
},
"nonsense": {
"n": 10,
"clean": 10,
"avg_false_positives": 0.0
},
"paraphrase": {
"n": 13,
"hit@5": 0.5384615384615384,
"recall@5": 0.5384615384615384,
"recall@10": 0.7692307692307693,
"mrr@10": 0.26324786324786326
},
"phrase": {
"n": 7,
"hit@5": 1.0,
"recall@5": 0.5596655328798186,
"recall@10": 0.5775226757369615,
"mrr@10": 0.8214285714285714
},
"superseded": {
"n": 3,
"hit@5": 0.3333333333333333,
"recall@5": 0.3333333333333333,
"recall@10": 0.6666666666666666,
"mrr@10": 0.20833333333333334,
"outranks": 2
}
}
},
"repeat_variance": {}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+9 -27
View File
@@ -6226,30 +6226,12 @@ static void eg_ctx_blend(const float* e, int32_t dim) {
}
}
/* Asymmetric task prefixes. The configured model (EL_EMBED_MODEL, default
* nomic-embed-text) is an ASYMMETRIC retrieval encoder: it is trained with a
* task prefix and places a question and its answer in different regions of the
* space unless told which role each text is playing. Embedding both sides
* bare as this file did measures topical similarity rather than
* answer-hood, which is the wrong quantity for claim 24's index.
* These restore no claim: Will's description specifies only "computed by an
* embedding model over the node's content" (05-detailed-description l.17), so
* the model is his choice and this is correct USE of it, not his design.
* They are the substrate under claim 24, whose "vector similarity index over
* the semantic embedding vectors" is only as good as the vectors in it. */
#define EL_EMBED_DOC_PREFIX "search_document: "
#define EL_EMBED_QUERY_PREFIX "search_query: "
/* Fetch an embedding from Ollama. Returns malloc'd float[dim] or NULL.
* `pfx` is the asymmetric task prefix (document or query); it is prepended
* verbatim and is NOT counted against the content truncation budget.
* Truncates input to ENGRAM_EMBED_MAX_CHARS and JSON-escapes it. Honors the
* circuit breaker; a NULL return is always safe to ignore (fail-soft). */
static float* eg_embed_fetch_pfx(const char* pfx, const char* text,
int32_t* out_dim) {
static float* eg_embed_fetch(const char* text, int32_t* out_dim) {
*out_dim = 0;
if (!text || !*text) return NULL;
if (!pfx) pfx = "";
int64_t now = engram_now_ms();
if (now < _eg_embed_breaker_until) return NULL;
/* Build request body with escaped, truncated prompt. */
@@ -6268,11 +6250,11 @@ static float* eg_embed_fetch_pfx(const char* pfx, const char* text,
else esc[w++] = (char)c;
}
esc[w] = '\0';
size_t blen = w + strlen(pfx) + strlen(eg_embed_model()) + 64;
size_t blen = w + strlen(eg_embed_model()) + 64;
char* body = malloc(blen);
if (!body) { free(esc); return NULL; }
snprintf(body, blen, "{\"model\":\"%s\",\"prompt\":\"%s%s\"}",
eg_embed_model(), pfx, esc);
snprintf(body, blen, "{\"model\":\"%s\",\"prompt\":\"%s\"}",
eg_embed_model(), esc);
free(esc);
struct curl_slist* h = curl_slist_append(NULL, "Content-Type: application/json");
el_val_t resp = http_do_t("POST", eg_embed_url(), body, h,
@@ -7792,7 +7774,7 @@ el_val_t engram_search(el_val_t query, el_val_t limit) {
/* Claim-24 semantic leg: one query embedding, fetched once per search.
* NULL (embedder down / circuit breaker open) => pure lexical, as before. */
int32_t qdim = 0;
float* qv = eg_embed_fetch_pfx(EL_EMBED_QUERY_PREFIX, q, &qdim);
float* qv = eg_embed_fetch(q, &qdim);
EngramSemEntry* sem = qv ? malloc((size_t)g->node_count * sizeof(EngramSemEntry)) : NULL;
int64_t nsem = 0;
int64_t nhits = 0;
@@ -8214,7 +8196,7 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) {
EngramNode* n = &g->nodes[i];
if (n->emb || !eg_embed_eligible(n)) continue;
int32_t d = 0;
float* v = eg_embed_fetch_pfx(EL_EMBED_DOC_PREFIX, n->content, &d);
float* v = eg_embed_fetch(n->content, &d);
if (!v) break; /* embedder down / breaker open — stop this call */
n->emb = v; n->emb_dim = d;
backfilled++;
@@ -8232,7 +8214,7 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) {
q_emb = _eg_qcache_emb; q_dim = _eg_qcache_dim;
} else {
int32_t d = 0;
float* v = eg_embed_fetch_pfx(EL_EMBED_QUERY_PREFIX, q, &d);
float* v = eg_embed_fetch(q, &d);
if (v) {
free(_eg_qcache_text); free(_eg_qcache_emb);
_eg_qcache_text = strdup(q);
@@ -9664,7 +9646,7 @@ el_val_t engram_search_json(el_val_t query, el_val_t limit) {
* so the semantic half of the retrieval surface has to land HERE
* to be observable to the MCP wrapper and the app. */
int32_t qdim = 0;
float* qv = eg_embed_fetch_pfx(EL_EMBED_QUERY_PREFIX, q, &qdim);
float* qv = eg_embed_fetch(q, &qdim);
EngramSemEntry* sem = qv ? malloc((size_t)g->node_count * sizeof(EngramSemEntry)) : NULL;
int64_t nsem = 0;
int64_t nhits = 0;
@@ -10242,7 +10224,7 @@ el_val_t engram_embed_backfill(el_val_t count) {
EngramNode* n = &g->nodes[i];
if (n->emb || !eg_embed_eligible(n)) continue;
int32_t d = 0;
float* v = eg_embed_fetch_pfx(EL_EMBED_DOC_PREFIX, n->content, &d);
float* v = eg_embed_fetch(n->content, &d);
if (!v) break; /* embedder down / breaker open — stop this call */
n->emb = v; n->emb_dim = d;
done++;