@codified/cli 0.1.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.
@@ -0,0 +1,34 @@
1
+ services:
2
+ postgres:
3
+ build:
4
+ context: ./postgres
5
+ dockerfile: Dockerfile
6
+ environment:
7
+ POSTGRES_USER: codify
8
+ POSTGRES_PASSWORD: codify
9
+ POSTGRES_DB: codify
10
+ ports:
11
+ - "5432:5432"
12
+ volumes:
13
+ - postgres-data:/var/lib/postgresql/data
14
+ - ./init:/docker-entrypoint-initdb.d
15
+ healthcheck:
16
+ test: ["CMD-SHELL", "pg_isready -U codify"]
17
+ interval: 5s
18
+ timeout: 5s
19
+ retries: 5
20
+ restart: unless-stopped
21
+
22
+ nats:
23
+ image: nats:2.11-alpine
24
+ command: --jetstream --store_dir /data
25
+ ports:
26
+ - "4222:4222"
27
+ - "8222:8222"
28
+ volumes:
29
+ - nats-data:/data
30
+ restart: unless-stopped
31
+
32
+ volumes:
33
+ postgres-data:
34
+ nats-data:
@@ -0,0 +1,10 @@
1
+ -- Enable required PostgreSQL extensions
2
+ CREATE EXTENSION IF NOT EXISTS age;
3
+ CREATE EXTENSION IF NOT EXISTS vector;
4
+
5
+ -- Load Apache AGE
6
+ LOAD 'age';
7
+ SET search_path = ag_catalog, "$user", public;
8
+
9
+ -- Create the context graph
10
+ SELECT create_graph('context_graph');
@@ -0,0 +1,33 @@
1
+ # PostgreSQL 16 with pgvector + Apache AGE extensions
2
+ # Start from pgvector (stable), add AGE from source
3
+
4
+ FROM pgvector/pgvector:pg16
5
+
6
+ USER root
7
+
8
+ # Install build dependencies for AGE
9
+ RUN apt-get update && \
10
+ apt-get install -y --no-install-recommends \
11
+ build-essential \
12
+ libreadline-dev \
13
+ zlib1g-dev \
14
+ flex \
15
+ bison \
16
+ git \
17
+ ca-certificates \
18
+ postgresql-server-dev-16 && \
19
+ # Build and install Apache AGE
20
+ cd /tmp && \
21
+ git clone --branch release/PG16/1.6.0 https://github.com/apache/age.git && \
22
+ cd age && \
23
+ make && \
24
+ make install && \
25
+ # Cleanup
26
+ cd / && \
27
+ rm -rf /tmp/age && \
28
+ apt-get purge -y build-essential libreadline-dev zlib1g-dev flex bison git postgresql-server-dev-16 && \
29
+ apt-get autoremove -y && \
30
+ apt-get clean && \
31
+ rm -rf /var/lib/apt/lists/*
32
+
33
+ USER postgres
@@ -0,0 +1,391 @@
1
+ -- =============================================================================
2
+ -- Codify Context Graph: Initial Schema Migration
3
+ -- =============================================================================
4
+ -- IMPORTANT: AGE search_path operations are at the END of this file.
5
+ -- Table creation happens first in the default (public) schema.
6
+ -- =============================================================================
7
+
8
+ -- ---------------------------------------------------------------------------
9
+ -- 1. Extensions (safe to re-run)
10
+ -- ---------------------------------------------------------------------------
11
+
12
+ CREATE EXTENSION IF NOT EXISTS age;
13
+ CREATE EXTENSION IF NOT EXISTS vector;
14
+
15
+
16
+ -- ---------------------------------------------------------------------------
17
+ -- 2. Node Type Registry
18
+ -- ---------------------------------------------------------------------------
19
+
20
+ CREATE TABLE IF NOT EXISTS node_types (
21
+ name TEXT PRIMARY KEY,
22
+ schema JSONB NOT NULL DEFAULT '{}',
23
+ parent_type TEXT REFERENCES node_types(name),
24
+ description TEXT,
25
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
26
+ version INT NOT NULL DEFAULT 1
27
+ );
28
+
29
+ INSERT INTO node_types (name, description) VALUES
30
+ ('Decision', 'A choice made by a person or team, with provenance'),
31
+ ('Feature', 'A product capability — proposed through shipped'),
32
+ ('Metric', 'A measurable quantity the organization tracks'),
33
+ ('CustomerSignal', 'Signal from a customer — feedback, ticket, churn indicator'),
34
+ ('CodeArtifact', 'A code-level entity — PR, commit, file, service, deploy'),
35
+ ('Discussion', 'A conversation — Slack, meeting, doc comment, email'),
36
+ ('Gap', 'A detected hole, staleness, or contradiction in the graph'),
37
+ ('Study', 'A research study tied to Codify interview system'),
38
+ ('Person', 'A human in or around the organization')
39
+ ON CONFLICT (name) DO NOTHING;
40
+
41
+
42
+ -- ---------------------------------------------------------------------------
43
+ -- 3. Edge Type Registry
44
+ -- ---------------------------------------------------------------------------
45
+
46
+ CREATE TABLE IF NOT EXISTS edge_types (
47
+ name TEXT PRIMARY KEY,
48
+ source_types TEXT[] NOT NULL DEFAULT '{}',
49
+ target_types TEXT[] NOT NULL DEFAULT '{}',
50
+ schema JSONB NOT NULL DEFAULT '{}',
51
+ description TEXT,
52
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
53
+ version INT NOT NULL DEFAULT 1
54
+ );
55
+
56
+ INSERT INTO edge_types (name, description) VALUES
57
+ ('caused_by', 'A was caused by B'),
58
+ ('informed_by', 'A was informed by B'),
59
+ ('derived_from', 'A was derived/computed from B'),
60
+ ('evidence_for', 'A provides evidence supporting B'),
61
+ ('contradicts', 'A and B are in conflict'),
62
+ ('validates', 'A validates/confirms B'),
63
+ ('invalidates', 'A disproves B'),
64
+ ('resolved_by', 'Gap/contradiction A was resolved by B'),
65
+ ('supersedes', 'A replaces B as the current truth'),
66
+ ('blocks', 'A blocks progress on B'),
67
+ ('depends_on', 'A depends on B'),
68
+ ('part_of', 'A is a component of B'),
69
+ ('owned_by', 'A is owned/authored by B'),
70
+ ('participated_in', 'Person A participated in B'),
71
+ ('evolved_from', 'A is an evolution of B'),
72
+ ('preceded_by', 'A happened after B (temporal)'),
73
+ ('deprioritized_because', 'A was deprioritized due to B'),
74
+ ('triggered', 'A triggered the creation of B'),
75
+ ('fills_gap', 'Study/signal A fills Gap B'),
76
+ ('collected_for', 'Signal A was collected for Study B'),
77
+ ('assigned_to', 'Gap A assigned to agent/person B'),
78
+ ('authored_by', 'A was authored/created by person B'),
79
+ ('contributed_to', 'A contributed to artifact/decision B'),
80
+ ('implements', 'A implements feature/decision B'),
81
+ ('relates_to', 'General relationship between A and B'),
82
+ ('addresses', 'A addresses gap/issue B'),
83
+ ('discussed_in', 'A was discussed in discussion B'),
84
+ ('measured_by', 'A is measured by metric B'),
85
+ ('blocked_by', 'A is blocked by issue/dependency B'),
86
+ ('mentions', 'A mentions entity B'),
87
+ ('corroborates', 'A corroborates/supports claim B'),
88
+ ('refines', 'A refines or improves upon B'),
89
+ ('competed_by', 'A has competition/alternative B'),
90
+ ('precedes', 'A came before/preceded B')
91
+ ON CONFLICT (name) DO NOTHING;
92
+
93
+
94
+ -- ---------------------------------------------------------------------------
95
+ -- 4. Branches (must exist before nodes/edges reference them)
96
+ -- ---------------------------------------------------------------------------
97
+
98
+ CREATE TABLE IF NOT EXISTS branches (
99
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
100
+ name TEXT NOT NULL,
101
+ parent_branch UUID REFERENCES branches(id),
102
+ branch_point TIMESTAMPTZ NOT NULL DEFAULT now(),
103
+ status TEXT NOT NULL DEFAULT 'active'
104
+ CHECK (status IN ('active', 'merged', 'pruned', 'archived')),
105
+ created_by UUID,
106
+ purpose TEXT NOT NULL DEFAULT '',
107
+ merge_policy TEXT NOT NULL DEFAULT 'manual'
108
+ CHECK (merge_policy IN ('manual', 'auto_on_confidence', 'auto_on_approval')),
109
+ prune_reason TEXT,
110
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
111
+ );
112
+
113
+
114
+ -- ---------------------------------------------------------------------------
115
+ -- 5. Nodes
116
+ -- ---------------------------------------------------------------------------
117
+
118
+ CREATE TABLE IF NOT EXISTS nodes (
119
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
120
+ type TEXT NOT NULL REFERENCES node_types(name),
121
+ layer TEXT NOT NULL DEFAULT 'permanent'
122
+ CHECK (layer IN ('ephemeral', 'hot', 'draft', 'permanent')),
123
+ branch_id UUID REFERENCES branches(id),
124
+ confidence REAL NOT NULL DEFAULT 0.5 CHECK (confidence >= 0 AND confidence <= 1),
125
+ freshness REAL NOT NULL DEFAULT 1.0 CHECK (freshness >= 0 AND freshness <= 1),
126
+ version INT NOT NULL DEFAULT 1,
127
+ superseded_by UUID,
128
+ source_system TEXT NOT NULL DEFAULT 'manual',
129
+ source_reference TEXT NOT NULL DEFAULT '',
130
+ source_agent_id TEXT,
131
+ source_reliability REAL NOT NULL DEFAULT 0.7 CHECK (source_reliability >= 0 AND source_reliability <= 1),
132
+ properties JSONB NOT NULL DEFAULT '{}',
133
+ embedding vector(1024),
134
+ tags TEXT[] NOT NULL DEFAULT '{}',
135
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
136
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
137
+ expires_at TIMESTAMPTZ,
138
+ metadata JSONB NOT NULL DEFAULT '{}'
139
+ );
140
+
141
+ DO $$
142
+ BEGIN
143
+ ALTER TABLE nodes ADD CONSTRAINT fk_superseded_by
144
+ FOREIGN KEY (superseded_by) REFERENCES nodes(id);
145
+ EXCEPTION WHEN duplicate_object THEN
146
+ NULL;
147
+ END;
148
+ $$;
149
+
150
+
151
+ -- ---------------------------------------------------------------------------
152
+ -- 6. Edges
153
+ -- ---------------------------------------------------------------------------
154
+
155
+ CREATE TABLE IF NOT EXISTS edges (
156
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
157
+ type TEXT NOT NULL REFERENCES edge_types(name),
158
+ source_id UUID NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
159
+ target_id UUID NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
160
+ branch_id UUID REFERENCES branches(id),
161
+ confidence REAL NOT NULL DEFAULT 0.5 CHECK (confidence >= 0 AND confidence <= 1),
162
+ weight REAL NOT NULL DEFAULT 0.5,
163
+ evidence TEXT,
164
+ properties JSONB NOT NULL DEFAULT '{}',
165
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
166
+ UNIQUE (type, source_id, target_id, branch_id)
167
+ );
168
+
169
+
170
+ -- ---------------------------------------------------------------------------
171
+ -- 7. Node Version History
172
+ -- ---------------------------------------------------------------------------
173
+
174
+ CREATE TABLE IF NOT EXISTS node_versions (
175
+ id UUID NOT NULL,
176
+ version INT NOT NULL,
177
+ type TEXT NOT NULL,
178
+ layer TEXT NOT NULL,
179
+ branch_id UUID,
180
+ confidence REAL NOT NULL,
181
+ freshness REAL NOT NULL,
182
+ properties JSONB NOT NULL,
183
+ source_system TEXT NOT NULL,
184
+ source_reference TEXT NOT NULL,
185
+ source_agent_id TEXT,
186
+ tags TEXT[] NOT NULL DEFAULT '{}',
187
+ created_at TIMESTAMPTZ NOT NULL,
188
+ updated_at TIMESTAMPTZ NOT NULL,
189
+ archived_at TIMESTAMPTZ NOT NULL DEFAULT now(),
190
+ PRIMARY KEY (id, version)
191
+ );
192
+
193
+
194
+ -- ---------------------------------------------------------------------------
195
+ -- 8. Indexes
196
+ -- ---------------------------------------------------------------------------
197
+
198
+ CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type);
199
+ CREATE INDEX IF NOT EXISTS idx_nodes_layer ON nodes(layer);
200
+ CREATE INDEX IF NOT EXISTS idx_nodes_branch ON nodes(branch_id) WHERE branch_id IS NOT NULL;
201
+ CREATE INDEX IF NOT EXISTS idx_nodes_freshness ON nodes(freshness);
202
+ CREATE INDEX IF NOT EXISTS idx_nodes_type_layer ON nodes(type, layer);
203
+ CREATE INDEX IF NOT EXISTS idx_nodes_type_freshness ON nodes(type, freshness);
204
+ CREATE INDEX IF NOT EXISTS idx_nodes_superseded_by ON nodes(superseded_by) WHERE superseded_by IS NOT NULL;
205
+ CREATE INDEX IF NOT EXISTS idx_nodes_expires_at ON nodes(expires_at) WHERE expires_at IS NOT NULL;
206
+ CREATE INDEX IF NOT EXISTS idx_nodes_tags ON nodes USING GIN(tags);
207
+ CREATE INDEX IF NOT EXISTS idx_nodes_properties ON nodes USING GIN(properties jsonb_path_ops);
208
+ CREATE INDEX IF NOT EXISTS idx_nodes_embedding ON nodes USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);
209
+
210
+ CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source_id);
211
+ CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target_id);
212
+ CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type);
213
+ CREATE INDEX IF NOT EXISTS idx_edges_branch ON edges(branch_id) WHERE branch_id IS NOT NULL;
214
+ CREATE INDEX IF NOT EXISTS idx_edges_source_type ON edges(source_id, type);
215
+ CREATE INDEX IF NOT EXISTS idx_edges_target_type ON edges(target_id, type);
216
+
217
+ CREATE INDEX IF NOT EXISTS idx_branches_status ON branches(status);
218
+
219
+ CREATE INDEX IF NOT EXISTS idx_node_versions_id ON node_versions(id);
220
+ CREATE INDEX IF NOT EXISTS idx_node_versions_archived ON node_versions(archived_at);
221
+
222
+
223
+ -- ---------------------------------------------------------------------------
224
+ -- 9. Helper Functions
225
+ -- ---------------------------------------------------------------------------
226
+
227
+ CREATE OR REPLACE FUNCTION compute_freshness(p_node_id UUID)
228
+ RETURNS REAL AS $$
229
+ DECLARE
230
+ v_node RECORD;
231
+ v_decay_rate REAL;
232
+ v_age_days REAL;
233
+ v_recency REAL;
234
+ v_corroboration_count INT;
235
+ v_corroboration REAL;
236
+ v_freshness REAL;
237
+ BEGIN
238
+ SELECT * INTO v_node FROM public.nodes WHERE id = p_node_id;
239
+ IF NOT FOUND THEN RETURN 0; END IF;
240
+
241
+ v_decay_rate := CASE v_node.type
242
+ WHEN 'CustomerSignal' THEN 0.0231
243
+ WHEN 'Metric' THEN 0.0990
244
+ WHEN 'Decision' THEN 0.00385
245
+ WHEN 'Feature' THEN 0.00770
246
+ WHEN 'CodeArtifact' THEN 0.01155
247
+ WHEN 'Discussion' THEN 0.0495
248
+ WHEN 'Gap' THEN 0.0495
249
+ WHEN 'Study' THEN 0.00578
250
+ WHEN 'Person' THEN 0.00190
251
+ ELSE 0.01155
252
+ END;
253
+
254
+ v_age_days := EXTRACT(EPOCH FROM (now() - v_node.updated_at)) / 86400.0;
255
+ IF v_age_days < 0 THEN v_age_days := 0; END IF;
256
+ v_recency := exp(-v_decay_rate * v_age_days);
257
+
258
+ SELECT COUNT(DISTINCT e.properties->>'source_system')
259
+ INTO v_corroboration_count
260
+ FROM public.edges e
261
+ WHERE e.target_id = p_node_id
262
+ AND e.type IN ('validates', 'evidence_for', 'informed_by');
263
+ v_corroboration := LEAST(1.0, v_corroboration_count::REAL / 3.0);
264
+
265
+ v_freshness := 0.5 * v_recency + 0.3 * v_corroboration + 0.2 * v_node.source_reliability;
266
+ RETURN GREATEST(0, LEAST(1, v_freshness));
267
+ END;
268
+ $$ LANGUAGE plpgsql STABLE;
269
+
270
+
271
+ CREATE OR REPLACE FUNCTION refresh_all_freshness()
272
+ RETURNS INT AS $$
273
+ DECLARE
274
+ v_count INT := 0;
275
+ v_node RECORD;
276
+ BEGIN
277
+ FOR v_node IN
278
+ SELECT id FROM public.nodes WHERE layer = 'permanent' AND superseded_by IS NULL
279
+ LOOP
280
+ UPDATE public.nodes
281
+ SET freshness = compute_freshness(v_node.id),
282
+ updated_at = updated_at
283
+ WHERE id = v_node.id;
284
+ v_count := v_count + 1;
285
+ END LOOP;
286
+ RETURN v_count;
287
+ END;
288
+ $$ LANGUAGE plpgsql;
289
+
290
+
291
+ CREATE OR REPLACE FUNCTION expire_hot_nodes()
292
+ RETURNS TABLE(node_id UUID, action TEXT) AS $$
293
+ DECLARE
294
+ v_node RECORD;
295
+ v_ref_count INT;
296
+ BEGIN
297
+ FOR v_node IN
298
+ SELECT id FROM public.nodes
299
+ WHERE layer = 'hot' AND expires_at IS NOT NULL AND expires_at <= now()
300
+ LOOP
301
+ SELECT COUNT(*) INTO v_ref_count
302
+ FROM public.edges WHERE target_id = v_node.id OR source_id = v_node.id;
303
+
304
+ IF v_ref_count >= 2 THEN
305
+ UPDATE public.nodes SET layer = 'draft', expires_at = NULL WHERE id = v_node.id;
306
+ node_id := v_node.id;
307
+ action := 'promoted_to_draft';
308
+ ELSE
309
+ INSERT INTO public.node_versions (id, version, type, layer, branch_id, confidence, freshness,
310
+ properties, source_system, source_reference, source_agent_id, tags, created_at, updated_at)
311
+ SELECT id, version, type, layer, branch_id, confidence, freshness,
312
+ properties, source_system, source_reference, source_agent_id, tags, created_at, updated_at
313
+ FROM public.nodes WHERE id = v_node.id;
314
+ DELETE FROM public.nodes WHERE id = v_node.id;
315
+ node_id := v_node.id;
316
+ action := 'deleted';
317
+ END IF;
318
+ RETURN NEXT;
319
+ END LOOP;
320
+ END;
321
+ $$ LANGUAGE plpgsql;
322
+
323
+
324
+ CREATE OR REPLACE FUNCTION archive_node_version()
325
+ RETURNS TRIGGER AS $$
326
+ BEGIN
327
+ IF OLD.properties IS DISTINCT FROM NEW.properties
328
+ OR OLD.confidence IS DISTINCT FROM NEW.confidence
329
+ OR OLD.layer IS DISTINCT FROM NEW.layer
330
+ THEN
331
+ INSERT INTO public.node_versions (id, version, type, layer, branch_id, confidence, freshness,
332
+ properties, source_system, source_reference, source_agent_id, tags, created_at, updated_at)
333
+ VALUES (OLD.id, OLD.version, OLD.type, OLD.layer, OLD.branch_id, OLD.confidence, OLD.freshness,
334
+ OLD.properties, OLD.source_system, OLD.source_reference, OLD.source_agent_id, OLD.tags,
335
+ OLD.created_at, OLD.updated_at);
336
+ NEW.version := OLD.version + 1;
337
+ NEW.updated_at := now();
338
+ END IF;
339
+ RETURN NEW;
340
+ END;
341
+ $$ LANGUAGE plpgsql;
342
+
343
+ DROP TRIGGER IF EXISTS trg_node_versioning ON nodes;
344
+ CREATE TRIGGER trg_node_versioning
345
+ BEFORE UPDATE ON nodes
346
+ FOR EACH ROW
347
+ EXECUTE FUNCTION archive_node_version();
348
+
349
+
350
+ -- ---------------------------------------------------------------------------
351
+ -- 10. AGE Graph Labels (requires search_path change — MUST be last)
352
+ -- ---------------------------------------------------------------------------
353
+ -- NOTE: The SET search_path below changes the default schema.
354
+ -- All table operations above are complete so this is safe.
355
+
356
+ SET search_path = ag_catalog, "$user", public;
357
+
358
+ DO $$ BEGIN PERFORM create_vlabel('context_graph', 'Decision'); EXCEPTION WHEN others THEN NULL; END; $$;
359
+ DO $$ BEGIN PERFORM create_vlabel('context_graph', 'Feature'); EXCEPTION WHEN others THEN NULL; END; $$;
360
+ DO $$ BEGIN PERFORM create_vlabel('context_graph', 'Metric'); EXCEPTION WHEN others THEN NULL; END; $$;
361
+ DO $$ BEGIN PERFORM create_vlabel('context_graph', 'CustomerSignal'); EXCEPTION WHEN others THEN NULL; END; $$;
362
+ DO $$ BEGIN PERFORM create_vlabel('context_graph', 'CodeArtifact'); EXCEPTION WHEN others THEN NULL; END; $$;
363
+ DO $$ BEGIN PERFORM create_vlabel('context_graph', 'Discussion'); EXCEPTION WHEN others THEN NULL; END; $$;
364
+ DO $$ BEGIN PERFORM create_vlabel('context_graph', 'Gap'); EXCEPTION WHEN others THEN NULL; END; $$;
365
+ DO $$ BEGIN PERFORM create_vlabel('context_graph', 'Study'); EXCEPTION WHEN others THEN NULL; END; $$;
366
+ DO $$ BEGIN PERFORM create_vlabel('context_graph', 'Person'); EXCEPTION WHEN others THEN NULL; END; $$;
367
+
368
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'caused_by'); EXCEPTION WHEN others THEN NULL; END; $$;
369
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'informed_by'); EXCEPTION WHEN others THEN NULL; END; $$;
370
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'derived_from'); EXCEPTION WHEN others THEN NULL; END; $$;
371
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'evidence_for'); EXCEPTION WHEN others THEN NULL; END; $$;
372
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'contradicts'); EXCEPTION WHEN others THEN NULL; END; $$;
373
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'validates'); EXCEPTION WHEN others THEN NULL; END; $$;
374
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'invalidates'); EXCEPTION WHEN others THEN NULL; END; $$;
375
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'resolved_by'); EXCEPTION WHEN others THEN NULL; END; $$;
376
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'supersedes'); EXCEPTION WHEN others THEN NULL; END; $$;
377
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'blocks'); EXCEPTION WHEN others THEN NULL; END; $$;
378
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'depends_on'); EXCEPTION WHEN others THEN NULL; END; $$;
379
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'part_of'); EXCEPTION WHEN others THEN NULL; END; $$;
380
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'owned_by'); EXCEPTION WHEN others THEN NULL; END; $$;
381
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'participated_in'); EXCEPTION WHEN others THEN NULL; END; $$;
382
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'evolved_from'); EXCEPTION WHEN others THEN NULL; END; $$;
383
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'preceded_by'); EXCEPTION WHEN others THEN NULL; END; $$;
384
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'deprioritized_because'); EXCEPTION WHEN others THEN NULL; END; $$;
385
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'triggered'); EXCEPTION WHEN others THEN NULL; END; $$;
386
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'fills_gap'); EXCEPTION WHEN others THEN NULL; END; $$;
387
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'collected_for'); EXCEPTION WHEN others THEN NULL; END; $$;
388
+ DO $$ BEGIN PERFORM create_elabel('context_graph', 'assigned_to'); EXCEPTION WHEN others THEN NULL; END; $$;
389
+
390
+ -- Reset search_path back to default
391
+ SET search_path = "$user", public;
@@ -0,0 +1,12 @@
1
+ -- =============================================================================
2
+ -- Change embedding dimension from 1536 to 1024 (Voyage AI voyage-3-lite)
3
+ -- =============================================================================
4
+
5
+ -- Drop the HNSW index first (required before altering the column type)
6
+ DROP INDEX IF EXISTS idx_nodes_embedding;
7
+
8
+ -- Alter the column dimension
9
+ ALTER TABLE nodes ALTER COLUMN embedding TYPE vector(1024);
10
+
11
+ -- Recreate the HNSW index
12
+ CREATE INDEX IF NOT EXISTS idx_nodes_embedding ON nodes USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);