feat(consume): fuse concept signals by RRF with declared tie-breaks

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-07 09:14:04 +02:00
commit f4b1f4ef0b
2 changed files with 120 additions and 0 deletions

View file

@ -576,3 +576,65 @@ def document_scores(
continue
scores[document] += float(_overlap(question_tokens, entry.label))
return scores
# --- Stage two: which concepts inside those documents -------------------------
#: Reciprocal Rank Fusion's smoothing constant. Lifted IN METHOD from the
#: reference implementation this repository read (`wiki-advise/rank.mjs:82`),
#: not in code and not as a quality claim: that engine's recall figures were
#: measured on an LLM candidate-generation pass this pre-pass deliberately does
#: not have, so its numbers say nothing about this one.
#:
#: RRF is chosen because it consumes RANKS ONLY. There is no score
#: normalisation to get wrong, no weight to tune against a test set, and the
#: fusion is invariant to any monotone transform of the individual signals.
RRF_K = 60
def concept_scores(
concepts: Sequence[Concept],
question: str,
document_score: Mapping[str, float],
) -> list[tuple[Concept, float]]:
"""Every concept, ordered best first, fused from three signals by RRF.
The signals: (1) the question against the concept's title and the segments
of its id, (2) the question against the body, (3) the stage-one score of the
document the concept belongs to.
**Ties break lexicographically by `concept_id`, at both the per-signal sort
and the fused sort.** Declared rather than inherited from dict insertion
order, so reproducibility is a property of the input SET and not of the
order it happened to arrive in.
**No float reaches the payload.** These scores order the cut; only ranks and
whole byte counts are emitted.
"""
question_tokens = normalise(question)
signals: list[dict[str, float]] = [
{
concept.concept_id: float(
_overlap(question_tokens, f"{concept.title} {concept.concept_id.replace('/', ' ')}")
)
for concept in concepts
},
{
concept.concept_id: float(_overlap(question_tokens, concept.body))
for concept in concepts
},
{
concept.concept_id: document_score.get(concept.concept_id.split("/", 1)[0], 0.0)
for concept in concepts
},
]
fused: dict[str, float] = {concept.concept_id: 0.0 for concept in concepts}
for signal in signals:
# Sort by score descending, then by id ascending -- the declared
# tie-break, applied before a rank is ever read.
order = sorted(signal, key=lambda key: (-signal[key], key))
for position, concept_id in enumerate(order, start=1):
fused[concept_id] += 1.0 / (RRF_K + position)
by_id = {concept.concept_id: concept for concept in concepts}
ranked_ids = sorted(fused, key=lambda key: (-fused[key], key))
return [(by_id[concept_id], fused[concept_id]) for concept_id in ranked_ids]