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:
@@ -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
@@ -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++;
|
||||
|
||||
Reference in New Issue
Block a user