@dsh-enhanced/preference-learning 0.1.7 → 0.1.14
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/README.md +50 -11
- package/cordis.patch.yml +3 -0
- package/lib/catalog.d.ts.map +1 -1
- package/lib/catalog.js +7 -6
- package/lib/catalog.js.map +1 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -2
- package/lib/index.js.map +1 -1
- package/lib/service.d.ts +104 -3
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +794 -29
- package/lib/service.js.map +1 -1
- package/lib/sqlite.d.ts +11 -1
- package/lib/sqlite.d.ts.map +1 -1
- package/lib/sqlite.js +643 -2
- package/lib/sqlite.js.map +1 -1
- package/lib/store.d.ts +233 -8
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +2581 -85
- package/lib/store.js.map +1 -1
- package/lib/types.d.ts +1 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.d.ts.map +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +7 -5
package/lib/sqlite.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import { chmodSync, closeSync, constants, lstatSync, mkdirSync, openSync, } from 'node:fs';
|
|
2
3
|
import { dirname, isAbsolute } from 'node:path';
|
|
3
4
|
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
-
export const preferenceSchemaVersion =
|
|
5
|
+
export const preferenceSchemaVersion = 12;
|
|
5
6
|
export class PreferenceDatabaseError extends Error {
|
|
6
7
|
code;
|
|
7
8
|
constructor(code, message) {
|
|
@@ -38,6 +39,20 @@ function preparePrivateFile(path) {
|
|
|
38
39
|
function userVersion(database) {
|
|
39
40
|
return database.prepare('PRAGMA user_version').get().user_version;
|
|
40
41
|
}
|
|
42
|
+
/** Opaque stable binding used after cancellation rows redact their owner lineage. */
|
|
43
|
+
export function preferencePromotionCancellationUpgradeBindingDigest(input) {
|
|
44
|
+
return createHash('sha256')
|
|
45
|
+
.update('preference-memory-promotion-cancellation-upgrade/v1\0')
|
|
46
|
+
.update(JSON.stringify([
|
|
47
|
+
input.promotionId,
|
|
48
|
+
input.promotionGeneration,
|
|
49
|
+
input.requestDigest,
|
|
50
|
+
input.principalLineageId,
|
|
51
|
+
input.principalLineageVersion,
|
|
52
|
+
input.ownerGeneration,
|
|
53
|
+
]))
|
|
54
|
+
.digest('hex');
|
|
55
|
+
}
|
|
41
56
|
function migrate(database) {
|
|
42
57
|
let transactionStarted = false;
|
|
43
58
|
try {
|
|
@@ -54,7 +69,8 @@ function migrate(database) {
|
|
|
54
69
|
transactionStarted = false;
|
|
55
70
|
return;
|
|
56
71
|
}
|
|
57
|
-
|
|
72
|
+
if (current < 1)
|
|
73
|
+
database.exec(`
|
|
58
74
|
CREATE TABLE preference_schema_meta (
|
|
59
75
|
key TEXT PRIMARY KEY,
|
|
60
76
|
value TEXT NOT NULL
|
|
@@ -153,6 +169,631 @@ function migrate(database) {
|
|
|
153
169
|
INSERT INTO preference_schema_meta(key, value) VALUES ('schema-version', '1');
|
|
154
170
|
PRAGMA user_version = 1;
|
|
155
171
|
`);
|
|
172
|
+
if (current < 2)
|
|
173
|
+
database.exec(`
|
|
174
|
+
CREATE TABLE preference_host_maintenance_receipts (
|
|
175
|
+
idempotency_key TEXT PRIMARY KEY,
|
|
176
|
+
payload_hash TEXT NOT NULL,
|
|
177
|
+
scope_digest TEXT NOT NULL,
|
|
178
|
+
deleted_signals INTEGER NOT NULL CHECK (deleted_signals IN (0, 1)),
|
|
179
|
+
occurred_at INTEGER NOT NULL
|
|
180
|
+
) STRICT;
|
|
181
|
+
CREATE INDEX preference_host_maintenance_scope_time
|
|
182
|
+
ON preference_host_maintenance_receipts(scope_digest, occurred_at DESC, idempotency_key);
|
|
183
|
+
UPDATE preference_schema_meta SET value = '2' WHERE key = 'schema-version';
|
|
184
|
+
PRAGMA user_version = 2;
|
|
185
|
+
`);
|
|
186
|
+
if (current < 3)
|
|
187
|
+
database.exec(`
|
|
188
|
+
CREATE TABLE preference_host_activation_receipts (
|
|
189
|
+
idempotency_key TEXT PRIMARY KEY,
|
|
190
|
+
payload_hash TEXT NOT NULL,
|
|
191
|
+
scope_digest TEXT NOT NULL,
|
|
192
|
+
hypothesis_id TEXT NOT NULL,
|
|
193
|
+
expected_version INTEGER NOT NULL CHECK (expected_version >= 1),
|
|
194
|
+
result_version INTEGER NOT NULL CHECK (result_version = expected_version + 1),
|
|
195
|
+
occurred_at INTEGER NOT NULL
|
|
196
|
+
) STRICT;
|
|
197
|
+
CREATE INDEX preference_host_activation_scope_time
|
|
198
|
+
ON preference_host_activation_receipts(scope_digest, occurred_at DESC, idempotency_key);
|
|
199
|
+
UPDATE preference_schema_meta SET value = '3' WHERE key = 'schema-version';
|
|
200
|
+
PRAGMA user_version = 3;
|
|
201
|
+
`);
|
|
202
|
+
if (current < 4)
|
|
203
|
+
database.exec(`
|
|
204
|
+
CREATE TABLE preference_exposures (
|
|
205
|
+
idempotency_key TEXT PRIMARY KEY,
|
|
206
|
+
payload_hash TEXT NOT NULL,
|
|
207
|
+
scope_key TEXT NOT NULL,
|
|
208
|
+
workspace TEXT NOT NULL,
|
|
209
|
+
preset TEXT NOT NULL,
|
|
210
|
+
hypothesis_id TEXT NOT NULL,
|
|
211
|
+
hypothesis_version INTEGER NOT NULL CHECK (hypothesis_version >= 1),
|
|
212
|
+
session_id TEXT NOT NULL,
|
|
213
|
+
source_event_id TEXT NOT NULL,
|
|
214
|
+
source_inbox_id TEXT,
|
|
215
|
+
reply_outbox_id TEXT,
|
|
216
|
+
state TEXT NOT NULL CHECK (state IN ('pending', 'bound')),
|
|
217
|
+
exposed_at INTEGER NOT NULL,
|
|
218
|
+
bound_at INTEGER,
|
|
219
|
+
expires_at INTEGER NOT NULL,
|
|
220
|
+
CHECK ((state = 'pending' AND source_inbox_id IS NULL AND reply_outbox_id IS NULL AND bound_at IS NULL)
|
|
221
|
+
OR (state = 'bound' AND source_inbox_id IS NOT NULL AND reply_outbox_id IS NOT NULL AND bound_at IS NOT NULL))
|
|
222
|
+
) STRICT;
|
|
223
|
+
CREATE INDEX preference_exposures_turn
|
|
224
|
+
ON preference_exposures(scope_key, session_id, source_event_id, state, hypothesis_id);
|
|
225
|
+
CREATE INDEX preference_exposures_outbox
|
|
226
|
+
ON preference_exposures(scope_key, reply_outbox_id, state, hypothesis_id);
|
|
227
|
+
CREATE INDEX preference_exposures_expiry
|
|
228
|
+
ON preference_exposures(expires_at, idempotency_key);
|
|
229
|
+
CREATE TABLE preference_exposure_corrections (
|
|
230
|
+
signal_id TEXT NOT NULL,
|
|
231
|
+
hypothesis_id TEXT NOT NULL,
|
|
232
|
+
hypothesis_version INTEGER NOT NULL CHECK (hypothesis_version >= 1),
|
|
233
|
+
source_inbox_id TEXT NOT NULL,
|
|
234
|
+
reply_outbox_id TEXT NOT NULL,
|
|
235
|
+
occurred_at INTEGER NOT NULL,
|
|
236
|
+
PRIMARY KEY (signal_id, hypothesis_id, hypothesis_version)
|
|
237
|
+
) STRICT;
|
|
238
|
+
CREATE INDEX preference_exposure_corrections_target
|
|
239
|
+
ON preference_exposure_corrections(reply_outbox_id, hypothesis_id, occurred_at);
|
|
240
|
+
UPDATE preference_schema_meta SET value = '4' WHERE key = 'schema-version';
|
|
241
|
+
PRAGMA user_version = 4;
|
|
242
|
+
`);
|
|
243
|
+
if (current < 5)
|
|
244
|
+
database.exec(`
|
|
245
|
+
CREATE TABLE preference_scope_principals (
|
|
246
|
+
scope_key TEXT PRIMARY KEY,
|
|
247
|
+
scope_digest TEXT NOT NULL,
|
|
248
|
+
principal_digest TEXT NOT NULL CHECK (
|
|
249
|
+
length(principal_digest) = 64 AND principal_digest NOT GLOB '*[^a-f0-9]*'
|
|
250
|
+
),
|
|
251
|
+
generation INTEGER NOT NULL CHECK (generation >= 1),
|
|
252
|
+
claimed_at INTEGER NOT NULL,
|
|
253
|
+
purge_pending INTEGER NOT NULL CHECK (purge_pending IN (0, 1)),
|
|
254
|
+
updated_at INTEGER NOT NULL
|
|
255
|
+
) STRICT;
|
|
256
|
+
CREATE INDEX preference_scope_principals_digest
|
|
257
|
+
ON preference_scope_principals(scope_digest, principal_digest);
|
|
258
|
+
UPDATE preference_schema_meta SET value = '5' WHERE key = 'schema-version';
|
|
259
|
+
PRAGMA user_version = 5;
|
|
260
|
+
`);
|
|
261
|
+
if (current < 6)
|
|
262
|
+
database.exec(`
|
|
263
|
+
ALTER TABLE preference_scope_principals
|
|
264
|
+
ADD COLUMN principal_lineage_id TEXT;
|
|
265
|
+
ALTER TABLE preference_scope_principals
|
|
266
|
+
ADD COLUMN principal_lineage_version INTEGER;
|
|
267
|
+
ALTER TABLE preference_scope_principals
|
|
268
|
+
ADD COLUMN learning_paused INTEGER NOT NULL DEFAULT 0
|
|
269
|
+
CHECK (learning_paused IN (0, 1));
|
|
270
|
+
ALTER TABLE preference_scope_principals
|
|
271
|
+
ADD COLUMN paused_at INTEGER;
|
|
272
|
+
ALTER TABLE preference_scope_principals
|
|
273
|
+
ADD COLUMN control_version INTEGER NOT NULL DEFAULT 1 CHECK (control_version >= 1);
|
|
274
|
+
ALTER TABLE preference_scope_principals
|
|
275
|
+
ADD COLUMN ignore_events_through INTEGER NOT NULL DEFAULT -1 CHECK (ignore_events_through >= -1);
|
|
276
|
+
ALTER TABLE preference_host_activation_receipts
|
|
277
|
+
ADD COLUMN owner_generation INTEGER;
|
|
278
|
+
ALTER TABLE preference_host_activation_receipts
|
|
279
|
+
ADD COLUMN principal_lineage_id TEXT;
|
|
280
|
+
ALTER TABLE preference_host_activation_receipts
|
|
281
|
+
ADD COLUMN principal_lineage_version INTEGER;
|
|
282
|
+
ALTER TABLE preference_host_maintenance_receipts
|
|
283
|
+
ADD COLUMN owner_generation INTEGER;
|
|
284
|
+
ALTER TABLE preference_host_maintenance_receipts
|
|
285
|
+
ADD COLUMN principal_lineage_id TEXT;
|
|
286
|
+
ALTER TABLE preference_host_maintenance_receipts
|
|
287
|
+
ADD COLUMN principal_lineage_version INTEGER;
|
|
288
|
+
CREATE TABLE preference_owner_control_receipts (
|
|
289
|
+
idempotency_key TEXT PRIMARY KEY,
|
|
290
|
+
payload_hash TEXT NOT NULL,
|
|
291
|
+
scope_digest TEXT NOT NULL,
|
|
292
|
+
principal_digest TEXT NOT NULL CHECK (
|
|
293
|
+
length(principal_digest) = 64 AND principal_digest NOT GLOB '*[^a-f0-9]*'
|
|
294
|
+
),
|
|
295
|
+
generation INTEGER NOT NULL CHECK (generation >= 1),
|
|
296
|
+
action TEXT NOT NULL CHECK (action IN ('pause', 'resume')),
|
|
297
|
+
result_paused INTEGER NOT NULL CHECK (result_paused IN (0, 1)),
|
|
298
|
+
result_control_version INTEGER NOT NULL CHECK (result_control_version >= 1),
|
|
299
|
+
result_ignore_events_through INTEGER NOT NULL CHECK (result_ignore_events_through >= -1),
|
|
300
|
+
occurred_at INTEGER NOT NULL
|
|
301
|
+
) STRICT;
|
|
302
|
+
CREATE INDEX preference_owner_control_scope_time
|
|
303
|
+
ON preference_owner_control_receipts(scope_digest, occurred_at DESC, idempotency_key);
|
|
304
|
+
UPDATE preference_schema_meta SET value = '6' WHERE key = 'schema-version';
|
|
305
|
+
PRAGMA user_version = 6;
|
|
306
|
+
`);
|
|
307
|
+
if (current < 7)
|
|
308
|
+
database.exec(`
|
|
309
|
+
ALTER TABLE preference_scope_principals
|
|
310
|
+
ADD COLUMN admission_cursor_epoch TEXT;
|
|
311
|
+
ALTER TABLE preference_scope_principals
|
|
312
|
+
ADD COLUMN lineage_claim_sequence INTEGER
|
|
313
|
+
CHECK (lineage_claim_sequence IS NULL OR lineage_claim_sequence >= 1);
|
|
314
|
+
ALTER TABLE preference_scope_principals
|
|
315
|
+
ADD COLUMN admission_high_water INTEGER
|
|
316
|
+
CHECK (admission_high_water IS NULL OR admission_high_water >= 1);
|
|
317
|
+
ALTER TABLE preference_scope_principals
|
|
318
|
+
ADD COLUMN admission_high_water_kind TEXT
|
|
319
|
+
CHECK (admission_high_water_kind IN ('control', 'event'));
|
|
320
|
+
ALTER TABLE preference_scope_principals
|
|
321
|
+
ADD COLUMN ignore_events_through_sequence INTEGER
|
|
322
|
+
CHECK (ignore_events_through_sequence IS NULL OR ignore_events_through_sequence >= 1);
|
|
323
|
+
|
|
324
|
+
-- v6 control receipts were ordered only by millisecond timestamps and
|
|
325
|
+
-- cannot safely participate in the v7 total order. Drop them instead of
|
|
326
|
+
-- inventing cursors during a rolling upgrade.
|
|
327
|
+
DROP TABLE preference_owner_control_receipts;
|
|
328
|
+
CREATE TABLE preference_owner_control_receipts (
|
|
329
|
+
idempotency_key TEXT PRIMARY KEY,
|
|
330
|
+
payload_hash TEXT NOT NULL,
|
|
331
|
+
scope_digest TEXT NOT NULL,
|
|
332
|
+
principal_digest TEXT NOT NULL CHECK (
|
|
333
|
+
length(principal_digest) = 64 AND principal_digest NOT GLOB '*[^a-f0-9]*'
|
|
334
|
+
),
|
|
335
|
+
generation INTEGER NOT NULL CHECK (generation >= 1),
|
|
336
|
+
action TEXT NOT NULL CHECK (action IN ('forget', 'pause', 'resume', 'status')),
|
|
337
|
+
admission_cursor_epoch TEXT NOT NULL,
|
|
338
|
+
admission_cursor_sequence INTEGER NOT NULL CHECK (admission_cursor_sequence >= 1),
|
|
339
|
+
result_applied INTEGER NOT NULL CHECK (result_applied IN (0, 1)),
|
|
340
|
+
result_paused INTEGER NOT NULL CHECK (result_paused IN (0, 1)),
|
|
341
|
+
result_control_version INTEGER NOT NULL CHECK (result_control_version >= 1),
|
|
342
|
+
result_admission_high_water INTEGER
|
|
343
|
+
CHECK (result_admission_high_water IS NULL OR result_admission_high_water >= 1),
|
|
344
|
+
result_ignore_events_through_sequence INTEGER
|
|
345
|
+
CHECK (result_ignore_events_through_sequence IS NULL
|
|
346
|
+
OR result_ignore_events_through_sequence >= 1),
|
|
347
|
+
result_signals INTEGER NOT NULL CHECK (result_signals >= 0),
|
|
348
|
+
result_hypotheses INTEGER NOT NULL CHECK (result_hypotheses >= 0),
|
|
349
|
+
result_active_overlays INTEGER NOT NULL CHECK (result_active_overlays >= 0),
|
|
350
|
+
result_shadow_hypotheses INTEGER NOT NULL CHECK (result_shadow_hypotheses >= 0),
|
|
351
|
+
result_deleted_signals INTEGER NOT NULL DEFAULT 0 CHECK (result_deleted_signals >= 0),
|
|
352
|
+
result_deleted_hypotheses INTEGER NOT NULL DEFAULT 0 CHECK (result_deleted_hypotheses >= 0),
|
|
353
|
+
result_forgotten_through INTEGER NOT NULL DEFAULT -1 CHECK (result_forgotten_through >= -1),
|
|
354
|
+
occurred_at INTEGER NOT NULL
|
|
355
|
+
) STRICT;
|
|
356
|
+
CREATE INDEX preference_owner_control_scope_time
|
|
357
|
+
ON preference_owner_control_receipts(
|
|
358
|
+
scope_digest, admission_cursor_epoch, admission_cursor_sequence DESC, idempotency_key
|
|
359
|
+
);
|
|
360
|
+
UPDATE preference_schema_meta SET value = '7' WHERE key = 'schema-version';
|
|
361
|
+
PRAGMA user_version = 7;
|
|
362
|
+
`);
|
|
363
|
+
if (current < 8)
|
|
364
|
+
database.exec(`
|
|
365
|
+
ALTER TABLE preference_owner_control_receipts
|
|
366
|
+
RENAME TO preference_owner_control_receipts_v7;
|
|
367
|
+
DROP INDEX preference_owner_control_scope_time;
|
|
368
|
+
CREATE TABLE preference_owner_control_receipts (
|
|
369
|
+
idempotency_key TEXT PRIMARY KEY,
|
|
370
|
+
payload_hash TEXT NOT NULL,
|
|
371
|
+
scope_digest TEXT NOT NULL,
|
|
372
|
+
principal_digest TEXT NOT NULL CHECK (
|
|
373
|
+
length(principal_digest) = 64 AND principal_digest NOT GLOB '*[^a-f0-9]*'
|
|
374
|
+
),
|
|
375
|
+
generation INTEGER NOT NULL CHECK (generation >= 1),
|
|
376
|
+
action TEXT NOT NULL CHECK (action IN (
|
|
377
|
+
'explain', 'forget', 'pause', 'resume', 'rollback', 'status'
|
|
378
|
+
)),
|
|
379
|
+
target_preference_key TEXT,
|
|
380
|
+
admission_cursor_epoch TEXT NOT NULL,
|
|
381
|
+
admission_cursor_sequence INTEGER NOT NULL CHECK (admission_cursor_sequence >= 1),
|
|
382
|
+
result_applied INTEGER NOT NULL CHECK (result_applied IN (0, 1)),
|
|
383
|
+
result_paused INTEGER NOT NULL CHECK (result_paused IN (0, 1)),
|
|
384
|
+
result_control_version INTEGER NOT NULL CHECK (result_control_version >= 1),
|
|
385
|
+
result_admission_high_water INTEGER
|
|
386
|
+
CHECK (result_admission_high_water IS NULL OR result_admission_high_water >= 1),
|
|
387
|
+
result_ignore_events_through_sequence INTEGER
|
|
388
|
+
CHECK (result_ignore_events_through_sequence IS NULL
|
|
389
|
+
OR result_ignore_events_through_sequence >= 1),
|
|
390
|
+
result_signals INTEGER NOT NULL CHECK (result_signals >= 0),
|
|
391
|
+
result_hypotheses INTEGER NOT NULL CHECK (result_hypotheses >= 0),
|
|
392
|
+
result_active_overlays INTEGER NOT NULL CHECK (result_active_overlays >= 0),
|
|
393
|
+
result_stored_active_overlays INTEGER NOT NULL DEFAULT 0
|
|
394
|
+
CHECK (result_stored_active_overlays >= 0),
|
|
395
|
+
result_shadow_hypotheses INTEGER NOT NULL CHECK (result_shadow_hypotheses >= 0),
|
|
396
|
+
result_deleted_signals INTEGER NOT NULL DEFAULT 0 CHECK (result_deleted_signals >= 0),
|
|
397
|
+
result_deleted_hypotheses INTEGER NOT NULL DEFAULT 0 CHECK (result_deleted_hypotheses >= 0),
|
|
398
|
+
result_forgotten_through INTEGER NOT NULL DEFAULT -1 CHECK (result_forgotten_through >= -1),
|
|
399
|
+
result_explanation_json TEXT,
|
|
400
|
+
result_rolled_back INTEGER NOT NULL DEFAULT 0 CHECK (result_rolled_back IN (0, 1)),
|
|
401
|
+
result_rolled_back_version INTEGER
|
|
402
|
+
CHECK (result_rolled_back_version IS NULL OR result_rolled_back_version >= 2),
|
|
403
|
+
occurred_at INTEGER NOT NULL,
|
|
404
|
+
CHECK ((action = 'rollback' AND target_preference_key IS NOT NULL)
|
|
405
|
+
OR (action != 'rollback' AND target_preference_key IS NULL)),
|
|
406
|
+
CHECK ((action = 'explain' AND result_explanation_json IS NOT NULL)
|
|
407
|
+
OR (action != 'explain' AND result_explanation_json IS NULL)),
|
|
408
|
+
CHECK (result_rolled_back = 0 OR action = 'rollback')
|
|
409
|
+
) STRICT;
|
|
410
|
+
INSERT INTO preference_owner_control_receipts(
|
|
411
|
+
idempotency_key, payload_hash, scope_digest, principal_digest, generation,
|
|
412
|
+
action, admission_cursor_epoch, admission_cursor_sequence, result_applied,
|
|
413
|
+
result_paused, result_control_version, result_admission_high_water,
|
|
414
|
+
result_ignore_events_through_sequence, result_signals, result_hypotheses,
|
|
415
|
+
result_active_overlays, result_stored_active_overlays, result_shadow_hypotheses,
|
|
416
|
+
result_deleted_signals, result_deleted_hypotheses,
|
|
417
|
+
result_forgotten_through, occurred_at
|
|
418
|
+
)
|
|
419
|
+
SELECT idempotency_key, payload_hash, scope_digest, principal_digest, generation,
|
|
420
|
+
action, admission_cursor_epoch, admission_cursor_sequence, result_applied,
|
|
421
|
+
result_paused, result_control_version, result_admission_high_water,
|
|
422
|
+
result_ignore_events_through_sequence, result_signals, result_hypotheses,
|
|
423
|
+
result_active_overlays, result_active_overlays, result_shadow_hypotheses,
|
|
424
|
+
result_deleted_signals, result_deleted_hypotheses,
|
|
425
|
+
result_forgotten_through, occurred_at
|
|
426
|
+
FROM preference_owner_control_receipts_v7;
|
|
427
|
+
DROP TABLE preference_owner_control_receipts_v7;
|
|
428
|
+
CREATE INDEX preference_owner_control_scope_time
|
|
429
|
+
ON preference_owner_control_receipts(
|
|
430
|
+
scope_digest, admission_cursor_epoch, admission_cursor_sequence DESC, idempotency_key
|
|
431
|
+
);
|
|
432
|
+
UPDATE preference_schema_meta SET value = '8' WHERE key = 'schema-version';
|
|
433
|
+
PRAGMA user_version = 8;
|
|
434
|
+
`);
|
|
435
|
+
if (current < 9)
|
|
436
|
+
database.exec(`
|
|
437
|
+
ALTER TABLE preference_owner_control_receipts
|
|
438
|
+
RENAME TO preference_owner_control_receipts_v8;
|
|
439
|
+
DROP INDEX preference_owner_control_scope_time;
|
|
440
|
+
CREATE TABLE preference_owner_control_receipts (
|
|
441
|
+
idempotency_key TEXT PRIMARY KEY,
|
|
442
|
+
payload_hash TEXT NOT NULL,
|
|
443
|
+
scope_digest TEXT NOT NULL,
|
|
444
|
+
principal_digest TEXT NOT NULL CHECK (
|
|
445
|
+
length(principal_digest) = 64 AND principal_digest NOT GLOB '*[^a-f0-9]*'
|
|
446
|
+
),
|
|
447
|
+
generation INTEGER NOT NULL CHECK (generation >= 1),
|
|
448
|
+
action TEXT NOT NULL CHECK (action IN (
|
|
449
|
+
'explain', 'export', 'forget', 'pause', 'resume', 'rollback', 'status'
|
|
450
|
+
)),
|
|
451
|
+
target_preference_key TEXT,
|
|
452
|
+
admission_cursor_epoch TEXT NOT NULL,
|
|
453
|
+
admission_cursor_sequence INTEGER NOT NULL CHECK (admission_cursor_sequence >= 1),
|
|
454
|
+
result_applied INTEGER NOT NULL CHECK (result_applied IN (0, 1)),
|
|
455
|
+
result_paused INTEGER NOT NULL CHECK (result_paused IN (0, 1)),
|
|
456
|
+
result_control_version INTEGER NOT NULL CHECK (result_control_version >= 1),
|
|
457
|
+
result_admission_high_water INTEGER
|
|
458
|
+
CHECK (result_admission_high_water IS NULL OR result_admission_high_water >= 1),
|
|
459
|
+
result_ignore_events_through_sequence INTEGER
|
|
460
|
+
CHECK (result_ignore_events_through_sequence IS NULL
|
|
461
|
+
OR result_ignore_events_through_sequence >= 1),
|
|
462
|
+
result_signals INTEGER NOT NULL CHECK (result_signals >= 0),
|
|
463
|
+
result_hypotheses INTEGER NOT NULL CHECK (result_hypotheses >= 0),
|
|
464
|
+
result_active_overlays INTEGER NOT NULL CHECK (result_active_overlays >= 0),
|
|
465
|
+
result_stored_active_overlays INTEGER NOT NULL DEFAULT 0
|
|
466
|
+
CHECK (result_stored_active_overlays >= 0),
|
|
467
|
+
result_shadow_hypotheses INTEGER NOT NULL CHECK (result_shadow_hypotheses >= 0),
|
|
468
|
+
result_deleted_signals INTEGER NOT NULL DEFAULT 0 CHECK (result_deleted_signals >= 0),
|
|
469
|
+
result_deleted_hypotheses INTEGER NOT NULL DEFAULT 0 CHECK (result_deleted_hypotheses >= 0),
|
|
470
|
+
result_forgotten_through INTEGER NOT NULL DEFAULT -1 CHECK (result_forgotten_through >= -1),
|
|
471
|
+
result_explanation_json TEXT,
|
|
472
|
+
result_rolled_back INTEGER NOT NULL DEFAULT 0 CHECK (result_rolled_back IN (0, 1)),
|
|
473
|
+
result_rolled_back_version INTEGER
|
|
474
|
+
CHECK (result_rolled_back_version IS NULL OR result_rolled_back_version >= 2),
|
|
475
|
+
occurred_at INTEGER NOT NULL,
|
|
476
|
+
CHECK ((action = 'rollback' AND target_preference_key IS NOT NULL)
|
|
477
|
+
OR (action != 'rollback' AND target_preference_key IS NULL)),
|
|
478
|
+
CHECK ((action IN ('explain', 'export') AND result_explanation_json IS NOT NULL)
|
|
479
|
+
OR (action NOT IN ('explain', 'export') AND result_explanation_json IS NULL)),
|
|
480
|
+
CHECK (result_rolled_back = 0 OR action = 'rollback')
|
|
481
|
+
) STRICT;
|
|
482
|
+
INSERT INTO preference_owner_control_receipts(
|
|
483
|
+
idempotency_key, payload_hash, scope_digest, principal_digest, generation,
|
|
484
|
+
action, target_preference_key, admission_cursor_epoch, admission_cursor_sequence,
|
|
485
|
+
result_applied, result_paused, result_control_version, result_admission_high_water,
|
|
486
|
+
result_ignore_events_through_sequence, result_signals, result_hypotheses,
|
|
487
|
+
result_active_overlays, result_stored_active_overlays, result_shadow_hypotheses,
|
|
488
|
+
result_deleted_signals, result_deleted_hypotheses, result_forgotten_through,
|
|
489
|
+
result_explanation_json, result_rolled_back, result_rolled_back_version, occurred_at
|
|
490
|
+
)
|
|
491
|
+
SELECT idempotency_key, payload_hash, scope_digest, principal_digest, generation,
|
|
492
|
+
action, target_preference_key, admission_cursor_epoch, admission_cursor_sequence,
|
|
493
|
+
result_applied, result_paused, result_control_version, result_admission_high_water,
|
|
494
|
+
result_ignore_events_through_sequence, result_signals, result_hypotheses,
|
|
495
|
+
result_active_overlays, result_stored_active_overlays, result_shadow_hypotheses,
|
|
496
|
+
result_deleted_signals, result_deleted_hypotheses, result_forgotten_through,
|
|
497
|
+
result_explanation_json, result_rolled_back, result_rolled_back_version, occurred_at
|
|
498
|
+
FROM preference_owner_control_receipts_v8;
|
|
499
|
+
DROP TABLE preference_owner_control_receipts_v8;
|
|
500
|
+
CREATE INDEX preference_owner_control_scope_time
|
|
501
|
+
ON preference_owner_control_receipts(
|
|
502
|
+
scope_digest, admission_cursor_epoch, admission_cursor_sequence DESC, idempotency_key
|
|
503
|
+
);
|
|
504
|
+
UPDATE preference_schema_meta SET value = '9' WHERE key = 'schema-version';
|
|
505
|
+
PRAGMA user_version = 9;
|
|
506
|
+
`);
|
|
507
|
+
if (current < 10)
|
|
508
|
+
database.exec(`
|
|
509
|
+
CREATE TABLE preference_memory_promotions (
|
|
510
|
+
promotion_id TEXT NOT NULL,
|
|
511
|
+
promotion_generation INTEGER NOT NULL CHECK (promotion_generation >= 1),
|
|
512
|
+
scope_key TEXT NOT NULL,
|
|
513
|
+
scope_digest TEXT NOT NULL CHECK (
|
|
514
|
+
length(scope_digest) = 64 AND scope_digest NOT GLOB '*[^a-f0-9]*'
|
|
515
|
+
),
|
|
516
|
+
workspace TEXT NOT NULL,
|
|
517
|
+
preset TEXT NOT NULL,
|
|
518
|
+
principal_id TEXT NOT NULL,
|
|
519
|
+
principal_digest TEXT NOT NULL CHECK (
|
|
520
|
+
length(principal_digest) = 64 AND principal_digest NOT GLOB '*[^a-f0-9]*'
|
|
521
|
+
),
|
|
522
|
+
principal_lineage_id TEXT NOT NULL,
|
|
523
|
+
principal_lineage_version INTEGER NOT NULL CHECK (principal_lineage_version >= 1),
|
|
524
|
+
owner_generation INTEGER NOT NULL CHECK (owner_generation >= 1),
|
|
525
|
+
hypothesis_id TEXT NOT NULL,
|
|
526
|
+
hypothesis_key TEXT NOT NULL CHECK (hypothesis_key = 'memory.retention'),
|
|
527
|
+
hypothesis_value TEXT NOT NULL CHECK (hypothesis_value = 'long-term'),
|
|
528
|
+
hypothesis_version INTEGER NOT NULL CHECK (hypothesis_version >= 1),
|
|
529
|
+
confidence_bps INTEGER NOT NULL CHECK (confidence_bps BETWEEN 0 AND 10000),
|
|
530
|
+
contradiction_bps INTEGER NOT NULL CHECK (contradiction_bps BETWEEN 0 AND 10000),
|
|
531
|
+
supporting_signals INTEGER NOT NULL CHECK (supporting_signals >= 2),
|
|
532
|
+
distinct_signal_sources INTEGER NOT NULL CHECK (distinct_signal_sources >= 1),
|
|
533
|
+
evidence_mass INTEGER NOT NULL CHECK (evidence_mass >= 1),
|
|
534
|
+
renderer_id TEXT NOT NULL CHECK (renderer_id = 'memory.retention.long-term/v1'),
|
|
535
|
+
observed_at INTEGER NOT NULL CHECK (observed_at >= 0),
|
|
536
|
+
deadline_at INTEGER NOT NULL CHECK (deadline_at > observed_at),
|
|
537
|
+
request_digest TEXT NOT NULL UNIQUE CHECK (
|
|
538
|
+
length(request_digest) = 64 AND request_digest NOT GLOB '*[^a-f0-9]*'
|
|
539
|
+
),
|
|
540
|
+
idempotency_key TEXT NOT NULL UNIQUE,
|
|
541
|
+
state TEXT NOT NULL CHECK (state IN (
|
|
542
|
+
'pending', 'submitted', 'confirmed', 'rejected', 'expired',
|
|
543
|
+
'conflicted', 'stale-owner', 'cancelled'
|
|
544
|
+
)),
|
|
545
|
+
memory_proposal_id TEXT,
|
|
546
|
+
submission_receipt_digest TEXT CHECK (submission_receipt_digest IS NULL OR (
|
|
547
|
+
length(submission_receipt_digest) = 64
|
|
548
|
+
AND submission_receipt_digest NOT GLOB '*[^a-f0-9]*'
|
|
549
|
+
)),
|
|
550
|
+
terminal_result_version INTEGER CHECK (
|
|
551
|
+
terminal_result_version IS NULL OR terminal_result_version >= 1
|
|
552
|
+
),
|
|
553
|
+
terminal_receipt_digest TEXT CHECK (terminal_receipt_digest IS NULL OR (
|
|
554
|
+
length(terminal_receipt_digest) = 64
|
|
555
|
+
AND terminal_receipt_digest NOT GLOB '*[^a-f0-9]*'
|
|
556
|
+
)),
|
|
557
|
+
created_at INTEGER NOT NULL,
|
|
558
|
+
updated_at INTEGER NOT NULL,
|
|
559
|
+
PRIMARY KEY (promotion_id, promotion_generation),
|
|
560
|
+
UNIQUE(scope_key, hypothesis_id, promotion_generation)
|
|
561
|
+
) STRICT;
|
|
562
|
+
CREATE INDEX preference_memory_promotions_scope_state
|
|
563
|
+
ON preference_memory_promotions(scope_key, state, updated_at, promotion_id);
|
|
564
|
+
CREATE INDEX preference_memory_promotions_hypothesis
|
|
565
|
+
ON preference_memory_promotions(hypothesis_id, promotion_generation DESC);
|
|
566
|
+
|
|
567
|
+
CREATE TABLE preference_memory_promotion_outbox (
|
|
568
|
+
promotion_id TEXT NOT NULL,
|
|
569
|
+
promotion_generation INTEGER NOT NULL CHECK (promotion_generation >= 1),
|
|
570
|
+
state TEXT NOT NULL CHECK (state IN ('pending', 'retry_wait', 'submitted', 'cancelled')),
|
|
571
|
+
attempt_count INTEGER NOT NULL CHECK (attempt_count >= 0),
|
|
572
|
+
next_attempt_at INTEGER NOT NULL CHECK (next_attempt_at >= 0),
|
|
573
|
+
submitted_at INTEGER,
|
|
574
|
+
last_error TEXT,
|
|
575
|
+
updated_at INTEGER NOT NULL,
|
|
576
|
+
PRIMARY KEY (promotion_id, promotion_generation),
|
|
577
|
+
FOREIGN KEY (promotion_id, promotion_generation)
|
|
578
|
+
REFERENCES preference_memory_promotions(promotion_id, promotion_generation)
|
|
579
|
+
ON DELETE CASCADE
|
|
580
|
+
) STRICT;
|
|
581
|
+
CREATE INDEX preference_memory_promotion_outbox_pending
|
|
582
|
+
ON preference_memory_promotion_outbox(state, next_attempt_at, updated_at, promotion_id);
|
|
583
|
+
|
|
584
|
+
CREATE TABLE preference_memory_promotion_results (
|
|
585
|
+
promotion_id TEXT NOT NULL,
|
|
586
|
+
promotion_generation INTEGER NOT NULL CHECK (promotion_generation >= 1),
|
|
587
|
+
result_version INTEGER NOT NULL CHECK (result_version >= 1),
|
|
588
|
+
request_digest TEXT NOT NULL CHECK (
|
|
589
|
+
length(request_digest) = 64 AND request_digest NOT GLOB '*[^a-f0-9]*'
|
|
590
|
+
),
|
|
591
|
+
receipt_digest TEXT NOT NULL UNIQUE CHECK (
|
|
592
|
+
length(receipt_digest) = 64 AND receipt_digest NOT GLOB '*[^a-f0-9]*'
|
|
593
|
+
),
|
|
594
|
+
status TEXT NOT NULL CHECK (status IN (
|
|
595
|
+
'confirmed', 'rejected', 'expired', 'conflicted', 'stale-owner'
|
|
596
|
+
)),
|
|
597
|
+
rejection_kind TEXT CHECK (rejection_kind IS NULL OR rejection_kind = 'owner-explicit'),
|
|
598
|
+
memory_proposal_id TEXT,
|
|
599
|
+
memory_proposal_version INTEGER CHECK (
|
|
600
|
+
memory_proposal_version IS NULL OR memory_proposal_version >= 1
|
|
601
|
+
),
|
|
602
|
+
memory_record_id TEXT,
|
|
603
|
+
memory_record_version INTEGER CHECK (
|
|
604
|
+
memory_record_version IS NULL OR memory_record_version >= 1
|
|
605
|
+
),
|
|
606
|
+
memory_record_digest TEXT CHECK (memory_record_digest IS NULL OR (
|
|
607
|
+
length(memory_record_digest) = 64
|
|
608
|
+
AND memory_record_digest NOT GLOB '*[^a-f0-9]*'
|
|
609
|
+
)),
|
|
610
|
+
occurred_at INTEGER NOT NULL CHECK (occurred_at >= 0),
|
|
611
|
+
projected_at INTEGER NOT NULL CHECK (projected_at >= 0),
|
|
612
|
+
PRIMARY KEY (promotion_id, promotion_generation),
|
|
613
|
+
FOREIGN KEY (promotion_id, promotion_generation)
|
|
614
|
+
REFERENCES preference_memory_promotions(promotion_id, promotion_generation)
|
|
615
|
+
ON DELETE CASCADE,
|
|
616
|
+
CHECK ((status = 'confirmed'
|
|
617
|
+
AND memory_proposal_id IS NOT NULL AND memory_proposal_version IS NOT NULL
|
|
618
|
+
AND memory_record_id IS NOT NULL AND memory_record_version IS NOT NULL
|
|
619
|
+
AND memory_record_digest IS NOT NULL AND rejection_kind IS NULL)
|
|
620
|
+
OR (status = 'rejected'
|
|
621
|
+
AND memory_proposal_id IS NOT NULL AND memory_proposal_version IS NOT NULL
|
|
622
|
+
AND rejection_kind = 'owner-explicit' AND memory_record_id IS NULL
|
|
623
|
+
AND memory_record_version IS NULL AND memory_record_digest IS NULL)
|
|
624
|
+
OR (status IN ('expired', 'conflicted')
|
|
625
|
+
AND memory_proposal_id IS NOT NULL AND memory_proposal_version IS NOT NULL
|
|
626
|
+
AND rejection_kind IS NULL AND memory_record_id IS NULL
|
|
627
|
+
AND memory_record_version IS NULL AND memory_record_digest IS NULL)
|
|
628
|
+
OR (status = 'stale-owner'
|
|
629
|
+
AND memory_proposal_id IS NULL AND memory_proposal_version IS NULL
|
|
630
|
+
AND rejection_kind IS NULL AND memory_record_id IS NULL
|
|
631
|
+
AND memory_record_version IS NULL AND memory_record_digest IS NULL))
|
|
632
|
+
) STRICT;
|
|
633
|
+
|
|
634
|
+
-- Privacy-preserving resurrection fence retained after owner rotation or
|
|
635
|
+
-- forget. It contains only opaque/digested promotion identity.
|
|
636
|
+
CREATE TABLE preference_memory_promotion_cancellations (
|
|
637
|
+
promotion_id TEXT NOT NULL,
|
|
638
|
+
promotion_generation INTEGER NOT NULL CHECK (promotion_generation >= 1),
|
|
639
|
+
request_digest TEXT NOT NULL CHECK (
|
|
640
|
+
length(request_digest) = 64 AND request_digest NOT GLOB '*[^a-f0-9]*'
|
|
641
|
+
),
|
|
642
|
+
principal_lineage_id TEXT NOT NULL,
|
|
643
|
+
principal_lineage_version INTEGER NOT NULL CHECK (principal_lineage_version >= 1),
|
|
644
|
+
owner_generation INTEGER NOT NULL CHECK (owner_generation >= 1),
|
|
645
|
+
reason TEXT NOT NULL CHECK (reason IN (
|
|
646
|
+
'forget', 'owner-rotated', 'superseded'
|
|
647
|
+
)),
|
|
648
|
+
cancelled_at INTEGER NOT NULL CHECK (cancelled_at >= 0),
|
|
649
|
+
cancellation_digest TEXT NOT NULL UNIQUE CHECK (
|
|
650
|
+
length(cancellation_digest) = 64 AND cancellation_digest NOT GLOB '*[^a-f0-9]*'
|
|
651
|
+
),
|
|
652
|
+
state TEXT NOT NULL CHECK (state IN (
|
|
653
|
+
'pending', 'retry_wait', 'cancelled', 'already-confirmed'
|
|
654
|
+
)),
|
|
655
|
+
attempt_count INTEGER NOT NULL CHECK (attempt_count >= 0),
|
|
656
|
+
next_attempt_at INTEGER NOT NULL CHECK (next_attempt_at >= 0),
|
|
657
|
+
receipt_digest TEXT CHECK (receipt_digest IS NULL OR (
|
|
658
|
+
length(receipt_digest) = 64 AND receipt_digest NOT GLOB '*[^a-f0-9]*'
|
|
659
|
+
)),
|
|
660
|
+
last_error TEXT,
|
|
661
|
+
updated_at INTEGER NOT NULL,
|
|
662
|
+
PRIMARY KEY (promotion_id, promotion_generation)
|
|
663
|
+
) STRICT;
|
|
664
|
+
CREATE INDEX preference_memory_promotion_cancellations_pending
|
|
665
|
+
ON preference_memory_promotion_cancellations(state, next_attempt_at, updated_at, promotion_id);
|
|
666
|
+
|
|
667
|
+
UPDATE preference_schema_meta SET value = '10' WHERE key = 'schema-version';
|
|
668
|
+
PRAGMA user_version = 10;
|
|
669
|
+
`);
|
|
670
|
+
if (current < 11)
|
|
671
|
+
database.exec(`
|
|
672
|
+
UPDATE preference_schema_meta SET value = '11' WHERE key = 'schema-version';
|
|
673
|
+
PRAGMA user_version = 11;
|
|
674
|
+
`);
|
|
675
|
+
if (current < 12) {
|
|
676
|
+
database.exec(`
|
|
677
|
+
ALTER TABLE preference_memory_promotion_cancellations
|
|
678
|
+
ADD COLUMN upgrade_binding_digest TEXT CHECK (
|
|
679
|
+
upgrade_binding_digest IS NULL OR (
|
|
680
|
+
length(upgrade_binding_digest) = 64
|
|
681
|
+
AND upgrade_binding_digest NOT GLOB '*[^a-f0-9]*'
|
|
682
|
+
)
|
|
683
|
+
);
|
|
684
|
+
`);
|
|
685
|
+
const rows = database.prepare(`
|
|
686
|
+
SELECT cancellation.promotion_id, cancellation.promotion_generation,
|
|
687
|
+
cancellation.request_digest, cancellation.principal_lineage_id,
|
|
688
|
+
cancellation.principal_lineage_version, cancellation.owner_generation,
|
|
689
|
+
cancellation.reason, cancellation.state, cancellation.receipt_digest,
|
|
690
|
+
promotion.request_digest AS promotion_request_digest,
|
|
691
|
+
promotion.principal_lineage_id AS promotion_principal_lineage_id,
|
|
692
|
+
promotion.principal_lineage_version AS promotion_principal_lineage_version,
|
|
693
|
+
promotion.owner_generation AS promotion_owner_generation
|
|
694
|
+
FROM preference_memory_promotion_cancellations cancellation
|
|
695
|
+
LEFT JOIN preference_memory_promotions promotion
|
|
696
|
+
ON promotion.promotion_id = cancellation.promotion_id
|
|
697
|
+
AND promotion.promotion_generation = cancellation.promotion_generation
|
|
698
|
+
`).all();
|
|
699
|
+
const update = database.prepare(`
|
|
700
|
+
UPDATE preference_memory_promotion_cancellations
|
|
701
|
+
SET upgrade_binding_digest = ?, principal_lineage_id = ?,
|
|
702
|
+
principal_lineage_version = ?, owner_generation = ?
|
|
703
|
+
WHERE promotion_id = ? AND promotion_generation = ?
|
|
704
|
+
`);
|
|
705
|
+
for (const row of rows) {
|
|
706
|
+
const redacted = row.receipt_digest !== null
|
|
707
|
+
&& row.principal_lineage_id.startsWith('redacted-');
|
|
708
|
+
const hasPromotionBinding = row.promotion_request_digest !== null
|
|
709
|
+
&& row.promotion_principal_lineage_id !== null
|
|
710
|
+
&& row.promotion_principal_lineage_version !== null
|
|
711
|
+
&& row.promotion_owner_generation !== null
|
|
712
|
+
&& row.promotion_request_digest === row.request_digest;
|
|
713
|
+
const requiresDelivery = row.state === 'pending' || row.state === 'retry_wait'
|
|
714
|
+
|| (row.state === 'already-confirmed' && row.reason !== 'superseded');
|
|
715
|
+
if (redacted && !hasPromotionBinding
|
|
716
|
+
&& (requiresDelivery || row.reason === 'superseded')) {
|
|
717
|
+
throw new PreferenceDatabaseError('unsafe-file', 'legacy promotion cancellation cannot be safely upgraded after owner-lineage redaction');
|
|
718
|
+
}
|
|
719
|
+
const binding = hasPromotionBinding ? {
|
|
720
|
+
promotionId: row.promotion_id,
|
|
721
|
+
promotionGeneration: row.promotion_generation,
|
|
722
|
+
requestDigest: row.promotion_request_digest,
|
|
723
|
+
principalLineageId: row.promotion_principal_lineage_id,
|
|
724
|
+
principalLineageVersion: row.promotion_principal_lineage_version,
|
|
725
|
+
ownerGeneration: row.promotion_owner_generation,
|
|
726
|
+
} : {
|
|
727
|
+
promotionId: row.promotion_id,
|
|
728
|
+
promotionGeneration: row.promotion_generation,
|
|
729
|
+
requestDigest: row.request_digest,
|
|
730
|
+
principalLineageId: row.principal_lineage_id,
|
|
731
|
+
principalLineageVersion: row.principal_lineage_version,
|
|
732
|
+
ownerGeneration: row.owner_generation,
|
|
733
|
+
};
|
|
734
|
+
const restoreLineage = redacted
|
|
735
|
+
&& requiresDelivery
|
|
736
|
+
&& hasPromotionBinding;
|
|
737
|
+
update.run(preferencePromotionCancellationUpgradeBindingDigest(binding), restoreLineage ? binding.principalLineageId : row.principal_lineage_id, restoreLineage ? binding.principalLineageVersion : row.principal_lineage_version, restoreLineage ? binding.ownerGeneration : row.owner_generation, row.promotion_id, row.promotion_generation);
|
|
738
|
+
}
|
|
739
|
+
database.exec(`
|
|
740
|
+
ALTER TABLE preference_memory_promotion_cancellations
|
|
741
|
+
RENAME TO preference_memory_promotion_cancellations_v11;
|
|
742
|
+
CREATE TABLE preference_memory_promotion_cancellations (
|
|
743
|
+
promotion_id TEXT NOT NULL,
|
|
744
|
+
promotion_generation INTEGER NOT NULL CHECK (promotion_generation >= 1),
|
|
745
|
+
request_digest TEXT NOT NULL CHECK (
|
|
746
|
+
length(request_digest) = 64 AND request_digest NOT GLOB '*[^a-f0-9]*'
|
|
747
|
+
),
|
|
748
|
+
principal_lineage_id TEXT NOT NULL,
|
|
749
|
+
principal_lineage_version INTEGER NOT NULL CHECK (principal_lineage_version >= 1),
|
|
750
|
+
owner_generation INTEGER NOT NULL CHECK (owner_generation >= 1),
|
|
751
|
+
reason TEXT NOT NULL CHECK (reason IN (
|
|
752
|
+
'forget', 'owner-rotated', 'superseded'
|
|
753
|
+
)),
|
|
754
|
+
cancelled_at INTEGER NOT NULL CHECK (cancelled_at >= 0),
|
|
755
|
+
cancellation_digest TEXT NOT NULL UNIQUE CHECK (
|
|
756
|
+
length(cancellation_digest) = 64 AND cancellation_digest NOT GLOB '*[^a-f0-9]*'
|
|
757
|
+
),
|
|
758
|
+
state TEXT NOT NULL CHECK (state IN (
|
|
759
|
+
'pending', 'retry_wait', 'cancelled', 'already-confirmed'
|
|
760
|
+
)),
|
|
761
|
+
attempt_count INTEGER NOT NULL CHECK (attempt_count >= 0),
|
|
762
|
+
next_attempt_at INTEGER NOT NULL CHECK (next_attempt_at >= 0),
|
|
763
|
+
receipt_digest TEXT CHECK (receipt_digest IS NULL OR (
|
|
764
|
+
length(receipt_digest) = 64 AND receipt_digest NOT GLOB '*[^a-f0-9]*'
|
|
765
|
+
)),
|
|
766
|
+
last_error TEXT,
|
|
767
|
+
upgrade_binding_digest TEXT NOT NULL CHECK (
|
|
768
|
+
length(upgrade_binding_digest) = 64
|
|
769
|
+
AND upgrade_binding_digest NOT GLOB '*[^a-f0-9]*'
|
|
770
|
+
),
|
|
771
|
+
updated_at INTEGER NOT NULL,
|
|
772
|
+
PRIMARY KEY (promotion_id, promotion_generation)
|
|
773
|
+
) STRICT;
|
|
774
|
+
INSERT INTO preference_memory_promotion_cancellations(
|
|
775
|
+
promotion_id, promotion_generation, request_digest, principal_lineage_id,
|
|
776
|
+
principal_lineage_version, owner_generation, reason, cancelled_at,
|
|
777
|
+
cancellation_digest, state, attempt_count, next_attempt_at, receipt_digest,
|
|
778
|
+
last_error, upgrade_binding_digest, updated_at
|
|
779
|
+
)
|
|
780
|
+
SELECT promotion_id, promotion_generation, request_digest, principal_lineage_id,
|
|
781
|
+
principal_lineage_version, owner_generation, reason, cancelled_at,
|
|
782
|
+
cancellation_digest, state, attempt_count, next_attempt_at, receipt_digest,
|
|
783
|
+
last_error, upgrade_binding_digest, updated_at
|
|
784
|
+
FROM preference_memory_promotion_cancellations_v11;
|
|
785
|
+
DROP TABLE preference_memory_promotion_cancellations_v11;
|
|
786
|
+
CREATE INDEX preference_memory_promotion_cancellations_pending
|
|
787
|
+
ON preference_memory_promotion_cancellations(
|
|
788
|
+
state, next_attempt_at, updated_at, promotion_id
|
|
789
|
+
);
|
|
790
|
+
UPDATE preference_memory_promotion_cancellations
|
|
791
|
+
SET state = 'pending', receipt_digest = NULL, last_error = NULL, next_attempt_at = 0
|
|
792
|
+
WHERE state = 'already-confirmed' AND reason IN ('forget', 'owner-rotated');
|
|
793
|
+
UPDATE preference_schema_meta SET value = '12' WHERE key = 'schema-version';
|
|
794
|
+
PRAGMA user_version = 12;
|
|
795
|
+
`);
|
|
796
|
+
}
|
|
156
797
|
database.exec('COMMIT');
|
|
157
798
|
transactionStarted = false;
|
|
158
799
|
}
|