videobook-engine 2.0.1 → 4.2.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 (148) hide show
  1. package/README.md +87 -41
  2. package/dist/artifact-names.d.ts +6 -0
  3. package/dist/artifact-names.d.ts.map +1 -0
  4. package/dist/artifact-names.js +56 -0
  5. package/dist/artifact-names.js.map +1 -0
  6. package/dist/artifacts.d.ts.map +1 -1
  7. package/dist/artifacts.js +57 -23
  8. package/dist/artifacts.js.map +1 -1
  9. package/dist/books.js +2 -1
  10. package/dist/books.js.map +1 -1
  11. package/dist/cas.d.ts +27 -1
  12. package/dist/cas.d.ts.map +1 -1
  13. package/dist/cas.js +78 -6
  14. package/dist/cas.js.map +1 -1
  15. package/dist/catalog-metadata.d.ts +56 -0
  16. package/dist/catalog-metadata.d.ts.map +1 -0
  17. package/dist/catalog-metadata.js +42 -0
  18. package/dist/catalog-metadata.js.map +1 -0
  19. package/dist/communications.js +4 -2
  20. package/dist/communications.js.map +1 -1
  21. package/dist/context.d.ts +6 -1
  22. package/dist/context.d.ts.map +1 -1
  23. package/dist/context.js +35 -6
  24. package/dist/context.js.map +1 -1
  25. package/dist/domain.d.ts +4 -0
  26. package/dist/domain.d.ts.map +1 -1
  27. package/dist/domain.js +870 -58
  28. package/dist/domain.js.map +1 -1
  29. package/dist/edit-policy.d.ts +3 -0
  30. package/dist/edit-policy.d.ts.map +1 -0
  31. package/dist/edit-policy.js +6 -0
  32. package/dist/edit-policy.js.map +1 -0
  33. package/dist/edits.d.ts +10 -0
  34. package/dist/edits.d.ts.map +1 -0
  35. package/dist/edits.js +1392 -0
  36. package/dist/edits.js.map +1 -0
  37. package/dist/engine-types.d.ts +110 -60
  38. package/dist/engine-types.d.ts.map +1 -1
  39. package/dist/engine-types.js +33 -0
  40. package/dist/engine-types.js.map +1 -1
  41. package/dist/engine.d.ts +69 -8
  42. package/dist/engine.d.ts.map +1 -1
  43. package/dist/engine.js +24 -18
  44. package/dist/engine.js.map +1 -1
  45. package/dist/files.d.ts.map +1 -1
  46. package/dist/files.js +31 -27
  47. package/dist/files.js.map +1 -1
  48. package/dist/fork.d.ts +147 -0
  49. package/dist/fork.d.ts.map +1 -0
  50. package/dist/fork.js +609 -0
  51. package/dist/fork.js.map +1 -0
  52. package/dist/history.d.ts +0 -4
  53. package/dist/history.d.ts.map +1 -1
  54. package/dist/history.js +166 -595
  55. package/dist/history.js.map +1 -1
  56. package/dist/index.d.ts +16 -4
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +12 -2
  59. package/dist/index.js.map +1 -1
  60. package/dist/job-queue.d.ts +2 -0
  61. package/dist/job-queue.d.ts.map +1 -1
  62. package/dist/job-queue.js +29 -2
  63. package/dist/job-queue.js.map +1 -1
  64. package/dist/media.d.ts.map +1 -1
  65. package/dist/media.js +1 -0
  66. package/dist/media.js.map +1 -1
  67. package/dist/merge-policy.d.ts +99 -0
  68. package/dist/merge-policy.d.ts.map +1 -0
  69. package/dist/merge-policy.js +310 -0
  70. package/dist/merge-policy.js.map +1 -0
  71. package/dist/metadata.d.ts.map +1 -1
  72. package/dist/metadata.js +15 -20
  73. package/dist/metadata.js.map +1 -1
  74. package/dist/migration.d.ts +9 -0
  75. package/dist/migration.d.ts.map +1 -0
  76. package/dist/migration.js +534 -0
  77. package/dist/migration.js.map +1 -0
  78. package/dist/mvp-contract-fixtures.d.ts +244 -0
  79. package/dist/mvp-contract-fixtures.d.ts.map +1 -0
  80. package/dist/mvp-contract-fixtures.js +556 -0
  81. package/dist/mvp-contract-fixtures.js.map +1 -0
  82. package/dist/mvp-contracts.d.ts +761 -0
  83. package/dist/mvp-contracts.d.ts.map +1 -0
  84. package/dist/mvp-contracts.js +59 -0
  85. package/dist/mvp-contracts.js.map +1 -0
  86. package/dist/mvp-time.d.ts +54 -0
  87. package/dist/mvp-time.d.ts.map +1 -0
  88. package/dist/mvp-time.js +148 -0
  89. package/dist/mvp-time.js.map +1 -0
  90. package/dist/notebook/types.d.ts +113 -8
  91. package/dist/notebook/types.d.ts.map +1 -1
  92. package/dist/order-keys.d.ts +22 -0
  93. package/dist/order-keys.d.ts.map +1 -0
  94. package/dist/order-keys.js +262 -0
  95. package/dist/order-keys.js.map +1 -0
  96. package/dist/runtime-services.js +4 -2
  97. package/dist/runtime-services.js.map +1 -1
  98. package/dist/schema.d.ts +24 -5
  99. package/dist/schema.d.ts.map +1 -1
  100. package/dist/schema.js +644 -132
  101. package/dist/schema.js.map +1 -1
  102. package/dist/search-benchmark.d.ts +4 -0
  103. package/dist/search-benchmark.d.ts.map +1 -0
  104. package/dist/search-benchmark.js +144 -0
  105. package/dist/search-benchmark.js.map +1 -0
  106. package/dist/sequences.d.ts +20 -0
  107. package/dist/sequences.d.ts.map +1 -0
  108. package/dist/sequences.js +825 -0
  109. package/dist/sequences.js.map +1 -0
  110. package/dist/similarity.js +1 -1
  111. package/dist/storage.d.ts +3 -1
  112. package/dist/storage.d.ts.map +1 -1
  113. package/dist/storage.js +388 -7
  114. package/dist/storage.js.map +1 -1
  115. package/dist/store.d.ts +63 -2
  116. package/dist/store.d.ts.map +1 -1
  117. package/dist/store.js +351 -65
  118. package/dist/store.js.map +1 -1
  119. package/dist/streams.d.ts +10 -0
  120. package/dist/streams.d.ts.map +1 -0
  121. package/dist/streams.js +183 -0
  122. package/dist/streams.js.map +1 -0
  123. package/dist/temporal-models.d.ts +48 -0
  124. package/dist/temporal-models.d.ts.map +1 -0
  125. package/dist/temporal-models.js +278 -0
  126. package/dist/temporal-models.js.map +1 -0
  127. package/dist/temporal-search.d.ts +29 -0
  128. package/dist/temporal-search.d.ts.map +1 -0
  129. package/dist/temporal-search.js +1507 -0
  130. package/dist/temporal-search.js.map +1 -0
  131. package/dist/transcripts.d.ts +16 -0
  132. package/dist/transcripts.d.ts.map +1 -0
  133. package/dist/transcripts.js +519 -0
  134. package/dist/transcripts.js.map +1 -0
  135. package/docs/engine-layout.md +346 -106
  136. package/docs/mvp-prd.md +918 -0
  137. package/fixtures/media/vancat.mp4 +0 -0
  138. package/fixtures/media/vancat_profile.jpg +0 -0
  139. package/fixtures/v5/contract-fixtures.json +1532 -0
  140. package/package.json +30 -5
  141. package/dist/history-types.d.ts +0 -74
  142. package/dist/history-types.d.ts.map +0 -1
  143. package/dist/history-types.js +0 -2
  144. package/dist/history-types.js.map +0 -1
  145. package/dist/timeline.d.ts +0 -9
  146. package/dist/timeline.d.ts.map +0 -1
  147. package/dist/timeline.js +0 -236
  148. package/dist/timeline.js.map +0 -1
package/dist/schema.js CHANGED
@@ -1,34 +1,85 @@
1
- export const SCHEMA_VERSION = 4;
1
+ export { SCHEMA_VERSION } from "./catalog-metadata.js";
2
+ export const NOTEBOOK_CELL_TYPES = [
3
+ "audio",
4
+ "image",
5
+ "video",
6
+ "extract_audio",
7
+ "split_video",
8
+ "prompt",
9
+ "character",
10
+ "analyze",
11
+ "analysis",
12
+ "generate_video",
13
+ "generate_image",
14
+ "generate_audio",
15
+ "concat",
16
+ "splice",
17
+ ];
18
+ export const NOTEBOOK_CELL_SLUG_PREFIXES = {
19
+ audio: "aud",
20
+ image: "img",
21
+ video: "vid",
22
+ extract_audio: "extract-audio",
23
+ split_video: "split-video",
24
+ prompt: "prompt",
25
+ character: "char",
26
+ analyze: "analyze",
27
+ analysis: "analysis",
28
+ generate_video: "generate-video",
29
+ generate_image: "generate-image",
30
+ generate_audio: "generate-audio",
31
+ concat: "concat",
32
+ splice: "splice",
33
+ };
34
+ const NOTEBOOK_CELL_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)+$/;
35
+ export function isValidNotebookCellSlug(type, slug) {
36
+ return NOTEBOOK_CELL_SLUG_PATTERN.test(slug)
37
+ && slug.startsWith(`${NOTEBOOK_CELL_SLUG_PREFIXES[type]}-`);
38
+ }
39
+ // The staging allowlist is also the restore table list: history.restore
40
+ // reloads every table below from its dolt_at_* projection, deleting in
41
+ // reverse order and inserting in forward order. Keep the list ordered
42
+ // parent-before-child so the mechanical reload satisfies foreign keys.
2
43
  export const SEMANTIC_TABLES = [
3
44
  "engine_schema",
4
45
  "book",
5
46
  "artifacts",
6
47
  "objects",
7
48
  "artifact_files",
49
+ "artifact_streams",
8
50
  "book_metadata",
9
51
  "artifact_metadata",
10
52
  "entities",
11
53
  "notebooks",
54
+ "notebook_fields",
12
55
  "cells",
56
+ "notebook_cell_executions",
57
+ "notebook_generation_plans",
58
+ "notebook_run_plans",
59
+ "notebook_transcript_edits",
60
+ "notebook_transcript_attachments",
13
61
  "edges",
14
62
  "runs",
15
- "timeline",
16
- "timeline_slots",
17
- "timeline_audio",
63
+ "cell_references",
64
+ "pinned_search_results",
65
+ "transcripts",
66
+ "transcript_segments",
67
+ "transcript_words",
68
+ "sequences",
69
+ "sequence_tracks",
70
+ "sequence_clips",
71
+ "clip_links",
72
+ "clip_transforms",
73
+ "transitions",
74
+ "caption_cues",
18
75
  "audio_waveforms",
19
76
  "prompt_entries",
20
77
  "messages",
21
- "operations",
22
- "actions",
23
- "action_events",
24
- "action_parents",
25
- "action_artifacts",
26
- "action_write_set",
27
- "job_runs",
28
78
  ];
29
79
  export const RUNTIME_TABLES = [
30
80
  "runtime_meta",
31
81
  "runtime_jobs",
82
+ "job_runs",
32
83
  "runtime_resource_leases",
33
84
  "runtime_object_publications",
34
85
  "runtime_workspace_entries",
@@ -38,6 +89,14 @@ export const RUNTIME_TABLES = [
38
89
  "runtime_settings",
39
90
  "runtime_logs",
40
91
  "runtime_commit_outbox",
92
+ "runtime_index_manifests",
93
+ "runtime_index_generations",
94
+ "runtime_index_coverage",
95
+ "runtime_media_segments",
96
+ "runtime_segment_text",
97
+ "runtime_segment_embeddings",
98
+ "runtime_segment_fingerprints",
99
+ "runtime_index_batches",
41
100
  "runtime_similarity_embeddings",
42
101
  "runtime_text_similarity_documents",
43
102
  "runtime_text_similarity_chunks",
@@ -69,7 +128,8 @@ export const SEMANTIC_SCHEMA_SQL = `
69
128
  CREATE TABLE IF NOT EXISTS objects (
70
129
  object_hash TEXT PRIMARY KEY,
71
130
  size_bytes INTEGER NOT NULL CHECK (size_bytes >= 0),
72
- created_at INTEGER NOT NULL
131
+ created_at INTEGER NOT NULL,
132
+ forgotten_at INTEGER
73
133
  );
74
134
 
75
135
  CREATE TABLE IF NOT EXISTS artifact_files (
@@ -78,10 +138,28 @@ export const SEMANTIC_SCHEMA_SQL = `
78
138
  path TEXT NOT NULL,
79
139
  object_hash TEXT NOT NULL
80
140
  REFERENCES objects(object_hash) ON DELETE RESTRICT,
81
- mtime_ms INTEGER NOT NULL,
82
141
  created_at INTEGER NOT NULL,
83
142
  PRIMARY KEY(artifact_id, path)
84
143
  );
144
+ CREATE TABLE IF NOT EXISTS artifact_streams (
145
+ stream_id TEXT PRIMARY KEY,
146
+ artifact_id TEXT NOT NULL
147
+ REFERENCES artifacts(artifact_id) ON DELETE RESTRICT,
148
+ source_path TEXT NOT NULL,
149
+ object_hash TEXT NOT NULL
150
+ REFERENCES objects(object_hash) ON DELETE RESTRICT,
151
+ stream_index INTEGER NOT NULL CHECK (stream_index >= 0),
152
+ kind TEXT NOT NULL CHECK (kind IN ('video','audio')),
153
+ time_base_numerator INTEGER NOT NULL CHECK (time_base_numerator > 0),
154
+ time_base_denominator INTEGER NOT NULL CHECK (time_base_denominator > 0),
155
+ duration_ticks INTEGER NOT NULL CHECK (duration_ticks > 0),
156
+ codec TEXT NOT NULL,
157
+ profile_json TEXT NOT NULL DEFAULT '{}',
158
+ created_at INTEGER NOT NULL,
159
+ UNIQUE(artifact_id, source_path, object_hash, stream_index),
160
+ FOREIGN KEY(artifact_id, source_path)
161
+ REFERENCES artifact_files(artifact_id, path) ON DELETE RESTRICT
162
+ );
85
163
  CREATE TABLE IF NOT EXISTS book_metadata (
86
164
  key TEXT PRIMARY KEY,
87
165
  value_json TEXT NOT NULL
@@ -107,27 +185,138 @@ export const SEMANTIC_SCHEMA_SQL = `
107
185
  CREATE TABLE IF NOT EXISTS notebooks (
108
186
  notebook_id TEXT PRIMARY KEY,
109
187
  name TEXT NOT NULL,
110
- properties_json TEXT NOT NULL DEFAULT '{}',
111
188
  created_at INTEGER NOT NULL
112
189
  );
190
+ CREATE TABLE IF NOT EXISTS notebook_fields (
191
+ notebook_id TEXT NOT NULL
192
+ REFERENCES notebooks(notebook_id) ON DELETE CASCADE,
193
+ field TEXT NOT NULL CHECK (
194
+ field IN (
195
+ 'description','lifecycle_state','workflow_version',
196
+ 'analysis_revision','audio_spine','current_selection','fixture'
197
+ )
198
+ ),
199
+ value_json TEXT NOT NULL,
200
+ PRIMARY KEY(notebook_id, field)
201
+ );
113
202
  CREATE TABLE IF NOT EXISTS cells (
114
203
  notebook_id TEXT NOT NULL
115
204
  REFERENCES notebooks(notebook_id) ON DELETE CASCADE,
116
205
  cell_id TEXT NOT NULL,
117
206
  type TEXT NOT NULL CHECK (
118
- type IN ('prompt','character','scene','asset','image','video')
207
+ type IN (
208
+ 'audio','image','video','extract_audio','split_video',
209
+ 'prompt','character',
210
+ 'analyze','analysis','generate_video','generate_image','generate_audio',
211
+ 'concat','splice'
212
+ )
119
213
  ),
120
- title TEXT NOT NULL,
121
- position_x REAL NOT NULL,
122
- position_y REAL NOT NULL,
123
- entity_id TEXT
214
+ slug TEXT NOT NULL CHECK (
215
+ slug GLOB '[a-z0-9]*'
216
+ AND slug NOT GLOB '*[^a-z0-9-]*'
217
+ AND slug NOT GLOB '*--*'
218
+ AND slug NOT LIKE '-%'
219
+ AND slug NOT LIKE '%-'
220
+ AND instr(slug, '-') > 0
221
+ ),
222
+ grid_row INTEGER NOT NULL CHECK (grid_row >= 0),
223
+ grid_column INTEGER NOT NULL,
224
+ output_entity_id TEXT
124
225
  REFERENCES entities(entity_id) ON DELETE RESTRICT,
125
226
  prompt TEXT,
227
+ provider TEXT,
126
228
  model TEXT,
229
+ operation TEXT,
230
+ tool TEXT,
127
231
  inputs_json TEXT NOT NULL DEFAULT '{}',
128
232
  output_artifact_id TEXT
129
233
  REFERENCES artifacts(artifact_id) ON DELETE RESTRICT,
130
- PRIMARY KEY(notebook_id, cell_id)
234
+ PRIMARY KEY(notebook_id, cell_id),
235
+ UNIQUE(notebook_id, slug),
236
+ CHECK (
237
+ (type = 'audio' AND slug LIKE 'aud-%')
238
+ OR (type = 'image' AND slug LIKE 'img-%')
239
+ OR (type = 'video' AND slug LIKE 'vid-%')
240
+ OR (type = 'extract_audio' AND slug LIKE 'extract-audio-%')
241
+ OR (type = 'split_video' AND slug LIKE 'split-video-%')
242
+ OR (type = 'prompt' AND slug LIKE 'prompt-%')
243
+ OR (type = 'character' AND slug LIKE 'char-%')
244
+ OR (type = 'analyze' AND slug LIKE 'analyze-%')
245
+ OR (type = 'analysis' AND slug LIKE 'analysis-%')
246
+ OR (type = 'generate_video' AND slug LIKE 'generate-video-%')
247
+ OR (type = 'generate_image' AND slug LIKE 'generate-image-%')
248
+ OR (type = 'generate_audio' AND slug LIKE 'generate-audio-%')
249
+ OR (type = 'concat' AND slug LIKE 'concat-%')
250
+ OR (type = 'splice' AND slug LIKE 'splice-%')
251
+ )
252
+ );
253
+ CREATE TABLE IF NOT EXISTS notebook_cell_executions (
254
+ notebook_id TEXT NOT NULL,
255
+ cell_id TEXT NOT NULL,
256
+ fingerprint TEXT,
257
+ status TEXT,
258
+ output_artifact_id TEXT,
259
+ provider_artifact_id TEXT,
260
+ run_id TEXT,
261
+ completed_at TEXT,
262
+ started_at TEXT,
263
+ updated_at TEXT,
264
+ tool TEXT,
265
+ error TEXT,
266
+ stale INTEGER NOT NULL DEFAULT 0 CHECK (stale IN (0, 1)),
267
+ fixture_baseline INTEGER NOT NULL DEFAULT 0
268
+ CHECK (fixture_baseline IN (0, 1)),
269
+ PRIMARY KEY(notebook_id, cell_id),
270
+ FOREIGN KEY(notebook_id, cell_id)
271
+ REFERENCES cells(notebook_id, cell_id) ON DELETE CASCADE
272
+ );
273
+ CREATE TABLE IF NOT EXISTS notebook_generation_plans (
274
+ notebook_id TEXT NOT NULL
275
+ REFERENCES notebooks(notebook_id) ON DELETE CASCADE,
276
+ plan_id TEXT NOT NULL,
277
+ cell_id TEXT NOT NULL,
278
+ status TEXT NOT NULL,
279
+ plan_json TEXT NOT NULL,
280
+ output_artifact_id TEXT,
281
+ error TEXT,
282
+ created_at TEXT NOT NULL,
283
+ updated_at TEXT NOT NULL,
284
+ PRIMARY KEY(notebook_id, plan_id),
285
+ FOREIGN KEY(notebook_id, cell_id)
286
+ REFERENCES cells(notebook_id, cell_id) ON DELETE CASCADE
287
+ );
288
+ CREATE TABLE IF NOT EXISTS notebook_run_plans (
289
+ notebook_id TEXT NOT NULL
290
+ REFERENCES notebooks(notebook_id) ON DELETE CASCADE,
291
+ plan_id TEXT NOT NULL,
292
+ status TEXT NOT NULL,
293
+ plan_json TEXT NOT NULL,
294
+ paid_cell_ids_json TEXT NOT NULL,
295
+ cell_fingerprints_json TEXT NOT NULL,
296
+ known_cost_usd REAL NOT NULL CHECK (known_cost_usd >= 0),
297
+ unknown_cost_count INTEGER NOT NULL CHECK (unknown_cost_count >= 0),
298
+ created_at TEXT NOT NULL,
299
+ updated_at TEXT NOT NULL,
300
+ run_id TEXT,
301
+ outputs_json TEXT,
302
+ error TEXT,
303
+ PRIMARY KEY(notebook_id, plan_id)
304
+ );
305
+ CREATE TABLE IF NOT EXISTS notebook_transcript_edits (
306
+ notebook_id TEXT NOT NULL
307
+ REFERENCES notebooks(notebook_id) ON DELETE CASCADE,
308
+ action_id TEXT NOT NULL,
309
+ kind TEXT NOT NULL,
310
+ restored INTEGER NOT NULL DEFAULT 0 CHECK (restored IN (0, 1)),
311
+ payload_json TEXT NOT NULL,
312
+ PRIMARY KEY(notebook_id, action_id)
313
+ );
314
+ CREATE TABLE IF NOT EXISTS notebook_transcript_attachments (
315
+ notebook_id TEXT NOT NULL
316
+ REFERENCES notebooks(notebook_id) ON DELETE CASCADE,
317
+ attachment_id TEXT NOT NULL,
318
+ payload_json TEXT NOT NULL,
319
+ PRIMARY KEY(notebook_id, attachment_id)
131
320
  );
132
321
  CREATE TABLE IF NOT EXISTS edges (
133
322
  notebook_id TEXT NOT NULL
@@ -140,7 +329,8 @@ export const SEMANTIC_SCHEMA_SQL = `
140
329
  FOREIGN KEY(notebook_id, source_cell_id)
141
330
  REFERENCES cells(notebook_id, cell_id) ON DELETE CASCADE,
142
331
  FOREIGN KEY(notebook_id, target_cell_id)
143
- REFERENCES cells(notebook_id, cell_id) ON DELETE CASCADE
332
+ REFERENCES cells(notebook_id, cell_id) ON DELETE CASCADE,
333
+ UNIQUE(notebook_id, target_cell_id, target_input)
144
334
  );
145
335
  CREATE TABLE IF NOT EXISTS runs (
146
336
  run_id TEXT PRIMARY KEY,
@@ -153,32 +343,276 @@ export const SEMANTIC_SCHEMA_SQL = `
153
343
  outputs_json TEXT NOT NULL,
154
344
  error TEXT
155
345
  );
156
- CREATE TABLE IF NOT EXISTS timeline (
157
- book_id TEXT PRIMARY KEY
158
- REFERENCES book(book_id) ON DELETE CASCADE,
159
- render TEXT NOT NULL DEFAULT 'landscape'
160
- CHECK (render IN ('landscape','portrait','square'))
346
+ CREATE TABLE IF NOT EXISTS cell_references (
347
+ notebook_id TEXT NOT NULL,
348
+ cell_id TEXT NOT NULL,
349
+ reference_id TEXT NOT NULL,
350
+ kind TEXT NOT NULL CHECK (
351
+ kind IN (
352
+ 'artifact','stream','source-range','transcript',
353
+ 'sequence','cell-output'
354
+ )
355
+ ),
356
+ target_id TEXT NOT NULL,
357
+ snapshot_json TEXT NOT NULL DEFAULT '{}',
358
+ ordinal INTEGER NOT NULL CHECK (ordinal >= 0),
359
+ PRIMARY KEY(notebook_id, cell_id, reference_id),
360
+ FOREIGN KEY(notebook_id, cell_id)
361
+ REFERENCES cells(notebook_id, cell_id) ON DELETE CASCADE
161
362
  );
162
-
163
- CREATE TABLE IF NOT EXISTS timeline_slots (
164
- slot_id TEXT PRIMARY KEY,
363
+ CREATE TABLE IF NOT EXISTS pinned_search_results (
364
+ notebook_id TEXT NOT NULL,
365
+ cell_id TEXT NOT NULL,
366
+ result_id TEXT NOT NULL,
165
367
  artifact_id TEXT NOT NULL
166
368
  REFERENCES artifacts(artifact_id) ON DELETE RESTRICT,
369
+ object_hash TEXT NOT NULL
370
+ REFERENCES objects(object_hash) ON DELETE RESTRICT,
371
+ location_json TEXT NOT NULL,
372
+ representative_json TEXT,
373
+ query_json TEXT NOT NULL,
374
+ signals_json TEXT NOT NULL,
375
+ selected_revision TEXT NOT NULL,
167
376
  ordinal INTEGER NOT NULL CHECK (ordinal >= 0),
168
- volume REAL CHECK (volume IS NULL OR volume >= 0),
169
- audio_fade_in REAL CHECK (audio_fade_in IS NULL OR audio_fade_in >= 0),
170
- audio_fade_out REAL CHECK (audio_fade_out IS NULL OR audio_fade_out >= 0)
377
+ created_at INTEGER NOT NULL,
378
+ PRIMARY KEY(notebook_id, cell_id, result_id),
379
+ FOREIGN KEY(notebook_id, cell_id)
380
+ REFERENCES cells(notebook_id, cell_id) ON DELETE CASCADE
171
381
  );
172
- CREATE TABLE IF NOT EXISTS timeline_audio (
173
- audio_id TEXT PRIMARY KEY,
382
+ CREATE TABLE IF NOT EXISTS transcripts (
383
+ transcript_id TEXT PRIMARY KEY,
174
384
  artifact_id TEXT NOT NULL
175
385
  REFERENCES artifacts(artifact_id) ON DELETE RESTRICT,
386
+ stream_id TEXT NOT NULL
387
+ REFERENCES artifact_streams(stream_id) ON DELETE RESTRICT,
388
+ object_hash TEXT NOT NULL
389
+ REFERENCES objects(object_hash) ON DELETE RESTRICT,
390
+ payload_hash TEXT NOT NULL
391
+ REFERENCES objects(object_hash) ON DELETE RESTRICT,
392
+ language TEXT NOT NULL,
393
+ provider TEXT,
394
+ model TEXT,
395
+ state TEXT NOT NULL CHECK (state IN ('current','derived')),
396
+ created_at INTEGER NOT NULL
397
+ );
398
+ CREATE INDEX IF NOT EXISTS transcripts_current
399
+ ON transcripts(artifact_id, stream_id, object_hash, state);
400
+ CREATE TABLE IF NOT EXISTS transcript_segments (
401
+ segment_id TEXT PRIMARY KEY,
402
+ transcript_id TEXT NOT NULL
403
+ REFERENCES transcripts(transcript_id) ON DELETE CASCADE,
404
+ ordinal INTEGER NOT NULL CHECK (ordinal >= 0),
405
+ start_tick INTEGER NOT NULL CHECK (start_tick >= 0),
406
+ duration_ticks INTEGER NOT NULL CHECK (duration_ticks > 0),
407
+ speaker TEXT,
408
+ confidence REAL CHECK (
409
+ confidence IS NULL OR (confidence >= 0 AND confidence <= 1)
410
+ ),
411
+ kind TEXT NOT NULL CHECK (
412
+ kind IN ('speech','music','sound','silence','other')
413
+ ),
414
+ UNIQUE(transcript_id, ordinal)
415
+ );
416
+ CREATE TABLE IF NOT EXISTS transcript_words (
417
+ word_id TEXT PRIMARY KEY,
418
+ segment_id TEXT NOT NULL
419
+ REFERENCES transcript_segments(segment_id) ON DELETE CASCADE,
176
420
  ordinal INTEGER NOT NULL CHECK (ordinal >= 0),
177
- start_frame INTEGER NOT NULL CHECK (start_frame >= 0),
421
+ start_tick INTEGER NOT NULL CHECK (start_tick >= 0),
422
+ duration_ticks INTEGER NOT NULL CHECK (duration_ticks > 0),
423
+ confidence REAL CHECK (
424
+ confidence IS NULL OR (confidence >= 0 AND confidence <= 1)
425
+ ),
426
+ corrected INTEGER NOT NULL DEFAULT 0 CHECK (corrected IN (0,1)),
427
+ UNIQUE(segment_id, ordinal)
428
+ );
429
+ CREATE TABLE IF NOT EXISTS sequences (
430
+ sequence_id TEXT PRIMARY KEY,
431
+ book_id TEXT NOT NULL
432
+ REFERENCES book(book_id) ON DELETE CASCADE,
433
+ name TEXT NOT NULL,
434
+ is_primary INTEGER NOT NULL DEFAULT 0 CHECK (is_primary IN (0,1)),
435
+ width INTEGER NOT NULL CHECK (width > 0),
436
+ height INTEGER NOT NULL CHECK (height > 0),
437
+ pixel_aspect_numerator INTEGER NOT NULL
438
+ CHECK (pixel_aspect_numerator > 0),
439
+ pixel_aspect_denominator INTEGER NOT NULL
440
+ CHECK (pixel_aspect_denominator > 0),
441
+ frame_rate_numerator INTEGER NOT NULL
442
+ CHECK (frame_rate_numerator > 0),
443
+ frame_rate_denominator INTEGER NOT NULL
444
+ CHECK (frame_rate_denominator > 0),
445
+ audio_sample_rate_hz INTEGER NOT NULL CHECK (audio_sample_rate_hz > 0),
446
+ audio_channel_layout TEXT NOT NULL,
447
+ background_rgba_json TEXT NOT NULL,
448
+ created_at INTEGER NOT NULL
449
+ );
450
+ CREATE INDEX IF NOT EXISTS sequences_primary
451
+ ON sequences(book_id, is_primary);
452
+ CREATE TABLE IF NOT EXISTS sequence_tracks (
453
+ track_id TEXT PRIMARY KEY,
454
+ sequence_id TEXT NOT NULL
455
+ REFERENCES sequences(sequence_id) ON DELETE CASCADE,
456
+ kind TEXT NOT NULL CHECK (kind IN ('video','audio','caption')),
457
+ order_key TEXT NOT NULL,
458
+ name TEXT NOT NULL,
459
+ enabled INTEGER NOT NULL DEFAULT 1 CHECK (enabled IN (0,1)),
460
+ locked INTEGER NOT NULL DEFAULT 0 CHECK (locked IN (0,1)),
461
+ muted INTEGER CHECK (muted IS NULL OR muted IN (0,1)),
462
+ solo INTEGER CHECK (solo IS NULL OR solo IN (0,1)),
463
+ blend_mode TEXT,
464
+ CHECK (
465
+ (kind = 'audio' AND muted IS NOT NULL AND solo IS NOT NULL)
466
+ OR (kind <> 'audio' AND muted IS NULL AND solo IS NULL)
467
+ ),
468
+ CHECK (
469
+ (kind = 'video' AND blend_mode = 'normal')
470
+ OR (kind <> 'video' AND blend_mode IS NULL)
471
+ )
472
+ );
473
+ CREATE TABLE IF NOT EXISTS sequence_clips (
474
+ clip_id TEXT PRIMARY KEY,
475
+ track_id TEXT NOT NULL
476
+ REFERENCES sequence_tracks(track_id) ON DELETE CASCADE,
477
+ source_kind TEXT NOT NULL CHECK (source_kind IN ('still','timed')),
478
+ artifact_id TEXT NOT NULL
479
+ REFERENCES artifacts(artifact_id) ON DELETE RESTRICT,
480
+ source_path TEXT,
481
+ stream_id TEXT
482
+ REFERENCES artifact_streams(stream_id) ON DELETE RESTRICT,
483
+ object_hash TEXT NOT NULL
484
+ REFERENCES objects(object_hash) ON DELETE RESTRICT,
485
+ source_start_tick INTEGER,
486
+ source_duration_ticks INTEGER,
487
+ time_base_numerator INTEGER,
488
+ time_base_denominator INTEGER,
489
+ timeline_start_frame INTEGER NOT NULL CHECK (timeline_start_frame >= 0),
490
+ duration_frames INTEGER NOT NULL CHECK (duration_frames > 0),
491
+ speed_numerator INTEGER,
492
+ speed_denominator INTEGER,
493
+ reverse INTEGER,
494
+ audio_policy TEXT,
495
+ gain_db REAL,
496
+ audio_muted INTEGER CHECK (audio_muted IS NULL OR audio_muted IN (0,1)),
497
+ fade_in_frames INTEGER CHECK (fade_in_frames IS NULL OR fade_in_frames >= 0),
498
+ fade_out_frames INTEGER CHECK (fade_out_frames IS NULL OR fade_out_frames >= 0),
499
+ enabled INTEGER NOT NULL DEFAULT 1 CHECK (enabled IN (0,1)),
500
+ CHECK (
501
+ (
502
+ source_kind = 'still'
503
+ AND source_path IS NOT NULL
504
+ AND stream_id IS NULL
505
+ AND source_start_tick IS NULL
506
+ AND source_duration_ticks IS NULL
507
+ AND time_base_numerator IS NULL
508
+ AND time_base_denominator IS NULL
509
+ AND speed_numerator IS NULL
510
+ AND speed_denominator IS NULL
511
+ AND reverse IS NULL
512
+ AND audio_policy IS NULL
513
+ )
514
+ OR
515
+ (
516
+ source_kind = 'timed'
517
+ AND source_path IS NULL
518
+ AND stream_id IS NOT NULL
519
+ AND source_start_tick >= 0
520
+ AND source_duration_ticks > 0
521
+ AND time_base_numerator > 0
522
+ AND time_base_denominator > 0
523
+ AND speed_numerator > 0
524
+ AND speed_denominator > 0
525
+ AND reverse IN (0,1)
526
+ AND audio_policy IN ('preserve-pitch','resample','mute')
527
+ )
528
+ ),
529
+ CHECK (
530
+ (
531
+ gain_db IS NULL
532
+ AND audio_muted IS NULL
533
+ AND fade_in_frames IS NULL
534
+ AND fade_out_frames IS NULL
535
+ )
536
+ OR
537
+ (
538
+ gain_db IS NOT NULL
539
+ AND audio_muted IS NOT NULL
540
+ AND fade_in_frames IS NOT NULL
541
+ AND fade_out_frames IS NOT NULL
542
+ )
543
+ )
544
+ );
545
+ CREATE TABLE IF NOT EXISTS clip_links (
546
+ link_group_id TEXT NOT NULL,
547
+ clip_id TEXT NOT NULL UNIQUE
548
+ REFERENCES sequence_clips(clip_id) ON DELETE CASCADE,
549
+ role TEXT NOT NULL,
550
+ PRIMARY KEY(link_group_id, clip_id)
551
+ );
552
+ CREATE TABLE IF NOT EXISTS clip_transforms (
553
+ clip_id TEXT PRIMARY KEY
554
+ REFERENCES sequence_clips(clip_id) ON DELETE CASCADE,
555
+ fit TEXT NOT NULL CHECK (fit IN ('fit','fill','crop')),
556
+ position_x REAL NOT NULL,
557
+ position_y REAL NOT NULL,
558
+ scale_x REAL NOT NULL CHECK (scale_x > 0),
559
+ scale_y REAL NOT NULL CHECK (scale_y > 0),
560
+ anchor_x REAL NOT NULL,
561
+ anchor_y REAL NOT NULL,
562
+ rotation_degrees REAL NOT NULL,
563
+ crop_top REAL NOT NULL CHECK (crop_top >= 0 AND crop_top <= 1),
564
+ crop_right REAL NOT NULL CHECK (crop_right >= 0 AND crop_right <= 1),
565
+ crop_bottom REAL NOT NULL CHECK (crop_bottom >= 0 AND crop_bottom <= 1),
566
+ crop_left REAL NOT NULL CHECK (crop_left >= 0 AND crop_left <= 1),
567
+ opacity REAL NOT NULL CHECK (opacity >= 0 AND opacity <= 1),
568
+ blend_mode TEXT NOT NULL CHECK (blend_mode = 'normal')
569
+ );
570
+ CREATE TABLE IF NOT EXISTS transitions (
571
+ transition_id TEXT PRIMARY KEY,
572
+ track_id TEXT NOT NULL
573
+ REFERENCES sequence_tracks(track_id) ON DELETE CASCADE,
574
+ outgoing_clip_id TEXT NOT NULL
575
+ REFERENCES sequence_clips(clip_id) ON DELETE CASCADE,
576
+ incoming_clip_id TEXT NOT NULL
577
+ REFERENCES sequence_clips(clip_id) ON DELETE CASCADE,
578
+ kind TEXT NOT NULL CHECK (kind IN ('cut','dissolve')),
579
+ duration_frames INTEGER NOT NULL CHECK (duration_frames > 0),
580
+ alignment TEXT NOT NULL CHECK (alignment IN ('start','center','end')),
581
+ parameters_json TEXT NOT NULL DEFAULT '{}',
582
+ UNIQUE(track_id, outgoing_clip_id, incoming_clip_id)
583
+ );
584
+ CREATE TABLE IF NOT EXISTS caption_cues (
585
+ cue_id TEXT PRIMARY KEY,
586
+ track_id TEXT NOT NULL
587
+ REFERENCES sequence_tracks(track_id) ON DELETE CASCADE,
588
+ timeline_start_frame INTEGER NOT NULL CHECK (timeline_start_frame >= 0),
178
589
  duration_frames INTEGER NOT NULL CHECK (duration_frames > 0),
179
- volume REAL CHECK (volume IS NULL OR volume >= 0),
180
- fade_in REAL CHECK (fade_in IS NULL OR fade_in >= 0),
181
- fade_out REAL CHECK (fade_out IS NULL OR fade_out >= 0)
590
+ text TEXT NOT NULL,
591
+ speaker TEXT,
592
+ style_id TEXT NOT NULL,
593
+ transcript_id TEXT
594
+ REFERENCES transcripts(transcript_id) ON DELETE RESTRICT,
595
+ transcript_revision TEXT,
596
+ start_word_id TEXT,
597
+ end_word_id TEXT,
598
+ source_range_json TEXT,
599
+ CHECK (
600
+ (
601
+ transcript_id IS NULL
602
+ AND transcript_revision IS NULL
603
+ AND start_word_id IS NULL
604
+ AND end_word_id IS NULL
605
+ AND source_range_json IS NULL
606
+ )
607
+ OR
608
+ (
609
+ transcript_id IS NOT NULL
610
+ AND transcript_revision IS NOT NULL
611
+ AND start_word_id IS NOT NULL
612
+ AND end_word_id IS NOT NULL
613
+ AND source_range_json IS NOT NULL
614
+ )
615
+ )
182
616
  );
183
617
  CREATE TABLE IF NOT EXISTS audio_waveforms (
184
618
  artifact_id TEXT PRIMARY KEY
@@ -199,95 +633,27 @@ export const SEMANTIC_SCHEMA_SQL = `
199
633
  body_json TEXT NOT NULL,
200
634
  created_at INTEGER NOT NULL
201
635
  );
202
- CREATE TABLE IF NOT EXISTS operations (
203
- operation_id TEXT PRIMARY KEY,
204
- operation TEXT NOT NULL,
205
- artifact_id TEXT,
206
- details_json TEXT NOT NULL DEFAULT '{}',
207
- write_set_json TEXT NOT NULL DEFAULT '[]',
208
- base_revision TEXT,
209
- created_at INTEGER NOT NULL,
210
- author TEXT NOT NULL
211
- );
212
- CREATE TABLE IF NOT EXISTS actions (
213
- action_id TEXT PRIMARY KEY,
214
- operation TEXT NOT NULL,
215
- scope TEXT NOT NULL CHECK (
216
- scope IN ('book','artifact','layout','external','system')
217
- ),
218
- actor TEXT NOT NULL,
219
- lane TEXT NOT NULL,
220
- phase TEXT NOT NULL CHECK (
221
- phase IN (
222
- 'requested','started','completed','failed','cancelled','conflicted'
223
- )
224
- ),
225
- base_revision TEXT,
226
- target_artifact_id TEXT,
227
- target_action_id TEXT,
228
- layout_json TEXT,
229
- details_json TEXT NOT NULL DEFAULT '{}',
230
- created_at INTEGER NOT NULL
231
- );
232
-
233
- CREATE TABLE IF NOT EXISTS action_events (
234
- event_id TEXT PRIMARY KEY,
235
- action_id TEXT NOT NULL
236
- REFERENCES actions(action_id) ON DELETE CASCADE,
237
- operation_id TEXT NOT NULL,
238
- phase TEXT NOT NULL CHECK (
239
- phase IN (
240
- 'requested','started','completed','failed','cancelled','conflicted'
241
- )
242
- ),
243
- details_json TEXT NOT NULL DEFAULT '{}',
244
- created_at INTEGER NOT NULL
245
- );
246
- CREATE TABLE IF NOT EXISTS action_parents (
247
- action_id TEXT NOT NULL
248
- REFERENCES actions(action_id) ON DELETE CASCADE,
249
- parent_action_id TEXT NOT NULL
250
- REFERENCES actions(action_id) ON DELETE RESTRICT,
251
- PRIMARY KEY(action_id, parent_action_id)
252
- );
253
-
254
- CREATE TABLE IF NOT EXISTS action_artifacts (
255
- action_id TEXT NOT NULL
256
- REFERENCES actions(action_id) ON DELETE CASCADE,
257
- artifact_id TEXT NOT NULL,
258
- direction TEXT NOT NULL CHECK (direction IN ('input','output')),
259
- PRIMARY KEY(action_id, artifact_id, direction)
260
- );
261
-
262
- CREATE TABLE IF NOT EXISTS action_write_set (
263
- action_id TEXT NOT NULL
264
- REFERENCES actions(action_id) ON DELETE CASCADE,
265
- resource TEXT NOT NULL,
266
- PRIMARY KEY(action_id, resource)
267
- );
268
-
269
- CREATE TABLE IF NOT EXISTS job_runs (
270
- run_id TEXT PRIMARY KEY,
271
- artifact_id TEXT,
272
- job_type TEXT NOT NULL,
273
- state TEXT NOT NULL CHECK (state IN ('done','failed','aborted')),
274
- payload_json TEXT NOT NULL,
275
- result_json TEXT,
276
- error_json TEXT,
277
- started_at INTEGER,
278
- finished_at INTEGER NOT NULL
279
- );
280
636
 
281
637
  CREATE INDEX IF NOT EXISTS artifacts_created
282
638
  ON artifacts(created_at, artifact_id);
283
639
  CREATE INDEX IF NOT EXISTS artifact_files_object
284
640
  ON artifact_files(object_hash);
641
+ CREATE INDEX IF NOT EXISTS artifact_streams_artifact
642
+ ON artifact_streams(artifact_id, source_path, stream_index);
643
+ CREATE INDEX IF NOT EXISTS artifact_streams_object
644
+ ON artifact_streams(object_hash, stream_id);
285
645
  CREATE INDEX IF NOT EXISTS entities_type_created
286
646
  ON entities(type, created_at, entity_id);
287
647
  CREATE INDEX IF NOT EXISTS notebooks_created
288
648
  ON notebooks(created_at, notebook_id);
289
- CREATE INDEX IF NOT EXISTS cells_entity
290
- ON cells(entity_id);
649
+ CREATE INDEX IF NOT EXISTS cells_output_entity
650
+ ON cells(output_entity_id);
651
+ CREATE INDEX IF NOT EXISTS notebook_generation_plans_cell
652
+ ON notebook_generation_plans(notebook_id, cell_id, updated_at, plan_id);
653
+ CREATE INDEX IF NOT EXISTS notebook_run_plans_updated
654
+ ON notebook_run_plans(notebook_id, updated_at, plan_id);
655
+ CREATE INDEX IF NOT EXISTS cells_grid
656
+ ON cells(notebook_id, grid_row, grid_column, cell_id);
291
657
  CREATE INDEX IF NOT EXISTS cells_output_artifact
292
658
  ON cells(output_artifact_id);
293
659
  CREATE INDEX IF NOT EXISTS edges_source
@@ -296,24 +662,30 @@ export const SEMANTIC_SCHEMA_SQL = `
296
662
  ON edges(notebook_id, target_cell_id);
297
663
  CREATE INDEX IF NOT EXISTS runs_notebook_completed
298
664
  ON runs(notebook_id, completed_at, run_id);
299
- CREATE INDEX IF NOT EXISTS timeline_slots_order
300
- ON timeline_slots(ordinal, slot_id);
301
- CREATE INDEX IF NOT EXISTS timeline_slots_artifact
302
- ON timeline_slots(artifact_id);
303
- CREATE INDEX IF NOT EXISTS timeline_audio_order
304
- ON timeline_audio(ordinal, audio_id);
305
- CREATE INDEX IF NOT EXISTS timeline_audio_artifact
306
- ON timeline_audio(artifact_id);
665
+ CREATE INDEX IF NOT EXISTS cell_references_target
666
+ ON cell_references(kind, target_id);
667
+ CREATE INDEX IF NOT EXISTS pinned_search_results_artifact
668
+ ON pinned_search_results(artifact_id, created_at, result_id);
669
+ CREATE INDEX IF NOT EXISTS transcripts_artifact
670
+ ON transcripts(artifact_id, stream_id, state, created_at);
671
+ CREATE INDEX IF NOT EXISTS transcript_segments_order
672
+ ON transcript_segments(transcript_id, ordinal);
673
+ CREATE INDEX IF NOT EXISTS transcript_words_order
674
+ ON transcript_words(segment_id, ordinal);
675
+ CREATE INDEX IF NOT EXISTS sequence_tracks_order
676
+ ON sequence_tracks(sequence_id, kind, order_key);
677
+ CREATE INDEX IF NOT EXISTS sequence_clips_timeline
678
+ ON sequence_clips(track_id, timeline_start_frame, clip_id);
679
+ CREATE INDEX IF NOT EXISTS sequence_clips_artifact
680
+ ON sequence_clips(artifact_id, object_hash);
681
+ CREATE INDEX IF NOT EXISTS transitions_track
682
+ ON transitions(track_id, outgoing_clip_id, incoming_clip_id);
683
+ CREATE INDEX IF NOT EXISTS caption_cues_timeline
684
+ ON caption_cues(track_id, timeline_start_frame, cue_id);
307
685
  CREATE INDEX IF NOT EXISTS prompt_entries_lookup
308
686
  ON prompt_entries(surface, created_at, prompt_id);
309
687
  CREATE INDEX IF NOT EXISTS messages_created
310
688
  ON messages(created_at, message_id);
311
- CREATE INDEX IF NOT EXISTS operations_created
312
- ON operations(created_at, operation_id);
313
- CREATE INDEX IF NOT EXISTS operations_artifact_created
314
- ON operations(artifact_id, created_at, operation_id);
315
- CREATE INDEX IF NOT EXISTS action_events_action_created
316
- ON action_events(action_id, created_at, event_id);
317
689
  `;
318
690
  const RUNTIME_SIMILARITY_SCHEMA_SQL = `
319
691
  CREATE TABLE IF NOT EXISTS runtime_similarity_embeddings (
@@ -375,6 +747,18 @@ export const RUNTIME_SCHEMA_SQL = `
375
747
  ON runtime_jobs(type, external_task_id)
376
748
  WHERE external_task_id IS NOT NULL;
377
749
 
750
+ CREATE TABLE IF NOT EXISTS job_runs (
751
+ run_id TEXT PRIMARY KEY,
752
+ artifact_id TEXT,
753
+ job_type TEXT NOT NULL,
754
+ state TEXT NOT NULL CHECK (state IN ('done','failed','aborted')),
755
+ payload_json TEXT NOT NULL,
756
+ result_json TEXT,
757
+ error_json TEXT,
758
+ started_at INTEGER,
759
+ finished_at INTEGER NOT NULL
760
+ );
761
+
378
762
  CREATE TABLE IF NOT EXISTS runtime_resource_leases (
379
763
  lease_id TEXT PRIMARY KEY,
380
764
  artifact_id TEXT,
@@ -463,6 +847,134 @@ export const RUNTIME_SCHEMA_SQL = `
463
847
  created_at INTEGER NOT NULL
464
848
  );
465
849
 
850
+ CREATE TABLE IF NOT EXISTS runtime_index_manifests (
851
+ manifest_id TEXT PRIMARY KEY,
852
+ provider TEXT NOT NULL,
853
+ model_id TEXT NOT NULL,
854
+ model_revision TEXT NOT NULL,
855
+ license TEXT,
856
+ embedding_space TEXT NOT NULL,
857
+ dimensions INTEGER NOT NULL CHECK (dimensions > 0),
858
+ modalities_json TEXT NOT NULL,
859
+ supported_languages_json TEXT NOT NULL,
860
+ preprocessing_version TEXT NOT NULL,
861
+ extractor_version TEXT NOT NULL,
862
+ created_at INTEGER NOT NULL
863
+ );
864
+
865
+ CREATE TABLE IF NOT EXISTS runtime_index_generations (
866
+ embedding_space TEXT NOT NULL,
867
+ generation TEXT NOT NULL,
868
+ manifest_id TEXT NOT NULL
869
+ REFERENCES runtime_index_manifests(manifest_id) ON DELETE RESTRICT,
870
+ state TEXT NOT NULL CHECK (state IN ('building','active','retired')),
871
+ activated_at INTEGER,
872
+ created_at INTEGER NOT NULL,
873
+ PRIMARY KEY(embedding_space, generation)
874
+ );
875
+ CREATE UNIQUE INDEX IF NOT EXISTS runtime_index_generation_active
876
+ ON runtime_index_generations(embedding_space)
877
+ WHERE state='active';
878
+
879
+ CREATE TABLE IF NOT EXISTS runtime_index_coverage (
880
+ artifact_id TEXT NOT NULL,
881
+ object_hash TEXT NOT NULL,
882
+ manifest_id TEXT NOT NULL
883
+ REFERENCES runtime_index_manifests(manifest_id) ON DELETE CASCADE,
884
+ generation TEXT NOT NULL,
885
+ phase TEXT NOT NULL,
886
+ state TEXT NOT NULL,
887
+ covered_ranges_json TEXT NOT NULL,
888
+ indexed_units INTEGER NOT NULL CHECK (indexed_units >= 0),
889
+ total_units INTEGER,
890
+ retryable INTEGER NOT NULL CHECK (retryable IN (0,1)),
891
+ error_json TEXT,
892
+ cursor TEXT,
893
+ updated_at INTEGER NOT NULL,
894
+ PRIMARY KEY(artifact_id, object_hash, manifest_id, generation, phase)
895
+ );
896
+ CREATE INDEX IF NOT EXISTS runtime_index_coverage_state
897
+ ON runtime_index_coverage(generation, state, artifact_id);
898
+
899
+ CREATE TABLE IF NOT EXISTS runtime_media_segments (
900
+ segment_id TEXT PRIMARY KEY,
901
+ artifact_id TEXT NOT NULL,
902
+ stream_id TEXT,
903
+ object_hash TEXT NOT NULL,
904
+ source_range_json TEXT,
905
+ source_path TEXT,
906
+ segment_kind TEXT NOT NULL,
907
+ representative_tick INTEGER,
908
+ segmentation_version TEXT NOT NULL,
909
+ generation TEXT NOT NULL,
910
+ manifest_id TEXT NOT NULL
911
+ REFERENCES runtime_index_manifests(manifest_id) ON DELETE CASCADE,
912
+ created_at INTEGER NOT NULL
913
+ );
914
+ CREATE INDEX IF NOT EXISTS runtime_media_segments_source
915
+ ON runtime_media_segments(
916
+ generation, artifact_id, stream_id, representative_tick
917
+ );
918
+
919
+ CREATE TABLE IF NOT EXISTS runtime_segment_text (
920
+ text_id TEXT PRIMARY KEY,
921
+ segment_id TEXT NOT NULL
922
+ REFERENCES runtime_media_segments(segment_id) ON DELETE CASCADE,
923
+ kind TEXT NOT NULL,
924
+ language TEXT,
925
+ text TEXT NOT NULL,
926
+ start_utf8_byte INTEGER,
927
+ end_utf8_byte INTEGER,
928
+ confidence REAL,
929
+ provenance_json TEXT NOT NULL,
930
+ generation TEXT NOT NULL
931
+ );
932
+ CREATE INDEX IF NOT EXISTS runtime_segment_text_lookup
933
+ ON runtime_segment_text(generation, kind, segment_id);
934
+
935
+ CREATE TABLE IF NOT EXISTS runtime_segment_embeddings (
936
+ embedding_id TEXT PRIMARY KEY,
937
+ segment_id TEXT NOT NULL
938
+ REFERENCES runtime_media_segments(segment_id) ON DELETE CASCADE,
939
+ modality TEXT NOT NULL,
940
+ embedding_space TEXT NOT NULL,
941
+ dimensions INTEGER NOT NULL,
942
+ vector_blob BLOB NOT NULL,
943
+ source_hash TEXT NOT NULL,
944
+ generation TEXT NOT NULL,
945
+ updated_at INTEGER NOT NULL,
946
+ UNIQUE(segment_id, modality, embedding_space, generation)
947
+ );
948
+ CREATE INDEX IF NOT EXISTS runtime_segment_embeddings_space
949
+ ON runtime_segment_embeddings(
950
+ generation, embedding_space, modality, segment_id
951
+ );
952
+
953
+ CREATE TABLE IF NOT EXISTS runtime_segment_fingerprints (
954
+ fingerprint_id TEXT PRIMARY KEY,
955
+ segment_id TEXT NOT NULL
956
+ REFERENCES runtime_media_segments(segment_id) ON DELETE CASCADE,
957
+ kind TEXT NOT NULL,
958
+ value TEXT NOT NULL,
959
+ extractor_version TEXT NOT NULL,
960
+ generation TEXT NOT NULL,
961
+ UNIQUE(kind, value, extractor_version, segment_id)
962
+ );
963
+ CREATE INDEX IF NOT EXISTS runtime_segment_fingerprints_lookup
964
+ ON runtime_segment_fingerprints(generation, kind, value);
965
+
966
+ CREATE TABLE IF NOT EXISTS runtime_index_batches (
967
+ batch_key TEXT PRIMARY KEY,
968
+ artifact_id TEXT NOT NULL,
969
+ object_hash TEXT NOT NULL,
970
+ manifest_id TEXT NOT NULL,
971
+ generation TEXT NOT NULL,
972
+ phase TEXT NOT NULL,
973
+ cursor TEXT,
974
+ result_json TEXT NOT NULL,
975
+ committed_at INTEGER NOT NULL
976
+ );
977
+
466
978
  ${RUNTIME_SIMILARITY_SCHEMA_SQL}
467
979
 
468
980
  CREATE TABLE IF NOT EXISTS runtime_text_similarity_documents (