LemonRouter. RoutingFeedbackStore
(lemon_router v0.1.0)
View Source
SQLite-backed store for routing feedback samples.
Records one row per finalized run, keyed by task fingerprint. Provides aggregate queries over outcome rates, durations, and sample sizes so the router can use past performance to break model-selection ties.
Design
- Separate SQLite database (
routing_feedback.sqlite3) — never touches the main store or run-history DB. - Writes are async casts (fire-and-forget). Read failures return
{:insufficient_data, n}rather than raising. - A
min_sample_sizethreshold (defaultElixir.LemonRouter.RoutingFeedbackStore.min_sample_size/0) guards aggregates so the router never acts on statistically weak data. - The write path is gated before Bus publication by
LemonMemory.Ingest; router reads are gated by the caller before consulting historical data.
Usage
# Called by the router-owned Bus subscriber when routing_feedback flag is on
RoutingFeedbackStore.record(fingerprint_key, outcome, duration_ms)
# Called by router to read aggregate stats
case RoutingFeedbackStore.aggregate(fingerprint_key) do
{:ok, agg} -> agg.success_rate
{:insufficient_data, _n} -> nil
endConfiguration
config :lemon_router, LemonRouter.RoutingFeedbackStore,
path: "~/.lemon/store", # directory — routing_feedback.sqlite3 created inside
min_sample_size: 5, # minimum samples before returning aggregate
retention_ms: 30 * 24 * 3600_000 # 30 days (default)
Summary
Functions
Return aggregate stats for a fingerprint key.
Return the best-performing model for a context key (3-segment prefix).
Returns a specification to start this module under a supervisor.
List all fingerprint keys with summary stats.
Returns the configured minimum sample size threshold.
Record a routing feedback sample for a fingerprint key.
Return store-level summary statistics.
Functions
@spec aggregate(String.t()) :: {:ok, map()} | {:insufficient_data, non_neg_integer()}
Return aggregate stats for a fingerprint key.
Returns {:ok, agg} when enough samples are available, or
{:insufficient_data, sample_count} when below the min_sample_size
threshold.
Aggregate map
%{
fingerprint_key: "code|bash,read_file|...",
total: 12,
outcomes: %{success: 8, partial: 2, failure: 2},
success_rate: 0.667,
mean_duration_ms: 4200
}
Return the best-performing model for a context key (3-segment prefix).
Queries all fingerprint keys that share the same family|toolset|workspace
prefix, aggregates success counts per model (across providers), and returns
the model with the highest success rate that meets min_sample_size.
Returns {:ok, model_string} or {:insufficient_data, 0} if no model
reaches the threshold.
Returns a specification to start this module under a supervisor.
See Supervisor.
List all fingerprint keys with summary stats.
Returns {:ok, [map()]} where each map has:
fingerprint_key, total, success_count, avg_duration_ms, last_seen_ms.
Returns {:error, :not_running} if the GenServer is not available.
@spec min_sample_size() :: pos_integer()
Returns the configured minimum sample size threshold.
Record a routing feedback sample for a fingerprint key.
Fire-and-forget cast. Returns :ok immediately. If the GenServer is not
running, the call is silently swallowed (non-fatal).
Return store-level summary statistics.
Returns {:ok, map()} with keys:
total_records, unique_fingerprints, oldest_ms, newest_ms.