@jungjaehoon/mama-core 1.4.2 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +48 -10
  2. package/db/migrations/026-create-canonical-entity-tables.sql +99 -0
  3. package/db/migrations/027-create-entity-review-support.sql +44 -0
  4. package/db/migrations/028-create-entity-audit-tables.sql +45 -0
  5. package/db/migrations/029-extend-entity-observations-observation-type.sql +60 -0
  6. package/db/migrations/030-case-first-memory-substrate.sql +901 -0
  7. package/db/migrations/031-wiki-page-index-provenance-columns.sql +2 -0
  8. package/db/migrations/032-add-memory-provenance-columns.sql +21 -0
  9. package/db/migrations/033-create-model-runs-and-tool-traces.sql +53 -0
  10. package/db/migrations/034-add-connector-event-scope-columns.sql +14 -0
  11. package/db/migrations/035-create-twin-edges.sql +63 -0
  12. package/db/migrations/036-create-agent-situation-packets.sql +61 -0
  13. package/dist/agent-graph/alias-write.d.ts +3 -0
  14. package/dist/agent-graph/alias-write.js +231 -0
  15. package/dist/agent-graph/entity-resolve.d.ts +3 -0
  16. package/dist/agent-graph/entity-resolve.js +275 -0
  17. package/dist/agent-graph/errors.d.ts +4 -0
  18. package/dist/agent-graph/errors.js +11 -0
  19. package/dist/agent-graph/graph-query.d.ts +5 -0
  20. package/dist/agent-graph/graph-query.js +359 -0
  21. package/dist/agent-graph/index.d.ts +6 -0
  22. package/dist/agent-graph/index.js +22 -0
  23. package/dist/agent-graph/types.d.ts +162 -0
  24. package/dist/agent-graph/types.js +3 -0
  25. package/dist/agent-situation/builder.d.ts +8 -0
  26. package/dist/agent-situation/builder.js +239 -0
  27. package/dist/agent-situation/cache-key.d.ts +4 -0
  28. package/dist/agent-situation/cache-key.js +64 -0
  29. package/dist/agent-situation/index.d.ts +7 -0
  30. package/dist/agent-situation/index.js +28 -0
  31. package/dist/agent-situation/packet-store.d.ts +27 -0
  32. package/dist/agent-situation/packet-store.js +228 -0
  33. package/dist/agent-situation/ranking-policy.d.ts +18 -0
  34. package/dist/agent-situation/ranking-policy.js +75 -0
  35. package/dist/agent-situation/source-readers.d.ts +52 -0
  36. package/dist/agent-situation/source-readers.js +300 -0
  37. package/dist/agent-situation/types.d.ts +195 -0
  38. package/dist/agent-situation/types.js +3 -0
  39. package/dist/canonicalize.d.ts +38 -0
  40. package/dist/canonicalize.js +106 -0
  41. package/dist/cases/case-links.d.ts +116 -0
  42. package/dist/cases/case-links.js +794 -0
  43. package/dist/cases/composition-overrides.d.ts +90 -0
  44. package/dist/cases/composition-overrides.js +724 -0
  45. package/dist/cases/corrections.d.ts +156 -0
  46. package/dist/cases/corrections.js +1045 -0
  47. package/dist/cases/freshness.d.ts +57 -0
  48. package/dist/cases/freshness.js +283 -0
  49. package/dist/cases/live-state.d.ts +48 -0
  50. package/dist/cases/live-state.js +256 -0
  51. package/dist/cases/membership-explain.d.ts +56 -0
  52. package/dist/cases/membership-explain.js +140 -0
  53. package/dist/cases/membership-matcher.d.ts +23 -0
  54. package/dist/cases/membership-matcher.js +193 -0
  55. package/dist/cases/merge-split.d.ts +61 -0
  56. package/dist/cases/merge-split.js +368 -0
  57. package/dist/cases/role-inference.d.ts +10 -0
  58. package/dist/cases/role-inference.js +85 -0
  59. package/dist/cases/search-rollup.d.ts +27 -0
  60. package/dist/cases/search-rollup.js +309 -0
  61. package/dist/cases/sqlite-transaction.d.ts +10 -0
  62. package/dist/cases/sqlite-transaction.js +62 -0
  63. package/dist/cases/store.d.ts +74 -0
  64. package/dist/cases/store.js +816 -0
  65. package/dist/cases/target-ref.d.ts +25 -0
  66. package/dist/cases/target-ref.js +22 -0
  67. package/dist/cases/timeline-range.d.ts +6 -0
  68. package/dist/cases/timeline-range.js +322 -0
  69. package/dist/cases/tombstone-sweeper.d.ts +13 -0
  70. package/dist/cases/tombstone-sweeper.js +128 -0
  71. package/dist/cases/types.d.ts +244 -0
  72. package/dist/cases/types.js +47 -0
  73. package/dist/cases/wiki-page-index.d.ts +50 -0
  74. package/dist/cases/wiki-page-index.js +350 -0
  75. package/dist/connectors/event-index.d.ts +45 -0
  76. package/dist/connectors/event-index.js +381 -0
  77. package/dist/connectors/raw-query.d.ts +18 -0
  78. package/dist/connectors/raw-query.js +305 -0
  79. package/dist/connectors/types.d.ts +109 -0
  80. package/dist/connectors/types.js +3 -0
  81. package/dist/db-adapter/node-sqlite-adapter.d.ts +6 -0
  82. package/dist/db-adapter/node-sqlite-adapter.js +131 -0
  83. package/dist/db-manager.d.ts +12 -1
  84. package/dist/db-manager.js +60 -5
  85. package/dist/decision-formatter.d.ts +2 -0
  86. package/dist/decision-formatter.js +11 -8
  87. package/dist/edges/ref-validation.d.ts +8 -0
  88. package/dist/edges/ref-validation.js +262 -0
  89. package/dist/edges/store.d.ts +10 -0
  90. package/dist/edges/store.js +343 -0
  91. package/dist/edges/types.d.ts +86 -0
  92. package/dist/edges/types.js +18 -0
  93. package/dist/embedding-server/mobile/daemon.d.ts +1 -0
  94. package/dist/embedding-server/mobile/daemon.js +11 -1
  95. package/dist/embeddings.js +13 -0
  96. package/dist/entities/audit-metrics.d.ts +73 -0
  97. package/dist/entities/audit-metrics.js +128 -0
  98. package/dist/entities/candidate-generator.d.ts +9 -0
  99. package/dist/entities/candidate-generator.js +436 -0
  100. package/dist/entities/entity-impact.d.ts +41 -0
  101. package/dist/entities/entity-impact.js +140 -0
  102. package/dist/entities/entity-linked-decision-counts.d.ts +2 -0
  103. package/dist/entities/entity-linked-decision-counts.js +29 -0
  104. package/dist/entities/entity-list.d.ts +23 -0
  105. package/dist/entities/entity-list.js +99 -0
  106. package/dist/entities/entity-orphan-list.d.ts +26 -0
  107. package/dist/entities/entity-orphan-list.js +91 -0
  108. package/dist/entities/entity-search.d.ts +21 -0
  109. package/dist/entities/entity-search.js +150 -0
  110. package/dist/entities/errors.d.ts +65 -0
  111. package/dist/entities/errors.js +124 -0
  112. package/dist/entities/exact-merge-backfill.d.ts +11 -0
  113. package/dist/entities/exact-merge-backfill.js +161 -0
  114. package/dist/entities/lineage-backfill.d.ts +12 -0
  115. package/dist/entities/lineage-backfill.js +101 -0
  116. package/dist/entities/lineage-store.d.ts +51 -0
  117. package/dist/entities/lineage-store.js +308 -0
  118. package/dist/entities/normalization.d.ts +14 -0
  119. package/dist/entities/normalization.js +63 -0
  120. package/dist/entities/policy-store.d.ts +17 -0
  121. package/dist/entities/policy-store.js +263 -0
  122. package/dist/entities/policy-types.d.ts +72 -0
  123. package/dist/entities/policy-types.js +59 -0
  124. package/dist/entities/projection.d.ts +8 -0
  125. package/dist/entities/projection.js +82 -0
  126. package/dist/entities/provenance-query.d.ts +33 -0
  127. package/dist/entities/provenance-query.js +167 -0
  128. package/dist/entities/read-identity.d.ts +31 -0
  129. package/dist/entities/read-identity.js +264 -0
  130. package/dist/entities/recall-bridge.d.ts +5 -0
  131. package/dist/entities/recall-bridge.js +171 -0
  132. package/dist/entities/resolution-engine.d.ts +15 -0
  133. package/dist/entities/resolution-engine.js +69 -0
  134. package/dist/entities/rollback-preview.d.ts +39 -0
  135. package/dist/entities/rollback-preview.js +235 -0
  136. package/dist/entities/source-locator.d.ts +3 -0
  137. package/dist/entities/source-locator.js +32 -0
  138. package/dist/entities/store.d.ts +75 -0
  139. package/dist/entities/store.js +465 -0
  140. package/dist/entities/types.d.ts +162 -0
  141. package/dist/entities/types.js +30 -0
  142. package/dist/index.d.ts +62 -3
  143. package/dist/index.js +116 -26
  144. package/dist/mama-api.d.ts +53 -35
  145. package/dist/mama-api.js +437 -78
  146. package/dist/memory/api.d.ts +26 -38
  147. package/dist/memory/api.js +772 -68
  148. package/dist/memory/event-store.d.ts +3 -0
  149. package/dist/memory/event-store.js +21 -2
  150. package/dist/memory/provenance-audit.d.ts +22 -0
  151. package/dist/memory/provenance-audit.js +112 -0
  152. package/dist/memory/provenance-query.d.ts +11 -0
  153. package/dist/memory/provenance-query.js +193 -0
  154. package/dist/memory/provenance.d.ts +29 -0
  155. package/dist/memory/provenance.js +136 -0
  156. package/dist/memory/scope-backfill.d.ts +17 -0
  157. package/dist/memory/scope-backfill.js +77 -0
  158. package/dist/memory/types.d.ts +97 -16
  159. package/dist/model-runs/store.d.ts +13 -0
  160. package/dist/model-runs/store.js +457 -0
  161. package/dist/model-runs/tool-trace-store.d.ts +4 -0
  162. package/dist/model-runs/tool-trace-store.js +114 -0
  163. package/dist/model-runs/types.d.ts +69 -0
  164. package/dist/model-runs/types.js +5 -0
  165. package/dist/runtime/trusted-provenance.d.ts +3 -0
  166. package/dist/runtime/trusted-provenance.js +6 -0
  167. package/dist/search/feedback-store.d.ts +59 -0
  168. package/dist/search/feedback-store.js +211 -0
  169. package/dist/search/question-type.d.ts +5 -0
  170. package/dist/search/question-type.js +41 -0
  171. package/dist/search/ranker-features.d.ts +23 -0
  172. package/dist/search/ranker-features.js +104 -0
  173. package/dist/search/ranker-rescore.d.ts +31 -0
  174. package/dist/search/ranker-rescore.js +226 -0
  175. package/dist/search/ranker-trainer.d.ts +94 -0
  176. package/dist/search/ranker-trainer.js +860 -0
  177. package/dist/search/search-quality.d.ts +36 -0
  178. package/dist/search/search-quality.js +29 -0
  179. package/dist/test-utils.d.ts +14 -0
  180. package/dist/test-utils.js +52 -0
  181. package/package.json +28 -3
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @jungjaehoon/mama-core
2
2
 
3
- Shared core modules for MAMA (Memory-Augmented MCP Assistant).
3
+ Shared memory, provenance, graph, and context substrate for MAMA.
4
4
 
5
5
  ## What is MAMA Core?
6
6
 
@@ -10,7 +10,9 @@ MAMA Core is a shared package containing the fundamental modules used by all MAM
10
10
  - **claude-code-plugin**: Claude Code plugin
11
11
  - **standalone**: Standalone HTTP server
12
12
 
13
- This package provides embedding generation, database management, decision tracking, and other core functionality without the transport layer (MCP/HTTP).
13
+ This package provides embedding generation, database management, scoped memory, provenance, raw
14
+ evidence refs, graph/entity helpers, and worker context primitives without the transport layer
15
+ (MCP/HTTP).
14
16
 
15
17
  ## Installation
16
18
 
@@ -78,7 +80,7 @@ const mamaApi = require('@jungjaehoon/mama-core/mama-api');
78
80
 
79
81
  - **memory/api** - Scoped memory operations
80
82
  - `saveMemory(input)` - Save typed memory with scopes and optional event_date (preference, fact, decision, lesson, constraint)
81
- - `recallMemory(query, options)` - Truth-aware recall with scope filtering
83
+ - `recallMemory(query, options)` - Truth-aware recall with scope filtering, strictness modes, and retrieval diagnostics
82
84
  - `buildProfile(scopes)` - Build memory profile (static/dynamic/evidence)
83
85
  - `ingestMemory(input)` - Ingest raw content as memory
84
86
  - `ingestConversation(input)` - Decompose conversations into typed memory units via optional LLM extraction
@@ -102,14 +104,39 @@ const mamaApi = require('@jungjaehoon/mama-core/mama-api');
102
104
  - **memory/channel-summary-state-store** - Channel state management
103
105
  - `recordChannelAudit(input)` - Accumulate audit outcomes into channel state
104
106
 
107
+ - **memory/provenance** - Trusted memory provenance
108
+ - Preserves compact runtime origin metadata in `provenance_json`
109
+ - Keeps underlying raw/memory/case/entity refs in `source_refs_json`
110
+ - Ignores caller-supplied untrusted provenance on public paths
111
+
112
+ - **model-runs** - Agent execution lineage
113
+ - `model-runs/store` records model run lifecycle and replay metadata
114
+ - `model-runs/tool-trace-store` records tool calls for later audit and reconstruction
115
+
116
+ - **connectors/raw-query** - Unified raw evidence reads
117
+ - Query raw connector rows through scope-aware filters
118
+ - Preserve raw source ids for downstream provenance
119
+
120
+ - **agent-situation** - Worker situation packets
121
+ - Build, rank, cache, insert, and read append-only situation packets for worker context
122
+
123
+ - **agent-graph** - Worker graph/entity helpers
124
+ - Query graph neighborhoods, resolve entities, and write aliases with visibility checks
125
+
105
126
  ### Core API (Legacy)
106
127
 
107
128
  - **mama-api** - High-level API interface (wraps memory API)
108
129
  - `save(decision)` - Save decision
109
130
  - `recall(topic)` - Retrieve decision history
110
- - `suggest(query)` - Semantic search with hybrid FTS5 + vector + recency
131
+ - `suggest(query, options)` - Semantic search with hybrid FTS5 + vector + recency, strictness controls, and diagnostics
111
132
  - `updateOutcome(id, outcome)` - Update decision outcome
112
133
 
134
+ - **search/search-quality** - Search option normalization
135
+ - `normalizeSearchQualityOptions(options)` - Normalize recall/balanced/strict thresholds and confirmation requirements
136
+
137
+ - **edges** - Twin edge ledger
138
+ - Validate refs and store durable edges between memory, raw, entity, case, and packet refs
139
+
113
140
  - **decision-tracker** - Decision graph management
114
141
  - `learnDecision(decision)` - Learn from decision
115
142
  - `createEdgesFromReasoning(reasoning)` - Parse decision links
@@ -135,7 +162,7 @@ const mamaApi = require('@jungjaehoon/mama-core/mama-api');
135
162
  ## Dependencies
136
163
 
137
164
  - **@huggingface/transformers** - Local embedding generation
138
- - **node:sqlite** - Built-in SQLite runtime (Node.js 22+)
165
+ - **better-sqlite3** - SQLite runtime with FTS5 support
139
166
  - **Pure-TS cosine similarity** - Vector search (no native extensions)
140
167
 
141
168
  ## Development
@@ -153,7 +180,7 @@ pnpm test:watch
153
180
 
154
181
  ## Test Coverage
155
182
 
156
- - 72 unit tests across 17 test files
183
+ - 120+ unit/integration test files in `packages/mama-core/tests`
157
184
  - 100% passing
158
185
  - Tests cover:
159
186
  - Config loader, database initialization, module exports
@@ -161,6 +188,9 @@ pnpm test:watch
161
188
  - Truth store, evolution engine, scope schema
162
189
  - Channel summary, channel summary state
163
190
  - Event store, finding store, bootstrap builder
191
+ - Memory provenance, model runs, tool traces
192
+ - Twin edges, raw query, agent situation, agent graph
193
+ - Strict search diagnostics and rollup provenance
164
194
  - Legacy shim compatibility
165
195
 
166
196
  ## Architecture
@@ -175,7 +205,7 @@ packages/mama-core/
175
205
  │ ├── db-manager.ts # Database management
176
206
  │ ├── mama-api.ts # High-level API (wraps memory API)
177
207
  │ ├── db-adapter/ # Database adapter (SQLite)
178
- │ └── memory/ # Memory infrastructure
208
+ │ ├── memory/ # Memory infrastructure
179
209
  │ ├── types.ts # MemoryRecord, MemoryScopeRef, RecallBundle, etc.
180
210
  │ ├── api.ts # saveMemory, recallMemory, buildProfile, etc.
181
211
  │ ├── truth-store.ts # Truth projection layer
@@ -188,13 +218,19 @@ packages/mama-core/
188
218
  │ ├── channel-summary-state-store.ts # Channel state reducer
189
219
  │ ├── bootstrap-builder.ts # Memory agent bootstrap
190
220
  │ └── profile-builder.ts # Profile classification
191
- ├── db/migrations/ # SQLite migrations (001-023)
192
- └── tests/ # 16 test files, 59 tests
221
+ │ ├── model-runs/ # Model run + tool trace lineage
222
+ │ ├── connectors/ # Raw connector query/index helpers
223
+ │ ├── edges/ # Twin edge ledger
224
+ │ ├── agent-situation/ # Worker situation packets
225
+ │ ├── agent-graph/ # Worker graph/entity helpers
226
+ │ └── search/ # Search quality option normalization
227
+ ├── db/migrations/ # SQLite migrations (001-036)
228
+ └── tests/ # Unit and integration tests
193
229
  ```
194
230
 
195
231
  ## Migration Files
196
232
 
197
- Database migrations are included in `db/migrations/` (001-023):
233
+ Database migrations are included in `db/migrations/` (001-036):
198
234
 
199
235
  - 001-013: Core schema (decisions, embeddings, graph edges)
200
236
  - 014: Add is_static column
@@ -204,6 +240,8 @@ Database migrations are included in `db/migrations/` (001-023):
204
240
  - 019-020: Memory events and audit findings
205
241
  - 021: Memory truth projection
206
242
  - 022-023: Channel summaries and state
243
+ - 024-036: event dates, connector memory kinds, canonical entities, case-first memory, wiki/index
244
+ provenance, model/tool traces, twin edges, and agent situation packets
207
245
 
208
246
  ## License
209
247
 
@@ -0,0 +1,99 @@
1
+ CREATE TABLE IF NOT EXISTS entity_nodes (
2
+ id TEXT PRIMARY KEY,
3
+ kind TEXT NOT NULL CHECK (kind IN ('project', 'person', 'organization', 'work_item')),
4
+ preferred_label TEXT NOT NULL,
5
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'merged', 'archived')),
6
+ scope_kind TEXT CHECK (scope_kind IN ('project', 'channel', 'user', 'global')),
7
+ scope_id TEXT,
8
+ merged_into TEXT,
9
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
10
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
11
+ FOREIGN KEY (merged_into) REFERENCES entity_nodes(id),
12
+ CHECK ((scope_kind = 'global' AND scope_id IS NULL) OR (scope_kind != 'global'))
13
+ );
14
+
15
+ CREATE TABLE IF NOT EXISTS entity_aliases (
16
+ id TEXT PRIMARY KEY,
17
+ entity_id TEXT NOT NULL,
18
+ label TEXT NOT NULL,
19
+ normalized_label TEXT NOT NULL,
20
+ lang TEXT,
21
+ script TEXT,
22
+ label_type TEXT NOT NULL CHECK (label_type IN ('pref', 'alt', 'hidden', 'source_native')),
23
+ source_type TEXT NOT NULL,
24
+ source_ref TEXT,
25
+ confidence REAL,
26
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'suppressed')),
27
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
28
+ FOREIGN KEY (entity_id) REFERENCES entity_nodes(id) ON DELETE CASCADE
29
+ );
30
+
31
+ CREATE TABLE IF NOT EXISTS entity_observations (
32
+ id TEXT PRIMARY KEY,
33
+ entity_kind_hint TEXT CHECK (entity_kind_hint IN ('project', 'person', 'organization', 'work_item')),
34
+ surface_form TEXT NOT NULL,
35
+ normalized_form TEXT NOT NULL,
36
+ lang TEXT,
37
+ script TEXT,
38
+ context_summary TEXT,
39
+ related_surface_forms TEXT NOT NULL DEFAULT '[]',
40
+ timestamp_observed INTEGER,
41
+ scope_kind TEXT CHECK (scope_kind IN ('project', 'channel', 'user', 'global')),
42
+ scope_id TEXT,
43
+ extractor_version TEXT NOT NULL,
44
+ embedding_model_version TEXT,
45
+ source_connector TEXT NOT NULL,
46
+ source_raw_db_ref TEXT,
47
+ source_raw_record_id TEXT NOT NULL,
48
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
49
+ CHECK ((scope_kind = 'global' AND scope_id IS NULL) OR (scope_kind != 'global'))
50
+ );
51
+
52
+ CREATE TABLE IF NOT EXISTS entity_links (
53
+ id TEXT PRIMARY KEY,
54
+ from_entity_id TEXT NOT NULL,
55
+ to_entity_id TEXT NOT NULL,
56
+ relation_type TEXT NOT NULL,
57
+ confidence REAL NOT NULL DEFAULT 0.5,
58
+ source_basis TEXT NOT NULL,
59
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
60
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
61
+ FOREIGN KEY (from_entity_id) REFERENCES entity_nodes(id) ON DELETE CASCADE,
62
+ FOREIGN KEY (to_entity_id) REFERENCES entity_nodes(id) ON DELETE CASCADE
63
+ );
64
+
65
+ CREATE TABLE IF NOT EXISTS entity_timeline_events (
66
+ id TEXT PRIMARY KEY,
67
+ entity_id TEXT NOT NULL,
68
+ event_type TEXT NOT NULL,
69
+ valid_from INTEGER,
70
+ valid_to INTEGER,
71
+ observed_at INTEGER,
72
+ source_ref TEXT,
73
+ summary TEXT NOT NULL,
74
+ details TEXT,
75
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
76
+ FOREIGN KEY (entity_id) REFERENCES entity_nodes(id) ON DELETE CASCADE
77
+ );
78
+
79
+ CREATE INDEX IF NOT EXISTS idx_entity_nodes_kind ON entity_nodes(kind);
80
+ CREATE INDEX IF NOT EXISTS idx_entity_nodes_preferred_label ON entity_nodes(preferred_label);
81
+ CREATE INDEX IF NOT EXISTS idx_entity_nodes_scope ON entity_nodes(scope_kind, scope_id);
82
+
83
+ CREATE INDEX IF NOT EXISTS idx_entity_aliases_entity_id ON entity_aliases(entity_id);
84
+ CREATE INDEX IF NOT EXISTS idx_entity_aliases_normalized_label ON entity_aliases(normalized_label);
85
+
86
+ CREATE INDEX IF NOT EXISTS idx_entity_observations_normalized_label ON entity_observations(normalized_form);
87
+ CREATE INDEX IF NOT EXISTS idx_entity_observations_observed_at ON entity_observations(timestamp_observed);
88
+ CREATE INDEX IF NOT EXISTS idx_entity_observations_scope ON entity_observations(scope_kind, scope_id);
89
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_entity_observations_source_record
90
+ ON entity_observations(source_connector, source_raw_record_id);
91
+
92
+ CREATE INDEX IF NOT EXISTS idx_entity_links_from ON entity_links(from_entity_id);
93
+ CREATE INDEX IF NOT EXISTS idx_entity_links_to ON entity_links(to_entity_id);
94
+
95
+ CREATE INDEX IF NOT EXISTS idx_entity_timeline_events_entity_id ON entity_timeline_events(entity_id);
96
+ CREATE INDEX IF NOT EXISTS idx_entity_timeline_events_observed_at ON entity_timeline_events(observed_at);
97
+
98
+ INSERT OR IGNORE INTO schema_version (version, description)
99
+ VALUES (26, 'Create canonical entity core tables');
@@ -0,0 +1,44 @@
1
+ CREATE TABLE IF NOT EXISTS entity_resolution_candidates (
2
+ id TEXT PRIMARY KEY,
3
+ candidate_kind TEXT NOT NULL CHECK (candidate_kind IN ('alias_to_entity', 'entity_to_entity', 'cluster')),
4
+ left_ref TEXT NOT NULL,
5
+ right_ref TEXT NOT NULL,
6
+ status TEXT NOT NULL CHECK (status IN ('pending', 'auto_merged', 'approved', 'rejected', 'deferred')),
7
+ score_total REAL NOT NULL DEFAULT 0,
8
+ score_structural REAL NOT NULL DEFAULT 0,
9
+ score_string REAL NOT NULL DEFAULT 0,
10
+ score_context REAL NOT NULL DEFAULT 0,
11
+ score_graph REAL NOT NULL DEFAULT 0,
12
+ score_embedding REAL NOT NULL DEFAULT 0,
13
+ rule_trace TEXT,
14
+ extractor_version TEXT NOT NULL,
15
+ embedding_model_version TEXT,
16
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
17
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
18
+ );
19
+
20
+ CREATE TABLE IF NOT EXISTS entity_merge_actions (
21
+ id TEXT PRIMARY KEY,
22
+ action_type TEXT NOT NULL CHECK (action_type IN ('merge', 'reject', 'defer', 'split')),
23
+ source_entity_id TEXT,
24
+ target_entity_id TEXT,
25
+ candidate_id TEXT,
26
+ actor_type TEXT NOT NULL CHECK (actor_type IN ('system', 'user', 'agent')),
27
+ actor_id TEXT,
28
+ reason TEXT NOT NULL,
29
+ evidence_json TEXT NOT NULL,
30
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
31
+ FOREIGN KEY (source_entity_id) REFERENCES entity_nodes(id) ON DELETE SET NULL,
32
+ FOREIGN KEY (target_entity_id) REFERENCES entity_nodes(id) ON DELETE SET NULL,
33
+ FOREIGN KEY (candidate_id) REFERENCES entity_resolution_candidates(id) ON DELETE SET NULL
34
+ );
35
+
36
+ CREATE INDEX IF NOT EXISTS idx_entity_candidates_status_score
37
+ ON entity_resolution_candidates(status, score_total DESC, created_at DESC);
38
+ CREATE INDEX IF NOT EXISTS idx_entity_merge_actions_candidate_id
39
+ ON entity_merge_actions(candidate_id);
40
+ CREATE INDEX IF NOT EXISTS idx_entity_merge_actions_source_target
41
+ ON entity_merge_actions(source_entity_id, target_entity_id);
42
+
43
+ INSERT OR IGNORE INTO schema_version (version, description)
44
+ VALUES (27, 'Create canonical entity review support tables');
@@ -0,0 +1,45 @@
1
+ CREATE TABLE IF NOT EXISTS entity_audit_runs (
2
+ id TEXT PRIMARY KEY,
3
+ status TEXT NOT NULL CHECK (status IN ('running', 'complete', 'failed', 'timeout')),
4
+ baseline_run_id TEXT,
5
+ classification TEXT CHECK (classification IN ('improved', 'stable', 'regressed', 'inconclusive')),
6
+ metric_summary_json TEXT,
7
+ reason TEXT,
8
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
9
+ completed_at INTEGER,
10
+ FOREIGN KEY (baseline_run_id) REFERENCES entity_audit_runs(id) ON DELETE SET NULL
11
+ );
12
+
13
+ CREATE UNIQUE INDEX IF NOT EXISTS entity_audit_runs_single_running
14
+ ON entity_audit_runs(status)
15
+ WHERE status = 'running';
16
+
17
+ CREATE INDEX IF NOT EXISTS idx_entity_audit_runs_created_at
18
+ ON entity_audit_runs(created_at DESC);
19
+
20
+ CREATE TABLE IF NOT EXISTS entity_audit_metrics (
21
+ run_id TEXT NOT NULL,
22
+ metric_name TEXT NOT NULL,
23
+ metric_value REAL NOT NULL,
24
+ metric_meta_json TEXT,
25
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
26
+ PRIMARY KEY (run_id, metric_name),
27
+ FOREIGN KEY (run_id) REFERENCES entity_audit_runs(id) ON DELETE CASCADE
28
+ );
29
+
30
+ CREATE TABLE IF NOT EXISTS entity_audit_findings (
31
+ id TEXT PRIMARY KEY,
32
+ run_id TEXT NOT NULL,
33
+ finding_kind TEXT NOT NULL,
34
+ severity TEXT NOT NULL CHECK (severity IN ('info', 'warn', 'critical')),
35
+ summary TEXT NOT NULL,
36
+ details_json TEXT,
37
+ created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
38
+ FOREIGN KEY (run_id) REFERENCES entity_audit_runs(id) ON DELETE CASCADE
39
+ );
40
+
41
+ CREATE INDEX IF NOT EXISTS idx_entity_audit_findings_run_id
42
+ ON entity_audit_findings(run_id);
43
+
44
+ INSERT OR IGNORE INTO schema_version (version, description)
45
+ VALUES (28, 'Create entity benchmark and audit run storage');
@@ -0,0 +1,60 @@
1
+ ALTER TABLE entity_observations
2
+ ADD COLUMN observation_type TEXT NOT NULL DEFAULT 'generic'
3
+ CHECK (observation_type IN ('generic', 'author', 'channel'));
4
+
5
+ UPDATE entity_observations
6
+ SET source_raw_db_ref = ''
7
+ WHERE source_raw_db_ref IS NULL;
8
+
9
+ DROP INDEX IF EXISTS idx_entity_observations_source_record;
10
+
11
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_entity_observations_source_record
12
+ ON entity_observations(
13
+ source_connector,
14
+ source_raw_db_ref,
15
+ source_raw_record_id,
16
+ observation_type
17
+ );
18
+
19
+ CREATE TRIGGER IF NOT EXISTS trg_entity_nodes_scope_guard_insert
20
+ BEFORE INSERT ON entity_nodes
21
+ WHEN (
22
+ (NEW.scope_kind = 'global' AND NEW.scope_id IS NOT NULL)
23
+ OR (NEW.scope_kind IS NOT NULL AND NEW.scope_kind != 'global' AND NEW.scope_id IS NULL)
24
+ )
25
+ BEGIN
26
+ SELECT RAISE(ABORT, 'entity_nodes scope_id invalid for scope_kind');
27
+ END;
28
+
29
+ CREATE TRIGGER IF NOT EXISTS trg_entity_nodes_scope_guard_update
30
+ BEFORE UPDATE ON entity_nodes
31
+ WHEN (
32
+ (NEW.scope_kind = 'global' AND NEW.scope_id IS NOT NULL)
33
+ OR (NEW.scope_kind IS NOT NULL AND NEW.scope_kind != 'global' AND NEW.scope_id IS NULL)
34
+ )
35
+ BEGIN
36
+ SELECT RAISE(ABORT, 'entity_nodes scope_id invalid for scope_kind');
37
+ END;
38
+
39
+ CREATE TRIGGER IF NOT EXISTS trg_entity_observations_scope_guard_insert
40
+ BEFORE INSERT ON entity_observations
41
+ WHEN (
42
+ (NEW.scope_kind = 'global' AND NEW.scope_id IS NOT NULL)
43
+ OR (NEW.scope_kind IS NOT NULL AND NEW.scope_kind != 'global' AND NEW.scope_id IS NULL)
44
+ )
45
+ BEGIN
46
+ SELECT RAISE(ABORT, 'entity_observations scope_id invalid for scope_kind');
47
+ END;
48
+
49
+ CREATE TRIGGER IF NOT EXISTS trg_entity_observations_scope_guard_update
50
+ BEFORE UPDATE ON entity_observations
51
+ WHEN (
52
+ (NEW.scope_kind = 'global' AND NEW.scope_id IS NOT NULL)
53
+ OR (NEW.scope_kind IS NOT NULL AND NEW.scope_kind != 'global' AND NEW.scope_id IS NULL)
54
+ )
55
+ BEGIN
56
+ SELECT RAISE(ABORT, 'entity_observations scope_id invalid for scope_kind');
57
+ END;
58
+
59
+ INSERT OR IGNORE INTO schema_version (version, description)
60
+ VALUES (29, 'Extend entity observations with observation type and scope guards');