@hasna/infinity 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.
- package/LICENSE +3 -0
- package/README.md +331 -0
- package/dist/cli.js +2965 -0
- package/dist/http-api.js +6448 -0
- package/dist/index.js +28536 -0
- package/dist/migrate.js +346 -0
- package/dist/self-hosted-migrate.js +2064 -0
- package/dist/self-hosted.js +13180 -0
- package/dist/types/authcapsules/codewith-local.d.ts +109 -0
- package/dist/types/authcapsules/infinity-agent-policy.d.ts +57 -0
- package/dist/types/authcapsules/os-isolated-runner.d.ts +87 -0
- package/dist/types/authority/authority.d.ts +342 -0
- package/dist/types/authority/effect-journal.d.ts +205 -0
- package/dist/types/authority/mutation-journal.d.ts +163 -0
- package/dist/types/authority/mutation-tuple.d.ts +26 -0
- package/dist/types/authority/state.d.ts +75 -0
- package/dist/types/authority/store.d.ts +15 -0
- package/dist/types/brokers/checkpoint/archive.d.ts +21 -0
- package/dist/types/brokers/checkpoint/bundle.d.ts +22 -0
- package/dist/types/brokers/checkpoint/bytes.d.ts +4 -0
- package/dist/types/brokers/checkpoint/clean-verifier-finalization.d.ts +62 -0
- package/dist/types/brokers/checkpoint/clean-verifier.d.ts +145 -0
- package/dist/types/brokers/checkpoint/final-trust-authority.d.ts +55 -0
- package/dist/types/brokers/checkpoint/idempotency.d.ts +25 -0
- package/dist/types/brokers/checkpoint/journaled-store.d.ts +9 -0
- package/dist/types/brokers/checkpoint/manifest-signature.d.ts +135 -0
- package/dist/types/brokers/checkpoint/manifest.d.ts +57 -0
- package/dist/types/brokers/checkpoint/s3-store.d.ts +215 -0
- package/dist/types/brokers/checkpoint/seal-authority.d.ts +86 -0
- package/dist/types/brokers/checkpoint/service.d.ts +198 -0
- package/dist/types/brokers/checkpoint/signing-message.d.ts +22 -0
- package/dist/types/brokers/checkpoint/store.d.ts +76 -0
- package/dist/types/brokers/checkpoint/verifier-cleanup-authority.d.ts +108 -0
- package/dist/types/brokers/checkpoint/verifier-cleanup.d.ts +391 -0
- package/dist/types/brokers/checkpoint/verifier.d.ts +225 -0
- package/dist/types/brokers/composition.d.ts +86 -0
- package/dist/types/brokers/git/github-app.d.ts +216 -0
- package/dist/types/brokers/git/promotion.d.ts +418 -0
- package/dist/types/brokers/persistence/contracts.d.ts +77 -0
- package/dist/types/brokers/persistence/memory.d.ts +5 -0
- package/dist/types/brokers/persistence/migration.d.ts +6 -0
- package/dist/types/brokers/persistence/postgres.d.ts +74 -0
- package/dist/types/cli/main.d.ts +2 -0
- package/dist/types/cli/operation-journal.d.ts +47 -0
- package/dist/types/cli/run.d.ts +15 -0
- package/dist/types/client/operator-client.d.ts +100 -0
- package/dist/types/contracts/dtos.d.ts +198 -0
- package/dist/types/contracts/events.d.ts +45 -0
- package/dist/types/contracts/fence.d.ts +39 -0
- package/dist/types/contracts/operations.d.ts +91 -0
- package/dist/types/contracts/runspec.d.ts +75 -0
- package/dist/types/contracts/validators.d.ts +8 -0
- package/dist/types/core/clock.d.ts +12 -0
- package/dist/types/core/errors.d.ts +18 -0
- package/dist/types/core/ids.d.ts +10 -0
- package/dist/types/core/int64.d.ts +7 -0
- package/dist/types/core/strict-json.d.ts +8 -0
- package/dist/types/core/validation.d.ts +25 -0
- package/dist/types/golden/disposable-task.d.ts +108 -0
- package/dist/types/golden/source-pins.d.ts +77 -0
- package/dist/types/http/api.d.ts +52 -0
- package/dist/types/http/bearer-auth.d.ts +8 -0
- package/dist/types/http/main.d.ts +3 -0
- package/dist/types/http/self-hosted-main.d.ts +17 -0
- package/dist/types/index.d.ts +65 -0
- package/dist/types/mcp/schema.d.ts +7 -0
- package/dist/types/node-agent/agent.d.ts +174 -0
- package/dist/types/node-agent/contracts.d.ts +119 -0
- package/dist/types/node-agent/macos-service.d.ts +33 -0
- package/dist/types/node-agent/service-cli.d.ts +26 -0
- package/dist/types/persistence/composition.d.ts +49 -0
- package/dist/types/persistence/migrate-main.d.ts +2 -0
- package/dist/types/persistence/migrations.d.ts +30 -0
- package/dist/types/persistence/postgres-accounts-operation.d.ts +26 -0
- package/dist/types/persistence/postgres-authority.d.ts +69 -0
- package/dist/types/persistence/postgres-external-mutation-journal.d.ts +22 -0
- package/dist/types/persistence/postgres-json.d.ts +1 -0
- package/dist/types/persistence/postgres-mutation-journal.d.ts +31 -0
- package/dist/types/persistence/postgres-reconciler.d.ts +34 -0
- package/dist/types/persistence/postgres-sandbox-dispatch-authority.d.ts +9 -0
- package/dist/types/persistence/self-hosted-migrate-main.d.ts +2 -0
- package/dist/types/ports/accounts-operation.d.ts +336 -0
- package/dist/types/ports/accounts.d.ts +293 -0
- package/dist/types/ports/sandbox-dispatch-authority.d.ts +154 -0
- package/dist/types/ports/sandboxes.d.ts +40 -0
- package/dist/types/providers/sandbox-dispatch.d.ts +143 -0
- package/dist/types/runtime/config.d.ts +61 -0
- package/dist/types/runtime/postgres.d.ts +18 -0
- package/dist/types/runtime/provider-activation.d.ts +45 -0
- package/dist/types/runtime/server.d.ts +68 -0
- package/dist/types/testing/accounts-fake.d.ts +31 -0
- package/dist/types/testing/fakes.d.ts +2 -0
- package/dist/types/testing/node-control-plane-fake.d.ts +20 -0
- package/dist/types/testing/reference.d.ts +27 -0
- package/dist/types/testing/sandboxes-fake.d.ts +22 -0
- package/evidence/provider-live-daytona-v3.json +1 -0
- package/evidence/provider-live-e2b-v3.json +1 -0
- package/evidence/provider-production-route-daytona-v1.json +1 -0
- package/evidence/provider-production-route-e2b-v1.json +1 -0
- package/migrations/0001_authority.sql +689 -0
- package/migrations/0002_effect_step_global_owner.sql +2 -0
- package/migrations/0003_effect_journal_observed_head.sql +34 -0
- package/migrations/0004_authority_mutation_journal_binding.sql +15 -0
- package/migrations/20260710_checkpoint_broker_v1.sql +163 -0
- package/migrations/20260711_accounts_operation_v1.sql +137 -0
- package/migrations/20260711_checkpoint_trust_v2.sql +17 -0
- package/migrations/20260711_verifier_cleanup_v2.sql +169 -0
- package/migrations/20260711_z_accounts_claim_authority_v2.sql +172 -0
- package/migrations/20260711_zz_sandbox_dispatch_authority_v1.sql +143 -0
- package/migrations/20260712_sandbox_dispatch_authority_v2.sql +58 -0
- package/migrations/external-journal/0001_external_authority_mutation_journal.sql +175 -0
- package/package.json +47 -0
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
CREATE SCHEMA IF NOT EXISTS infinity;
|
|
2
|
+
|
|
3
|
+
CREATE TABLE infinity.authority_epochs (
|
|
4
|
+
authority_epoch bigint PRIMARY KEY CHECK (authority_epoch > 0),
|
|
5
|
+
state text NOT NULL CHECK (state IN ('recovery_pending', 'reconciled', 'unknown_requires_review')),
|
|
6
|
+
activation_receipt_digest text NOT NULL CHECK (activation_receipt_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
7
|
+
activated_at timestamptz NOT NULL,
|
|
8
|
+
is_current boolean NOT NULL DEFAULT false
|
|
9
|
+
);
|
|
10
|
+
CREATE UNIQUE INDEX authority_epochs_one_current ON infinity.authority_epochs ((is_current)) WHERE is_current;
|
|
11
|
+
|
|
12
|
+
CREATE TABLE infinity.authority_runtime_meta (
|
|
13
|
+
singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton),
|
|
14
|
+
next_queue_sequence bigint NOT NULL CHECK (next_queue_sequence > 0),
|
|
15
|
+
next_commit_sequence bigint NOT NULL CHECK (next_commit_sequence > 0),
|
|
16
|
+
journal_acknowledged_through bigint NOT NULL CHECK (journal_acknowledged_through >= 0),
|
|
17
|
+
budget_limit_units bigint NOT NULL CHECK (budget_limit_units >= 0),
|
|
18
|
+
budget_reserved_units bigint NOT NULL CHECK (budget_reserved_units >= 0),
|
|
19
|
+
budget_charged_units bigint NOT NULL CHECK (budget_charged_units >= 0),
|
|
20
|
+
budget_released_units bigint NOT NULL CHECK (budget_released_units >= 0)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE TABLE infinity.authority_mutation_change_buffer (
|
|
24
|
+
change_id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
25
|
+
commit_sequence bigint NOT NULL CHECK (commit_sequence > 0),
|
|
26
|
+
table_name text NOT NULL CHECK (table_name ~ '^[a-z][a-z0-9_]*$'),
|
|
27
|
+
mutation_kind text NOT NULL CHECK (mutation_kind IN ('INSERT','UPDATE','DELETE')),
|
|
28
|
+
row_record jsonb NOT NULL,
|
|
29
|
+
captured_at timestamptz NOT NULL
|
|
30
|
+
);
|
|
31
|
+
CREATE INDEX authority_mutation_change_sequence ON infinity.authority_mutation_change_buffer (commit_sequence, change_id);
|
|
32
|
+
|
|
33
|
+
CREATE TABLE infinity.authority_mutation_envelopes (
|
|
34
|
+
commit_sequence bigint PRIMARY KEY CHECK (commit_sequence > 0),
|
|
35
|
+
operation_id text NOT NULL UNIQUE,
|
|
36
|
+
operation_digest text NOT NULL CHECK (operation_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
37
|
+
envelope_digest text NOT NULL UNIQUE CHECK (envelope_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
38
|
+
envelope_record jsonb NOT NULL,
|
|
39
|
+
created_at timestamptz NOT NULL
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
CREATE TABLE infinity.authority_mutation_acknowledgements (
|
|
43
|
+
commit_sequence bigint PRIMARY KEY REFERENCES infinity.authority_mutation_envelopes(commit_sequence),
|
|
44
|
+
frontier_digest text NOT NULL UNIQUE CHECK (frontier_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
45
|
+
acknowledgement_digest text NOT NULL UNIQUE CHECK (acknowledgement_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
46
|
+
restore_domain_id text NOT NULL CHECK (restore_domain_id ~ '^[A-Za-z0-9][A-Za-z0-9:_-]{0,95}$'),
|
|
47
|
+
signer_principal text NOT NULL CHECK (signer_principal ~ '^[A-Za-z0-9][A-Za-z0-9:_-]{0,95}$'),
|
|
48
|
+
signing_key_id text NOT NULL CHECK (signing_key_id ~ '^[A-Za-z0-9][A-Za-z0-9:_-]{0,95}$'),
|
|
49
|
+
signature text NOT NULL CHECK (signature ~ '^[A-Za-z0-9_-]{80,128}$'),
|
|
50
|
+
acknowledgement_record jsonb NOT NULL,
|
|
51
|
+
acknowledged_at timestamptz NOT NULL
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
ALTER TABLE infinity.authority_mutation_change_buffer
|
|
55
|
+
ADD CONSTRAINT authority_mutation_change_envelope_fk
|
|
56
|
+
FOREIGN KEY (commit_sequence) REFERENCES infinity.authority_mutation_envelopes(commit_sequence)
|
|
57
|
+
DEFERRABLE INITIALLY DEFERRED;
|
|
58
|
+
|
|
59
|
+
CREATE TABLE infinity.routes (
|
|
60
|
+
route_lineage_id text PRIMARY KEY,
|
|
61
|
+
route_id text NOT NULL,
|
|
62
|
+
route_epoch bigint NOT NULL CHECK (route_epoch > 0),
|
|
63
|
+
state text NOT NULL CHECK (state IN ('active','draining','inactive')),
|
|
64
|
+
UNIQUE (route_lineage_id, route_epoch),
|
|
65
|
+
UNIQUE (route_lineage_id, route_id, route_epoch)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
CREATE TABLE infinity.run_specs (
|
|
69
|
+
id text PRIMARY KEY,
|
|
70
|
+
digest text NOT NULL UNIQUE CHECK (digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
71
|
+
schema_version text NOT NULL,
|
|
72
|
+
canonical_spec jsonb NOT NULL,
|
|
73
|
+
created_at timestamptz NOT NULL,
|
|
74
|
+
UNIQUE (id, digest)
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
CREATE TABLE infinity.runs (
|
|
78
|
+
id text PRIMARY KEY,
|
|
79
|
+
run_spec_id text NOT NULL REFERENCES infinity.run_specs(id),
|
|
80
|
+
run_spec_digest text NOT NULL CHECK (run_spec_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
81
|
+
route_lineage_id text NOT NULL,
|
|
82
|
+
route_id text NOT NULL,
|
|
83
|
+
route_epoch bigint NOT NULL CHECK (route_epoch > 0),
|
|
84
|
+
admitted_authority_epoch bigint NOT NULL REFERENCES infinity.authority_epochs(authority_epoch) CHECK (admitted_authority_epoch > 0),
|
|
85
|
+
logical_work_key text NOT NULL,
|
|
86
|
+
owner_principal text NOT NULL,
|
|
87
|
+
project_id text NOT NULL,
|
|
88
|
+
repository_id text NOT NULL,
|
|
89
|
+
current_attempt_id text NOT NULL,
|
|
90
|
+
state text NOT NULL CHECK (state IN ('admitted','active','cancel_requested','finalizing','succeeded','failed','canceled','lost_uncheckpointed','discarded_uncheckpointed')),
|
|
91
|
+
terminal_outcome text,
|
|
92
|
+
revision integer NOT NULL CHECK (revision > 0),
|
|
93
|
+
next_event_sequence integer NOT NULL CHECK (next_event_sequence > 0),
|
|
94
|
+
created_at timestamptz NOT NULL,
|
|
95
|
+
updated_at timestamptz NOT NULL,
|
|
96
|
+
CHECK (updated_at >= created_at),
|
|
97
|
+
CHECK (
|
|
98
|
+
(state IN ('admitted','active','cancel_requested','finalizing') AND terminal_outcome IS NULL)
|
|
99
|
+
OR (state = 'succeeded' AND terminal_outcome = 'succeeded')
|
|
100
|
+
OR (state = 'failed' AND terminal_outcome IN ('failed_permanent','policy_denied','budget_exhausted'))
|
|
101
|
+
OR (state = 'canceled' AND terminal_outcome = 'canceled')
|
|
102
|
+
OR (state = 'lost_uncheckpointed' AND terminal_outcome = 'lost_uncheckpointed')
|
|
103
|
+
OR (state = 'discarded_uncheckpointed' AND terminal_outcome = 'discarded_uncheckpointed')
|
|
104
|
+
),
|
|
105
|
+
FOREIGN KEY (run_spec_id, run_spec_digest) REFERENCES infinity.run_specs(id, digest),
|
|
106
|
+
FOREIGN KEY (route_lineage_id, route_id, route_epoch) REFERENCES infinity.routes(route_lineage_id, route_id, route_epoch),
|
|
107
|
+
UNIQUE (route_lineage_id, logical_work_key),
|
|
108
|
+
UNIQUE (id, route_lineage_id, logical_work_key, run_spec_digest)
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
CREATE TABLE infinity.attempts (
|
|
112
|
+
id text PRIMARY KEY,
|
|
113
|
+
run_id text NOT NULL REFERENCES infinity.runs(id) DEFERRABLE INITIALLY DEFERRED,
|
|
114
|
+
attempt_number integer NOT NULL CHECK (attempt_number > 0),
|
|
115
|
+
phase text NOT NULL CHECK (phase IN ('queued','lane_leased','sandbox_allocating','running','checkpointed','verifying','finalizing','terminal')),
|
|
116
|
+
outcome text CHECK (outcome IS NULL OR outcome IN ('succeeded','failed_retryable','failed_permanent','canceled','lost_uncheckpointed','discarded_uncheckpointed','policy_denied','budget_exhausted')),
|
|
117
|
+
pending_outcome text CHECK (pending_outcome IS NULL OR pending_outcome IN ('succeeded','failed_retryable','failed_permanent','canceled','lost_uncheckpointed','discarded_uncheckpointed','policy_denied','budget_exhausted')),
|
|
118
|
+
runner_principal text,
|
|
119
|
+
attempt_lease_id text,
|
|
120
|
+
lease_epoch bigint CHECK (lease_epoch > 0),
|
|
121
|
+
lease_holder_principal text,
|
|
122
|
+
lease_expires_at timestamptz,
|
|
123
|
+
cancellation_state text NOT NULL CHECK (cancellation_state IN ('none','requested','fenced','cleanup_pending','complete')),
|
|
124
|
+
retry_cause text,
|
|
125
|
+
terminal_reason text,
|
|
126
|
+
revision integer NOT NULL CHECK (revision > 0),
|
|
127
|
+
created_at timestamptz NOT NULL,
|
|
128
|
+
updated_at timestamptz NOT NULL,
|
|
129
|
+
UNIQUE (run_id, attempt_number),
|
|
130
|
+
UNIQUE (id, run_id),
|
|
131
|
+
CHECK (updated_at >= created_at),
|
|
132
|
+
CHECK ((attempt_lease_id IS NULL AND lease_epoch IS NULL AND lease_holder_principal IS NULL AND lease_expires_at IS NULL)
|
|
133
|
+
OR (attempt_lease_id IS NOT NULL AND lease_epoch IS NOT NULL AND lease_holder_principal IS NOT NULL AND lease_expires_at IS NOT NULL)),
|
|
134
|
+
CHECK ((attempt_lease_id IS NULL AND runner_principal IS NULL)
|
|
135
|
+
OR (attempt_lease_id IS NOT NULL AND runner_principal IS NOT NULL)),
|
|
136
|
+
CHECK (phase <> 'queued' OR attempt_lease_id IS NULL),
|
|
137
|
+
CHECK (phase IN ('queued','terminal') OR attempt_lease_id IS NOT NULL),
|
|
138
|
+
CHECK ((phase = 'terminal') = (outcome IS NOT NULL)),
|
|
139
|
+
CHECK (phase = 'finalizing' OR pending_outcome IS NULL),
|
|
140
|
+
CHECK (phase <> 'terminal' OR pending_outcome IS NULL),
|
|
141
|
+
CHECK (phase <> 'terminal' OR attempt_lease_id IS NOT NULL OR outcome = 'policy_denied')
|
|
142
|
+
);
|
|
143
|
+
CREATE UNIQUE INDEX attempts_one_nonterminal_per_run ON infinity.attempts (run_id) WHERE phase <> 'terminal';
|
|
144
|
+
|
|
145
|
+
ALTER TABLE infinity.runs
|
|
146
|
+
ADD CONSTRAINT runs_current_attempt_fk FOREIGN KEY (current_attempt_id, id) REFERENCES infinity.attempts(id, run_id) DEFERRABLE INITIALLY DEFERRED;
|
|
147
|
+
|
|
148
|
+
CREATE TABLE infinity.attempt_lease_grants (
|
|
149
|
+
attempt_lease_id text PRIMARY KEY,
|
|
150
|
+
attempt_id text NOT NULL REFERENCES infinity.attempts(id),
|
|
151
|
+
run_id text NOT NULL REFERENCES infinity.runs(id),
|
|
152
|
+
lease_epoch bigint NOT NULL CHECK (lease_epoch > 0),
|
|
153
|
+
lease_holder_principal text NOT NULL,
|
|
154
|
+
audience text NOT NULL,
|
|
155
|
+
issued_at timestamptz NOT NULL,
|
|
156
|
+
lease_expires_at timestamptz NOT NULL CHECK (lease_expires_at > issued_at),
|
|
157
|
+
grant_digest text NOT NULL CHECK (grant_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
158
|
+
kind text NOT NULL CHECK (kind IN ('worker','cancel_recovery')),
|
|
159
|
+
UNIQUE (attempt_id, lease_epoch),
|
|
160
|
+
UNIQUE (attempt_lease_id, attempt_id, lease_epoch),
|
|
161
|
+
FOREIGN KEY (attempt_id, run_id) REFERENCES infinity.attempts(id, run_id)
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
CREATE TABLE infinity.attempt_lease_events (
|
|
165
|
+
id text PRIMARY KEY,
|
|
166
|
+
attempt_lease_id text NOT NULL,
|
|
167
|
+
attempt_id text NOT NULL REFERENCES infinity.attempts(id),
|
|
168
|
+
lease_epoch bigint NOT NULL CHECK (lease_epoch > 0),
|
|
169
|
+
kind text NOT NULL CHECK (kind IN ('granted','renewed','fenced','released','expired')),
|
|
170
|
+
actor_principal text NOT NULL,
|
|
171
|
+
database_time timestamptz NOT NULL,
|
|
172
|
+
detail_digest text NOT NULL CHECK (detail_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
173
|
+
UNIQUE (attempt_id, lease_epoch, kind, database_time),
|
|
174
|
+
FOREIGN KEY (attempt_lease_id, attempt_id, lease_epoch)
|
|
175
|
+
REFERENCES infinity.attempt_lease_grants(attempt_lease_id, attempt_id, lease_epoch)
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
CREATE TABLE infinity.queue_entries (
|
|
179
|
+
attempt_id text PRIMARY KEY REFERENCES infinity.attempts(id),
|
|
180
|
+
run_id text NOT NULL REFERENCES infinity.runs(id),
|
|
181
|
+
project_id text NOT NULL,
|
|
182
|
+
lane_pool_id text NOT NULL,
|
|
183
|
+
enqueue_sequence bigint NOT NULL UNIQUE CHECK (enqueue_sequence > 0),
|
|
184
|
+
admitted_at timestamptz NOT NULL,
|
|
185
|
+
state text NOT NULL CHECK (state IN ('queued','reserved','removed')),
|
|
186
|
+
FOREIGN KEY (attempt_id, run_id) REFERENCES infinity.attempts(id, run_id)
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
CREATE TABLE infinity.budget_reservations (
|
|
190
|
+
run_id text PRIMARY KEY REFERENCES infinity.runs(id),
|
|
191
|
+
ceiling_units bigint NOT NULL CHECK (ceiling_units >= 0),
|
|
192
|
+
charged_units bigint NOT NULL CHECK (charged_units >= 0),
|
|
193
|
+
state text NOT NULL CHECK (state IN ('reserved','settled','released')),
|
|
194
|
+
CHECK (charged_units <= ceiling_units)
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
CREATE TABLE infinity.admission_keys (
|
|
198
|
+
route_lineage_id text NOT NULL,
|
|
199
|
+
logical_work_key text NOT NULL,
|
|
200
|
+
run_spec_digest text NOT NULL CHECK (run_spec_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
201
|
+
run_id text NOT NULL REFERENCES infinity.runs(id),
|
|
202
|
+
disposition text NOT NULL CHECK (disposition IN ('admitted','tombstone')),
|
|
203
|
+
created_at timestamptz NOT NULL,
|
|
204
|
+
PRIMARY KEY (route_lineage_id, logical_work_key),
|
|
205
|
+
FOREIGN KEY (run_id, route_lineage_id, logical_work_key, run_spec_digest)
|
|
206
|
+
REFERENCES infinity.runs(id, route_lineage_id, logical_work_key, run_spec_digest)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
CREATE TABLE infinity.idempotency_records (
|
|
210
|
+
operation_id text PRIMARY KEY,
|
|
211
|
+
actor_principal text NOT NULL,
|
|
212
|
+
command text NOT NULL,
|
|
213
|
+
scope text NOT NULL,
|
|
214
|
+
idempotency_key text NOT NULL,
|
|
215
|
+
request_hash text NOT NULL CHECK (request_hash ~ '^sha256:[0-9a-f]{64}$'),
|
|
216
|
+
source_namespace text NOT NULL,
|
|
217
|
+
request_execution_epoch bigint NOT NULL CHECK (request_execution_epoch > 0),
|
|
218
|
+
request_execution_holder text NOT NULL,
|
|
219
|
+
request_execution_expires_at timestamptz NOT NULL,
|
|
220
|
+
state text NOT NULL CHECK (state IN ('in_flight','committed','aborted')),
|
|
221
|
+
result jsonb,
|
|
222
|
+
created_at timestamptz NOT NULL,
|
|
223
|
+
updated_at timestamptz NOT NULL,
|
|
224
|
+
UNIQUE (actor_principal, command, scope, idempotency_key)
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
ALTER TABLE infinity.authority_mutation_envelopes
|
|
228
|
+
ADD CONSTRAINT authority_mutation_envelope_operation_fk
|
|
229
|
+
FOREIGN KEY (operation_id) REFERENCES infinity.idempotency_records(operation_id)
|
|
230
|
+
DEFERRABLE INITIALLY DEFERRED;
|
|
231
|
+
|
|
232
|
+
CREATE TABLE infinity.event_stream_heads (
|
|
233
|
+
aggregate_type text NOT NULL,
|
|
234
|
+
aggregate_id text NOT NULL,
|
|
235
|
+
sequence integer NOT NULL CHECK (sequence > 0),
|
|
236
|
+
digest text NOT NULL CHECK (digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
237
|
+
PRIMARY KEY (aggregate_type, aggregate_id)
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
CREATE TABLE infinity.events (
|
|
241
|
+
event_id text PRIMARY KEY,
|
|
242
|
+
authority_commit_sequence bigint NOT NULL UNIQUE CHECK (authority_commit_sequence > 0),
|
|
243
|
+
operation_id text NOT NULL,
|
|
244
|
+
operation_digest text NOT NULL CHECK (operation_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
245
|
+
aggregate_type text NOT NULL,
|
|
246
|
+
aggregate_id text NOT NULL,
|
|
247
|
+
aggregate_sequence integer NOT NULL CHECK (aggregate_sequence > 0),
|
|
248
|
+
run_id text,
|
|
249
|
+
run_sequence integer,
|
|
250
|
+
actor_principal text NOT NULL,
|
|
251
|
+
authority_epoch bigint NOT NULL CHECK (authority_epoch > 0),
|
|
252
|
+
route_lineage_id text,
|
|
253
|
+
route_id text,
|
|
254
|
+
route_epoch bigint CHECK (route_epoch > 0),
|
|
255
|
+
attempt_id text,
|
|
256
|
+
attempt_lease_id text,
|
|
257
|
+
lease_epoch bigint CHECK (lease_epoch > 0),
|
|
258
|
+
lease_holder_principal text,
|
|
259
|
+
audience text,
|
|
260
|
+
resource_lease_id text,
|
|
261
|
+
resource_id text,
|
|
262
|
+
resource_lifecycle_generation bigint CHECK (resource_lifecycle_generation > 0),
|
|
263
|
+
operation_executor_principal text,
|
|
264
|
+
event_schema text NOT NULL,
|
|
265
|
+
event_type text NOT NULL,
|
|
266
|
+
event_digest text NOT NULL UNIQUE CHECK (event_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
267
|
+
prior_event_digest text CHECK (prior_event_digest IS NULL OR prior_event_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
268
|
+
payload jsonb NOT NULL,
|
|
269
|
+
payload_digest text NOT NULL CHECK (payload_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
270
|
+
event_record jsonb NOT NULL,
|
|
271
|
+
database_time timestamptz NOT NULL,
|
|
272
|
+
UNIQUE (aggregate_type, aggregate_id, aggregate_sequence),
|
|
273
|
+
UNIQUE (run_id, run_sequence),
|
|
274
|
+
UNIQUE (event_id, authority_commit_sequence, event_digest),
|
|
275
|
+
CHECK ((route_lineage_id IS NULL AND route_id IS NULL AND route_epoch IS NULL)
|
|
276
|
+
OR (route_lineage_id IS NOT NULL AND route_id IS NOT NULL AND route_epoch IS NOT NULL)),
|
|
277
|
+
CHECK ((attempt_lease_id IS NULL AND lease_epoch IS NULL AND lease_holder_principal IS NULL AND audience IS NULL)
|
|
278
|
+
OR (attempt_lease_id IS NOT NULL AND lease_epoch IS NOT NULL AND lease_holder_principal IS NOT NULL AND audience IS NOT NULL)),
|
|
279
|
+
CHECK ((resource_lease_id IS NULL AND resource_id IS NULL AND resource_lifecycle_generation IS NULL)
|
|
280
|
+
OR (resource_lease_id IS NOT NULL AND resource_id IS NOT NULL AND resource_lifecycle_generation IS NOT NULL))
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
CREATE TABLE infinity.outbox (
|
|
284
|
+
id text PRIMARY KEY,
|
|
285
|
+
event_id text NOT NULL REFERENCES infinity.events(event_id),
|
|
286
|
+
destination text NOT NULL,
|
|
287
|
+
projection_version text NOT NULL,
|
|
288
|
+
outbox_identity_digest text NOT NULL UNIQUE CHECK (outbox_identity_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
289
|
+
payload_digest text NOT NULL CHECK (payload_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
290
|
+
state text NOT NULL CHECK (state IN ('held','pending','leased','delivered','blocked')),
|
|
291
|
+
authority_commit_sequence bigint NOT NULL CHECK (authority_commit_sequence > 0),
|
|
292
|
+
lease_owner text,
|
|
293
|
+
lease_expires_at timestamptz,
|
|
294
|
+
created_at timestamptz NOT NULL,
|
|
295
|
+
CHECK ((lease_owner IS NULL) = (lease_expires_at IS NULL)),
|
|
296
|
+
UNIQUE (event_id, destination, projection_version),
|
|
297
|
+
FOREIGN KEY (event_id, authority_commit_sequence, payload_digest)
|
|
298
|
+
REFERENCES infinity.events(event_id, authority_commit_sequence, event_digest)
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
CREATE TABLE infinity.external_operations (
|
|
302
|
+
id text NOT NULL,
|
|
303
|
+
operation_step_id text NOT NULL,
|
|
304
|
+
operation_execution_epoch bigint NOT NULL CHECK (operation_execution_epoch > 0),
|
|
305
|
+
provider_idempotency_token text NOT NULL,
|
|
306
|
+
state text NOT NULL CHECK (state IN ('planned','intent_committed','prepared','dispatched','succeeded','failed_effect','failed_no_effect','unknown','suppressed','quarantined')),
|
|
307
|
+
fence_digest text NOT NULL CHECK (fence_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
308
|
+
operation_record jsonb NOT NULL,
|
|
309
|
+
revision integer NOT NULL CHECK (revision > 0),
|
|
310
|
+
updated_at timestamptz NOT NULL,
|
|
311
|
+
PRIMARY KEY (id, operation_execution_epoch)
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
CREATE TABLE infinity.effect_operation_steps (
|
|
315
|
+
operation_id text NOT NULL,
|
|
316
|
+
operation_step_id text NOT NULL,
|
|
317
|
+
step_ordinal integer NOT NULL CHECK (step_ordinal > 0),
|
|
318
|
+
operation_step_digest text NOT NULL CHECK (operation_step_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
319
|
+
step_record jsonb NOT NULL,
|
|
320
|
+
PRIMARY KEY (operation_id, operation_step_id),
|
|
321
|
+
UNIQUE (operation_id, step_ordinal)
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
CREATE TABLE infinity.effect_journal_records (
|
|
325
|
+
operation_id text NOT NULL,
|
|
326
|
+
operation_step_id text NOT NULL,
|
|
327
|
+
operation_execution_epoch bigint NOT NULL CHECK (operation_execution_epoch > 0),
|
|
328
|
+
record_kind text NOT NULL CHECK (record_kind IN ('DISPATCHED','OUTCOME')),
|
|
329
|
+
outcome_kind text CHECK (outcome_kind IS NULL OR outcome_kind IN ('succeeded','failed_effect','failed_no_effect','reconciliation_blocked')),
|
|
330
|
+
outcome_receipt_digest text CHECK (outcome_receipt_digest IS NULL OR outcome_receipt_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
331
|
+
operation_digest text NOT NULL CHECK (operation_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
332
|
+
operation_step_digest text NOT NULL CHECK (operation_step_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
333
|
+
request_digest text NOT NULL CHECK (request_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
334
|
+
target_digest text NOT NULL CHECK (target_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
335
|
+
resource_id text NOT NULL,
|
|
336
|
+
resource_lifecycle_generation bigint NOT NULL CHECK (resource_lifecycle_generation > 0),
|
|
337
|
+
predecessor_receipt_digest text CHECK (predecessor_receipt_digest IS NULL OR predecessor_receipt_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
338
|
+
provider_idempotency_token text NOT NULL,
|
|
339
|
+
journal_sequence bigint NOT NULL UNIQUE CHECK (journal_sequence > 0),
|
|
340
|
+
prior_frontier_digest text CHECK (prior_frontier_digest IS NULL OR prior_frontier_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
341
|
+
record_digest text NOT NULL CHECK (record_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
342
|
+
frontier_digest text NOT NULL UNIQUE CHECK (frontier_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
343
|
+
signer_principal text NOT NULL,
|
|
344
|
+
signing_key_id text NOT NULL,
|
|
345
|
+
signature text NOT NULL,
|
|
346
|
+
anchor_record jsonb NOT NULL,
|
|
347
|
+
created_at timestamptz NOT NULL,
|
|
348
|
+
PRIMARY KEY (operation_id, operation_step_id, operation_execution_epoch, record_kind),
|
|
349
|
+
FOREIGN KEY (operation_id, operation_step_id) REFERENCES infinity.effect_operation_steps(operation_id, operation_step_id),
|
|
350
|
+
CHECK ((record_kind = 'DISPATCHED' AND outcome_kind IS NULL AND outcome_receipt_digest IS NULL)
|
|
351
|
+
OR (record_kind = 'OUTCOME' AND outcome_kind IS NOT NULL AND outcome_receipt_digest IS NOT NULL))
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
CREATE TABLE infinity.effect_journal_frontier (
|
|
355
|
+
singleton boolean PRIMARY KEY DEFAULT true CHECK (singleton),
|
|
356
|
+
journal_sequence bigint NOT NULL CHECK (journal_sequence >= 0),
|
|
357
|
+
frontier_digest text CHECK (frontier_digest IS NULL OR frontier_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
358
|
+
updated_at timestamptz NOT NULL,
|
|
359
|
+
CHECK ((journal_sequence = 0) = (frontier_digest IS NULL))
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
CREATE OR REPLACE FUNCTION infinity.reject_immutable_mutation() RETURNS trigger
|
|
363
|
+
LANGUAGE plpgsql AS $$
|
|
364
|
+
BEGIN
|
|
365
|
+
RAISE EXCEPTION 'immutable Infinity record cannot be updated or deleted' USING ERRCODE = '55000';
|
|
366
|
+
END;
|
|
367
|
+
$$;
|
|
368
|
+
|
|
369
|
+
CREATE OR REPLACE FUNCTION infinity.capture_authority_mutation_change() RETURNS trigger
|
|
370
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
371
|
+
SET search_path = pg_catalog, infinity AS $$
|
|
372
|
+
DECLARE
|
|
373
|
+
sequence_text text;
|
|
374
|
+
image jsonb;
|
|
375
|
+
BEGIN
|
|
376
|
+
IF TG_TABLE_NAME = 'authority_runtime_meta' AND TG_OP = 'UPDATE'
|
|
377
|
+
AND (to_jsonb(NEW) - 'journal_acknowledged_through') = (to_jsonb(OLD) - 'journal_acknowledged_through') THEN
|
|
378
|
+
RETURN NEW;
|
|
379
|
+
END IF;
|
|
380
|
+
sequence_text := NULLIF(current_setting('infinity.authority_commit_sequence', true), '');
|
|
381
|
+
IF sequence_text IS NULL OR sequence_text !~ '^[1-9][0-9]*$' THEN
|
|
382
|
+
RAISE EXCEPTION 'authority mutation lacks a committed sequence context' USING ERRCODE = '55000';
|
|
383
|
+
END IF;
|
|
384
|
+
IF TG_OP = 'DELETE' THEN image := to_jsonb(OLD); ELSE image := to_jsonb(NEW); END IF;
|
|
385
|
+
INSERT INTO infinity.authority_mutation_change_buffer
|
|
386
|
+
(commit_sequence, table_name, mutation_kind, row_record, captured_at)
|
|
387
|
+
VALUES (sequence_text::bigint, TG_TABLE_NAME, TG_OP, image, clock_timestamp());
|
|
388
|
+
IF TG_OP = 'DELETE' THEN RETURN OLD; ELSE RETURN NEW; END IF;
|
|
389
|
+
END;
|
|
390
|
+
$$;
|
|
391
|
+
|
|
392
|
+
CREATE OR REPLACE FUNCTION infinity.validate_authority_mutation_envelope() RETURNS trigger
|
|
393
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
394
|
+
SET search_path = pg_catalog, infinity AS $$
|
|
395
|
+
DECLARE
|
|
396
|
+
mismatch boolean;
|
|
397
|
+
BEGIN
|
|
398
|
+
IF NEW.envelope_record->>'schema_version' IS DISTINCT FROM 'infinity.authority-mutation-reconstruction/v1'
|
|
399
|
+
OR (NEW.envelope_record->>'commit_sequence')::bigint IS DISTINCT FROM NEW.commit_sequence
|
|
400
|
+
OR NEW.envelope_record->>'operation_id' IS DISTINCT FROM NEW.operation_id
|
|
401
|
+
OR NEW.envelope_record->>'operation_digest' IS DISTINCT FROM NEW.operation_digest
|
|
402
|
+
OR jsonb_typeof(NEW.envelope_record->'changes') IS DISTINCT FROM 'array' THEN
|
|
403
|
+
RAISE EXCEPTION 'authority mutation envelope columns differ from reconstruction record' USING ERRCODE = '23514';
|
|
404
|
+
END IF;
|
|
405
|
+
IF NOT EXISTS (
|
|
406
|
+
SELECT 1 FROM infinity.authority_runtime_meta
|
|
407
|
+
WHERE singleton
|
|
408
|
+
AND next_commit_sequence = NEW.commit_sequence + 1
|
|
409
|
+
AND journal_acknowledged_through = NEW.commit_sequence - 1
|
|
410
|
+
) THEN
|
|
411
|
+
RAISE EXCEPTION 'authority mutation envelope does not extend the local contiguous frontier' USING ERRCODE = '23514';
|
|
412
|
+
END IF;
|
|
413
|
+
IF NOT EXISTS (
|
|
414
|
+
SELECT 1 FROM infinity.idempotency_records
|
|
415
|
+
WHERE operation_id = NEW.operation_id AND request_hash = NEW.operation_digest AND state = 'committed'
|
|
416
|
+
) THEN
|
|
417
|
+
RAISE EXCEPTION 'authority mutation envelope lacks its committed idempotency record' USING ERRCODE = '23514';
|
|
418
|
+
END IF;
|
|
419
|
+
WITH buffered AS (
|
|
420
|
+
SELECT row_number() OVER (ORDER BY change_id) AS ordinal, table_name, mutation_kind, row_record
|
|
421
|
+
FROM infinity.authority_mutation_change_buffer WHERE commit_sequence = NEW.commit_sequence
|
|
422
|
+
), encoded AS (
|
|
423
|
+
SELECT ordinality AS ordinal, value
|
|
424
|
+
FROM jsonb_array_elements(NEW.envelope_record->'changes') WITH ORDINALITY AS item(value, ordinality)
|
|
425
|
+
)
|
|
426
|
+
SELECT EXISTS (
|
|
427
|
+
SELECT 1 FROM buffered FULL JOIN encoded USING (ordinal)
|
|
428
|
+
WHERE buffered.ordinal IS NULL OR encoded.ordinal IS NULL
|
|
429
|
+
OR (encoded.value->>'change_ordinal')::bigint IS DISTINCT FROM buffered.ordinal
|
|
430
|
+
OR encoded.value->>'table_name' IS DISTINCT FROM buffered.table_name
|
|
431
|
+
OR encoded.value->>'mutation_kind' IS DISTINCT FROM buffered.mutation_kind
|
|
432
|
+
OR encoded.value->'row' IS DISTINCT FROM buffered.row_record
|
|
433
|
+
) INTO mismatch;
|
|
434
|
+
IF mismatch OR NOT EXISTS (
|
|
435
|
+
SELECT 1 FROM infinity.authority_mutation_change_buffer WHERE commit_sequence = NEW.commit_sequence
|
|
436
|
+
) THEN
|
|
437
|
+
RAISE EXCEPTION 'authority mutation envelope changes differ from captured row images' USING ERRCODE = '23514';
|
|
438
|
+
END IF;
|
|
439
|
+
RETURN NEW;
|
|
440
|
+
END;
|
|
441
|
+
$$;
|
|
442
|
+
|
|
443
|
+
CREATE OR REPLACE FUNCTION infinity.validate_authority_mutation_acknowledgement() RETURNS trigger
|
|
444
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
445
|
+
SET search_path = pg_catalog, infinity AS $$
|
|
446
|
+
BEGIN
|
|
447
|
+
IF NEW.acknowledgement_record->>'ack_schema_version' IS DISTINCT FROM 'infinity.authority-mutation-journal-ack/v1'
|
|
448
|
+
OR (NEW.acknowledgement_record->>'acknowledged_through')::bigint IS DISTINCT FROM NEW.commit_sequence
|
|
449
|
+
OR NEW.acknowledgement_record->>'frontier_digest' IS DISTINCT FROM NEW.frontier_digest
|
|
450
|
+
OR NEW.acknowledgement_record->>'restore_domain_id' IS DISTINCT FROM NEW.restore_domain_id
|
|
451
|
+
OR NEW.acknowledgement_record->'encrypted_at_rest' IS DISTINCT FROM 'true'::jsonb THEN
|
|
452
|
+
RAISE EXCEPTION 'authority mutation acknowledgement columns differ from signed record' USING ERRCODE = '23514';
|
|
453
|
+
END IF;
|
|
454
|
+
IF NEW.acknowledgement_record->>'signer_principal' IS DISTINCT FROM NEW.signer_principal
|
|
455
|
+
OR NEW.acknowledgement_record->>'signing_key_id' IS DISTINCT FROM NEW.signing_key_id
|
|
456
|
+
OR NEW.acknowledgement_record->>'signature' IS DISTINCT FROM NEW.signature THEN
|
|
457
|
+
RAISE EXCEPTION 'authority mutation acknowledgement columns differ from signed record' USING ERRCODE = '23514';
|
|
458
|
+
END IF;
|
|
459
|
+
RETURN NEW;
|
|
460
|
+
END;
|
|
461
|
+
$$;
|
|
462
|
+
|
|
463
|
+
CREATE OR REPLACE FUNCTION infinity.validate_authority_ack_frontier_update() RETURNS trigger
|
|
464
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
465
|
+
SET search_path = pg_catalog, infinity AS $$
|
|
466
|
+
BEGIN
|
|
467
|
+
IF NEW.journal_acknowledged_through = OLD.journal_acknowledged_through THEN
|
|
468
|
+
RETURN NEW;
|
|
469
|
+
END IF;
|
|
470
|
+
IF (to_jsonb(NEW) - 'journal_acknowledged_through') IS DISTINCT FROM (to_jsonb(OLD) - 'journal_acknowledged_through')
|
|
471
|
+
OR NEW.journal_acknowledged_through <> OLD.journal_acknowledged_through + 1
|
|
472
|
+
OR NEW.journal_acknowledged_through >= NEW.next_commit_sequence
|
|
473
|
+
OR NOT EXISTS (
|
|
474
|
+
SELECT 1 FROM infinity.authority_mutation_acknowledgements
|
|
475
|
+
WHERE commit_sequence = NEW.journal_acknowledged_through
|
|
476
|
+
AND (acknowledgement_record->>'acknowledged_through')::bigint = NEW.journal_acknowledged_through
|
|
477
|
+
AND acknowledgement_record->>'frontier_digest' = frontier_digest
|
|
478
|
+
) THEN
|
|
479
|
+
RAISE EXCEPTION 'authority mutation acknowledgement frontier update lacks the exact next signed record' USING ERRCODE = '23514';
|
|
480
|
+
END IF;
|
|
481
|
+
RETURN NEW;
|
|
482
|
+
END;
|
|
483
|
+
$$;
|
|
484
|
+
|
|
485
|
+
CREATE OR REPLACE FUNCTION infinity.validate_outbox_write() RETURNS trigger
|
|
486
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
487
|
+
SET search_path = pg_catalog, infinity AS $$
|
|
488
|
+
DECLARE
|
|
489
|
+
acknowledged bigint;
|
|
490
|
+
BEGIN
|
|
491
|
+
IF TG_OP = 'INSERT' THEN
|
|
492
|
+
IF NEW.state <> 'held' OR NEW.lease_owner IS NOT NULL OR NEW.lease_expires_at IS NOT NULL THEN
|
|
493
|
+
RAISE EXCEPTION 'new outbox records must begin held behind the journal barrier' USING ERRCODE = '23514';
|
|
494
|
+
END IF;
|
|
495
|
+
RETURN NEW;
|
|
496
|
+
END IF;
|
|
497
|
+
IF (to_jsonb(NEW) - 'state' - 'lease_owner' - 'lease_expires_at')
|
|
498
|
+
IS DISTINCT FROM (to_jsonb(OLD) - 'state' - 'lease_owner' - 'lease_expires_at') THEN
|
|
499
|
+
RAISE EXCEPTION 'immutable outbox authority binding cannot change' USING ERRCODE = '23514';
|
|
500
|
+
END IF;
|
|
501
|
+
IF NEW.state <> 'held' THEN
|
|
502
|
+
SELECT journal_acknowledged_through INTO acknowledged
|
|
503
|
+
FROM infinity.authority_runtime_meta WHERE singleton;
|
|
504
|
+
IF acknowledged IS NULL OR acknowledged < NEW.authority_commit_sequence THEN
|
|
505
|
+
RAISE EXCEPTION 'outbox record cannot cross an unacknowledged authority frontier' USING ERRCODE = '23514';
|
|
506
|
+
END IF;
|
|
507
|
+
END IF;
|
|
508
|
+
IF OLD.state = 'held' AND NEW.state = 'pending'
|
|
509
|
+
AND NEW.lease_owner IS NULL AND NEW.lease_expires_at IS NULL THEN
|
|
510
|
+
RETURN NEW;
|
|
511
|
+
ELSIF OLD.state = 'pending' AND NEW.state = 'leased'
|
|
512
|
+
AND OLD.lease_owner IS NULL AND OLD.lease_expires_at IS NULL
|
|
513
|
+
AND NEW.lease_owner IS NOT NULL AND NEW.lease_expires_at > clock_timestamp() THEN
|
|
514
|
+
RETURN NEW;
|
|
515
|
+
ELSIF OLD.state = 'leased' AND NEW.state = 'leased'
|
|
516
|
+
AND OLD.lease_expires_at <= clock_timestamp()
|
|
517
|
+
AND NEW.lease_owner IS NOT NULL AND NEW.lease_expires_at > clock_timestamp() THEN
|
|
518
|
+
RETURN NEW;
|
|
519
|
+
ELSIF OLD.state = 'leased' AND NEW.state = 'delivered'
|
|
520
|
+
AND OLD.lease_expires_at > clock_timestamp()
|
|
521
|
+
AND NEW.lease_owner IS NULL AND NEW.lease_expires_at IS NULL THEN
|
|
522
|
+
RETURN NEW;
|
|
523
|
+
ELSIF OLD.state = 'leased' AND NEW.state = 'pending'
|
|
524
|
+
AND OLD.lease_expires_at <= clock_timestamp()
|
|
525
|
+
AND NEW.lease_owner IS NULL AND NEW.lease_expires_at IS NULL THEN
|
|
526
|
+
RETURN NEW;
|
|
527
|
+
ELSIF OLD.state IN ('pending', 'leased') AND NEW.state = 'blocked'
|
|
528
|
+
AND NEW.lease_owner IS NULL AND NEW.lease_expires_at IS NULL THEN
|
|
529
|
+
RETURN NEW;
|
|
530
|
+
END IF;
|
|
531
|
+
RAISE EXCEPTION 'invalid outbox state or lease transition' USING ERRCODE = '23514';
|
|
532
|
+
END;
|
|
533
|
+
$$;
|
|
534
|
+
|
|
535
|
+
CREATE OR REPLACE FUNCTION infinity.validate_effect_journal_insert() RETURNS trigger
|
|
536
|
+
LANGUAGE plpgsql AS $$
|
|
537
|
+
DECLARE
|
|
538
|
+
current_sequence bigint;
|
|
539
|
+
current_digest text;
|
|
540
|
+
dispatched infinity.effect_journal_records%ROWTYPE;
|
|
541
|
+
prior_outcome infinity.effect_journal_records%ROWTYPE;
|
|
542
|
+
BEGIN
|
|
543
|
+
SELECT journal_sequence, frontier_digest INTO current_sequence, current_digest
|
|
544
|
+
FROM infinity.effect_journal_frontier WHERE singleton FOR UPDATE;
|
|
545
|
+
IF NEW.journal_sequence <> current_sequence + 1 OR NEW.prior_frontier_digest IS DISTINCT FROM current_digest THEN
|
|
546
|
+
RAISE EXCEPTION 'effect journal record does not extend contiguous frontier' USING ERRCODE = '23514';
|
|
547
|
+
END IF;
|
|
548
|
+
IF NEW.anchor_record->>'record_digest' IS DISTINCT FROM NEW.record_digest
|
|
549
|
+
OR NEW.anchor_record->>'frontier_digest' IS DISTINCT FROM NEW.frontier_digest
|
|
550
|
+
OR NEW.anchor_record->>'signer_principal' IS DISTINCT FROM NEW.signer_principal
|
|
551
|
+
OR NEW.anchor_record->>'signing_key_id' IS DISTINCT FROM NEW.signing_key_id
|
|
552
|
+
OR NEW.anchor_record->'record'->>'operation_id' IS DISTINCT FROM NEW.operation_id
|
|
553
|
+
OR NEW.anchor_record->'record'->>'operation_step_id' IS DISTINCT FROM NEW.operation_step_id
|
|
554
|
+
OR (NEW.anchor_record->'record'->>'operation_execution_epoch')::bigint IS DISTINCT FROM NEW.operation_execution_epoch
|
|
555
|
+
OR NEW.anchor_record->'record'->>'record_kind' IS DISTINCT FROM NEW.record_kind
|
|
556
|
+
OR NEW.anchor_record->'record'->>'operation_digest' IS DISTINCT FROM NEW.operation_digest
|
|
557
|
+
OR NEW.anchor_record->'record'->>'operation_step_digest' IS DISTINCT FROM NEW.operation_step_digest
|
|
558
|
+
OR NEW.anchor_record->'record'->>'request_digest' IS DISTINCT FROM NEW.request_digest
|
|
559
|
+
OR NEW.anchor_record->'record'->>'target_digest' IS DISTINCT FROM NEW.target_digest
|
|
560
|
+
OR NEW.anchor_record->'record'->>'resource_id' IS DISTINCT FROM NEW.resource_id
|
|
561
|
+
OR (NEW.anchor_record->'record'->>'resource_lifecycle_generation')::bigint IS DISTINCT FROM NEW.resource_lifecycle_generation
|
|
562
|
+
OR NEW.anchor_record->'record'->>'predecessor_receipt_digest' IS DISTINCT FROM NEW.predecessor_receipt_digest
|
|
563
|
+
OR NEW.anchor_record->'record'->>'provider_idempotency_token' IS DISTINCT FROM NEW.provider_idempotency_token THEN
|
|
564
|
+
RAISE EXCEPTION 'effect journal columns differ from signed anchor envelope' USING ERRCODE = '23514';
|
|
565
|
+
END IF;
|
|
566
|
+
IF NEW.record_kind = 'OUTCOME' THEN
|
|
567
|
+
SELECT * INTO dispatched FROM infinity.effect_journal_records
|
|
568
|
+
WHERE operation_id = NEW.operation_id AND operation_step_id = NEW.operation_step_id
|
|
569
|
+
AND operation_execution_epoch = NEW.operation_execution_epoch AND record_kind = 'DISPATCHED';
|
|
570
|
+
IF NOT FOUND OR dispatched.anchor_record->'record'->'fence' <> NEW.anchor_record->'record'->'fence'
|
|
571
|
+
OR dispatched.operation_digest <> NEW.operation_digest
|
|
572
|
+
OR dispatched.operation_step_digest <> NEW.operation_step_digest
|
|
573
|
+
OR dispatched.request_digest <> NEW.request_digest
|
|
574
|
+
OR dispatched.target_digest <> NEW.target_digest
|
|
575
|
+
OR dispatched.resource_id <> NEW.resource_id
|
|
576
|
+
OR dispatched.resource_lifecycle_generation <> NEW.resource_lifecycle_generation
|
|
577
|
+
OR dispatched.predecessor_receipt_digest IS DISTINCT FROM NEW.predecessor_receipt_digest
|
|
578
|
+
OR dispatched.provider_idempotency_token <> NEW.provider_idempotency_token THEN
|
|
579
|
+
RAISE EXCEPTION 'OUTCOME requires the matching immutable DISPATCHED fence' USING ERRCODE = '23514';
|
|
580
|
+
END IF;
|
|
581
|
+
ELSE
|
|
582
|
+
IF NEW.operation_execution_epoch = 1 THEN
|
|
583
|
+
NULL;
|
|
584
|
+
ELSE
|
|
585
|
+
SELECT * INTO prior_outcome FROM infinity.effect_journal_records
|
|
586
|
+
WHERE operation_id = NEW.operation_id AND operation_step_id = NEW.operation_step_id
|
|
587
|
+
AND operation_execution_epoch = NEW.operation_execution_epoch - 1 AND record_kind = 'OUTCOME';
|
|
588
|
+
IF NOT FOUND OR prior_outcome.outcome_kind <> 'failed_no_effect'
|
|
589
|
+
OR prior_outcome.operation_digest <> NEW.operation_digest
|
|
590
|
+
OR prior_outcome.operation_step_digest <> NEW.operation_step_digest
|
|
591
|
+
OR prior_outcome.request_digest <> NEW.request_digest
|
|
592
|
+
OR prior_outcome.target_digest <> NEW.target_digest
|
|
593
|
+
OR prior_outcome.resource_id <> NEW.resource_id
|
|
594
|
+
OR prior_outcome.resource_lifecycle_generation <> NEW.resource_lifecycle_generation
|
|
595
|
+
OR prior_outcome.predecessor_receipt_digest IS DISTINCT FROM NEW.predecessor_receipt_digest
|
|
596
|
+
OR prior_outcome.provider_idempotency_token <> NEW.provider_idempotency_token THEN
|
|
597
|
+
RAISE EXCEPTION 'higher execution epoch lacks stable failed_no_effect predecessor' USING ERRCODE = '23514';
|
|
598
|
+
END IF;
|
|
599
|
+
END IF;
|
|
600
|
+
END IF;
|
|
601
|
+
RETURN NEW;
|
|
602
|
+
END;
|
|
603
|
+
$$;
|
|
604
|
+
|
|
605
|
+
CREATE TRIGGER run_specs_immutable BEFORE UPDATE OR DELETE ON infinity.run_specs
|
|
606
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.reject_immutable_mutation();
|
|
607
|
+
CREATE TRIGGER admission_keys_immutable BEFORE UPDATE OR DELETE ON infinity.admission_keys
|
|
608
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.reject_immutable_mutation();
|
|
609
|
+
CREATE TRIGGER attempt_lease_grants_immutable BEFORE UPDATE OR DELETE ON infinity.attempt_lease_grants
|
|
610
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.reject_immutable_mutation();
|
|
611
|
+
CREATE TRIGGER attempt_lease_events_immutable BEFORE UPDATE OR DELETE ON infinity.attempt_lease_events
|
|
612
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.reject_immutable_mutation();
|
|
613
|
+
CREATE TRIGGER events_immutable BEFORE UPDATE OR DELETE ON infinity.events
|
|
614
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.reject_immutable_mutation();
|
|
615
|
+
CREATE TRIGGER effect_operation_steps_immutable BEFORE UPDATE OR DELETE ON infinity.effect_operation_steps
|
|
616
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.reject_immutable_mutation();
|
|
617
|
+
CREATE TRIGGER effect_journal_records_immutable BEFORE UPDATE OR DELETE ON infinity.effect_journal_records
|
|
618
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.reject_immutable_mutation();
|
|
619
|
+
CREATE TRIGGER effect_journal_insert_guard BEFORE INSERT ON infinity.effect_journal_records
|
|
620
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.validate_effect_journal_insert();
|
|
621
|
+
CREATE TRIGGER authority_mutation_envelope_insert_guard BEFORE INSERT ON infinity.authority_mutation_envelopes
|
|
622
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.validate_authority_mutation_envelope();
|
|
623
|
+
CREATE TRIGGER authority_mutation_acknowledgement_insert_guard BEFORE INSERT ON infinity.authority_mutation_acknowledgements
|
|
624
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.validate_authority_mutation_acknowledgement();
|
|
625
|
+
CREATE TRIGGER authority_ack_frontier_update_guard BEFORE UPDATE ON infinity.authority_runtime_meta
|
|
626
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.validate_authority_ack_frontier_update();
|
|
627
|
+
CREATE TRIGGER outbox_write_guard BEFORE INSERT OR UPDATE ON infinity.outbox
|
|
628
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.validate_outbox_write();
|
|
629
|
+
|
|
630
|
+
CREATE TRIGGER run_specs_mutation_capture AFTER INSERT ON infinity.run_specs
|
|
631
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
632
|
+
CREATE TRIGGER runs_mutation_capture AFTER INSERT OR UPDATE OR DELETE ON infinity.runs
|
|
633
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
634
|
+
CREATE TRIGGER attempts_mutation_capture AFTER INSERT OR UPDATE OR DELETE ON infinity.attempts
|
|
635
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
636
|
+
CREATE TRIGGER attempt_lease_grants_mutation_capture AFTER INSERT ON infinity.attempt_lease_grants
|
|
637
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
638
|
+
CREATE TRIGGER attempt_lease_events_mutation_capture AFTER INSERT ON infinity.attempt_lease_events
|
|
639
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
640
|
+
CREATE TRIGGER queue_entries_mutation_capture AFTER INSERT OR UPDATE OR DELETE ON infinity.queue_entries
|
|
641
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
642
|
+
CREATE TRIGGER budget_reservations_mutation_capture AFTER INSERT OR UPDATE OR DELETE ON infinity.budget_reservations
|
|
643
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
644
|
+
CREATE TRIGGER admission_keys_mutation_capture AFTER INSERT ON infinity.admission_keys
|
|
645
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
646
|
+
CREATE TRIGGER idempotency_records_mutation_capture AFTER INSERT OR UPDATE ON infinity.idempotency_records
|
|
647
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
648
|
+
CREATE TRIGGER event_stream_heads_mutation_capture AFTER INSERT OR UPDATE ON infinity.event_stream_heads
|
|
649
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
650
|
+
CREATE TRIGGER events_mutation_capture AFTER INSERT ON infinity.events
|
|
651
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
652
|
+
CREATE TRIGGER outbox_mutation_capture AFTER INSERT ON infinity.outbox
|
|
653
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
654
|
+
CREATE TRIGGER external_operations_mutation_capture AFTER INSERT OR UPDATE OR DELETE ON infinity.external_operations
|
|
655
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
656
|
+
CREATE TRIGGER authority_runtime_meta_mutation_capture AFTER UPDATE ON infinity.authority_runtime_meta
|
|
657
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
658
|
+
|
|
659
|
+
CREATE TRIGGER authority_mutation_change_buffer_immutable BEFORE UPDATE OR DELETE ON infinity.authority_mutation_change_buffer
|
|
660
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.reject_immutable_mutation();
|
|
661
|
+
CREATE TRIGGER authority_mutation_envelopes_immutable BEFORE UPDATE OR DELETE ON infinity.authority_mutation_envelopes
|
|
662
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.reject_immutable_mutation();
|
|
663
|
+
CREATE TRIGGER authority_mutation_acknowledgements_immutable BEFORE UPDATE OR DELETE ON infinity.authority_mutation_acknowledgements
|
|
664
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.reject_immutable_mutation();
|
|
665
|
+
|
|
666
|
+
INSERT INTO infinity.authority_epochs (
|
|
667
|
+
authority_epoch, state, activation_receipt_digest, activated_at, is_current
|
|
668
|
+
) VALUES (
|
|
669
|
+
1, 'reconciled', 'sha256:0000000000000000000000000000000000000000000000000000000000000000', clock_timestamp(), true
|
|
670
|
+
) ON CONFLICT (authority_epoch) DO NOTHING;
|
|
671
|
+
|
|
672
|
+
INSERT INTO infinity.authority_runtime_meta (
|
|
673
|
+
singleton, next_queue_sequence, next_commit_sequence, journal_acknowledged_through,
|
|
674
|
+
budget_limit_units, budget_reserved_units, budget_charged_units, budget_released_units
|
|
675
|
+
) VALUES (true, 1, 1, 0, 1000000, 0, 0, 0)
|
|
676
|
+
ON CONFLICT (singleton) DO NOTHING;
|
|
677
|
+
|
|
678
|
+
INSERT INTO infinity.routes (route_lineage_id, route_id, route_epoch, state)
|
|
679
|
+
VALUES ('route-lineage-direct', 'route-direct', 1, 'active')
|
|
680
|
+
ON CONFLICT (route_lineage_id) DO NOTHING;
|
|
681
|
+
|
|
682
|
+
INSERT INTO infinity.effect_journal_frontier (singleton, journal_sequence, frontier_digest, updated_at)
|
|
683
|
+
VALUES (true, 0, NULL, clock_timestamp())
|
|
684
|
+
ON CONFLICT (singleton) DO NOTHING;
|
|
685
|
+
|
|
686
|
+
CREATE TRIGGER authority_epochs_mutation_capture AFTER INSERT OR UPDATE OR DELETE ON infinity.authority_epochs
|
|
687
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|
|
688
|
+
CREATE TRIGGER routes_mutation_capture AFTER INSERT OR UPDATE OR DELETE ON infinity.routes
|
|
689
|
+
FOR EACH ROW EXECUTE FUNCTION infinity.capture_authority_mutation_change();
|