1use anyhow::Result;
6use duckdb::Connection;
7
8fn add_column_if_not_exists(conn: &Connection, table: &str, column: &str, col_type: &str) {
10 let sql = format!("ALTER TABLE {} ADD COLUMN {} {}", table, column, col_type);
11 let _ = conn.execute(&sql, []);
12}
13
14pub fn init_schema(conn: &Connection) -> Result<()> {
16 conn.execute(
18 r#"
19 CREATE TABLE IF NOT EXISTS sessions (
20 session_id VARCHAR PRIMARY KEY,
21 task TEXT NOT NULL,
22 working_dir TEXT NOT NULL,
23 merkle_root BLOB,
24 detected_toolchain VARCHAR,
25 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
26 updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
27 status VARCHAR DEFAULT 'active'
28 )
29 "#,
30 [],
31 )?;
32
33 conn.execute(
35 "CREATE SEQUENCE IF NOT EXISTS seq_node_states_id START 1",
36 [],
37 )?;
38 conn.execute(
39 "CREATE SEQUENCE IF NOT EXISTS seq_energy_history_id START 1",
40 [],
41 )?;
42 conn.execute(
43 "CREATE SEQUENCE IF NOT EXISTS seq_llm_requests_id START 1",
44 [],
45 )?;
46
47 conn.execute(
49 r#"
50 CREATE TABLE IF NOT EXISTS node_states (
51 id INTEGER PRIMARY KEY DEFAULT nextval('seq_node_states_id'),
52 node_id VARCHAR NOT NULL,
53 session_id VARCHAR NOT NULL,
54 state VARCHAR NOT NULL,
55 v_total REAL DEFAULT 0.0,
56 merkle_hash BLOB,
57 attempt_count INTEGER DEFAULT 0,
58 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
59 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
60 )
61 "#,
62 [],
63 )?;
64
65 conn.execute(
67 r#"
68 CREATE TABLE IF NOT EXISTS energy_history (
69 id INTEGER PRIMARY KEY DEFAULT nextval('seq_energy_history_id'),
70 node_id VARCHAR NOT NULL,
71 session_id VARCHAR NOT NULL,
72 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
73 v_syn REAL DEFAULT 0.0,
74 v_str REAL DEFAULT 0.0,
75 v_log REAL DEFAULT 0.0,
76 v_boot REAL DEFAULT 0.0,
77 v_sheaf REAL DEFAULT 0.0,
78 v_total REAL DEFAULT 0.0,
79 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
80 )
81 "#,
82 [],
83 )?;
84
85 conn.execute(
87 "CREATE INDEX IF NOT EXISTS idx_node_states_session ON node_states(session_id)",
88 [],
89 )?;
90
91 conn.execute(
92 "CREATE INDEX IF NOT EXISTS idx_energy_history_session ON energy_history(session_id)",
93 [],
94 )?;
95
96 conn.execute(
98 r#"
99 CREATE TABLE IF NOT EXISTS llm_requests (
100 id INTEGER PRIMARY KEY DEFAULT nextval('seq_llm_requests_id'),
101 session_id VARCHAR NOT NULL,
102 node_id VARCHAR,
103 model VARCHAR NOT NULL,
104 prompt TEXT NOT NULL,
105 response TEXT NOT NULL,
106 tokens_in INTEGER DEFAULT 0,
107 tokens_out INTEGER DEFAULT 0,
108 latency_ms INTEGER DEFAULT 0,
109 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
110 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
111 )
112 "#,
113 [],
114 )?;
115
116 conn.execute(
117 "CREATE INDEX IF NOT EXISTS idx_llm_requests_session ON llm_requests(session_id)",
118 [],
119 )?;
120
121 conn.execute(
123 "CREATE SEQUENCE IF NOT EXISTS seq_structural_digests_id START 1",
124 [],
125 )?;
126 conn.execute(
127 "CREATE SEQUENCE IF NOT EXISTS seq_context_provenance_id START 1",
128 [],
129 )?;
130
131 conn.execute(
133 r#"
134 CREATE TABLE IF NOT EXISTS structural_digests (
135 id INTEGER PRIMARY KEY DEFAULT nextval('seq_structural_digests_id'),
136 digest_id VARCHAR NOT NULL,
137 session_id VARCHAR NOT NULL,
138 node_id VARCHAR NOT NULL,
139 source_path VARCHAR NOT NULL,
140 artifact_kind VARCHAR NOT NULL,
141 hash BLOB NOT NULL,
142 version INTEGER DEFAULT 1,
143 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
144 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
145 )
146 "#,
147 [],
148 )?;
149
150 conn.execute(
151 "CREATE INDEX IF NOT EXISTS idx_structural_digests_session ON structural_digests(session_id)",
152 [],
153 )?;
154
155 conn.execute(
157 r#"
158 CREATE TABLE IF NOT EXISTS context_provenance (
159 id INTEGER PRIMARY KEY DEFAULT nextval('seq_context_provenance_id'),
160 session_id VARCHAR NOT NULL,
161 node_id VARCHAR NOT NULL,
162 context_package_id VARCHAR NOT NULL,
163 structural_hashes TEXT,
164 summary_hashes TEXT,
165 dependency_hashes TEXT,
166 included_file_count INTEGER DEFAULT 0,
167 total_bytes INTEGER DEFAULT 0,
168 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
169 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
170 )
171 "#,
172 [],
173 )?;
174
175 conn.execute(
176 "CREATE INDEX IF NOT EXISTS idx_context_provenance_session ON context_provenance(session_id)",
177 [],
178 )?;
179
180 conn.execute(
185 "CREATE SEQUENCE IF NOT EXISTS seq_escalation_reports_id START 1",
186 [],
187 )?;
188 conn.execute(
189 "CREATE SEQUENCE IF NOT EXISTS seq_rewrite_records_id START 1",
190 [],
191 )?;
192 conn.execute(
193 "CREATE SEQUENCE IF NOT EXISTS seq_sheaf_validations_id START 1",
194 [],
195 )?;
196
197 conn.execute(
199 r#"
200 CREATE TABLE IF NOT EXISTS escalation_reports (
201 id INTEGER PRIMARY KEY DEFAULT nextval('seq_escalation_reports_id'),
202 session_id VARCHAR NOT NULL,
203 node_id VARCHAR NOT NULL,
204 category VARCHAR NOT NULL,
205 action VARCHAR NOT NULL,
206 energy_snapshot TEXT,
207 stage_outcomes TEXT,
208 evidence TEXT,
209 affected_node_ids TEXT,
210 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
211 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
212 )
213 "#,
214 [],
215 )?;
216 conn.execute(
217 "CREATE INDEX IF NOT EXISTS idx_escalation_reports_session ON escalation_reports(session_id)",
218 [],
219 )?;
220
221 conn.execute(
223 r#"
224 CREATE TABLE IF NOT EXISTS rewrite_records (
225 id INTEGER PRIMARY KEY DEFAULT nextval('seq_rewrite_records_id'),
226 session_id VARCHAR NOT NULL,
227 node_id VARCHAR NOT NULL,
228 action VARCHAR NOT NULL,
229 category VARCHAR NOT NULL,
230 requeued_nodes TEXT,
231 inserted_nodes TEXT,
232 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
233 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
234 )
235 "#,
236 [],
237 )?;
238 conn.execute(
239 "CREATE INDEX IF NOT EXISTS idx_rewrite_records_session ON rewrite_records(session_id)",
240 [],
241 )?;
242
243 conn.execute(
245 r#"
246 CREATE TABLE IF NOT EXISTS sheaf_validations (
247 id INTEGER PRIMARY KEY DEFAULT nextval('seq_sheaf_validations_id'),
248 session_id VARCHAR NOT NULL,
249 node_id VARCHAR NOT NULL,
250 validator_class VARCHAR NOT NULL,
251 plugin_source VARCHAR,
252 passed BOOLEAN NOT NULL,
253 evidence_summary TEXT,
254 affected_files TEXT,
255 v_sheaf_contribution REAL DEFAULT 0.0,
256 requeue_targets TEXT,
257 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
258 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
259 )
260 "#,
261 [],
262 )?;
263 conn.execute(
264 "CREATE INDEX IF NOT EXISTS idx_sheaf_validations_session ON sheaf_validations(session_id)",
265 [],
266 )?;
267
268 conn.execute(
273 "CREATE SEQUENCE IF NOT EXISTS seq_provisional_branches_id START 1",
274 [],
275 )?;
276 conn.execute(
277 "CREATE SEQUENCE IF NOT EXISTS seq_branch_lineage_id START 1",
278 [],
279 )?;
280 conn.execute(
281 "CREATE SEQUENCE IF NOT EXISTS seq_interface_seals_id START 1",
282 [],
283 )?;
284 conn.execute(
285 "CREATE SEQUENCE IF NOT EXISTS seq_branch_flushes_id START 1",
286 [],
287 )?;
288
289 conn.execute(
291 r#"
292 CREATE TABLE IF NOT EXISTS provisional_branches (
293 id INTEGER PRIMARY KEY DEFAULT nextval('seq_provisional_branches_id'),
294 branch_id VARCHAR NOT NULL,
295 session_id VARCHAR NOT NULL,
296 node_id VARCHAR NOT NULL,
297 parent_node_id VARCHAR NOT NULL,
298 state VARCHAR NOT NULL DEFAULT 'active',
299 parent_seal_hash BLOB,
300 sandbox_dir VARCHAR,
301 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
302 updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
303 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
304 )
305 "#,
306 [],
307 )?;
308 conn.execute(
309 "CREATE INDEX IF NOT EXISTS idx_provisional_branches_session ON provisional_branches(session_id)",
310 [],
311 )?;
312 conn.execute(
313 "CREATE INDEX IF NOT EXISTS idx_provisional_branches_parent ON provisional_branches(parent_node_id)",
314 [],
315 )?;
316
317 conn.execute(
319 r#"
320 CREATE TABLE IF NOT EXISTS branch_lineage (
321 id INTEGER PRIMARY KEY DEFAULT nextval('seq_branch_lineage_id'),
322 lineage_id VARCHAR NOT NULL,
323 parent_branch_id VARCHAR NOT NULL,
324 child_branch_id VARCHAR NOT NULL,
325 depends_on_seal BOOLEAN NOT NULL DEFAULT true,
326 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
327 )
328 "#,
329 [],
330 )?;
331 conn.execute(
332 "CREATE INDEX IF NOT EXISTS idx_branch_lineage_parent ON branch_lineage(parent_branch_id)",
333 [],
334 )?;
335
336 conn.execute(
338 r#"
339 CREATE TABLE IF NOT EXISTS interface_seals (
340 id INTEGER PRIMARY KEY DEFAULT nextval('seq_interface_seals_id'),
341 seal_id VARCHAR NOT NULL,
342 session_id VARCHAR NOT NULL,
343 node_id VARCHAR NOT NULL,
344 sealed_path VARCHAR NOT NULL,
345 artifact_kind VARCHAR NOT NULL,
346 seal_hash BLOB NOT NULL,
347 version INTEGER DEFAULT 1,
348 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
349 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
350 )
351 "#,
352 [],
353 )?;
354 conn.execute(
355 "CREATE INDEX IF NOT EXISTS idx_interface_seals_session ON interface_seals(session_id)",
356 [],
357 )?;
358 conn.execute(
359 "CREATE INDEX IF NOT EXISTS idx_interface_seals_node ON interface_seals(node_id)",
360 [],
361 )?;
362
363 conn.execute(
365 r#"
366 CREATE TABLE IF NOT EXISTS branch_flushes (
367 id INTEGER PRIMARY KEY DEFAULT nextval('seq_branch_flushes_id'),
368 flush_id VARCHAR NOT NULL,
369 session_id VARCHAR NOT NULL,
370 parent_node_id VARCHAR NOT NULL,
371 flushed_branch_ids TEXT NOT NULL,
372 requeue_node_ids TEXT NOT NULL,
373 reason TEXT NOT NULL,
374 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
375 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
376 )
377 "#,
378 [],
379 )?;
380 conn.execute(
381 "CREATE INDEX IF NOT EXISTS idx_branch_flushes_session ON branch_flushes(session_id)",
382 [],
383 )?;
384
385 add_column_if_not_exists(conn, "node_states", "node_class", "VARCHAR");
393 add_column_if_not_exists(conn, "node_states", "owner_plugin", "VARCHAR");
394 add_column_if_not_exists(conn, "node_states", "goal", "TEXT");
395 add_column_if_not_exists(conn, "node_states", "parent_id", "VARCHAR");
396 add_column_if_not_exists(conn, "node_states", "children", "TEXT");
397 add_column_if_not_exists(conn, "node_states", "last_error_type", "VARCHAR");
398 add_column_if_not_exists(conn, "node_states", "committed_at", "VARCHAR");
399
400 conn.execute(
402 "CREATE SEQUENCE IF NOT EXISTS seq_task_graph_edges_id START 1",
403 [],
404 )?;
405
406 conn.execute(
407 r#"
408 CREATE TABLE IF NOT EXISTS task_graph_edges (
409 id INTEGER PRIMARY KEY DEFAULT nextval('seq_task_graph_edges_id'),
410 session_id VARCHAR NOT NULL,
411 parent_node_id VARCHAR NOT NULL,
412 child_node_id VARCHAR NOT NULL,
413 edge_type VARCHAR NOT NULL DEFAULT 'dependency',
414 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
415 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
416 )
417 "#,
418 [],
419 )?;
420 conn.execute(
421 "CREATE INDEX IF NOT EXISTS idx_task_graph_edges_session ON task_graph_edges(session_id)",
422 [],
423 )?;
424 conn.execute(
425 "CREATE INDEX IF NOT EXISTS idx_task_graph_edges_parent ON task_graph_edges(parent_node_id)",
426 [],
427 )?;
428
429 conn.execute(
431 "CREATE SEQUENCE IF NOT EXISTS seq_review_outcomes_id START 1",
432 [],
433 )?;
434
435 conn.execute(
436 r#"
437 CREATE TABLE IF NOT EXISTS review_outcomes (
438 id INTEGER PRIMARY KEY DEFAULT nextval('seq_review_outcomes_id'),
439 session_id VARCHAR NOT NULL,
440 node_id VARCHAR NOT NULL,
441 outcome VARCHAR NOT NULL,
442 reviewer_note TEXT,
443 energy_at_review DOUBLE,
444 degraded BOOLEAN,
445 escalation_category VARCHAR,
446 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
447 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
448 )
449 "#,
450 [],
451 )?;
452 conn.execute(
453 "CREATE INDEX IF NOT EXISTS idx_review_outcomes_session ON review_outcomes(session_id)",
454 [],
455 )?;
456 conn.execute(
457 "CREATE INDEX IF NOT EXISTS idx_review_outcomes_node ON review_outcomes(node_id)",
458 [],
459 )?;
460
461 conn.execute(
463 "CREATE SEQUENCE IF NOT EXISTS seq_verification_results_id START 1",
464 [],
465 )?;
466
467 conn.execute(
468 r#"
469 CREATE TABLE IF NOT EXISTS verification_results (
470 id INTEGER PRIMARY KEY DEFAULT nextval('seq_verification_results_id'),
471 session_id VARCHAR NOT NULL,
472 node_id VARCHAR NOT NULL,
473 result_json TEXT NOT NULL,
474 syntax_ok BOOLEAN NOT NULL DEFAULT false,
475 build_ok BOOLEAN NOT NULL DEFAULT false,
476 tests_ok BOOLEAN NOT NULL DEFAULT false,
477 lint_ok BOOLEAN NOT NULL DEFAULT false,
478 diagnostics_count INTEGER DEFAULT 0,
479 tests_passed INTEGER DEFAULT 0,
480 tests_failed INTEGER DEFAULT 0,
481 degraded BOOLEAN NOT NULL DEFAULT false,
482 degraded_reason VARCHAR,
483 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
484 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
485 )
486 "#,
487 [],
488 )?;
489 conn.execute(
490 "CREATE INDEX IF NOT EXISTS idx_verification_results_session ON verification_results(session_id)",
491 [],
492 )?;
493 conn.execute(
494 "CREATE INDEX IF NOT EXISTS idx_verification_results_node ON verification_results(node_id)",
495 [],
496 )?;
497
498 conn.execute(
500 "CREATE SEQUENCE IF NOT EXISTS seq_artifact_bundles_id START 1",
501 [],
502 )?;
503
504 conn.execute(
505 r#"
506 CREATE TABLE IF NOT EXISTS artifact_bundles (
507 id INTEGER PRIMARY KEY DEFAULT nextval('seq_artifact_bundles_id'),
508 session_id VARCHAR NOT NULL,
509 node_id VARCHAR NOT NULL,
510 bundle_json TEXT NOT NULL,
511 artifact_count INTEGER DEFAULT 0,
512 command_count INTEGER DEFAULT 0,
513 touched_files TEXT,
514 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
515 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
516 )
517 "#,
518 [],
519 )?;
520 conn.execute(
521 "CREATE INDEX IF NOT EXISTS idx_artifact_bundles_session ON artifact_bundles(session_id)",
522 [],
523 )?;
524 conn.execute(
525 "CREATE INDEX IF NOT EXISTS idx_artifact_bundles_node ON artifact_bundles(node_id)",
526 [],
527 )?;
528
529 conn.execute(
535 r#"
536 CREATE TABLE IF NOT EXISTS feature_charters (
537 charter_id VARCHAR PRIMARY KEY,
538 session_id VARCHAR NOT NULL,
539 scope_description TEXT NOT NULL,
540 max_modules INTEGER,
541 max_files INTEGER,
542 max_revisions INTEGER,
543 language_constraint VARCHAR,
544 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
545 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
546 )
547 "#,
548 [],
549 )?;
550 conn.execute(
551 "CREATE INDEX IF NOT EXISTS idx_feature_charters_session ON feature_charters(session_id)",
552 [],
553 )?;
554
555 conn.execute(
557 r#"
558 CREATE TABLE IF NOT EXISTS plan_revisions (
559 revision_id VARCHAR PRIMARY KEY,
560 session_id VARCHAR NOT NULL,
561 sequence INTEGER NOT NULL,
562 plan_json TEXT NOT NULL,
563 reason VARCHAR NOT NULL,
564 supersedes VARCHAR,
565 status VARCHAR NOT NULL DEFAULT 'active',
566 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
567 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
568 )
569 "#,
570 [],
571 )?;
572 conn.execute(
573 "CREATE INDEX IF NOT EXISTS idx_plan_revisions_session ON plan_revisions(session_id)",
574 [],
575 )?;
576 conn.execute(
577 "CREATE INDEX IF NOT EXISTS idx_plan_revisions_status ON plan_revisions(status)",
578 [],
579 )?;
580
581 conn.execute(
583 "CREATE SEQUENCE IF NOT EXISTS seq_repair_footprints_id START 1",
584 [],
585 )?;
586 conn.execute(
587 r#"
588 CREATE TABLE IF NOT EXISTS repair_footprints (
589 id INTEGER PRIMARY KEY DEFAULT nextval('seq_repair_footprints_id'),
590 footprint_id VARCHAR NOT NULL UNIQUE,
591 session_id VARCHAR NOT NULL,
592 node_id VARCHAR NOT NULL,
593 revision_id VARCHAR NOT NULL,
594 attempt INTEGER NOT NULL,
595 affected_files TEXT NOT NULL,
596 bundle_json TEXT NOT NULL,
597 diagnosis TEXT NOT NULL,
598 resolved BOOLEAN NOT NULL DEFAULT false,
599 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
600 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
601 )
602 "#,
603 [],
604 )?;
605 conn.execute(
606 "CREATE INDEX IF NOT EXISTS idx_repair_footprints_session ON repair_footprints(session_id)",
607 [],
608 )?;
609 conn.execute(
610 "CREATE INDEX IF NOT EXISTS idx_repair_footprints_node ON repair_footprints(node_id)",
611 [],
612 )?;
613
614 conn.execute(
616 r#"
617 CREATE TABLE IF NOT EXISTS budget_envelopes (
618 session_id VARCHAR PRIMARY KEY,
619 max_steps INTEGER,
620 steps_used INTEGER NOT NULL DEFAULT 0,
621 max_revisions INTEGER,
622 revisions_used INTEGER NOT NULL DEFAULT 0,
623 max_cost_usd DOUBLE,
624 cost_used_usd DOUBLE NOT NULL DEFAULT 0.0,
625 updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
626 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
627 )
628 "#,
629 [],
630 )?;
631
632 conn.execute(
637 "CREATE SEQUENCE IF NOT EXISTS seq_srbn_step_records_id START 1",
638 [],
639 )?;
640 conn.execute(
641 "CREATE SEQUENCE IF NOT EXISTS seq_correction_attempts_id START 1",
642 [],
643 )?;
644
645 conn.execute(
647 r#"
648 CREATE TABLE IF NOT EXISTS srbn_step_records (
649 id INTEGER PRIMARY KEY DEFAULT nextval('seq_srbn_step_records_id'),
650 session_id VARCHAR NOT NULL,
651 node_id VARCHAR NOT NULL,
652 step VARCHAR NOT NULL,
653 outcome VARCHAR NOT NULL,
654 energy_json TEXT,
655 parse_state VARCHAR,
656 retry_classification VARCHAR,
657 attempt_count INTEGER DEFAULT 0,
658 duration_ms INTEGER DEFAULT 0,
659 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
660 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
661 )
662 "#,
663 [],
664 )?;
665 conn.execute(
666 "CREATE INDEX IF NOT EXISTS idx_srbn_step_records_session ON srbn_step_records(session_id)",
667 [],
668 )?;
669 conn.execute(
670 "CREATE INDEX IF NOT EXISTS idx_srbn_step_records_node ON srbn_step_records(session_id, node_id)",
671 [],
672 )?;
673
674 conn.execute(
676 r#"
677 CREATE TABLE IF NOT EXISTS correction_attempts (
678 id INTEGER PRIMARY KEY DEFAULT nextval('seq_correction_attempts_id'),
679 session_id VARCHAR NOT NULL,
680 node_id VARCHAR NOT NULL,
681 attempt INTEGER NOT NULL,
682 parse_state VARCHAR NOT NULL,
683 retry_classification VARCHAR,
684 response_fingerprint VARCHAR NOT NULL,
685 response_length INTEGER NOT NULL,
686 energy_json TEXT,
687 accepted BOOLEAN NOT NULL,
688 rejection_reason TEXT,
689 created_at BIGINT NOT NULL,
690 FOREIGN KEY (session_id) REFERENCES sessions(session_id)
691 )
692 "#,
693 [],
694 )?;
695 conn.execute(
696 "CREATE INDEX IF NOT EXISTS idx_correction_attempts_session ON correction_attempts(session_id)",
697 [],
698 )?;
699 conn.execute(
700 "CREATE INDEX IF NOT EXISTS idx_correction_attempts_node ON correction_attempts(session_id, node_id)",
701 [],
702 )?;
703
704 log::info!("DuckDB schema initialized successfully");
705 Ok(())
706}