fix(wiki): pass chunks explicitly to compile_concept (single retrieve)

compile_concept now accepts chunks as a positional parameter; compile_all
retrieves chunks once and passes them directly, avoiding double-retrieve.
Also separates all_concepts (full list) from compile_concepts (filtered),
so cross-ref injection always uses the complete concept list regardless of
--concept filter (Fix 6 + Fix 8).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-06-14 03:48:33 +02:00
parent 60e40f6f36
commit 0202a2266e
2 changed files with 48 additions and 24 deletions

View File

@@ -426,6 +426,7 @@ def _render_page_markdown(
def compile_concept(
concept: Concept,
chunks: list[dict[str, Any]],
*,
top_k: int,
llm: LLMClient,
@@ -434,19 +435,24 @@ def compile_concept(
) -> ConceptPage:
"""Compile a single concept page.
1. Retrieve Top-K chunks (hybrid dense+FTS) for concept title + aliases.
2. Synthesise via LLM (Ollama) with per-claim citation format.
3. Run Grounding-Guard: mark ungrounded claims as ⚠.
4. Inject cross-references to other concepts as [[slug]] links.
5. Embed formula chunks if ``formulas`` table is present (graceful).
Parameters
----------
concept:
The concept to compile.
chunks:
Pre-retrieved source chunks for this concept (from :func:`_retrieve_chunks`).
Passing chunks explicitly avoids a second retrieve and ensures the stored
hash matches the chunks actually used for synthesis.
1. Synthesise via LLM (Ollama) with per-claim citation format.
2. Run Grounding-Guard: mark ungrounded claims as ⚠.
3. Inject cross-references to other concepts as [[slug]] links.
4. Embed formula chunks if ``formulas`` table is present (graceful).
Returns a :class:`ConceptPage` with full markdown and claim list.
"""
settings = get_settings()
_wiki_dir = wiki_dir or Path(settings.wiki_dir)
queries = [concept.title] + concept.aliases
chunks = _retrieve_chunks(queries, top_k=top_k)
_wiki_dir = wiki_dir or Path(settings.wiki_dir) # noqa: F841 — kept for future use
h = _chunk_hash(chunks)
prompt = _build_synthesis_prompt(concept, chunks)
@@ -532,10 +538,13 @@ def compile_all(
if not concepts_path.exists():
# Fall back to sibling concepts.yaml next to wiki/ dir
concepts_path = wiki_dir.parent / "wiki" / "concepts.yaml"
concepts = load_concepts(str(concepts_path))
# Load the FULL concept list — used for cross-reference injection regardless of filter
all_concepts = load_concepts(str(concepts_path))
if concept_filter:
concepts = [c for c in concepts if c.slug == concept_filter]
# Apply filter only to the set of concepts that will be (re-)compiled
compile_concepts = (
[c for c in all_concepts if c.slug == concept_filter] if concept_filter else all_concepts
)
state_path = wiki_dir / ".compile-state.json"
state = _load_compile_state(state_path)
@@ -549,8 +558,8 @@ def compile_all(
report = CompileReport()
for concept in concepts:
# Fast check: retrieve chunks and compare hash
for concept in compile_concepts:
# Retrieve chunks once — reuse for hash check and synthesis
queries = [concept.title] + concept.aliases
chunks = _retrieve_chunks(queries, top_k=k)
h = _chunk_hash(chunks)
@@ -561,9 +570,10 @@ def compile_all(
page = compile_concept(
concept,
chunks,
top_k=k,
llm=_llm,
all_concepts=concepts,
all_concepts=all_concepts, # always the full list for cross-refs
wiki_dir=wiki_dir,
)