You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The #517 canonical memory model names reflection as a memory type (synthesized lessons, procedural insights, episode-derived lessons) alongside fact and episode. PR #653 added write-scope routing for fact and episode extractions; reflections were not part of that PR's surface because the reflection generator does not yet exist. As of 2026-06-13, no production code writes rows with memory_type="reflection" — only "fact" and "episode" are written.
When the reflection generator does land (in a separate epic; see Out of scope), it must ship with scope binding from day one. The cost of shipping reflection generation without scope routing is the exact failure mode #517 exists to prevent: project-local lessons leaking into other projects' prompts because the scope label is missing or wrong.
This issue documents the binding rules and the integration plan so the reflection generator lands with the scope routing already specified, not as a retrofit. The hazard pattern this avoids: PR adding reflection generation gets reviewed for the generation logic; reviewers do not catch the missing scope routing because it is a one-line absence, not a one-line presence; reflections start writing as default-scope rows; a follow-up reclassification pass is required to repair the corpus. That is the same shape PR #665 had to repair for legacy fact and episode rows.
A reflection is project-scoped (scope="project", project_id set, workspace_root set) when every piece of evidence that produced it is itself project-scoped to the same project. Concretely:
All source episodes are project-scoped to project P.
All source facts cited by the reflection are either project-scoped to P or global (global facts may inform a project reflection without changing its scope).
The active workspace at synthesis time was inside project P's root.
The reflection inherits project P's project_id and workspace_root. scope_confidence reflects the reasoner's confidence; scope_source = "extraction_default" if generated by the extraction pipeline, or "classifier" if a separate scope reasoner was consulted.
Rule 2: Cross-project evidence proposes global reflections or candidate preferences
A reflection synthesized from evidence spanning multiple projects (or generated without a specific active project) is NOT silently written as global. Cross-project synthesis raises an authority question that the operator must resolve. Two valid outcomes:
Global reflection: when the lesson is genuinely operator-wide (a procedural insight about how the operator works across projects), the row writes as scope="global", project_id=null, scope_source="classifier" if a reasoner made the call, else queued for operator approval.
Candidate preference: when the lesson reads as a proposed always-on rule ("always do X", "prefer Y over Z"), the row writes as memory_type="candidate_preference" and scope="global". The candidate-preference type is the gate: the operator must approve before it influences future turns.
Cross-project reflections are NEVER written silently as scope="global" with high confidence and no operator gate. The default for ambiguous cross-project synthesis is "queue for review", not "store and hope".
Orthogonality with reflection_kind
Scope and reflection_kind describe different axes. reflection_kind (e.g. procedural, corrective, episode_lesson) describes the shape of the lesson. Scope describes its authority. A procedural reflection can be either project or global; a corrective reflection can be either project or global; the type does not imply the scope and vice versa.
A reflection row therefore carries both fields independently. The metadata schema must reserve both keys at the same nesting level so a later evolution of either axis does not collide.
Integration plan
When the reflection generator lands, the integration touches three modules:
The reflection generator itself (in the future epic) emits a structured proposal that names the evidence (source episode ids, source fact ids), the active workspace at synthesis time, the proposed reflection_kind, and the proposed scope decision (project / global / candidate_preference). The scope decision is computed by the rules above, not picked by the LLM as a free string.
kai.memory_extraction (or its reflection sibling) receives the proposal and routes the write. The routing mirrors _route_extraction_scope for facts and episodes (PR feat(memory): add write-scope routing for memory extraction #653): build the same ResolvedMemoryScope, run the same _validated_metadata_for_write builder, write through the same Mem0 path. No new write surface; new routing logic only.
kai.memory_command (/memory UI) already shows scope on every detail view, so reflections surface their scope automatically once they exist. The reclassification CLI must include reflections in its selection pass (or explicitly exclude them with a documented rationale); leaving reflections out of reclassification would re-create the pre-2026-06-12 audit gap for a new memory type.
What "ships with scope binding from day one" means
Acceptance for the reflection generator PR (when it lands) is augmented by:
Every test that asserts a reflection is written must ALSO assert its scope, project_id, and scope_source are populated and correct for the test's evidence shape.
The reflection generator's PR description names which rule (project-local or cross-project) each test case exercises.
A regression probe in the scoped evaluator's corpus asserts that a project-scoped reflection does NOT appear in another project's prompt slice.
Reclassification CLI selection logic is updated to include reflections OR explicitly exclude them with a comment naming the rationale.
Out of scope
The reflection generator itself. That is the larger reflection / self-improvement epic, separate from Epic: Scoped global/project memory #517. This issue exists so that epic does not ship without scope binding.
The reflection synthesis prompt and the reasoning-quality question (what reflections are good reflections). That is the reflection epic's concern; this issue is only about scope.
Reflection deletion and refresh semantics. Same scope binding rules apply, but the storage-layer questions belong to the reflection epic.
Candidate-preference approval UI. Mentioned because the rules name it, but the approval surface is its own work.
Acceptance
Reflection scope binding rules are documented in the operator-facing memory model docs (the existing scoped-project-memory.md or its successor).
When the reflection generator PR opens, this issue's rules are linked from its PR description as the binding contract the PR must satisfy.
The reflection generator PR adds tests for both Rule 1 (project-local evidence → project scope) and Rule 2 (cross-project evidence → global OR candidate_preference, never silent global).
At least one scoped-evaluator probe verifies project-scoped reflections do not leak across projects.
Reclassification CLI either selects reflections or explicitly excludes them with a one-line rationale.
Issue closes when the reflection generator PR merges with scope binding in place, or when the operator decides reflections are deferred indefinitely (in which case this issue closes as wontfix and Epic: Scoped global/project memory #517 is updated to drop the reflection-binding bullet).
Why this exists
The #517 canonical memory model names
reflectionas a memory type (synthesized lessons, procedural insights, episode-derived lessons) alongsidefactandepisode. PR #653 added write-scope routing forfactandepisodeextractions; reflections were not part of that PR's surface because the reflection generator does not yet exist. As of 2026-06-13, no production code writes rows withmemory_type="reflection"— only"fact"and"episode"are written.When the reflection generator does land (in a separate epic; see Out of scope), it must ship with scope binding from day one. The cost of shipping reflection generation without scope routing is the exact failure mode #517 exists to prevent: project-local lessons leaking into other projects' prompts because the scope label is missing or wrong.
This issue documents the binding rules and the integration plan so the reflection generator lands with the scope routing already specified, not as a retrofit. The hazard pattern this avoids: PR adding reflection generation gets reviewed for the generation logic; reviewers do not catch the missing scope routing because it is a one-line absence, not a one-line presence; reflections start writing as default-scope rows; a follow-up reclassification pass is required to repair the corpus. That is the same shape PR #665 had to repair for legacy
factandepisoderows.Scope binding rules
Two binding rules cover every reflection write:
Rule 1: Project-local evidence creates project-scoped reflections
A reflection is project-scoped (
scope="project",project_idset,workspace_rootset) when every piece of evidence that produced it is itself project-scoped to the same project. Concretely:The reflection inherits project P's
project_idandworkspace_root.scope_confidencereflects the reasoner's confidence;scope_source = "extraction_default"if generated by the extraction pipeline, or"classifier"if a separate scope reasoner was consulted.Rule 2: Cross-project evidence proposes global reflections or candidate preferences
A reflection synthesized from evidence spanning multiple projects (or generated without a specific active project) is NOT silently written as
global. Cross-project synthesis raises an authority question that the operator must resolve. Two valid outcomes:scope="global",project_id=null,scope_source="classifier"if a reasoner made the call, else queued for operator approval.memory_type="candidate_preference"andscope="global". The candidate-preference type is the gate: the operator must approve before it influences future turns.Cross-project reflections are NEVER written silently as
scope="global"with high confidence and no operator gate. The default for ambiguous cross-project synthesis is "queue for review", not "store and hope".Orthogonality with
reflection_kindScope and
reflection_kinddescribe different axes.reflection_kind(e.g.procedural,corrective,episode_lesson) describes the shape of the lesson. Scope describes its authority. Aproceduralreflection can be either project or global; acorrectivereflection can be either project or global; the type does not imply the scope and vice versa.A reflection row therefore carries both fields independently. The metadata schema must reserve both keys at the same nesting level so a later evolution of either axis does not collide.
Integration plan
When the reflection generator lands, the integration touches three modules:
The reflection generator itself (in the future epic) emits a structured proposal that names the evidence (source episode ids, source fact ids), the active workspace at synthesis time, the proposed
reflection_kind, and the proposed scope decision (project/global/candidate_preference). The scope decision is computed by the rules above, not picked by the LLM as a free string.kai.memory_extraction(or its reflection sibling) receives the proposal and routes the write. The routing mirrors_route_extraction_scopefor facts and episodes (PR feat(memory): add write-scope routing for memory extraction #653): build the sameResolvedMemoryScope, run the same_validated_metadata_for_writebuilder, write through the same Mem0 path. No new write surface; new routing logic only.kai.memory_command(/memoryUI) already shows scope on every detail view, so reflections surface their scope automatically once they exist. The reclassification CLI must include reflections in its selection pass (or explicitly exclude them with a documented rationale); leaving reflections out of reclassification would re-create the pre-2026-06-12 audit gap for a new memory type.What "ships with scope binding from day one" means
Acceptance for the reflection generator PR (when it lands) is augmented by:
scope,project_id, andscope_sourceare populated and correct for the test's evidence shape.Out of scope
Acceptance
scoped-project-memory.mdor its successor).Refs #517.