Tenant lessons are visible and controllable — a project sees what its planner learned, and decides what it keeps
The planner learns from a project's own mistakes and the project cannot see any of it. Tenant lessons are written by captureMistake, injected into every subsequent plan, and exposed nowhere — so a customer whose plans changed has no way to find out why, and no way to disagree.
That is a product problem before it is a trust problem. A lesson is a standing instruction the planner applies to their work; it was distilled by a model from one incident; it may be wrong, out of date, or right about a thing that has since changed. The only people who can judge that are the people whose project it is.
What this opens
- See them — every lesson bound to this project, in a list and a detail view, inside the existing AI-planning settings surface.
- Retire one — a soft state change, never a delete. A retired lesson stops being injected and stays readable, because "we stopped applying this on 3 March" is the part worth keeping.
- Turn capture off — an AI-planning setting for whether a planning mistake is recorded at all, on by default, with copy that explains what a lesson is and where it gets used.
All of it behind permissions, held by the project admin.
What already exists
- The surface:
app/(authed)/settings/project/ai-planning/—page.tsxandAiPlanningSettingsEditor.tsx, already holding three setting groups (auto-plan, sprint, planner) with at('aiPlanning.…')i18n catalog and a settings API atapp/api/projects/[key]/ai-settings/route.ts. - The design area:
design/ai-settings/with the full three-file set —ai-planning-settings.mock.html,.png,design-notes.md. - The permission machinery:
lib/permissions/catalog.tsandbuiltinRoles.ts, keys likeproject:administermapped to built-in roles. - The data: tenant lessons are
aiProjectId = <project>andlistForInjectionalready scopes reads toscope = 'global' OR aiProjectId = <caller>, so a project's lessons are already separable from everyone else's.
What does NOT exist
No lesson UI is designed. grep -ci lesson over both design/ai-settings/ai-planning-settings.mock.html and design-notes.md returns 0. This is the design gate's none-exists case, so the surface is drawn before it is built — including the retired state and the retire affordance, so the whole surface is designed once rather than in two passes.
Acceptance criteria
- A project admin can open AI-planning settings, see every lesson bound to their project, and open one to read it in full.
- An admin can retire a lesson; it stops being injected into plans and remains readable, with when and by whom recorded.
- An admin can turn planning-mistake recording off; the copy beside it explains what is captured and where it is used.
- Every one of those is permission-guarded, and a user without the permission sees neither the data nor the controls.
- Global lessons are not editable here — a project may retire what it taught the planner, not what the product ships.
- The surface is drawn in
design/ai-settings/before any of it is built.
Context refs
motir-coreapp/(authed)/settings/project/ai-planning/— the surface this extends.motir-coredesign/ai-settings/— the three-file asset, today with no lesson content.motir-corelib/permissions/catalog.ts,lib/permissions/builtinRoles.ts.motir-coreapp/api/projects/[key]/ai-settings/route.ts— the settings API.motir-aisrc/services/lessonService.ts,src/repositories/lessonRepository.ts— where tenant lessons live and how they are scoped.- MOTIR-3293 — the corpus epic; this is its customer-facing half.
- MOTIR-3327 — tenant-only capture, which is what makes these lessons the project's own.