Repository navigation
Add ragger re-summarize CLI (turns level ready; rollup-level uniqueness TBD) #73
Description
Summary
Add a ragger re-summarize CLI command to regenerate stored summaries with the current summarizer model (e.g. after switching summarizer models). Design is settled for the turns level; the episodes/sessions/projects levels have an open uniqueness question (below) that Reid wants to resolve first.
Proposed CLI shape
ragger re-summarize turns|episodes|sessions|projects [--after-date=X] [--before-date=Y] [--model=NAME]
Settled semantics (from design discussion 2026-07-28):
- Date filter = the dates of the turns being summarized (
turn_datetimefor theturnslevel), notsummarized_on. (Note: existing CLI already has--since/--untilwith exactly this meaning — decide whether to reuse those or add--after-date/--before-date. Reusing avoids duplicate flags.) - Output model = current
settings.ini [summarizer] model(whatever is configured now). --model=NAME= a filter: only re-summarize rows whose currentsummary_model_idisNAME. This is the "I switched summarizers, redo the ones done by the old model" flow.- Levels:
episodes|sessions|projects— see initial-comment deferral; start withturnsonly, add rollup levels once the turn path is proven.
Write-path design (turns level — READY to build)
Do not convert finalize_turn_summary into an upsert. Keep it INSERT-only (first-time summarize; the live-capture safety net and the existing test_finalize_turn_summary_rejects_duplicate contract stay intact).
Instead add a separate resummarize_turn(turn_id, text, model) with UPDATE-only semantics:
- Fails (returns false) if no existing
turn_summariesrow for thatturn_id. - Preserves
turn_summary_id(row identity unchanged). - Replaces
text/embedding/phon/summary_model_id. - Sets
summarized_on = unixepoch()(real re-summarize time). - Added across all four backend layers (pure virtual → SqliteBackend header → Impl → RaggerMemory/SqliteBackend wrapper — the "all four layers or vtable link error" rule).
Plus a query turns_to_resummarize(after, before, filter_model) returning turn_ids + text for rows matching the filters.
CLI notes:
- First CLI command to use
InferenceClient— build viaInferenceClient::from_config(cfg)(same asserver.cpp:init_inference), callsummarize_transcriptper turn. - Count-first + confirmation prompt +
--yes+ DB backup, mirroringrebuild-embeddings. - Warn if the daemon is running (two summarizing processes racing).
busy_timeoutcovers lock contention, but cleanest isragger stopfirst — print a warning rather than silently racing. - RED-first tests:
resummarize_turnupdates in place / bumpssummarized_on/ preserves id / fails on nonexistent;turns_to_resummarizerespects date + model filters.
OPEN QUESTION — uniqueness for episodes/sessions/projects (Reid to resolve)
The turns level upserts cleanly because turn_summaries has a real unique key (idx_turn_summaries_turn_id_uniq on turn_id). The rollup levels live in the summaries table under the immutable-insert-per-closed-run model with no uniqueness key per run — that's exactly what caused the watermark=0 runaway (duplicate level='session' rows on every re-close; see the boundary-detection fix landed 2026-07-28).
So re-summarize sessions (etc.) needs a decision on how to identify "the existing summary for this run" so a re-summarize replaces rather than appends:
- (a) delete the old row(s) for the run's span and insert fresh, or
- (b) add a per-run uniqueness key to
summariesso it can upsert like turns.
Reid has ideas but wants to be sure about keeping the uniqueness of the rollup levels before this is built. Turns-level work can proceed independently of this decision.
Related context
- Boundary-detection no-lookback fix +
migrate_to_db0.12.shwatermark stamp (landed 2026-07-28) — same subsystem. turn_summaries.summarized_on == turn_datetimefor all migrated rows is an accepted artifact (old schema never recorded a true summarize-time); re-summarize is the forward path that gives those rows a realsummarized_on.
Activity