Skip to content

zettelkasten.reranking

zettelkasten.reranking

Blended recall-then-rerank scoring for Zettelkasten retrieval.

The pure scoring core (RerankConfig, rerank, MMR, note_importance) now lives in :mod:memory.reranking — the base layer — so both the memory tree and the zettelkasten can use it without violating the one-way dependency direction (zettelkasten may import memory; memory never imports zettelkasten). This module RE-EXPORTS those names for backward compatibility and adds the one channel that is genuinely zettelkasten-specific: the syllabus-backed source-work importance map (:func:source_work_importance), which depends on :mod:zettelkasten.syllabus.

See :mod:memory.reranking for the recall-then-rerank design and the non-punitive invariant.

source_work_importance

source_work_importance(get_graph: 'GetGraph', *, project: str = '', graphs_dir: 'Path | None' = None, namespace: Callable[[str], str] | None = None, use_cache: bool = True) -> dict[str, float]

Syllabus work/paper importance scores for a source scope, work_id -> 0..1.

Thin wrapper over :func:zettelkasten.syllabus.build_corpus + :func:zettelkasten.syllabus.importance — the real influence/salience layer, NOT a reimplementation. Building the corpus is potentially expensive (walks every source's notes + the citation store), so this is lazy (syllabus is imported only when called) and cached by (project, graphs_dir) scope. Pass use_cache=False to force a rebuild; :func:clear_source_importance_cache drops all cached scopes.

This channel is OFF by default: the reranker never calls it. The wiring layer opts in (via RerankConfig.use_source_importance), calls this, and folds the result into the importance_map it hands :func:rerank.

Scores are addressable by BOTH Work.id AND Work.source_graph. A work built from a promoted source keeps its Work.id == source graph name, but a source that dedups onto a citation keeps the CITATION id as Work.id while holding the writable source folder in source_graph. The wiring folds by a candidate's source_graph, so emitting the source_graph alias lets a citation-deduped source still receive its boost (keyed by Work.id alone it would silently miss).

Source code in zettelkasten/reranking.py
def source_work_importance(
    get_graph: "GetGraph",
    *,
    project: str = "",
    graphs_dir: "Path | None" = None,
    namespace: Callable[[str], str] | None = None,
    use_cache: bool = True,
) -> dict[str, float]:
    """Syllabus work/paper importance scores for a source scope, ``work_id -> 0..1``.

    Thin wrapper over :func:`zettelkasten.syllabus.build_corpus` +
    :func:`zettelkasten.syllabus.importance` — the real influence/salience layer,
    NOT a reimplementation. Building the corpus is potentially expensive (walks
    every source's notes + the citation store), so this is lazy (syllabus is
    imported only when called) and cached by ``(project, graphs_dir)`` scope. Pass
    ``use_cache=False`` to force a rebuild; :func:`clear_source_importance_cache`
    drops all cached scopes.

    This channel is OFF by default: the reranker never calls it. The wiring layer
    opts in (via ``RerankConfig.use_source_importance``), calls this, and folds
    the result into the ``importance_map`` it hands :func:`rerank`.

    Scores are addressable by BOTH ``Work.id`` AND ``Work.source_graph``. A work
    built from a promoted source keeps its ``Work.id`` == source graph name, but a
    source that dedups onto a citation keeps the CITATION id as ``Work.id`` while
    holding the writable source folder in ``source_graph``. The wiring folds by a
    candidate's ``source_graph``, so emitting the ``source_graph`` alias lets a
    citation-deduped source still receive its boost (keyed by ``Work.id`` alone it
    would silently miss).
    """
    key = (project, str(graphs_dir) if graphs_dir is not None else "")
    if use_cache and key in _source_importance_cache:
        return _source_importance_cache[key]

    from zettelkasten.syllabus import build_corpus, importance

    works, _ = build_corpus(
        get_graph, project=project, graphs_dir=graphs_dir, namespace=namespace
    )
    by_work_id = importance(works)
    scores = dict(by_work_id)
    # Alias each owned work's score onto its source_graph name so the wiring's
    # source_graph lookup hits even when Work.id is a (citation-deduped) id that
    # differs from the folder name. If two works share a folder, keep the max.
    for w in works:
        sg = getattr(w, "source_graph", None)
        if not sg:
            continue
        val = by_work_id.get(w.id)
        if val is None:
            continue
        if val > scores.get(sg, float("-inf")):
            scores[sg] = val
    if use_cache:
        _source_importance_cache[key] = scores
    return scores

clear_source_importance_cache

clear_source_importance_cache() -> None

Drop every cached source-work importance scope.

Source code in zettelkasten/reranking.py
def clear_source_importance_cache() -> None:
    """Drop every cached source-work importance scope."""
    _source_importance_cache.clear()