@shadowforge0/aquifer-memory 1.6.0 → 1.8.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 (44) hide show
  1. package/.env.example +8 -0
  2. package/README.md +72 -0
  3. package/README_CN.md +17 -0
  4. package/README_TW.md +4 -0
  5. package/aquifer.config.example.json +19 -0
  6. package/consumers/cli.js +259 -12
  7. package/consumers/codex-active-checkpoint.js +186 -0
  8. package/consumers/codex-current-memory.js +106 -0
  9. package/consumers/codex-handoff.js +551 -6
  10. package/consumers/codex.js +209 -25
  11. package/consumers/mcp.js +144 -6
  12. package/consumers/shared/config.js +60 -1
  13. package/consumers/shared/factory.js +10 -3
  14. package/core/aquifer.js +357 -838
  15. package/core/backends/capabilities.js +89 -0
  16. package/core/backends/local.js +430 -0
  17. package/core/legacy-bootstrap.js +140 -0
  18. package/core/mcp-manifest.js +66 -2
  19. package/core/memory-bootstrap.js +20 -8
  20. package/core/memory-consolidation.js +365 -11
  21. package/core/memory-promotion.js +157 -26
  22. package/core/memory-recall.js +341 -22
  23. package/core/memory-records.js +347 -11
  24. package/core/memory-serving.js +132 -0
  25. package/core/postgres-migrations.js +533 -0
  26. package/core/public-session-filter.js +40 -0
  27. package/core/recall-runtime.js +115 -0
  28. package/core/scope-attribution.js +279 -0
  29. package/core/session-checkpoint-producer.js +412 -0
  30. package/core/session-checkpoints.js +432 -0
  31. package/core/session-finalization.js +98 -2
  32. package/core/storage-checkpoints.js +546 -0
  33. package/core/storage.js +121 -8
  34. package/docs/getting-started.md +6 -0
  35. package/docs/setup.md +66 -3
  36. package/package.json +8 -4
  37. package/schema/014-v1-checkpoint-runs.sql +349 -0
  38. package/schema/015-v1-evidence-items.sql +92 -0
  39. package/schema/016-v1-evidence-ref-multi-item.sql +19 -0
  40. package/schema/017-v1-memory-record-embeddings.sql +25 -0
  41. package/schema/018-v1-finalization-candidate-envelope.sql +39 -0
  42. package/scripts/codex-checkpoint-commands.js +464 -0
  43. package/scripts/codex-checkpoint-runtime.js +520 -0
  44. package/scripts/codex-recovery.js +246 -1
@@ -0,0 +1,349 @@
1
+ -- Aquifer v1 rolling checkpoint ledger
2
+ -- Requires: 007-v1-foundation.sql, 008-session-finalizations.sql, and 010-v1-finalization-review.sql
3
+ -- Usage: replace ${schema} with actual schema name
4
+ --
5
+ -- Adds additive checkpoint-run audit tables plus scope FK/snapshot support on
6
+ -- session_finalizations. This does not change serving truth or promotion.
7
+
8
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_scopes_tenant_row
9
+ ON ${schema}.scopes (tenant_id, id);
10
+
11
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_session_finalizations_tenant_row
12
+ ON ${schema}.session_finalizations (tenant_id, id);
13
+
14
+ ALTER TABLE ${schema}.scopes
15
+ DROP CONSTRAINT IF EXISTS scopes_scope_kind_check;
16
+
17
+ ALTER TABLE ${schema}.scopes
18
+ ADD CONSTRAINT scopes_scope_kind_check
19
+ CHECK (scope_kind IN (
20
+ 'global','user','workspace','project','event','session',
21
+ 'host_runtime','assistant_instance','repo','task'
22
+ ));
23
+
24
+ ALTER TABLE ${schema}.session_finalizations
25
+ ADD COLUMN IF NOT EXISTS scope_id BIGINT,
26
+ ADD COLUMN IF NOT EXISTS scope_snapshot JSONB NOT NULL DEFAULT '{}'::jsonb;
27
+
28
+ DO $$
29
+ BEGIN
30
+ IF NOT EXISTS (
31
+ SELECT 1
32
+ FROM pg_constraint
33
+ WHERE conrelid = '${schema}.session_finalizations'::regclass
34
+ AND conname = 'session_finalizations_scope_snapshot_object_check'
35
+ ) THEN
36
+ ALTER TABLE ${schema}.session_finalizations
37
+ ADD CONSTRAINT session_finalizations_scope_snapshot_object_check
38
+ CHECK (jsonb_typeof(scope_snapshot) = 'object');
39
+ END IF;
40
+ END;
41
+ $$;
42
+
43
+ UPDATE ${schema}.session_finalizations sf
44
+ SET scope_id = s.id
45
+ FROM ${schema}.scopes s
46
+ WHERE sf.scope_id IS NULL
47
+ AND sf.scope_kind IS NOT NULL
48
+ AND sf.scope_key IS NOT NULL
49
+ AND s.tenant_id = sf.tenant_id
50
+ AND s.scope_kind = sf.scope_kind
51
+ AND s.scope_key = sf.scope_key;
52
+
53
+ UPDATE ${schema}.session_finalizations sf
54
+ SET scope_snapshot = jsonb_strip_nulls(
55
+ jsonb_build_object(
56
+ 'scopeId', COALESCE(sf.scope_id, s.id),
57
+ 'scopeKind', COALESCE(sf.scope_kind, s.scope_kind),
58
+ 'scopeKey', COALESCE(sf.scope_key, s.scope_key),
59
+ 'contextKey', COALESCE(sf.context_key, s.context_key),
60
+ 'topicKey', COALESCE(sf.topic_key, s.topic_key),
61
+ 'parentScopeId', s.parent_scope_id,
62
+ 'inheritanceMode', s.inheritance_mode,
63
+ 'activeFrom', s.active_from,
64
+ 'activeTo', s.active_to
65
+ )
66
+ )
67
+ FROM ${schema}.scopes s
68
+ WHERE sf.scope_id = s.id
69
+ AND sf.tenant_id = s.tenant_id
70
+ AND sf.scope_snapshot = '{}'::jsonb;
71
+
72
+ UPDATE ${schema}.session_finalizations
73
+ SET scope_snapshot = jsonb_strip_nulls(
74
+ jsonb_build_object(
75
+ 'scopeId', scope_id,
76
+ 'scopeKind', scope_kind,
77
+ 'scopeKey', scope_key,
78
+ 'contextKey', context_key,
79
+ 'topicKey', topic_key
80
+ )
81
+ )
82
+ WHERE scope_snapshot = '{}'::jsonb
83
+ AND (
84
+ scope_id IS NOT NULL
85
+ OR scope_kind IS NOT NULL
86
+ OR scope_key IS NOT NULL
87
+ OR context_key IS NOT NULL
88
+ OR topic_key IS NOT NULL
89
+ );
90
+
91
+ DO $$
92
+ BEGIN
93
+ IF NOT EXISTS (
94
+ SELECT 1
95
+ FROM pg_constraint
96
+ WHERE conrelid = '${schema}.session_finalizations'::regclass
97
+ AND conname = 'session_finalizations_scope_fk'
98
+ ) THEN
99
+ ALTER TABLE ${schema}.session_finalizations
100
+ ADD CONSTRAINT session_finalizations_scope_fk
101
+ FOREIGN KEY (tenant_id, scope_id)
102
+ REFERENCES ${schema}.scopes (tenant_id, id)
103
+ ON DELETE RESTRICT
104
+ NOT VALID;
105
+ END IF;
106
+ END;
107
+ $$;
108
+
109
+ CREATE INDEX IF NOT EXISTS idx_session_finalizations_scope
110
+ ON ${schema}.session_finalizations (tenant_id, scope_id, finalized_at DESC, updated_at DESC)
111
+ WHERE scope_id IS NOT NULL;
112
+
113
+ COMMENT ON COLUMN ${schema}.session_finalizations.scope_id IS
114
+ 'Resolved v1 scope row for this finalization when the producer knows it.';
115
+
116
+ COMMENT ON COLUMN ${schema}.session_finalizations.scope_snapshot IS
117
+ 'Compact scope audit snapshot captured at finalization time; serving still reads live curated memory.';
118
+
119
+ CREATE TABLE IF NOT EXISTS ${schema}.checkpoint_runs (
120
+ id BIGSERIAL PRIMARY KEY,
121
+ tenant_id TEXT NOT NULL DEFAULT 'default',
122
+ scope_id BIGINT NOT NULL,
123
+ checkpoint_key TEXT NOT NULL CHECK (btrim(checkpoint_key) <> ''),
124
+ from_finalization_id_exclusive BIGINT NOT NULL DEFAULT 0 CHECK (from_finalization_id_exclusive >= 0),
125
+ to_finalization_id_inclusive BIGINT,
126
+ status TEXT NOT NULL DEFAULT 'pending'
127
+ CHECK (status IN (
128
+ 'pending','processing','finalized','failed','skipped'
129
+ )),
130
+ window_start TIMESTAMPTZ,
131
+ window_end TIMESTAMPTZ,
132
+ scope_snapshot JSONB NOT NULL DEFAULT '{}'::jsonb,
133
+ checkpoint_text TEXT,
134
+ checkpoint_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
135
+ error TEXT,
136
+ metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
137
+ claimed_at TIMESTAMPTZ,
138
+ finalized_at TIMESTAMPTZ,
139
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
140
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
141
+ CHECK (jsonb_typeof(scope_snapshot) = 'object'),
142
+ CHECK (jsonb_typeof(checkpoint_payload) = 'object'),
143
+ CHECK (jsonb_typeof(metadata) = 'object'),
144
+ CHECK (
145
+ to_finalization_id_inclusive IS NULL
146
+ OR to_finalization_id_inclusive > from_finalization_id_exclusive
147
+ ),
148
+ CHECK (
149
+ (window_start IS NULL AND window_end IS NULL)
150
+ OR (
151
+ window_start IS NOT NULL
152
+ AND window_end IS NOT NULL
153
+ AND window_end > window_start
154
+ )
155
+ )
156
+ );
157
+
158
+ ALTER TABLE ${schema}.checkpoint_runs
159
+ ADD COLUMN IF NOT EXISTS from_finalization_id_exclusive BIGINT,
160
+ ADD COLUMN IF NOT EXISTS to_finalization_id_inclusive BIGINT;
161
+
162
+ UPDATE ${schema}.checkpoint_runs
163
+ SET from_finalization_id_exclusive = COALESCE(
164
+ from_finalization_id_exclusive,
165
+ substring(checkpoint_key FROM 'finalization:([0-9]+)-')::bigint,
166
+ 0
167
+ ),
168
+ to_finalization_id_inclusive = COALESCE(
169
+ to_finalization_id_inclusive,
170
+ substring(checkpoint_key FROM '-([0-9]+)$')::bigint
171
+ )
172
+ WHERE from_finalization_id_exclusive IS NULL
173
+ OR to_finalization_id_inclusive IS NULL;
174
+
175
+ ALTER TABLE ${schema}.checkpoint_runs
176
+ ALTER COLUMN from_finalization_id_exclusive SET DEFAULT 0;
177
+
178
+ ALTER TABLE ${schema}.checkpoint_runs
179
+ ALTER COLUMN from_finalization_id_exclusive SET NOT NULL;
180
+
181
+ DO $$
182
+ BEGIN
183
+ IF NOT EXISTS (
184
+ SELECT 1
185
+ FROM pg_constraint
186
+ WHERE conrelid = '${schema}.checkpoint_runs'::regclass
187
+ AND conname = 'checkpoint_runs_from_finalization_nonnegative_check'
188
+ ) THEN
189
+ ALTER TABLE ${schema}.checkpoint_runs
190
+ ADD CONSTRAINT checkpoint_runs_from_finalization_nonnegative_check
191
+ CHECK (from_finalization_id_exclusive >= 0)
192
+ NOT VALID;
193
+ END IF;
194
+ END;
195
+ $$;
196
+
197
+ DO $$
198
+ BEGIN
199
+ IF NOT EXISTS (
200
+ SELECT 1
201
+ FROM pg_constraint
202
+ WHERE conrelid = '${schema}.checkpoint_runs'::regclass
203
+ AND conname = 'checkpoint_runs_finalization_range_order_check'
204
+ ) THEN
205
+ ALTER TABLE ${schema}.checkpoint_runs
206
+ ADD CONSTRAINT checkpoint_runs_finalization_range_order_check
207
+ CHECK (
208
+ to_finalization_id_inclusive IS NULL
209
+ OR to_finalization_id_inclusive > from_finalization_id_exclusive
210
+ )
211
+ NOT VALID;
212
+ END IF;
213
+ END;
214
+ $$;
215
+
216
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_checkpoint_runs_identity
217
+ ON ${schema}.checkpoint_runs (tenant_id, scope_id, checkpoint_key);
218
+
219
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_checkpoint_runs_scope_range
220
+ ON ${schema}.checkpoint_runs (
221
+ tenant_id, scope_id, from_finalization_id_exclusive, to_finalization_id_inclusive
222
+ )
223
+ WHERE to_finalization_id_inclusive IS NOT NULL;
224
+
225
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_checkpoint_runs_tenant_row
226
+ ON ${schema}.checkpoint_runs (tenant_id, id);
227
+
228
+ CREATE INDEX IF NOT EXISTS idx_checkpoint_runs_status
229
+ ON ${schema}.checkpoint_runs (tenant_id, status, updated_at DESC, id DESC);
230
+
231
+ CREATE INDEX IF NOT EXISTS idx_checkpoint_runs_scope_window
232
+ ON ${schema}.checkpoint_runs (tenant_id, scope_id, window_end DESC, updated_at DESC, id DESC);
233
+
234
+ CREATE INDEX IF NOT EXISTS idx_checkpoint_runs_scope_finalization_range
235
+ ON ${schema}.checkpoint_runs (
236
+ tenant_id, scope_id, from_finalization_id_exclusive, to_finalization_id_inclusive, status
237
+ )
238
+ WHERE to_finalization_id_inclusive IS NOT NULL;
239
+
240
+ DO $$
241
+ BEGIN
242
+ IF NOT EXISTS (
243
+ SELECT 1
244
+ FROM pg_constraint
245
+ WHERE conrelid = '${schema}.checkpoint_runs'::regclass
246
+ AND conname = 'checkpoint_runs_scope_fk'
247
+ ) THEN
248
+ ALTER TABLE ${schema}.checkpoint_runs
249
+ ADD CONSTRAINT checkpoint_runs_scope_fk
250
+ FOREIGN KEY (tenant_id, scope_id)
251
+ REFERENCES ${schema}.scopes (tenant_id, id)
252
+ ON DELETE RESTRICT
253
+ NOT VALID;
254
+ END IF;
255
+ END;
256
+ $$;
257
+
258
+ COMMENT ON TABLE ${schema}.checkpoint_runs IS
259
+ 'Rolling checkpoint audit ledger. Runs summarize scope-bounded source finalizations without changing serving truth.';
260
+
261
+ CREATE TABLE IF NOT EXISTS ${schema}.checkpoint_run_sources (
262
+ id BIGSERIAL PRIMARY KEY,
263
+ tenant_id TEXT NOT NULL DEFAULT 'default',
264
+ checkpoint_run_id BIGINT NOT NULL,
265
+ finalization_id BIGINT NOT NULL,
266
+ source_index INTEGER NOT NULL CHECK (source_index >= 0),
267
+ scope_id BIGINT,
268
+ scope_snapshot JSONB NOT NULL DEFAULT '{}'::jsonb,
269
+ session_row_id BIGINT,
270
+ session_id TEXT,
271
+ transcript_hash TEXT,
272
+ summary_row_id BIGINT,
273
+ finalized_at TIMESTAMPTZ,
274
+ metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
275
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
276
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
277
+ CHECK (jsonb_typeof(scope_snapshot) = 'object'),
278
+ CHECK (jsonb_typeof(metadata) = 'object')
279
+ );
280
+
281
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_checkpoint_run_sources_position
282
+ ON ${schema}.checkpoint_run_sources (tenant_id, checkpoint_run_id, source_index);
283
+
284
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_checkpoint_run_sources_finalization
285
+ ON ${schema}.checkpoint_run_sources (tenant_id, checkpoint_run_id, finalization_id);
286
+
287
+ CREATE INDEX IF NOT EXISTS idx_checkpoint_run_sources_scope
288
+ ON ${schema}.checkpoint_run_sources (tenant_id, scope_id, finalized_at DESC, id DESC)
289
+ WHERE scope_id IS NOT NULL;
290
+
291
+ CREATE INDEX IF NOT EXISTS idx_checkpoint_run_sources_lookup
292
+ ON ${schema}.checkpoint_run_sources (tenant_id, finalization_id, created_at DESC);
293
+
294
+ DO $$
295
+ BEGIN
296
+ IF NOT EXISTS (
297
+ SELECT 1
298
+ FROM pg_constraint
299
+ WHERE conrelid = '${schema}.checkpoint_run_sources'::regclass
300
+ AND conname = 'checkpoint_run_sources_run_fk'
301
+ ) THEN
302
+ ALTER TABLE ${schema}.checkpoint_run_sources
303
+ ADD CONSTRAINT checkpoint_run_sources_run_fk
304
+ FOREIGN KEY (tenant_id, checkpoint_run_id)
305
+ REFERENCES ${schema}.checkpoint_runs (tenant_id, id)
306
+ ON DELETE CASCADE
307
+ NOT VALID;
308
+ END IF;
309
+ END;
310
+ $$;
311
+
312
+ DO $$
313
+ BEGIN
314
+ IF NOT EXISTS (
315
+ SELECT 1
316
+ FROM pg_constraint
317
+ WHERE conrelid = '${schema}.checkpoint_run_sources'::regclass
318
+ AND conname = 'checkpoint_run_sources_finalization_fk'
319
+ ) THEN
320
+ ALTER TABLE ${schema}.checkpoint_run_sources
321
+ ADD CONSTRAINT checkpoint_run_sources_finalization_fk
322
+ FOREIGN KEY (tenant_id, finalization_id)
323
+ REFERENCES ${schema}.session_finalizations (tenant_id, id)
324
+ ON DELETE CASCADE
325
+ NOT VALID;
326
+ END IF;
327
+ END;
328
+ $$;
329
+
330
+ DO $$
331
+ BEGIN
332
+ IF NOT EXISTS (
333
+ SELECT 1
334
+ FROM pg_constraint
335
+ WHERE conrelid = '${schema}.checkpoint_run_sources'::regclass
336
+ AND conname = 'checkpoint_run_sources_scope_fk'
337
+ ) THEN
338
+ ALTER TABLE ${schema}.checkpoint_run_sources
339
+ ADD CONSTRAINT checkpoint_run_sources_scope_fk
340
+ FOREIGN KEY (tenant_id, scope_id)
341
+ REFERENCES ${schema}.scopes (tenant_id, id)
342
+ ON DELETE RESTRICT
343
+ NOT VALID;
344
+ END IF;
345
+ END;
346
+ $$;
347
+
348
+ COMMENT ON TABLE ${schema}.checkpoint_run_sources IS
349
+ 'Per-checkpoint source lineage. Each row captures the finalization input used to build a rolling checkpoint.';
@@ -0,0 +1,92 @@
1
+ -- Aquifer v1 retrieval-grade evidence items
2
+ -- Requires: 001-base.sql, 007-v1-foundation.sql, 008-session-finalizations.sql
3
+ -- Usage: replace ${schema} with actual schema name
4
+
5
+ CREATE TABLE IF NOT EXISTS ${schema}.evidence_items (
6
+ id BIGSERIAL PRIMARY KEY,
7
+ tenant_id TEXT NOT NULL DEFAULT 'default',
8
+ source_kind TEXT NOT NULL
9
+ CHECK (source_kind IN (
10
+ 'session','session_summary','turn_embedding','insight',
11
+ 'entity_state','evidence_item','raw_event','external'
12
+ )),
13
+ source_ref TEXT NOT NULL CHECK (btrim(source_ref) <> ''),
14
+ session_row_id BIGINT REFERENCES ${schema}.sessions(id) ON DELETE SET NULL,
15
+ turn_embedding_id BIGINT REFERENCES ${schema}.turn_embeddings(id) ON DELETE SET NULL,
16
+ summary_row_id BIGINT REFERENCES ${schema}.session_summaries(session_row_id) ON DELETE SET NULL,
17
+ created_by_finalization_id BIGINT REFERENCES ${schema}.session_finalizations(id) ON DELETE SET NULL,
18
+ excerpt_text TEXT NOT NULL CHECK (btrim(excerpt_text) <> ''),
19
+ excerpt_hash TEXT NOT NULL CHECK (btrim(excerpt_hash) <> ''),
20
+ embedding vector(1024),
21
+ search_tsv TSVECTOR,
22
+ metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
23
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
24
+ );
25
+
26
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_evidence_items_dedupe
27
+ ON ${schema}.evidence_items (tenant_id, source_kind, source_ref, excerpt_hash);
28
+
29
+ CREATE INDEX IF NOT EXISTS idx_evidence_items_source
30
+ ON ${schema}.evidence_items (tenant_id, source_kind, source_ref);
31
+
32
+ CREATE INDEX IF NOT EXISTS idx_evidence_items_finalization
33
+ ON ${schema}.evidence_items (tenant_id, created_by_finalization_id)
34
+ WHERE created_by_finalization_id IS NOT NULL;
35
+
36
+ CREATE INDEX IF NOT EXISTS idx_evidence_items_search_tsv
37
+ ON ${schema}.evidence_items USING GIN (search_tsv);
38
+
39
+ CREATE INDEX IF NOT EXISTS idx_evidence_items_excerpt_trgm
40
+ ON ${schema}.evidence_items USING GIN (excerpt_text gin_trgm_ops);
41
+
42
+ CREATE OR REPLACE FUNCTION ${schema}.evidence_items_search_tsv_update()
43
+ RETURNS trigger
44
+ LANGUAGE plpgsql
45
+ AS $$
46
+ BEGIN
47
+ BEGIN
48
+ NEW.search_tsv := to_tsvector('zhcfg', COALESCE(NEW.excerpt_text, ''));
49
+ EXCEPTION WHEN undefined_object OR undefined_function THEN
50
+ NEW.search_tsv := to_tsvector('simple', COALESCE(NEW.excerpt_text, ''));
51
+ END;
52
+ RETURN NEW;
53
+ END;
54
+ $$;
55
+
56
+ DROP TRIGGER IF EXISTS trg_evidence_items_search_tsv
57
+ ON ${schema}.evidence_items;
58
+
59
+ CREATE TRIGGER trg_evidence_items_search_tsv
60
+ BEFORE INSERT OR UPDATE OF excerpt_text
61
+ ON ${schema}.evidence_items
62
+ FOR EACH ROW
63
+ EXECUTE FUNCTION ${schema}.evidence_items_search_tsv_update();
64
+
65
+ ALTER TABLE ${schema}.evidence_refs
66
+ ADD COLUMN IF NOT EXISTS evidence_item_id BIGINT;
67
+
68
+ CREATE INDEX IF NOT EXISTS idx_evidence_refs_evidence_item
69
+ ON ${schema}.evidence_refs (tenant_id, evidence_item_id)
70
+ WHERE evidence_item_id IS NOT NULL;
71
+
72
+ DO $$
73
+ BEGIN
74
+ IF NOT EXISTS (
75
+ SELECT 1
76
+ FROM pg_constraint
77
+ WHERE conrelid = '${schema}.evidence_refs'::regclass
78
+ AND conname = 'evidence_refs_evidence_item_fk'
79
+ ) THEN
80
+ ALTER TABLE ${schema}.evidence_refs
81
+ ADD CONSTRAINT evidence_refs_evidence_item_fk
82
+ FOREIGN KEY (evidence_item_id)
83
+ REFERENCES ${schema}.evidence_items(id)
84
+ ON DELETE SET NULL;
85
+ END IF;
86
+ END$$;
87
+
88
+ COMMENT ON TABLE ${schema}.evidence_items IS
89
+ 'Retrieval-grade evidence units. Unlike coarse session_summary refs, these are searchable anchors that can support individual memory_records.';
90
+
91
+ COMMENT ON COLUMN ${schema}.evidence_refs.evidence_item_id IS
92
+ 'Optional typed link to a retrieval-grade evidence item. source_kind/source_ref remain the audit-compatible source identity.';
@@ -0,0 +1,19 @@
1
+ -- Aquifer v1 evidence refs can point at multiple retrieval-grade evidence items
2
+ -- Requires: 007-v1-foundation.sql, 015-v1-evidence-items.sql
3
+ -- Usage: replace ${schema} with actual schema name
4
+
5
+ DROP INDEX IF EXISTS ${schema}.idx_evidence_refs_dedupe;
6
+
7
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_evidence_refs_source_dedupe
8
+ ON ${schema}.evidence_refs (tenant_id, owner_kind, owner_id, source_kind, source_ref, relation_kind)
9
+ WHERE evidence_item_id IS NULL;
10
+
11
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_evidence_refs_evidence_item_dedupe
12
+ ON ${schema}.evidence_refs (tenant_id, owner_kind, owner_id, evidence_item_id, relation_kind)
13
+ WHERE evidence_item_id IS NOT NULL;
14
+
15
+ COMMENT ON INDEX ${schema}.idx_evidence_refs_source_dedupe IS
16
+ 'Legacy/coarse provenance dedupe for refs that do not yet point at retrieval-grade evidence_items.';
17
+
18
+ COMMENT ON INDEX ${schema}.idx_evidence_refs_evidence_item_dedupe IS
19
+ 'Allows multiple evidence_items for the same owner/source while deduping each typed evidence item link.';
@@ -0,0 +1,25 @@
1
+ -- Aquifer v1 current-memory semantic recall anchors
2
+ -- Requires: 007-v1-foundation.sql
3
+ -- Usage: replace ${schema} with actual schema name
4
+
5
+ ALTER TABLE ${schema}.memory_records
6
+ ADD COLUMN IF NOT EXISTS embedding vector(1024);
7
+
8
+ DO $$
9
+ BEGIN
10
+ BEGIN
11
+ EXECUTE 'CREATE INDEX IF NOT EXISTS idx_memory_records_embedding_hnsw
12
+ ON ${schema}.memory_records USING hnsw (embedding vector_cosine_ops)
13
+ WHERE status = ''active'' AND visible_in_recall = true AND embedding IS NOT NULL';
14
+ EXCEPTION
15
+ WHEN undefined_object THEN
16
+ RAISE WARNING '[aquifer] pgvector HNSW operator class unavailable; memory_records semantic recall will use lexical/coarse anchors until vector index is available';
17
+ WHEN out_of_memory THEN
18
+ RAISE WARNING '[aquifer] HNSW build on memory_records.embedding ran out of memory; raise maintenance_work_mem and re-run migrate()';
19
+ WHEN program_limit_exceeded THEN
20
+ RAISE WARNING '[aquifer] HNSW build on memory_records.embedding exceeded an internal limit; inspect pgvector logs';
21
+ END;
22
+ END$$;
23
+
24
+ COMMENT ON COLUMN ${schema}.memory_records.embedding IS
25
+ 'Optional current-memory embedding used by curated semantic/hybrid session_recall. Legacy summaries remain evidence anchors, not current truth.';
@@ -0,0 +1,39 @@
1
+ -- Aquifer v1 finalization candidate envelope
2
+ -- Requires: 008-session-finalizations.sql, 010-v1-finalization-review.sql
3
+ -- Usage: replace ${schema} with actual schema name
4
+ --
5
+ -- The candidate envelope is producer material, not serving truth. It records
6
+ -- the structured synthesis input/output that core finalization validated before
7
+ -- promoting active current memory.
8
+
9
+ ALTER TABLE ${schema}.session_finalizations
10
+ ADD COLUMN IF NOT EXISTS candidate_envelope JSONB NOT NULL DEFAULT '{}'::jsonb,
11
+ ADD COLUMN IF NOT EXISTS candidate_envelope_hash TEXT,
12
+ ADD COLUMN IF NOT EXISTS candidate_envelope_version TEXT,
13
+ ADD COLUMN IF NOT EXISTS coverage JSONB NOT NULL DEFAULT '{}'::jsonb;
14
+
15
+ COMMENT ON COLUMN ${schema}.session_finalizations.candidate_envelope IS
16
+ 'Structured current-memory candidate envelope produced by handoff/recovery synthesis; producer material, not serving truth.';
17
+
18
+ COMMENT ON COLUMN ${schema}.session_finalizations.candidate_envelope_hash IS
19
+ 'Stable hash of the candidate envelope used for audit and replay comparison.';
20
+
21
+ COMMENT ON COLUMN ${schema}.session_finalizations.candidate_envelope_version IS
22
+ 'Version of the producer envelope contract, for example handoff_current_memory_synthesis_v1.';
23
+
24
+ COMMENT ON COLUMN ${schema}.session_finalizations.coverage IS
25
+ 'Coverage metadata for partial transcript, previous bootstrap, checkpoint, or other synthesis inputs.';
26
+
27
+ CREATE INDEX IF NOT EXISTS idx_session_finalizations_candidate_envelope_hash
28
+ ON ${schema}.session_finalizations (tenant_id, candidate_envelope_hash)
29
+ WHERE candidate_envelope_hash IS NOT NULL;
30
+
31
+ ALTER TABLE ${schema}.finalization_candidates
32
+ ADD COLUMN IF NOT EXISTS candidate_hash TEXT;
33
+
34
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_finalization_candidates_hash
35
+ ON ${schema}.finalization_candidates (tenant_id, finalization_id, candidate_hash)
36
+ WHERE candidate_hash IS NOT NULL;
37
+
38
+ COMMENT ON COLUMN ${schema}.finalization_candidates.candidate_hash IS
39
+ 'Stable per-candidate hash. candidate_index remains an ordered audit position.';