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
Third of the memory-model design trio (provenance #13, lifecycle #14). Design only — no code yet.
What exists
The schema is already ahead of the code. fact_links (001 migration) is a generic directional edge table with a free-form link_type, and SQLiteStore#insert_fact_link accepts any type. But only two types are ever written:
supersedes — Resolver, on supersession (resolver.rb:276)
conflicts_with — conflict pathway
Core::FactGraph BFS-traverses exactly those two via hardcoded discover_supersedes / discover_superseded_by / discover_conflicts methods. Nothing else in the system can create or read another edge type.
The gap
Facts carry no why and no where. Two relations would earn their keep:
motivated_by — preference → the fact that explains it. "Val prefers squash merges" motivated_by "linear history requirement on ups.dev". Recall of the preference without its motivation invites the agent to over-generalize it; and when the motivating fact is superseded or expires (Fact lifecycle: expiry-unless-reaffirmed + ratification surface #14), the preference should be flagged for re-review, not silently persist.
applies_to — fact → scope fact (a project, a repo, a person). Today scoping is a column (project scoping, 002); an edge generalizes it to non-project scopes and lets one fact scope several others.
Proposed design
No schema change.fact_links.link_type already takes any string. Add a VALID_LINK_TYPES constant (supersedes, conflicts_with, motivated_by, applies_to) validated in insert_fact_link, so typos don't create orphan vocabularies.
Creation paths (in priority order):
MCP management tool link_facts(from_id, to_id, type) + inverse unlink — cheapest, lets the agent record relations it infers during conversation.
Distill-time: the distiller prompt emits optional relations: [{to: <sibling index>, type: ...}] between facts extracted from the same content item. Same-batch only — no cross-corpus matching at distill time.
Traversal: collapse FactGraph's per-type discover methods into one generic discover_links_of_type over VALID_LINK_TYPES; edges gain direction labels for the formatter.
Recall surfacing: when a recalled fact has outgoing motivated_by edges, append the target fact as one-line context ("because: …"). applies_to filters rather than annotates.
Third of the memory-model design trio (provenance #13, lifecycle #14). Design only — no code yet.
What exists
The schema is already ahead of the code.
fact_links(001 migration) is a generic directional edge table with a free-formlink_type, andSQLiteStore#insert_fact_linkaccepts any type. But only two types are ever written:supersedes— Resolver, on supersession (resolver.rb:276)conflicts_with— conflict pathwayCore::FactGraphBFS-traverses exactly those two via hardcodeddiscover_supersedes/discover_superseded_by/discover_conflictsmethods. Nothing else in the system can create or read another edge type.The gap
Facts carry no why and no where. Two relations would earn their keep:
motivated_by— preference → the fact that explains it. "Val prefers squash merges" motivated_by "linear history requirement on ups.dev". Recall of the preference without its motivation invites the agent to over-generalize it; and when the motivating fact is superseded or expires (Fact lifecycle: expiry-unless-reaffirmed + ratification surface #14), the preference should be flagged for re-review, not silently persist.applies_to— fact → scope fact (a project, a repo, a person). Today scoping is a column (projectscoping, 002); an edge generalizes it to non-project scopes and lets one fact scope several others.Proposed design
fact_links.link_typealready takes any string. Add aVALID_LINK_TYPESconstant (supersedes,conflicts_with,motivated_by,applies_to) validated ininsert_fact_link, so typos don't create orphan vocabularies.link_facts(from_id, to_id, type)+ inverseunlink— cheapest, lets the agent record relations it infers during conversation.relations: [{to: <sibling index>, type: ...}]between facts extracted from the same content item. Same-batch only — no cross-corpus matching at distill time.discover_links_of_typeoverVALID_LINK_TYPES; edges gain direction labels for the formatter.motivated_byedges, append the target fact as one-line context ("because: …").applies_tofilters rather than annotates.motivated_byedges and mark dependentsneeds_reviewwhen a motivating fact expires or is superseded.Non-goals
Implementation is gated on reaction to this trio; a tracked task exists for it on my side.