@sixb/sqlite 0.1.1 → 0.1.2

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 (108) hide show
  1. package/README.md +18 -13
  2. package/dist/action-run-storage.d.ts +5 -2
  3. package/dist/action-run-storage.d.ts.map +1 -1
  4. package/dist/agents/agent-storage.d.ts +4 -2
  5. package/dist/agents/agent-storage.d.ts.map +1 -1
  6. package/dist/agents/rows.d.ts +3 -10
  7. package/dist/agents/rows.d.ts.map +1 -1
  8. package/dist/agents/runs.d.ts +3 -2
  9. package/dist/agents/runs.d.ts.map +1 -1
  10. package/dist/ai-usage-storage.d.ts +22 -0
  11. package/dist/ai-usage-storage.d.ts.map +1 -0
  12. package/dist/auth-storage/service-accounts.d.ts.map +1 -1
  13. package/dist/auth-storage/shared.d.ts +1 -10
  14. package/dist/auth-storage/shared.d.ts.map +1 -1
  15. package/dist/connector-connection-storage.d.ts +9 -0
  16. package/dist/connector-connection-storage.d.ts.map +1 -0
  17. package/dist/execution-storage.d.ts +14 -0
  18. package/dist/execution-storage.d.ts.map +1 -0
  19. package/dist/index.d.ts +13 -9
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +3862 -1042
  22. package/dist/index.js.map +30 -27
  23. package/dist/latest-run-query.d.ts.map +1 -1
  24. package/dist/migrations.d.ts +0 -1
  25. package/dist/migrations.d.ts.map +1 -1
  26. package/dist/ontology-storage/materialization-session.d.ts +50 -8
  27. package/dist/ontology-storage/materialization-session.d.ts.map +1 -1
  28. package/dist/ontology-storage/materialization-state.d.ts +4 -5
  29. package/dist/ontology-storage/materialization-state.d.ts.map +1 -1
  30. package/dist/ontology-storage/materialization-writer.d.ts.map +1 -1
  31. package/dist/ontology-storage/materializations.d.ts +0 -2
  32. package/dist/ontology-storage/materializations.d.ts.map +1 -1
  33. package/dist/ontology-storage/outbox.d.ts.map +1 -1
  34. package/dist/ontology-storage/shared.d.ts +3 -3
  35. package/dist/ontology-storage/shared.d.ts.map +1 -1
  36. package/dist/ontology-storage/sources.d.ts.map +1 -1
  37. package/dist/pipeline-run-storage.d.ts +7 -2
  38. package/dist/pipeline-run-storage.d.ts.map +1 -1
  39. package/dist/projection-run-storage.d.ts +9 -2
  40. package/dist/projection-run-storage.d.ts.map +1 -1
  41. package/dist/run-list-query.d.ts +1 -1
  42. package/dist/run-list-query.d.ts.map +1 -1
  43. package/dist/sync-run-storage.d.ts +7 -2
  44. package/dist/sync-run-storage.d.ts.map +1 -1
  45. package/dist/testing.d.ts +6 -0
  46. package/dist/testing.d.ts.map +1 -0
  47. package/dist/transactions.d.ts +3 -0
  48. package/dist/transactions.d.ts.map +1 -1
  49. package/dist/webhook-run-storage.d.ts +9 -2
  50. package/dist/webhook-run-storage.d.ts.map +1 -1
  51. package/dist/workflow-run-storage.d.ts +7 -3
  52. package/dist/workflow-run-storage.d.ts.map +1 -1
  53. package/package.json +3 -3
  54. package/src/action-run-storage.ts +51 -74
  55. package/src/agents/agent-storage.ts +5 -3
  56. package/src/agents/rows.ts +8 -40
  57. package/src/agents/runs.ts +27 -21
  58. package/src/ai-usage-storage.ts +324 -0
  59. package/src/auth-storage/service-accounts.ts +14 -21
  60. package/src/auth-storage/shared.ts +0 -22
  61. package/src/connector-connection-storage.ts +784 -0
  62. package/src/execution-storage.ts +158 -0
  63. package/src/index.ts +63 -22
  64. package/src/latest-run-query.ts +7 -1
  65. package/src/migrations/004-executions.sql +142 -0
  66. package/src/migrations/005-workflow-executions.sql +7 -0
  67. package/src/migrations/006-narrow-ontology-source-root-index.sql +4 -0
  68. package/src/migrations/007-split-overrides.sql +154 -0
  69. package/src/migrations/008-action-executions.sql +4 -0
  70. package/src/migrations/009-agent-executions.sql +115 -0
  71. package/src/migrations/010-ai-usage-accounting-foundation.sql +74 -0
  72. package/src/migrations/011-sync-failure-record.sql +22 -0
  73. package/src/migrations/012-pipeline-failure-record.sql +45 -0
  74. package/src/migrations/013-workflow-failure-record.sql +45 -0
  75. package/src/migrations/014-agent-failure-record.sql +59 -0
  76. package/src/migrations/015-projection-failure-record.sql +20 -0
  77. package/src/migrations/016-webhook-run-failure-record.sql +19 -0
  78. package/src/migrations/017-action-failure-record.sql +65 -0
  79. package/src/migrations/018-ontology-outbox-failure-record.sql +80 -0
  80. package/src/migrations/019-webhook-delivery-failure-record.sql +62 -0
  81. package/src/migrations/020-drop-run-usage-projections.sql +7 -0
  82. package/src/migrations/021-sync-pipeline-executions.sql +101 -0
  83. package/src/migrations/022-projection-executions.sql +244 -0
  84. package/src/migrations/023-webhook-executions.sql +51 -0
  85. package/src/migrations/024-ontology-commit-executions.sql +58 -0
  86. package/src/migrations/025-connector-connections.sql +257 -0
  87. package/src/migrations.ts +119 -4
  88. package/src/ontology-storage/materialization-session.ts +317 -143
  89. package/src/ontology-storage/materialization-state.ts +321 -112
  90. package/src/ontology-storage/materialization-writer.ts +142 -67
  91. package/src/ontology-storage/materializations.ts +67 -141
  92. package/src/ontology-storage/outbox.ts +10 -3
  93. package/src/ontology-storage/shared.ts +10 -4
  94. package/src/ontology-storage/sources.ts +4 -1
  95. package/src/pipeline-run-storage.ts +128 -43
  96. package/src/projection-run-storage.ts +209 -97
  97. package/src/run-list-query.ts +9 -4
  98. package/src/sync-run-storage.ts +118 -32
  99. package/src/testing.ts +20 -0
  100. package/src/transactions.ts +10 -3
  101. package/src/webhook-run-storage.ts +118 -74
  102. package/src/workflow-run-storage.ts +117 -131
  103. package/dist/validation.d.ts +0 -5
  104. package/dist/validation.d.ts.map +0 -1
  105. package/dist/webhook-delivery-storage.d.ts +0 -27
  106. package/dist/webhook-delivery-storage.d.ts.map +0 -1
  107. package/src/validation.ts +0 -30
  108. package/src/webhook-delivery-storage.ts +0 -272
@@ -0,0 +1,80 @@
1
+ -- SQLite cannot add the JSON constraint while changing the legacy column, so rebuild the table.
2
+ -- The legacy record has no failure timestamp. Use its next availability time as the closest
3
+ -- durable timestamp and mark that approximation explicitly in details.
4
+ DROP INDEX idx_ontology_outbox_claim;
5
+ DROP INDEX idx_ontology_outbox_published;
6
+
7
+ ALTER TABLE ontology_outbox RENAME TO ontology_outbox_before_failure_record;
8
+
9
+ CREATE TABLE ontology_outbox (
10
+ project_id TEXT NOT NULL,
11
+ id TEXT NOT NULL,
12
+ commit_id TEXT NOT NULL,
13
+ commit_ordinal INTEGER NOT NULL CHECK (commit_ordinal >= 0),
14
+ envelope TEXT NOT NULL CHECK (json_valid(envelope)),
15
+ available_at TEXT NOT NULL,
16
+ attempts INTEGER NOT NULL DEFAULT 0 CHECK (attempts >= 0),
17
+ lease_id TEXT,
18
+ lease_expires_at TEXT,
19
+ published_at TEXT,
20
+ last_failure TEXT CHECK (last_failure IS NULL OR json_valid(last_failure)),
21
+ created_at TEXT NOT NULL,
22
+ PRIMARY KEY (project_id, id),
23
+ UNIQUE (project_id, commit_id, commit_ordinal),
24
+ CHECK ((lease_id IS NULL) = (lease_expires_at IS NULL))
25
+ );
26
+
27
+ INSERT INTO ontology_outbox (
28
+ project_id,
29
+ id,
30
+ commit_id,
31
+ commit_ordinal,
32
+ envelope,
33
+ available_at,
34
+ attempts,
35
+ lease_id,
36
+ lease_expires_at,
37
+ published_at,
38
+ last_failure,
39
+ created_at
40
+ )
41
+ SELECT
42
+ project_id,
43
+ id,
44
+ commit_id,
45
+ commit_ordinal,
46
+ envelope,
47
+ available_at,
48
+ attempts,
49
+ lease_id,
50
+ lease_expires_at,
51
+ published_at,
52
+ CASE
53
+ WHEN last_error IS NULL
54
+ OR last_error = 'Outbox dispatcher stopped before publication completed.'
55
+ THEN NULL
56
+ ELSE json_object(
57
+ 'code', 'event.delivery_failed',
58
+ 'message', 'Event delivery failed.',
59
+ 'retryable', json('true'),
60
+ 'at', available_at,
61
+ 'details', json_object(
62
+ 'attempts', attempts,
63
+ 'eventIds', json_array(id),
64
+ 'eventTypes', json_array(json_extract(envelope, '$.type')),
65
+ 'migratedFromLegacyLastError', json('true'),
66
+ 'timestampSource', 'availableAt'
67
+ )
68
+ )
69
+ END,
70
+ created_at
71
+ FROM ontology_outbox_before_failure_record;
72
+
73
+ DROP TABLE ontology_outbox_before_failure_record;
74
+
75
+ CREATE INDEX idx_ontology_outbox_claim
76
+ ON ontology_outbox(project_id, available_at, lease_expires_at, created_at, commit_id, commit_ordinal)
77
+ WHERE published_at IS NULL;
78
+ CREATE INDEX idx_ontology_outbox_published
79
+ ON ontology_outbox(project_id, published_at, id)
80
+ WHERE published_at IS NOT NULL;
@@ -0,0 +1,62 @@
1
+ -- SQLite cannot add the JSON constraint while changing the legacy column, so rebuild the table.
2
+ -- Legacy deliveries normally have an exact failure timestamp. Fall back to the receipt timestamp
3
+ -- only for inconsistent historical rows and record the source so the approximation stays visible.
4
+ DROP INDEX idx_webhook_deliveries_project_received;
5
+
6
+ ALTER TABLE webhook_deliveries RENAME TO webhook_deliveries_before_failure_record;
7
+
8
+ CREATE TABLE webhook_deliveries (
9
+ project_id TEXT NOT NULL,
10
+ connector_id TEXT NOT NULL,
11
+ webhook_id TEXT NOT NULL,
12
+ idempotency_key TEXT NOT NULL,
13
+ status TEXT NOT NULL CHECK (status IN ('in_progress', 'completed', 'failed')),
14
+ received_at TEXT NOT NULL,
15
+ completed_at TEXT,
16
+ failed_at TEXT,
17
+ failure TEXT CHECK (failure IS NULL OR json_valid(failure)),
18
+ PRIMARY KEY (project_id, connector_id, webhook_id, idempotency_key)
19
+ );
20
+
21
+ INSERT INTO webhook_deliveries (
22
+ project_id,
23
+ connector_id,
24
+ webhook_id,
25
+ idempotency_key,
26
+ status,
27
+ received_at,
28
+ completed_at,
29
+ failed_at,
30
+ failure
31
+ )
32
+ SELECT
33
+ project_id,
34
+ connector_id,
35
+ webhook_id,
36
+ idempotency_key,
37
+ status,
38
+ received_at,
39
+ completed_at,
40
+ failed_at,
41
+ CASE
42
+ WHEN error IS NULL THEN NULL
43
+ ELSE json_object(
44
+ 'code', 'webhook.delivery_failed',
45
+ 'message', 'Webhook delivery failed.',
46
+ 'retryable', json('true'),
47
+ 'at', COALESCE(failed_at, received_at),
48
+ 'details', json_object(
49
+ 'connectorId', connector_id,
50
+ 'webhookId', webhook_id,
51
+ 'idempotencyKey', idempotency_key,
52
+ 'migratedFromLegacyError', json('true'),
53
+ 'timestampSource', CASE WHEN failed_at IS NULL THEN 'receivedAt' ELSE 'failedAt' END
54
+ )
55
+ )
56
+ END
57
+ FROM webhook_deliveries_before_failure_record;
58
+
59
+ DROP TABLE webhook_deliveries_before_failure_record;
60
+
61
+ CREATE INDEX idx_webhook_deliveries_project_received
62
+ ON webhook_deliveries(project_id, received_at DESC);
@@ -0,0 +1,7 @@
1
+ ALTER TABLE agent_runs DROP COLUMN usage_input_tokens;
2
+ ALTER TABLE agent_runs DROP COLUMN usage_output_tokens;
3
+ ALTER TABLE agent_runs DROP COLUMN usage_total_tokens;
4
+ ALTER TABLE agent_runs DROP COLUMN usage_reasoning_tokens;
5
+ ALTER TABLE agent_runs DROP COLUMN usage_cached_input_tokens;
6
+
7
+ ALTER TABLE workflow_agent_node_runs DROP COLUMN usage;
@@ -0,0 +1,101 @@
1
+ -- Existing rows cannot be assigned honest authority retroactively. These NOT NULL additions
2
+ -- intentionally fail on non-empty legacy tables instead of inventing execution provenance.
3
+ ALTER TABLE sync_runs ADD COLUMN execution_id TEXT NOT NULL;
4
+ ALTER TABLE sync_runs ADD COLUMN queued_at TEXT NOT NULL;
5
+
6
+ DROP INDEX idx_sync_runs_project_started;
7
+ DROP INDEX idx_sync_runs_project_dataset_started;
8
+ DROP INDEX idx_sync_runs_project_sync_started;
9
+ DROP INDEX idx_sync_runs_project_status_started;
10
+
11
+ CREATE TABLE sync_runs_v2 (
12
+ project_id TEXT NOT NULL,
13
+ id TEXT NOT NULL,
14
+ execution_id TEXT NOT NULL,
15
+ sync_id TEXT NOT NULL,
16
+ dataset_id TEXT NOT NULL,
17
+ mode TEXT NOT NULL CHECK (mode IN ('snapshot', 'append', 'merge')),
18
+ status TEXT NOT NULL CHECK (status IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')),
19
+ queued_at TEXT NOT NULL,
20
+ started_at TEXT,
21
+ finished_at TEXT,
22
+ rows_read INTEGER CHECK (rows_read IS NULL OR rows_read >= 0),
23
+ output_version_id TEXT,
24
+ expected_latest_version_id TEXT,
25
+ commit_message TEXT,
26
+ error TEXT CHECK (error IS NULL OR json_valid(error)),
27
+ checkpoint TEXT,
28
+ PRIMARY KEY (project_id, id),
29
+ UNIQUE (project_id, execution_id),
30
+ FOREIGN KEY (project_id, execution_id)
31
+ REFERENCES executions (project_id, id)
32
+ ON DELETE RESTRICT
33
+ );
34
+
35
+ INSERT INTO sync_runs_v2 (
36
+ project_id, id, execution_id, sync_id, dataset_id, mode, status, queued_at, started_at,
37
+ finished_at, rows_read, output_version_id, expected_latest_version_id, commit_message,
38
+ error, checkpoint
39
+ )
40
+ SELECT
41
+ project_id, id, execution_id, sync_id, dataset_id, mode, status, queued_at, started_at,
42
+ finished_at, rows_read, output_version_id, expected_latest_version_id, commit_message,
43
+ error, checkpoint
44
+ FROM sync_runs;
45
+
46
+ DROP TABLE sync_runs;
47
+ ALTER TABLE sync_runs_v2 RENAME TO sync_runs;
48
+
49
+ CREATE INDEX idx_sync_runs_project_started
50
+ ON sync_runs(project_id, COALESCE(started_at, queued_at) DESC);
51
+ CREATE INDEX idx_sync_runs_project_dataset_started
52
+ ON sync_runs(project_id, dataset_id, COALESCE(started_at, queued_at) DESC);
53
+ CREATE INDEX idx_sync_runs_project_sync_started
54
+ ON sync_runs(project_id, sync_id, COALESCE(started_at, queued_at) DESC);
55
+ CREATE INDEX idx_sync_runs_project_status_started
56
+ ON sync_runs(project_id, status, COALESCE(started_at, queued_at) DESC);
57
+
58
+ ALTER TABLE pipeline_runs ADD COLUMN execution_id TEXT NOT NULL;
59
+ ALTER TABLE pipeline_runs ADD COLUMN queued_at TEXT NOT NULL;
60
+
61
+ DROP INDEX idx_pipeline_runs_project_started;
62
+ DROP INDEX idx_pipeline_runs_project_pipeline_started;
63
+ DROP INDEX idx_pipeline_runs_project_status_started;
64
+
65
+ CREATE TABLE pipeline_runs_v2 (
66
+ project_id TEXT NOT NULL,
67
+ id TEXT NOT NULL,
68
+ execution_id TEXT NOT NULL,
69
+ pipeline_id TEXT NOT NULL,
70
+ status TEXT NOT NULL CHECK (status IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')),
71
+ queued_at TEXT NOT NULL,
72
+ started_at TEXT,
73
+ finished_at TEXT,
74
+ output_dataset_id TEXT,
75
+ output_version_id TEXT,
76
+ error TEXT CHECK (error IS NULL OR json_valid(error)),
77
+ PRIMARY KEY (project_id, id),
78
+ UNIQUE (project_id, execution_id),
79
+ FOREIGN KEY (project_id, execution_id)
80
+ REFERENCES executions (project_id, id)
81
+ ON DELETE RESTRICT
82
+ );
83
+
84
+ INSERT INTO pipeline_runs_v2 (
85
+ project_id, id, execution_id, pipeline_id, status, queued_at, started_at, finished_at,
86
+ output_dataset_id, output_version_id, error
87
+ )
88
+ SELECT
89
+ project_id, id, execution_id, pipeline_id, status, queued_at, started_at, finished_at,
90
+ output_dataset_id, output_version_id, error
91
+ FROM pipeline_runs;
92
+
93
+ DROP TABLE pipeline_runs;
94
+ ALTER TABLE pipeline_runs_v2 RENAME TO pipeline_runs;
95
+
96
+ CREATE INDEX idx_pipeline_runs_project_started
97
+ ON pipeline_runs(project_id, COALESCE(started_at, queued_at) DESC);
98
+ CREATE INDEX idx_pipeline_runs_project_pipeline_started
99
+ ON pipeline_runs(project_id, pipeline_id, COALESCE(started_at, queued_at) DESC);
100
+ CREATE INDEX idx_pipeline_runs_project_status_started
101
+ ON pipeline_runs(project_id, status, COALESCE(started_at, queued_at) DESC);
@@ -0,0 +1,244 @@
1
+ -- Dataset versions are first-class durable execution sources. Rebuild the parent table so the
2
+ -- source kind remains truthful instead of encoding a version as an event or synthetic execution.
3
+ CREATE TABLE executions_v2 (
4
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
5
+ id TEXT NOT NULL CHECK (length(trim(id)) > 0),
6
+ executor_kind TEXT NOT NULL CHECK (
7
+ executor_kind IN (
8
+ 'request', 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow',
9
+ 'agent', 'kernel'
10
+ )
11
+ ),
12
+ executor_id TEXT NOT NULL CHECK (length(trim(executor_id)) > 0),
13
+ source_kind TEXT NOT NULL CHECK (
14
+ source_kind IN ('http', 'webhook', 'schedule', 'event', 'datasetVersion', 'execution')
15
+ ),
16
+ source_id TEXT NOT NULL CHECK (length(trim(source_id)) > 0),
17
+ requested_by_user_id TEXT,
18
+ requested_by_service_account_id TEXT,
19
+ correlation_id TEXT NOT NULL CHECK (length(trim(correlation_id)) > 0),
20
+ parent_execution_id TEXT,
21
+ authority_kind TEXT NOT NULL CHECK (
22
+ authority_kind IN ('principal', 'trustedPrimitive', 'kernel', 'disabled')
23
+ ),
24
+ authority_user_id TEXT,
25
+ authority_service_account_id TEXT,
26
+ authority_session_id TEXT,
27
+ authority_access_token_id TEXT,
28
+ authority_primitive_kind TEXT CHECK (
29
+ authority_primitive_kind IS NULL
30
+ OR authority_primitive_kind IN (
31
+ 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow'
32
+ )
33
+ ),
34
+ authority_primitive_id TEXT,
35
+ authority_kernel_operation TEXT CHECK (
36
+ authority_kernel_operation IS NULL OR authority_kernel_operation = 'ontology.recover'
37
+ ),
38
+ created_at TEXT NOT NULL,
39
+ PRIMARY KEY (project_id, id),
40
+ -- Keep the final table name here. Foreign-key rewriting is intentionally disabled while this
41
+ -- parent table is rebuilt, so a reference to executions_v2 would survive the later rename.
42
+ FOREIGN KEY (project_id, parent_execution_id) REFERENCES executions (project_id, id),
43
+ FOREIGN KEY (project_id, requested_by_user_id) REFERENCES auth_users (project_id, id),
44
+ FOREIGN KEY (project_id, requested_by_service_account_id)
45
+ REFERENCES auth_service_accounts (project_id, id),
46
+ FOREIGN KEY (project_id, authority_user_id) REFERENCES auth_users (project_id, id),
47
+ FOREIGN KEY (project_id, authority_service_account_id)
48
+ REFERENCES auth_service_accounts (project_id, id),
49
+ FOREIGN KEY (project_id, authority_session_id) REFERENCES auth_sessions (project_id, id),
50
+ FOREIGN KEY (project_id, authority_access_token_id)
51
+ REFERENCES auth_access_tokens (project_id, id),
52
+ CHECK ((requested_by_user_id IS NOT NULL) + (requested_by_service_account_id IS NOT NULL) <= 1),
53
+ CHECK (
54
+ (source_kind = 'execution' AND parent_execution_id = source_id)
55
+ OR (source_kind <> 'execution' AND parent_execution_id IS NULL)
56
+ ),
57
+ CHECK (
58
+ (
59
+ authority_kind = 'principal'
60
+ AND (authority_user_id IS NOT NULL) + (authority_service_account_id IS NOT NULL) = 1
61
+ AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) <= 1
62
+ AND (authority_session_id IS NULL OR authority_user_id IS NOT NULL)
63
+ AND authority_primitive_kind IS NULL
64
+ AND authority_primitive_id IS NULL
65
+ AND authority_kernel_operation IS NULL
66
+ )
67
+ OR (
68
+ authority_kind = 'trustedPrimitive'
69
+ AND authority_user_id IS NULL
70
+ AND authority_service_account_id IS NULL
71
+ AND authority_session_id IS NULL
72
+ AND authority_access_token_id IS NULL
73
+ AND authority_primitive_kind IS NOT NULL
74
+ AND authority_primitive_id IS NOT NULL
75
+ AND length(trim(authority_primitive_id)) > 0
76
+ AND authority_kernel_operation IS NULL
77
+ )
78
+ OR (
79
+ authority_kind = 'kernel'
80
+ AND authority_user_id IS NULL
81
+ AND authority_service_account_id IS NULL
82
+ AND authority_session_id IS NULL
83
+ AND authority_access_token_id IS NULL
84
+ AND authority_primitive_kind IS NULL
85
+ AND authority_primitive_id IS NULL
86
+ AND authority_kernel_operation IS NOT NULL
87
+ )
88
+ OR (
89
+ authority_kind = 'disabled'
90
+ AND authority_user_id IS NULL
91
+ AND authority_service_account_id IS NULL
92
+ AND authority_session_id IS NULL
93
+ AND authority_access_token_id IS NULL
94
+ AND authority_primitive_kind IS NULL
95
+ AND authority_primitive_id IS NULL
96
+ AND authority_kernel_operation IS NULL
97
+ )
98
+ ),
99
+ CHECK (
100
+ (
101
+ executor_kind = 'request'
102
+ AND source_kind = 'http'
103
+ AND executor_id = source_id
104
+ AND (
105
+ (
106
+ authority_kind = 'principal'
107
+ AND requested_by_user_id IS authority_user_id
108
+ AND requested_by_service_account_id IS authority_service_account_id
109
+ )
110
+ OR (
111
+ authority_kind = 'disabled'
112
+ AND requested_by_user_id IS NULL
113
+ AND requested_by_service_account_id IS NULL
114
+ )
115
+ )
116
+ )
117
+ OR (
118
+ executor_kind IN ('action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow')
119
+ AND authority_kind = 'trustedPrimitive'
120
+ AND executor_kind = authority_primitive_kind
121
+ )
122
+ OR (
123
+ executor_kind = 'agent'
124
+ AND authority_kind = 'principal'
125
+ AND authority_service_account_id IS NOT NULL
126
+ AND authority_session_id IS NULL
127
+ AND authority_access_token_id IS NULL
128
+ )
129
+ OR (executor_kind = 'kernel' AND authority_kind = 'kernel')
130
+ )
131
+ );
132
+
133
+ INSERT INTO executions_v2 SELECT * FROM executions;
134
+ DROP TABLE executions;
135
+ ALTER TABLE executions_v2 RENAME TO executions;
136
+
137
+ -- The migration step checks that projection_runs is empty before executing this schema rebuild:
138
+ -- legacy rows cannot be assigned honest execution authority.
139
+
140
+ DROP INDEX idx_projection_runs_project_started;
141
+ DROP INDEX idx_projection_runs_project_projection_started;
142
+ DROP INDEX idx_projection_runs_project_dataset_started;
143
+ DROP INDEX idx_projection_runs_project_version_started;
144
+ DROP INDEX idx_projection_runs_project_status_started;
145
+ DROP INDEX idx_projection_runs_project_object_type_started;
146
+
147
+ DROP TABLE projection_runs;
148
+
149
+ CREATE TABLE projection_runs (
150
+ project_id TEXT NOT NULL,
151
+ id TEXT NOT NULL,
152
+ execution_id TEXT NOT NULL,
153
+ projection_id TEXT NOT NULL,
154
+ projection_kind TEXT NOT NULL CHECK (projection_kind IN ('object', 'link', 'telemetry')),
155
+ materialization_protocol TEXT NOT NULL CHECK (
156
+ materialization_protocol IN ('replacement', 'telemetry')
157
+ ),
158
+ dataset_id TEXT NOT NULL,
159
+ dataset_version_id TEXT NOT NULL,
160
+ dataset_version_created_at TEXT NOT NULL,
161
+ ontology_revision TEXT NOT NULL,
162
+ projection_revision TEXT NOT NULL,
163
+ ownership_hash TEXT NOT NULL,
164
+ object_type_id TEXT,
165
+ source_object_type_id TEXT,
166
+ target_object_type_id TEXT,
167
+ status TEXT NOT NULL CHECK (status IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')),
168
+ queued_at TEXT NOT NULL,
169
+ started_at TEXT,
170
+ finished_at TEXT,
171
+ attempt INTEGER NOT NULL CHECK (attempt >= 0),
172
+ execution_token TEXT,
173
+ fixed_batch_size INTEGER CHECK (fixed_batch_size > 0),
174
+ next_batch_ordinal INTEGER CHECK (next_batch_ordinal >= 0),
175
+ next_row_offset INTEGER CHECK (next_row_offset >= 0),
176
+ input_exhausted INTEGER CHECK (input_exhausted IN (0, 1)),
177
+ missing_target_object_type_id TEXT,
178
+ missing_target_object_id TEXT,
179
+ missing_target_batch_ordinal INTEGER CHECK (
180
+ missing_target_batch_ordinal IS NULL OR missing_target_batch_ordinal >= 0
181
+ ),
182
+ missing_target_first_seen_at TEXT,
183
+ source_rows_read INTEGER NOT NULL DEFAULT 0 CHECK (source_rows_read >= 0),
184
+ source_rows_skipped INTEGER NOT NULL DEFAULT 0 CHECK (source_rows_skipped >= 0),
185
+ error TEXT CHECK (error IS NULL OR json_valid(error)),
186
+ PRIMARY KEY (project_id, id),
187
+ UNIQUE (project_id, execution_id),
188
+ FOREIGN KEY (project_id, execution_id) REFERENCES executions (project_id, id) ON DELETE RESTRICT,
189
+ CHECK (source_rows_skipped <= source_rows_read),
190
+ CHECK ((status = 'running') = (execution_token IS NOT NULL)),
191
+ CHECK (
192
+ (status = 'queued' AND attempt = 0 AND started_at IS NULL AND finished_at IS NULL
193
+ AND error IS NULL)
194
+ OR (status = 'running' AND attempt >= 1 AND started_at IS NOT NULL AND finished_at IS NULL
195
+ AND error IS NULL)
196
+ OR (
197
+ status IN ('succeeded', 'failed', 'cancelled')
198
+ AND finished_at IS NOT NULL
199
+ AND (
200
+ (json_extract(error, '$.code') = 'queue.enqueue_failed'
201
+ AND status = 'failed' AND attempt = 0 AND started_at IS NULL)
202
+ OR (COALESCE(json_extract(error, '$.code'), '') != 'queue.enqueue_failed'
203
+ AND attempt >= 1 AND started_at IS NOT NULL)
204
+ )
205
+ )
206
+ ),
207
+ CHECK (status != 'succeeded' OR error IS NULL),
208
+ CHECK ((projection_kind = 'telemetry') = (materialization_protocol = 'telemetry')),
209
+ CHECK (
210
+ (projection_kind = 'link' AND object_type_id IS NULL
211
+ AND source_object_type_id IS NOT NULL AND target_object_type_id IS NOT NULL)
212
+ OR (projection_kind IN ('object', 'telemetry') AND object_type_id IS NOT NULL
213
+ AND source_object_type_id IS NULL AND target_object_type_id IS NULL)
214
+ ),
215
+ CHECK (
216
+ (materialization_protocol = 'replacement' AND fixed_batch_size IS NULL
217
+ AND next_batch_ordinal IS NULL AND next_row_offset IS NULL AND input_exhausted IS NULL)
218
+ OR (materialization_protocol = 'telemetry' AND fixed_batch_size IS NOT NULL
219
+ AND next_batch_ordinal IS NOT NULL AND next_row_offset IS NOT NULL
220
+ AND input_exhausted IS NOT NULL)
221
+ ),
222
+ CHECK (
223
+ (missing_target_object_type_id IS NULL AND missing_target_object_id IS NULL
224
+ AND missing_target_batch_ordinal IS NULL AND missing_target_first_seen_at IS NULL)
225
+ OR (projection_kind = 'telemetry' AND missing_target_object_type_id = object_type_id
226
+ AND missing_target_object_id IS NOT NULL
227
+ AND missing_target_batch_ordinal = next_batch_ordinal
228
+ AND missing_target_first_seen_at IS NOT NULL)
229
+ ),
230
+ CHECK (projection_kind != 'telemetry' OR status != 'succeeded' OR input_exhausted = 1)
231
+ );
232
+
233
+ CREATE INDEX idx_projection_runs_project_started
234
+ ON projection_runs(project_id, COALESCE(started_at, queued_at) DESC);
235
+ CREATE INDEX idx_projection_runs_project_projection_started
236
+ ON projection_runs(project_id, projection_id, COALESCE(started_at, queued_at) DESC);
237
+ CREATE INDEX idx_projection_runs_project_dataset_started
238
+ ON projection_runs(project_id, dataset_id, COALESCE(started_at, queued_at) DESC);
239
+ CREATE INDEX idx_projection_runs_project_version_started
240
+ ON projection_runs(project_id, dataset_version_id, COALESCE(started_at, queued_at) DESC);
241
+ CREATE INDEX idx_projection_runs_project_status_started
242
+ ON projection_runs(project_id, status, COALESCE(started_at, queued_at) DESC);
243
+ CREATE INDEX idx_projection_runs_project_object_type_started
244
+ ON projection_runs(project_id, object_type_id, COALESCE(started_at, queued_at) DESC);
@@ -0,0 +1,51 @@
1
+ DROP INDEX idx_webhook_runs_project_started;
2
+ DROP INDEX idx_webhook_runs_project_connector_started;
3
+ DROP INDEX idx_webhook_runs_project_webhook_started;
4
+ DROP INDEX idx_webhook_runs_project_status_started;
5
+ DROP INDEX idx_webhook_runs_project_idempotency;
6
+
7
+ CREATE TABLE webhook_runs_v2 (
8
+ project_id TEXT NOT NULL,
9
+ id TEXT NOT NULL,
10
+ execution_id TEXT NOT NULL,
11
+ connector_id TEXT NOT NULL,
12
+ webhook_id TEXT NOT NULL,
13
+ status TEXT NOT NULL CHECK (status IN ('running', 'succeeded', 'failed')),
14
+ method TEXT NOT NULL,
15
+ route TEXT NOT NULL,
16
+ started_at TEXT NOT NULL,
17
+ finished_at TEXT,
18
+ request_body_bytes INTEGER NOT NULL CHECK (request_body_bytes >= 0),
19
+ request_body_sha256 TEXT NOT NULL CHECK (length(request_body_sha256) = 64),
20
+ response_status INTEGER CHECK (
21
+ response_status IS NULL OR (response_status >= 100 AND response_status <= 599)
22
+ ),
23
+ idempotency_key TEXT,
24
+ error TEXT CHECK (error IS NULL OR json_valid(error)),
25
+ PRIMARY KEY (project_id, id),
26
+ UNIQUE (project_id, execution_id),
27
+ UNIQUE (project_id, connector_id, webhook_id, idempotency_key),
28
+ FOREIGN KEY (project_id, execution_id)
29
+ REFERENCES executions (project_id, id)
30
+ ON DELETE RESTRICT,
31
+ CHECK (
32
+ (status = 'running' AND finished_at IS NULL AND response_status IS NULL AND error IS NULL)
33
+ OR (status = 'succeeded' AND finished_at IS NOT NULL AND error IS NULL)
34
+ OR (status = 'failed' AND finished_at IS NOT NULL AND error IS NOT NULL)
35
+ )
36
+ );
37
+
38
+ DROP TABLE webhook_runs;
39
+ ALTER TABLE webhook_runs_v2 RENAME TO webhook_runs;
40
+ DROP TABLE webhook_deliveries;
41
+
42
+ CREATE INDEX idx_webhook_runs_project_started
43
+ ON webhook_runs(project_id, started_at DESC);
44
+ CREATE INDEX idx_webhook_runs_project_connector_started
45
+ ON webhook_runs(project_id, connector_id, started_at DESC);
46
+ CREATE INDEX idx_webhook_runs_project_webhook_started
47
+ ON webhook_runs(project_id, connector_id, webhook_id, started_at DESC);
48
+ CREATE INDEX idx_webhook_runs_project_status_started
49
+ ON webhook_runs(project_id, status, started_at DESC);
50
+ CREATE INDEX idx_webhook_runs_project_idempotency
51
+ ON webhook_runs(project_id, idempotency_key);
@@ -0,0 +1,58 @@
1
+ DROP INDEX idx_ontology_commits_action_origin;
2
+ DROP INDEX idx_ontology_commits_projection_origin;
3
+ DROP INDEX idx_ontology_commits_telemetry_origin;
4
+ DROP INDEX idx_ontology_commits_history;
5
+ DROP INDEX idx_ontology_commits_origin;
6
+
7
+ CREATE TABLE ontology_commits_v2 (
8
+ project_id TEXT NOT NULL,
9
+ id TEXT NOT NULL,
10
+ idempotency_key TEXT NOT NULL,
11
+ request_hash TEXT NOT NULL,
12
+ execution_id TEXT NOT NULL,
13
+ origin_kind TEXT NOT NULL CHECK (origin_kind IN ('action', 'runtime', 'projection', 'telemetry')),
14
+ origin_run_id TEXT,
15
+ origin_batch_ordinal INTEGER CHECK (
16
+ origin_batch_ordinal IS NULL OR origin_batch_ordinal >= 0
17
+ ),
18
+ origin TEXT NOT NULL CHECK (json_valid(origin)),
19
+ actor TEXT CHECK (actor IS NULL OR json_valid(actor)),
20
+ ontology_revision TEXT NOT NULL,
21
+ projection_revision TEXT,
22
+ ownership_hash TEXT,
23
+ intent TEXT NOT NULL CHECK (json_valid(intent)),
24
+ result TEXT NOT NULL CHECK (json_valid(result)),
25
+ committed_at TEXT NOT NULL,
26
+ PRIMARY KEY (project_id, id),
27
+ UNIQUE (project_id, idempotency_key),
28
+ FOREIGN KEY (project_id, execution_id)
29
+ REFERENCES executions (project_id, id)
30
+ ON DELETE RESTRICT,
31
+ CHECK (
32
+ (origin_kind IN ('action', 'projection') AND origin_run_id IS NOT NULL AND origin_batch_ordinal IS NULL)
33
+ OR (origin_kind = 'telemetry' AND (
34
+ (origin_run_id IS NULL AND origin_batch_ordinal IS NULL)
35
+ OR (origin_run_id IS NOT NULL AND origin_batch_ordinal IS NOT NULL)
36
+ ))
37
+ OR (origin_kind = 'runtime' AND origin_run_id IS NULL AND origin_batch_ordinal IS NULL)
38
+ )
39
+ );
40
+
41
+ DROP TABLE ontology_commits;
42
+ ALTER TABLE ontology_commits_v2 RENAME TO ontology_commits;
43
+
44
+ CREATE UNIQUE INDEX idx_ontology_commits_action_origin
45
+ ON ontology_commits(project_id, origin_run_id)
46
+ WHERE origin_kind = 'action';
47
+ CREATE UNIQUE INDEX idx_ontology_commits_projection_origin
48
+ ON ontology_commits(project_id, origin_run_id)
49
+ WHERE origin_kind = 'projection';
50
+ CREATE UNIQUE INDEX idx_ontology_commits_telemetry_origin
51
+ ON ontology_commits(project_id, origin_run_id, origin_batch_ordinal)
52
+ WHERE origin_kind = 'telemetry' AND origin_run_id IS NOT NULL;
53
+ CREATE INDEX idx_ontology_commits_history
54
+ ON ontology_commits(project_id, committed_at, id);
55
+ CREATE INDEX idx_ontology_commits_origin
56
+ ON ontology_commits(project_id, origin_kind, origin_run_id, origin_batch_ordinal);
57
+ CREATE INDEX idx_ontology_commits_execution
58
+ ON ontology_commits(project_id, execution_id);