Closes the cycle J asked for: curated cloud output lands structured
knowledge in the KB so future audits have architectural context, not
just a log of per-finding signatures.
Three pieces:
1. Inference curation (tree-split) — when diff > 30KB, shard at 4.5KB,
summarize each shard via cloud (temp=0, think=false on small
shards; think=true on main call). Merge into scratchpad. The cloud
verification then runs against the scratchpad, not truncated raw.
Eliminates the 40KB MAX_DIFF_CHARS truncation path for large PRs
(PR #8 is 102KB — was losing 62KB). Anti-false-positive guard in
the prompt: cloud is told scratchpad absence is NOT diff absence,
so it doesn't flag curated-out symbols as missing. unflagged_gaps
section is dropped entirely when curated (scratchpad can't ground
them).
2. fact_extractor — TS client for llm_team_ui's extract-facts mode at
localhost:5000/api/run. Sends curated scratchpad through qwen2.5
extractor + gemma2 verifier, parses SSE stream, returns structured
{facts, entities, relationships, verification, llm_team_run_id}.
Best-effort: if llm_team is down, extraction fails silently and
the audit still completes. AWAITED so CLI tools (audit_one.ts)
don't exit before extraction lands — the systemd poller has 90s
headroom so the extra ~15s doesn't matter.
3. audit_facts.jsonl + checkAuditFacts() — one row per curated audit
with the extraction result. kb_query tails the jsonl, explodes
entity rows, aggregates by entity name with distinct-PR counting,
surfaces entities recurring in 2+ PRs as info findings. Filters
out short names (<3 chars, extractor truncation artifacts) and
generic types (string/number/etc.) so signal isn't drowned.
Verified end-to-end on PR #8: 102KB diff → 23 shards → 1KB scratchpad
→ qwen2.5 extracted 4 facts + 6 entities + 6 relationships (real
code-level knowledge: AggregateOptions<T> type, aggregate<T> async
function with real signature, typed relationships). llm_team_run_id
cross-references to llm_team's own team_runs table.
Also: audit.ts passes (pr_number, head_sha) as InferenceContext so
extracted facts are scope-tagged for the KB index.