Problem
Skill distillation reviews one conversation at a time, so a habitual request
is structurally invisible to it. The skills a user would most value — the ones
they ask for every week — can never be proposed.
Evidence
autobot-backend/services/skill_management/skill_extractor.py:86 —
extract_skills(conversation_history, ...) takes a single conversation.
autobot-backend/services/skill_management/skill_distillation_scheduler.py —
feeds conversations one at a time behind a durable cursor, MAX_SESSIONS_PER_RUN
each pass.
skill_extractor.py:35 — ExtractedSkill.usage_count exists but is populated
per extraction, not across sessions.
- Grep for
distill|routine.?min|habit|recurren across the backend finds no
cross-conversation pass.
Why a separate pass is required
This is not a tuning problem in the existing reviewer. Within one conversation
window a habitual request and a one-off task look identical, and the reviewer is
right to decline writing a skill for a one-off narrative. The signal it needs —
"this same request recurs" — is only visible across sessions. No prompt change to
a single-conversation reviewer can recover it.
Proposed approach
A recurrence miner alongside skill_extractor.py, not inside it:
- Cluster the opening message of each recent conversation (shingles), after
redacting URLs, filesystem paths, and long digit runs — those carry no routine
identity and would both fragment clusters and leak secrets into candidate rows.
- Count distinct conversations and distinct days per cluster. Days matter: ten
openers in one afternoon is one task, not a habit.
- Promote clusters past a threshold into skill candidates through the existing
SkillProposer.
Recompute each sweep from scratch over the lookback window; do not increment
counters. Two properties follow directly:
- re-runs are idempotent — a repeated sweep cannot inflate a count;
- an abandoned routine decays out of the window on its own, with no expiry job.
An accumulating counter has neither, and a double-counted sweep is invisible.
Blocked — do not build yet
AUTOBOT_SKILL_DISTILLATION_ENABLED defaults to False
(skill_distillation_scheduler.py:44 — "Ships inert. Enable deliberately once the
LLM cost of an hourly pass is accepted"). Building a recurrence miner for a
pipeline nobody has turned on adds maintained-but-dormant surface — the same shape
as #13685, where a whole context stack was built and never ran.
Gate: this issue starts only after distillation is enabled somewhere real and
has produced accepted proposals. Until then the correct state is filed-and-waiting.
Acceptance criteria
Order
Wave 2 — blocked on the distillation-enabled gate above. No code dependency on
#14027/#14028/#14029.
Found during a comparative audit of an external agent-harness architecture, whose
routine miner documents this exact blind spot in a per-conversation reviewer and
solves it with a recompute-per-sweep cross-session pass.
Problem
Skill distillation reviews one conversation at a time, so a habitual request
is structurally invisible to it. The skills a user would most value — the ones
they ask for every week — can never be proposed.
Evidence
autobot-backend/services/skill_management/skill_extractor.py:86—extract_skills(conversation_history, ...)takes a single conversation.autobot-backend/services/skill_management/skill_distillation_scheduler.py—feeds conversations one at a time behind a durable cursor,
MAX_SESSIONS_PER_RUNeach pass.
skill_extractor.py:35—ExtractedSkill.usage_countexists but is populatedper extraction, not across sessions.
distill|routine.?min|habit|recurrenacross the backend finds nocross-conversation pass.
Why a separate pass is required
This is not a tuning problem in the existing reviewer. Within one conversation
window a habitual request and a one-off task look identical, and the reviewer is
right to decline writing a skill for a one-off narrative. The signal it needs —
"this same request recurs" — is only visible across sessions. No prompt change to
a single-conversation reviewer can recover it.
Proposed approach
A recurrence miner alongside
skill_extractor.py, not inside it:redacting URLs, filesystem paths, and long digit runs — those carry no routine
identity and would both fragment clusters and leak secrets into candidate rows.
openers in one afternoon is one task, not a habit.
SkillProposer.Recompute each sweep from scratch over the lookback window; do not increment
counters. Two properties follow directly:
An accumulating counter has neither, and a double-counted sweep is invisible.
Blocked — do not build yet
AUTOBOT_SKILL_DISTILLATION_ENABLEDdefaults toFalse(
skill_distillation_scheduler.py:44— "Ships inert. Enable deliberately once theLLM cost of an hourly pass is accepted"). Building a recurrence miner for a
pipeline nobody has turned on adds maintained-but-dormant surface — the same shape
as #13685, where a whole context stack was built and never ran.
Gate: this issue starts only after distillation is enabled somewhere real and
has produced accepted proposals. Until then the correct state is filed-and-waiting.
Acceptance criteria
(precondition, not work).
asserted, since an inflating counter is exactly the failure being designed out.
expiry job involved.
long digit run must not reach a stored candidate row.
Order
Wave 2 — blocked on the distillation-enabled gate above. No code dependency on
#14027/#14028/#14029.
Found during a comparative audit of an external agent-harness architecture, whose
routine miner documents this exact blind spot in a per-conversation reviewer and
solves it with a recompute-per-sweep cross-session pass.