Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
144
planned
1,362
shipped

Motir · Work items

MOTIR-3322Done

The lesson lifecycle is controlled — curated writes in, recurrence revives, non-recurrence retires

A lesson earns its place in the always-limited eight by still being relevant. The mechanism for that is retire by non-recurrence, and most of it ships — but the loop is open at both ends, so today it only ever removes.

What already works (lessonService, lessonRepository):

  • lastOccurredAt on every lesson, and retirementCutoff() = now − 90 days.
  • listForInjection filters AND "lastOccurredAt" >= staleCutoff — an un-hit lesson drops out of the search.
  • findNearestTenant + CAPTURE_DEDUP_DISTANCE — semantic matching of a new mistake against the library.
  • recordRecurrence(id, now) — bumps the clock and re-asserts enabled, and its comment already promises the revival Yue describes: "re-activates the lesson if it had already aged out … since retirement is only a read-time injection filter."

Where the loop is open:

  1. The re-plan path never consults the library. filePlanningBug files a bug in core and returns — no embedding, no match, no recordRecurrence. The log_planning_bug engine tool's own footer says "Filed by the Motir planner during a re-plan", so the commonest recurrence signal there is never lands on a lesson. A mistake can repeat indefinitely through re-plans while its lesson quietly ages out.
  2. Global lessons can never be reinforced. The near-dup/reinforce branch is tenant-only; global goes straight to createFromBase. The curated base corpus is global, so its rows are stamped once at seed time and expire 90 days later with no path back — and MOTIR-3296 is about to add ~195 more.

Close both and the loop runs in both directions: a repeat mistake is detected, the lesson it matches comes back into the search, and a lesson nobody has repeated in N days steps aside for one that matters.

Acceptance criteria

  • A planning bug filed on the re-plan path is matched against the lesson library on the same semantic + axis basis capture uses; a hit calls recordRecurrence and links the bug to the lesson it matched.
  • A miss is a genuinely new mistake and is handled explicitly — the card states whether it creates a lesson or only files the bug, and why.
  • Global lessons are reinforceable: a recurrence bumps a global lesson's clock and re-enables it, exactly as it does for a tenant lesson.
  • A revived lesson reappears in the axis + text search, asserted end to end: seed → advance past the cutoff → confirm it is gone from results → record a recurrence → confirm it is back.
  • The retention window stays a runtime-editable setting rather than a constant; it is not hard-coded by this story.
  • The hit or miss is visible on the filed bug, so a reader can tell the third recurrence of one mistake from three unrelated ones.

Context refs

  • motir-ai src/services/lessonService.tscaptureMistake's tenant-only reinforce branch, filePlanningBug, retirementCutoff, lessonRetentionDays.
  • motir-ai src/repositories/lessonRepository.tsfindNearestTenant, recordRecurrence, and the lastOccurredAt >= staleCutoff clause in listForInjection.
  • motir-ai src/jobs/handlers/generateTree.tscaptureMistake and filePlanningBug called as separate steps.
  • MOTIR-3294 — the axes the match narrows on.
  • MOTIR-3296 — the backfill whose global rows the second defect would expire.