Oban worker in the :compaction queue that saves durable facts from the entries a compaction cuts.
Compaction destroys information, which makes it the best moment to keep some of it. The work is
asynchronous because before_compact sits on the machine's critical path
(SuperPi.Plugins.Memory.before_compact/2 only enqueues, and compaction proceeds unchanged).
It shares the queue because a queue of its own would push the sum of the queue limits above the
SQLite pool size, which a config test forbids. The cost is that two slow harvests can delay a
background compaction.
Job
Args: conversation_id, head_entry_id, entry_ids, scope_kind, scope_id. The job is unique
on conversation_id and head_entry_id, so a repeated compaction of the same cut enqueues one job.
A retry or a re-run is also safe: a fact gets a slug from the head entry and a hash of its title, so
a second run updates the same notes.
Facts
The worker renders the entries as a transcript (each message cut at 1 500 characters, at most
24 000 characters in all, the newest kept) and asks the model for JSON:
{"facts": [{"title", "body", "topics"}]}. At most :harvest_max_facts facts (8) are stored, with
compaction provenance, confidence 0.3 and source naming the conversation and head entry. Such a
note cannot be pinned, and the index lists its title only. The transcript may hold hostile web
content, which is why the facts stay low-trust.
The model is :harvest_model (a fast one). Tests set config :super_pi, :memory, harvest_llm: fun,
a function from the prompt text to {:ok, text} or {:error, reason}. Unusable model output
fails the job, and Oban retries it up to 3 times.
Summary
Functions
Parses the model reply into facts. Accepts a fenced block or text around the JSON object.
The prompt text for a transcript.