@dsh-enhanced/assistant-evolution 0.1.7 → 0.1.12

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/lib/sqlite.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { chmodSync, mkdirSync } from 'node:fs';
2
2
  import { dirname, isAbsolute } from 'node:path';
3
3
  import { DatabaseSync } from 'node:sqlite';
4
- export const evolutionSchemaVersion = 4;
4
+ export const evolutionSchemaVersion = 12;
5
5
  export class EvolutionDatabaseError extends Error {
6
6
  code;
7
7
  constructor(code, message) {
@@ -119,6 +119,398 @@ function migrateV3ToV4(database) {
119
119
  PRAGMA user_version = 4;
120
120
  `);
121
121
  }
122
+ function migrateV4ToV5(database) {
123
+ database.exec(`
124
+ ALTER TABLE evolution_episodes ADD COLUMN evidence_kind TEXT NOT NULL
125
+ DEFAULT 'legacy-unknown'
126
+ CHECK (evidence_kind IN ('operational', 'objective', 'verification', 'legacy-unknown'));
127
+ ALTER TABLE evolution_episodes ADD COLUMN evidence_ref TEXT;
128
+ ALTER TABLE evolution_episodes ADD COLUMN learning_eligible INTEGER NOT NULL DEFAULT 0
129
+ CHECK (learning_eligible IN (0, 1))
130
+ CHECK (learning_eligible = 0 OR (
131
+ trust = 'trusted'
132
+ AND evidence_kind IN ('objective', 'verification')
133
+ AND evidence_ref IS NOT NULL));
134
+
135
+ -- A v4 trusted automation row proved only that execution stopped in a
136
+ -- binary state. It did not prove objective correctness. Keep every row for
137
+ -- audit, but quarantine it from all learning projections.
138
+ UPDATE evolution_episodes
139
+ SET evidence_kind = 'legacy-unknown', evidence_ref = NULL, learning_eligible = 0;
140
+
141
+ -- Every pre-v5 pending mutation was computed from evidence that did not
142
+ -- distinguish execution status from objective quality. A later approval
143
+ -- must not activate that stale conclusion after the evidence quarantine.
144
+ UPDATE evolution_proposals
145
+ SET status = 'conflicted', version = version + 1
146
+ WHERE status = 'pending';
147
+
148
+ DROP INDEX IF EXISTS evolution_episodes_adoption;
149
+ DROP INDEX IF EXISTS evolution_episodes_evaluation;
150
+ CREATE INDEX evolution_episodes_adoption
151
+ ON evolution_episodes(
152
+ scope_key, situation, learning_eligible, rule_id, occurred_at DESC, id DESC);
153
+ CREATE INDEX evolution_episodes_evaluation
154
+ ON evolution_episodes(
155
+ rule_id, guidance_version, learning_eligible, occurred_at DESC, id DESC);
156
+
157
+ INSERT INTO schema_meta(key, value) VALUES ('schema-version', '5')
158
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value;
159
+ PRAGMA user_version = 5;
160
+ `);
161
+ }
162
+ function migrateV5ToV6(database) {
163
+ database.exec(`
164
+ -- v5 made immutable Evaluation references mandatory, but caller-owned
165
+ -- idempotency keys could still alias the same result into several rows.
166
+ -- Retain the earliest deterministic row and quarantine every duplicate so
167
+ -- historical ledgers migrate before the uniqueness constraint is created.
168
+ CREATE TEMP TABLE evolution_v6_duplicate_quality AS
169
+ WITH ranked AS (
170
+ SELECT id, scope_key,
171
+ row_number() OVER (
172
+ PARTITION BY scope_key, evidence_ref
173
+ ORDER BY occurred_at ASC, id ASC
174
+ ) AS duplicate_rank
175
+ FROM evolution_episodes
176
+ WHERE learning_eligible = 1
177
+ AND evidence_kind IN ('objective', 'verification')
178
+ AND evidence_ref IS NOT NULL
179
+ )
180
+ SELECT id, scope_key FROM ranked WHERE duplicate_rank > 1;
181
+
182
+ UPDATE evolution_episodes
183
+ SET evidence_kind = 'legacy-unknown', evidence_ref = NULL, learning_eligible = 0
184
+ WHERE id IN (SELECT id FROM evolution_v6_duplicate_quality);
185
+
186
+ -- A pending mutation in an affected scope may have been computed from an
187
+ -- inflated sample. Preserve it for audit but prevent delayed activation.
188
+ UPDATE evolution_proposals
189
+ SET status = 'conflicted', version = version + 1
190
+ WHERE status = 'pending'
191
+ AND scope_key IN (SELECT DISTINCT scope_key FROM evolution_v6_duplicate_quality);
192
+
193
+ DROP TABLE evolution_v6_duplicate_quality;
194
+
195
+ CREATE UNIQUE INDEX evolution_episodes_quality_evidence_identity
196
+ ON evolution_episodes(scope_key, evidence_ref)
197
+ WHERE learning_eligible = 1;
198
+
199
+ INSERT INTO schema_meta(key, value) VALUES ('schema-version', '6')
200
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value;
201
+ PRAGMA user_version = 6;
202
+ `);
203
+ }
204
+ function migrateV6ToV7(database) {
205
+ database.exec(`
206
+ -- Every pre-v7 quality row came through the retired caller-controlled
207
+ -- projection seam and cannot be rebound to an authoritative Evaluation
208
+ -- receipt after the fact. Preserve it for audit, but revoke learning
209
+ -- eligibility and invalidate pending conclusions derived from it.
210
+ CREATE TEMP TABLE evolution_v7_legacy_quality_scopes AS
211
+ SELECT DISTINCT scope_key FROM evolution_episodes WHERE learning_eligible = 1;
212
+
213
+ UPDATE evolution_episodes
214
+ SET evidence_kind = 'legacy-unknown', evidence_ref = NULL, learning_eligible = 0
215
+ WHERE learning_eligible = 1;
216
+ UPDATE evolution_proposals
217
+ SET status = 'conflicted', version = version + 1
218
+ WHERE status = 'pending'
219
+ AND scope_key IN (SELECT scope_key FROM evolution_v7_legacy_quality_scopes);
220
+ DROP TABLE evolution_v7_legacy_quality_scopes;
221
+
222
+ -- Evaluation is an independent provenance source. Rebuild the table because
223
+ -- SQLite cannot widen an existing CHECK constraint in place.
224
+ ALTER TABLE evolution_episodes RENAME TO evolution_episodes_v6;
225
+ DROP INDEX IF EXISTS evolution_episodes_adoption;
226
+ DROP INDEX IF EXISTS evolution_episodes_evaluation;
227
+ DROP INDEX IF EXISTS evolution_episodes_quality_evidence_identity;
228
+
229
+ CREATE TABLE evolution_episodes (
230
+ id TEXT PRIMARY KEY,
231
+ idempotency_key TEXT NOT NULL UNIQUE,
232
+ situation TEXT NOT NULL,
233
+ outcome TEXT NOT NULL CHECK (outcome IN ('succeeded', 'failed')),
234
+ detail TEXT NOT NULL,
235
+ source TEXT NOT NULL CHECK (source IN ('automation', 'evaluation', 'foreground')),
236
+ scope_key TEXT NOT NULL,
237
+ trust TEXT NOT NULL CHECK (trust IN ('trusted', 'self-reported', 'legacy')),
238
+ evidence_kind TEXT NOT NULL CHECK (
239
+ evidence_kind IN ('operational', 'objective', 'verification', 'legacy-unknown')),
240
+ evidence_ref TEXT,
241
+ learning_eligible INTEGER NOT NULL CHECK (learning_eligible IN (0, 1)),
242
+ rule_id TEXT,
243
+ guidance_version INTEGER CHECK (guidance_version IS NULL OR guidance_version >= 1),
244
+ claimed_rule_id TEXT,
245
+ occurred_at INTEGER NOT NULL,
246
+ CHECK (learning_eligible = 0 OR (
247
+ source = 'evaluation'
248
+ AND
249
+ trust = 'trusted'
250
+ AND evidence_kind IN ('objective', 'verification')
251
+ AND evidence_ref IS NOT NULL))
252
+ ) STRICT;
253
+
254
+ INSERT INTO evolution_episodes(
255
+ id, idempotency_key, situation, outcome, detail, source, scope_key,
256
+ trust, evidence_kind, evidence_ref, learning_eligible,
257
+ rule_id, guidance_version, claimed_rule_id, occurred_at)
258
+ SELECT
259
+ id, idempotency_key, situation, outcome, detail, source, scope_key,
260
+ trust, evidence_kind, evidence_ref, learning_eligible,
261
+ rule_id, guidance_version, claimed_rule_id, occurred_at
262
+ FROM evolution_episodes_v6;
263
+ DROP TABLE evolution_episodes_v6;
264
+
265
+ CREATE INDEX evolution_episodes_adoption
266
+ ON evolution_episodes(
267
+ scope_key, situation, learning_eligible, rule_id, occurred_at DESC, id DESC);
268
+ CREATE INDEX evolution_episodes_evaluation
269
+ ON evolution_episodes(
270
+ rule_id, guidance_version, learning_eligible, occurred_at DESC, id DESC);
271
+ CREATE UNIQUE INDEX evolution_episodes_quality_evidence_identity
272
+ ON evolution_episodes(scope_key, evidence_ref)
273
+ WHERE learning_eligible = 1;
274
+
275
+ INSERT INTO schema_meta(key, value) VALUES ('schema-version', '7')
276
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value;
277
+ PRAGMA user_version = 7;
278
+ `);
279
+ }
280
+ function migrateV7ToV8(database) {
281
+ database.exec(`
282
+ ALTER TABLE evolution_episodes ADD COLUMN learning_subject_ref TEXT;
283
+
284
+ -- v7 recorded only the Evaluation identity. For an Automation objective it
285
+ -- therefore cannot prove whether several Evaluation rows assessed one run.
286
+ -- Preserve those rows for audit, but quarantine every old learning row and
287
+ -- every pending conclusion that may have counted it more than once.
288
+ CREATE TEMP TABLE evolution_v8_legacy_learning_scopes AS
289
+ SELECT DISTINCT scope_key FROM evolution_episodes WHERE learning_eligible = 1;
290
+ UPDATE evolution_episodes
291
+ SET evidence_kind = 'legacy-unknown', evidence_ref = NULL,
292
+ learning_subject_ref = NULL, learning_eligible = 0
293
+ WHERE learning_eligible = 1;
294
+ UPDATE evolution_proposals
295
+ SET status = 'conflicted', version = version + 1
296
+ WHERE status = 'pending'
297
+ AND scope_key IN (SELECT scope_key FROM evolution_v8_legacy_learning_scopes);
298
+ DROP TABLE evolution_v8_legacy_learning_scopes;
299
+
300
+ CREATE UNIQUE INDEX evolution_episodes_learning_subject_identity
301
+ ON evolution_episodes(scope_key, learning_subject_ref)
302
+ WHERE learning_eligible = 1;
303
+
304
+ -- SQLite cannot extend the v7 table CHECK in place. These triggers make the
305
+ -- migrated schema enforce the same invariant as a fresh v8 database.
306
+ CREATE TRIGGER evolution_episodes_learning_subject_insert
307
+ BEFORE INSERT ON evolution_episodes
308
+ WHEN (NEW.learning_eligible = 1 AND NEW.learning_subject_ref IS NULL)
309
+ OR (NEW.learning_eligible = 0 AND NEW.learning_subject_ref IS NOT NULL)
310
+ BEGIN
311
+ SELECT RAISE(ABORT, 'learning subject eligibility mismatch');
312
+ END;
313
+ CREATE TRIGGER evolution_episodes_learning_subject_update
314
+ BEFORE UPDATE OF learning_eligible, learning_subject_ref ON evolution_episodes
315
+ WHEN (NEW.learning_eligible = 1 AND NEW.learning_subject_ref IS NULL)
316
+ OR (NEW.learning_eligible = 0 AND NEW.learning_subject_ref IS NOT NULL)
317
+ BEGIN
318
+ SELECT RAISE(ABORT, 'learning subject eligibility mismatch');
319
+ END;
320
+
321
+ INSERT INTO schema_meta(key, value) VALUES ('schema-version', '8')
322
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value;
323
+ PRAGMA user_version = 8;
324
+ `);
325
+ }
326
+ const taskLearningProjectionSchema = `
327
+ CREATE TABLE evolution_task_learning_state (
328
+ scope_key TEXT NOT NULL,
329
+ scope_watermark INTEGER NOT NULL CHECK (scope_watermark >= 1),
330
+ subject_kind TEXT NOT NULL CHECK (subject_kind IN ('automation-run', 'outcome')),
331
+ subject_ref TEXT NOT NULL,
332
+ version INTEGER NOT NULL CHECK (version >= 1),
333
+ digest TEXT NOT NULL CHECK (length(digest) = 64),
334
+ disposition TEXT NOT NULL CHECK (disposition IN ('upsert', 'retract')),
335
+ situation TEXT NOT NULL,
336
+ episode_id TEXT,
337
+ updated_at INTEGER NOT NULL,
338
+ PRIMARY KEY(scope_key, subject_kind, subject_ref),
339
+ CHECK ((disposition = 'upsert' AND episode_id IS NOT NULL)
340
+ OR (disposition = 'retract' AND episode_id IS NULL)),
341
+ FOREIGN KEY(episode_id) REFERENCES evolution_episodes(id) ON DELETE RESTRICT
342
+ ) STRICT, WITHOUT ROWID;
343
+ CREATE INDEX evolution_task_learning_state_situation
344
+ ON evolution_task_learning_state(scope_key, situation, disposition, updated_at DESC);
345
+
346
+ CREATE TABLE evolution_task_learning_revisions (
347
+ scope_key TEXT NOT NULL,
348
+ scope_watermark INTEGER NOT NULL CHECK (scope_watermark >= 1),
349
+ subject_kind TEXT NOT NULL CHECK (subject_kind IN ('automation-run', 'outcome')),
350
+ subject_ref TEXT NOT NULL,
351
+ version INTEGER NOT NULL CHECK (version >= 1),
352
+ digest TEXT NOT NULL CHECK (length(digest) = 64),
353
+ disposition TEXT NOT NULL CHECK (disposition IN ('upsert', 'retract')),
354
+ situation TEXT NOT NULL,
355
+ episode_id TEXT,
356
+ applied_at INTEGER NOT NULL,
357
+ PRIMARY KEY(scope_key, subject_kind, subject_ref, version),
358
+ CHECK ((disposition = 'upsert' AND episode_id IS NOT NULL)
359
+ OR (disposition = 'retract' AND episode_id IS NULL)),
360
+ FOREIGN KEY(episode_id) REFERENCES evolution_episodes(id) ON DELETE RESTRICT
361
+ ) STRICT, WITHOUT ROWID;
362
+ CREATE INDEX evolution_task_learning_revisions_applied
363
+ ON evolution_task_learning_revisions(applied_at, scope_key, subject_kind, subject_ref);
364
+ `;
365
+ const supervisedGrowthAnalystSchema = `
366
+ CREATE TABLE evolution_supervised_analyst_reviews (
367
+ review_token TEXT PRIMARY KEY,
368
+ scope_key TEXT NOT NULL,
369
+ occurrence_id TEXT NOT NULL,
370
+ contract_version TEXT NOT NULL CHECK (contract_version = 'supervised-growth-analyst/v1'),
371
+ situation TEXT NOT NULL,
372
+ failures INTEGER NOT NULL CHECK (failures >= 0),
373
+ total INTEGER NOT NULL CHECK (total > 0 AND failures <= total),
374
+ evidence_digest TEXT NOT NULL CHECK (length(evidence_digest) = 64),
375
+ evidence_total INTEGER NOT NULL CHECK (evidence_total = total),
376
+ evidence_window INTEGER NOT NULL CHECK (evidence_window >= evidence_total),
377
+ sample_episode_ids_json TEXT NOT NULL CHECK (
378
+ json_valid(sample_episode_ids_json)
379
+ AND json_type(sample_episode_ids_json) = 'array'
380
+ AND json_array_length(sample_episode_ids_json) BETWEEN 1 AND 50
381
+ AND json_array_length(sample_episode_ids_json) <= evidence_total),
382
+ evidence_json TEXT NOT NULL CHECK (
383
+ json_valid(evidence_json) AND json_type(evidence_json) = 'array'),
384
+ scope_watermark INTEGER NOT NULL CHECK (scope_watermark >= 1),
385
+ task_revisions_json TEXT NOT NULL CHECK (
386
+ json_valid(task_revisions_json) AND json_type(task_revisions_json) = 'array'),
387
+ proposal_id TEXT,
388
+ created_at INTEGER NOT NULL,
389
+ proposed_at INTEGER,
390
+ UNIQUE(scope_key, occurrence_id),
391
+ FOREIGN KEY(proposal_id) REFERENCES evolution_proposals(id) ON DELETE RESTRICT
392
+ ) STRICT;
393
+ CREATE INDEX evolution_supervised_analyst_reviews_proposal
394
+ ON evolution_supervised_analyst_reviews(proposal_id)
395
+ WHERE proposal_id IS NOT NULL;
396
+ `;
397
+ const applicationReceiptSchema = `
398
+ CREATE TABLE evolution_application_receipts (
399
+ local_proposal_id TEXT PRIMARY KEY,
400
+ policy_proposal_id TEXT NOT NULL UNIQUE,
401
+ application_status TEXT NOT NULL CHECK (
402
+ application_status IN ('applied', 'conflicted', 'expired', 'rejected')),
403
+ operation TEXT NOT NULL CHECK (operation IN ('adopt', 'owner-undo', 'retire')),
404
+ terminal_at INTEGER NOT NULL,
405
+ receipt_digest TEXT NOT NULL UNIQUE CHECK (length(receipt_digest) = 64),
406
+ revision INTEGER NOT NULL CHECK (revision >= 2),
407
+ rule_id TEXT,
408
+ resulting_rule_version INTEGER CHECK (
409
+ resulting_rule_version IS NULL OR resulting_rule_version >= 1),
410
+ rule_status TEXT CHECK (rule_status IS NULL OR rule_status IN ('active', 'retired')),
411
+ CHECK (application_status <> 'applied' OR (
412
+ rule_id IS NOT NULL AND resulting_rule_version IS NOT NULL AND rule_status IS NOT NULL)),
413
+ FOREIGN KEY(local_proposal_id) REFERENCES evolution_proposals(id) ON DELETE RESTRICT
414
+ ) STRICT;
415
+
416
+ CREATE TABLE evolution_application_outbox (
417
+ local_proposal_id TEXT PRIMARY KEY,
418
+ state TEXT NOT NULL CHECK (state IN ('pending', 'published')),
419
+ attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
420
+ updated_at INTEGER NOT NULL,
421
+ published_at INTEGER,
422
+ last_error TEXT,
423
+ FOREIGN KEY(local_proposal_id)
424
+ REFERENCES evolution_application_receipts(local_proposal_id) ON DELETE RESTRICT
425
+ ) STRICT, WITHOUT ROWID;
426
+ CREATE INDEX evolution_application_outbox_pending
427
+ ON evolution_application_outbox(state, updated_at, local_proposal_id);
428
+ `;
429
+ function migrateV8ToV9(database) {
430
+ database.exec(`
431
+ -- v8 rows were projected from a raw immutable Evaluation outcome. They
432
+ -- cannot represent a later owner override or objective conflict, so they
433
+ -- must not remain votes once the canonical task projection becomes the
434
+ -- only source. Evaluation v5 requeues retained tasks and repopulates this
435
+ -- ledger through the versioned seam after startup.
436
+ CREATE TEMP TABLE evolution_v9_legacy_learning_scopes AS
437
+ SELECT DISTINCT scope_key FROM evolution_episodes WHERE learning_eligible = 1;
438
+ UPDATE evolution_episodes
439
+ SET evidence_kind = 'legacy-unknown', evidence_ref = NULL,
440
+ learning_subject_ref = NULL, learning_eligible = 0
441
+ WHERE learning_eligible = 1;
442
+ UPDATE evolution_proposals
443
+ SET status = 'conflicted', version = version + 1
444
+ WHERE status = 'pending'
445
+ AND scope_key IN (SELECT scope_key FROM evolution_v9_legacy_learning_scopes);
446
+ DROP TABLE evolution_v9_legacy_learning_scopes;
447
+
448
+ ${taskLearningProjectionSchema}
449
+
450
+ INSERT INTO schema_meta(key, value) VALUES ('schema-version', '9')
451
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value;
452
+ PRAGMA user_version = 9;
453
+ `);
454
+ }
455
+ function migrateV9ToV10(database) {
456
+ database.exec(`
457
+ ${supervisedGrowthAnalystSchema}
458
+
459
+ INSERT INTO schema_meta(key, value) VALUES ('schema-version', '10')
460
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value;
461
+ PRAGMA user_version = 10;
462
+ `);
463
+ }
464
+ function migrateV10ToV11(database) {
465
+ database.exec(`
466
+ ${applicationReceiptSchema}
467
+
468
+ INSERT INTO schema_meta(key, value) VALUES ('schema-version', '11')
469
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value;
470
+ PRAGMA user_version = 11;
471
+ `);
472
+ }
473
+ function migrateV11ToV12(database) {
474
+ const hasColumn = (table, column) => database
475
+ .prepare(`SELECT name FROM pragma_table_info(?) WHERE name = ?`)
476
+ .get(table, column) !== undefined;
477
+ if (!hasColumn('evolution_task_learning_state', 'scope_watermark')) {
478
+ database.exec(`ALTER TABLE evolution_task_learning_state
479
+ ADD COLUMN scope_watermark INTEGER NOT NULL DEFAULT 0 CHECK (scope_watermark >= 0)`);
480
+ }
481
+ if (!hasColumn('evolution_task_learning_revisions', 'scope_watermark')) {
482
+ database.exec(`ALTER TABLE evolution_task_learning_revisions
483
+ ADD COLUMN scope_watermark INTEGER NOT NULL DEFAULT 0 CHECK (scope_watermark >= 0)`);
484
+ }
485
+ if (!hasColumn('evolution_supervised_analyst_reviews', 'scope_watermark')) {
486
+ database.exec(`ALTER TABLE evolution_supervised_analyst_reviews
487
+ ADD COLUMN scope_watermark INTEGER NOT NULL DEFAULT 0 CHECK (scope_watermark >= 0)`);
488
+ }
489
+ if (!hasColumn('evolution_supervised_analyst_reviews', 'task_revisions_json')) {
490
+ database.exec(`ALTER TABLE evolution_supervised_analyst_reviews
491
+ ADD COLUMN task_revisions_json TEXT NOT NULL DEFAULT '[]'
492
+ CHECK (json_valid(task_revisions_json) AND json_type(task_revisions_json) = 'array')`);
493
+ }
494
+ database.exec(`
495
+ CREATE TABLE IF NOT EXISTS evolution_scope_learning_watermarks (
496
+ scope_key TEXT PRIMARY KEY,
497
+ watermark INTEGER NOT NULL CHECK (watermark >= 1),
498
+ updated_at INTEGER NOT NULL
499
+ ) STRICT, WITHOUT ROWID;
500
+
501
+ -- No pre-v12 pending proposal froze the authoritative Evaluation scope
502
+ -- watermark and complete task tuple. Preserve it for audit, but never let a
503
+ -- later approval apply it. Attached rows receive terminal receipts during
504
+ -- the normal constructor backfill.
505
+ UPDATE evolution_proposals
506
+ SET status = 'conflicted', version = version + 1
507
+ WHERE status = 'pending';
508
+
509
+ INSERT INTO schema_meta(key, value) VALUES ('schema-version', '12')
510
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value;
511
+ PRAGMA user_version = 12;
512
+ `);
513
+ }
122
514
  function createCurrentSchema(database) {
123
515
  database.exec(`
124
516
  CREATE TABLE schema_meta (
@@ -134,19 +526,41 @@ function createCurrentSchema(database) {
134
526
  situation TEXT NOT NULL,
135
527
  outcome TEXT NOT NULL CHECK (outcome IN ('succeeded', 'failed')),
136
528
  detail TEXT NOT NULL,
137
- source TEXT NOT NULL CHECK (source IN ('automation', 'foreground')),
529
+ source TEXT NOT NULL CHECK (source IN ('automation', 'evaluation', 'foreground')),
138
530
  scope_key TEXT NOT NULL,
139
531
  trust TEXT NOT NULL CHECK (trust IN ('trusted', 'self-reported', 'legacy')),
532
+ evidence_kind TEXT NOT NULL CHECK (
533
+ evidence_kind IN ('operational', 'objective', 'verification', 'legacy-unknown')),
534
+ evidence_ref TEXT,
535
+ learning_subject_ref TEXT,
536
+ learning_eligible INTEGER NOT NULL CHECK (learning_eligible IN (0, 1)),
140
537
  rule_id TEXT,
141
538
  guidance_version INTEGER CHECK (guidance_version IS NULL OR guidance_version >= 1),
142
539
  claimed_rule_id TEXT,
143
- occurred_at INTEGER NOT NULL
540
+ occurred_at INTEGER NOT NULL,
541
+ CHECK ((learning_eligible = 0 AND learning_subject_ref IS NULL) OR (
542
+ learning_eligible = 1
543
+ AND learning_subject_ref IS NOT NULL
544
+ AND
545
+ source = 'evaluation'
546
+ AND
547
+ trust = 'trusted'
548
+ AND evidence_kind IN ('objective', 'verification')
549
+ AND evidence_ref IS NOT NULL))
144
550
  ) STRICT;
145
551
 
146
552
  CREATE INDEX evolution_episodes_adoption
147
- ON evolution_episodes(scope_key, situation, trust, rule_id, occurred_at DESC, id DESC);
553
+ ON evolution_episodes(
554
+ scope_key, situation, learning_eligible, rule_id, occurred_at DESC, id DESC);
148
555
  CREATE INDEX evolution_episodes_evaluation
149
- ON evolution_episodes(rule_id, trust, occurred_at DESC, id DESC);
556
+ ON evolution_episodes(
557
+ rule_id, guidance_version, learning_eligible, occurred_at DESC, id DESC);
558
+ CREATE UNIQUE INDEX evolution_episodes_quality_evidence_identity
559
+ ON evolution_episodes(scope_key, evidence_ref)
560
+ WHERE learning_eligible = 1;
561
+ CREATE UNIQUE INDEX evolution_episodes_learning_subject_identity
562
+ ON evolution_episodes(scope_key, learning_subject_ref)
563
+ WHERE learning_eligible = 1;
150
564
 
151
565
  CREATE TABLE evolution_rules (
152
566
  id TEXT PRIMARY KEY,
@@ -233,8 +647,20 @@ function createCurrentSchema(database) {
233
647
  CREATE INDEX evolution_autonomous_rollbacks_occurred
234
648
  ON evolution_autonomous_rollbacks(occurred_at);
235
649
 
236
- INSERT INTO schema_meta(key, value) VALUES ('schema-version', '4');
237
- PRAGMA user_version = 4;
650
+ ${taskLearningProjectionSchema}
651
+
652
+ CREATE TABLE evolution_scope_learning_watermarks (
653
+ scope_key TEXT PRIMARY KEY,
654
+ watermark INTEGER NOT NULL CHECK (watermark >= 1),
655
+ updated_at INTEGER NOT NULL
656
+ ) STRICT, WITHOUT ROWID;
657
+
658
+ ${supervisedGrowthAnalystSchema}
659
+
660
+ ${applicationReceiptSchema}
661
+
662
+ INSERT INTO schema_meta(key, value) VALUES ('schema-version', '12');
663
+ PRAGMA user_version = 12;
238
664
  `);
239
665
  }
240
666
  /** Serialize every schema transition and re-read the version after the lock. */
@@ -258,6 +684,22 @@ function migrate(database) {
258
684
  migrateV2ToV3(database);
259
685
  else if (version === 3)
260
686
  migrateV3ToV4(database);
687
+ else if (version === 4)
688
+ migrateV4ToV5(database);
689
+ else if (version === 5)
690
+ migrateV5ToV6(database);
691
+ else if (version === 6)
692
+ migrateV6ToV7(database);
693
+ else if (version === 7)
694
+ migrateV7ToV8(database);
695
+ else if (version === 8)
696
+ migrateV8ToV9(database);
697
+ else if (version === 9)
698
+ migrateV9ToV10(database);
699
+ else if (version === 10)
700
+ migrateV10ToV11(database);
701
+ else if (version === 11)
702
+ migrateV11ToV12(database);
261
703
  version = schemaVersion(database);
262
704
  }
263
705
  database.exec('COMMIT');
package/lib/sqlite.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAA;AAEvC,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAEpC;IADX,YACW,IAAuC,EAChD,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAA;QAHL,SAAI,GAAJ,IAAI,CAAmC;QAIhD,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAA;IACtC,CAAC;CACF;AAED,SAAS,aAAa,CAAC,QAAsB;IAC3C,OAAQ,QAAQ,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAA+B,CAAC,YAAY,CAAA;AACjG,CAAC;AAED,SAAS,eAAe,CAAC,OAAe;IACtC,IAAI,OAAO,GAAG,sBAAsB,EAAE,CAAC;QACrC,MAAM,IAAI,sBAAsB,CAC9B,gBAAgB,EAChB,oBAAoB,OAAO,mCAAmC,sBAAsB,EAAE,CACvF,CAAA;IACH,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,QAAsB;IAC3C,QAAQ,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCb,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,QAAsB;IAC3C,QAAQ,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4Bb,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,QAAsB;IAC3C,QAAQ,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6Bb,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAsB;IACjD,QAAQ,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmHb,CAAC,CAAA;AACJ,CAAC;AAED,gFAAgF;AAChF,SAAS,OAAO,CAAC,QAAsB;IACrC,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;IACvC,eAAe,CAAC,OAAO,CAAC,CAAA;IACxB,IAAI,OAAO,KAAK,sBAAsB;QAAE,OAAM;IAE9C,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;IAChC,IAAI,CAAC;QACH,IAAI,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QACrC,eAAe,CAAC,OAAO,CAAC,CAAA;QACxB,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;YAClB,mBAAmB,CAAC,QAAQ,CAAC,CAAA;YAC7B,OAAO,GAAG,sBAAsB,CAAA;QAClC,CAAC;QACD,OAAO,OAAO,GAAG,sBAAsB,EAAE,CAAC;YACxC,IAAI,OAAO,KAAK,CAAC;gBAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;iBACrC,IAAI,OAAO,KAAK,CAAC;gBAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;iBAC1C,IAAI,OAAO,KAAK,CAAC;gBAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;YAC/C,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QACnC,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACzB,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,YAAY,GAAG,IAAI,UAAU,CAAC,IAAI,iBAAiB,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAExF,SAAS,SAAS,CAAC,QAAsB;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;IACnC,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,GAAG,EAA8B,CAAA;YAC3F,IAAI,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC7C,MAAM,IAAI,KAAK,CAAC,wCAAwC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAA;YAC7E,CAAC;YACD,OAAM;QACR,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,SAAS,GAAG,KAAK,YAAY,KAAK,IAAI,8BAA8B,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YAC9F,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ;gBAAE,MAAM,KAAK,CAAA;YACrD,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;QACtC,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,sBAAsB,CAAC,cAAc,EAAE,0CAA0C,CAAC,CAAA;IAC9F,CAAC;IACD,IAAI,IAAI,KAAK,UAAU;QAAE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACnF,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAA;IACvC,IAAI,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;QACzC,QAAQ,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAA;QAC3C,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;QAC1C,OAAO,CAAC,QAAQ,CAAC,CAAA;QACjB,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,SAAS,CAAC,QAAQ,CAAC,CAAA;YACnB,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACxB,CAAC;QACD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,KAAK,EAAE,CAAA;QAChB,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"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"}
package/lib/store.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { EpisodeInput, EvolutionCreationIntent, EvolutionMutation, EvolutionSettlementExpectation, GuidanceExposure, ProposalStatus, RuleCandidate, RuleInput, SituationStats, StoredEpisode, StoredAutonomousRollback, StoredProposal, StoredRule } from './types.js';
1
+ import type { EpisodeInput, EvolutionCreationInput, EvolutionMutation, EvolutionSettlementExpectation, GuidanceExposure, ProposalStatus, RuleCandidate, RuleInput, SituationStats, StoredEpisode, StoredEvolutionApplicationOutboxEntry, StoredEvolutionApplicationReceipt, StoredAutonomousRollback, StoredProposal, StoredRule, StoredSupervisedGrowthAnalystReview, StoredTaskLearningProjection, SupervisedGrowthAnalystContractVersion, TaskLearningProjectionInput, TaskLearningProjectionResult } from './types.js';
2
2
  export type EvolutionStoreErrorCode = 'idempotency-conflict' | 'invalid-input' | 'invalid-state' | 'not-found' | 'version-conflict';
3
3
  export declare class EvolutionStoreError extends Error {
4
4
  readonly code: EvolutionStoreErrorCode;
@@ -18,11 +18,31 @@ export interface EvolutionStoreHealth {
18
18
  pendingProposals: number;
19
19
  conflictedProposals: number;
20
20
  trustedEpisodes: number;
21
+ qualityEligibleEpisodes: number;
22
+ operationalEpisodes: number;
23
+ legacyQuarantinedEpisodes: number;
21
24
  unattributedTrustedEpisodes: number;
25
+ unattributedQualityEligibleEpisodes: number;
22
26
  lastTrustedEpisodeAt: number;
27
+ lastQualityEligibleEpisodeAt: number;
23
28
  autonomousRollbacks: number;
29
+ taskLearningProjections: number;
30
+ retractedTaskLearningProjections: number;
31
+ taskLearningProjectionRevisions: number;
32
+ taskLearningProjectionIntegrityErrors: number;
24
33
  }
25
34
  declare function digest(value: unknown): string;
35
+ /**
36
+ * Stable analyst proposal identity. Deliberately do not add guidance, owner,
37
+ * execution, token, TTL, samples or timestamps: those are not the learned fact.
38
+ */
39
+ export declare function supervisedGrowthAnalystProposalIdempotencyKey(input: {
40
+ scopeKey: string;
41
+ situation: string;
42
+ evidenceDigest: string;
43
+ evidenceTotal: number;
44
+ contractVersion: SupervisedGrowthAnalystContractVersion;
45
+ }): string;
26
46
  /**
27
47
  * Durable evidence and rule ledger.
28
48
  *
@@ -43,10 +63,28 @@ export declare class EvolutionStore {
43
63
  health(): Readonly<EvolutionStoreHealth>;
44
64
  /** Record one observed outcome. Idempotent on `idempotencyKey`. */
45
65
  recordEpisode(input: EpisodeInput): StoredEpisode;
46
- /** Failure counts for one situation over the most recent `window` episodes. */
66
+ /**
67
+ * Apply one authoritative Evaluation task revision. The current pointer,
68
+ * immutable revision audit, active learning vote and stale-proposal fence are
69
+ * committed under one SQLite writer lock.
70
+ *
71
+ * The first accepted revision may be greater than one because several old
72
+ * Evaluation outbox triggers all resolve to the latest canonical task. A
73
+ * lower revision is never acknowledged: it indicates an Evaluation rollback
74
+ * or a mismatched database restore and must remain visible to recovery.
75
+ */
76
+ applyTaskLearningProjection(input: TaskLearningProjectionInput): TaskLearningProjectionResult;
77
+ getTaskLearningProjection(input: {
78
+ scopeKey: string;
79
+ subjectKind: 'automation-run' | 'outcome';
80
+ subjectRef: string;
81
+ }): StoredTaskLearningProjection | undefined;
82
+ /** Failure counts over the most recent explicitly quality-eligible episodes. */
47
83
  stats(scopeKey: string, situation: string, window: number): SituationStats;
48
84
  listRules(scopeKey: string, status?: 'active' | 'retired'): StoredRule[];
49
85
  getRule(ruleId: string): StoredRule | undefined;
86
+ /** Principal whose exact approved adoption created this immutable rule. */
87
+ ruleApprovalPrincipal(ruleId: string): string | undefined;
50
88
  activeRule(scopeKey: string, situation: string): StoredRule | undefined;
51
89
  nextGeneration(scopeKey: string, situation: string): number;
52
90
  /** Persist proof only after the corresponding guidance injection returned. */
@@ -58,6 +96,7 @@ export declare class EvolutionStore {
58
96
  guidanceVersion: number;
59
97
  }): GuidanceExposure;
60
98
  hasGuidanceExposure(sessionId: string, scopeKey: string, ruleId: string, guidanceVersion: number): boolean;
99
+ countGuidanceExposures(sessionId: string, scopeKey: string): number;
61
100
  /** Return only an unambiguous exact-situation receipt for one session. */
62
101
  captureGuidanceExposure(sessionId: string, scopeKey: string, situation: string): GuidanceExposure | undefined;
63
102
  /**
@@ -93,6 +132,41 @@ export declare class EvolutionStore {
93
132
  retireFailureRate: number;
94
133
  evidenceSampleLimit?: number;
95
134
  }): RuleCandidate | undefined;
135
+ /**
136
+ * Freeze the one adoption candidate shown to an exact production analyst
137
+ * execution. Repeating review in the same occurrence returns the same opaque
138
+ * token; if its evidence changed, the old execution is fenced instead.
139
+ */
140
+ registerSupervisedGrowthAnalystReview(input: {
141
+ scopeKey: string;
142
+ occurrenceId: string;
143
+ candidate: RuleCandidate;
144
+ evidenceWindow: number;
145
+ }): Readonly<{
146
+ review: StoredSupervisedGrowthAnalystReview;
147
+ proposalExists: boolean;
148
+ }>;
149
+ getSupervisedGrowthAnalystReview(reviewToken: string): StoredSupervisedGrowthAnalystReview | undefined;
150
+ /**
151
+ * Create or join the proposal for one evidence identity under the SQLite
152
+ * writer lock. The existing proposal is deliberately returned without
153
+ * comparing guidance: the first committed wording is the durable winner.
154
+ */
155
+ createSupervisedGrowthAnalystProposal(input: {
156
+ reviewToken: string;
157
+ scopeKey: string;
158
+ occurrenceId: string;
159
+ requester: string;
160
+ principal: string;
161
+ mutation: Extract<EvolutionMutation, {
162
+ op: 'adopt';
163
+ }>;
164
+ expiresAt: number;
165
+ creationIntent: EvolutionCreationInput;
166
+ }): Readonly<{
167
+ proposal: StoredProposal;
168
+ replayed: boolean;
169
+ }>;
96
170
  /**
97
171
  * Retire one exact active guidance generation through the narrow autonomous
98
172
  * rollback lane.
@@ -121,11 +195,32 @@ export declare class EvolutionStore {
121
195
  principal: string;
122
196
  mutation: EvolutionMutation;
123
197
  expiresAt: number;
124
- creationIntent?: EvolutionCreationIntent;
198
+ creationIntent?: EvolutionCreationInput;
125
199
  }): StoredProposal;
126
200
  attachPolicy(proposalId: string, policyProposalId: string, expectation?: EvolutionSettlementExpectation): StoredProposal;
127
201
  getProposal(proposalId: string): StoredProposal | undefined;
202
+ getProposalByIdempotencyKey(idempotencyKey: string): StoredProposal | undefined;
128
203
  listPendingProposals(limit: number): StoredProposal[];
204
+ /**
205
+ * Recover cross-database creation intents that may already own a Policy card
206
+ * even when local evidence invalidation made the proposal terminal first.
207
+ */
208
+ listUnattachedProposalIntents(limit: number): StoredProposal[];
209
+ /**
210
+ * Policy has authoritatively confirmed that an expired unattached intent did
211
+ * not create a proposal. Drop only that now-useless recovery payload so the
212
+ * terminal local conflict is not rediscovered forever.
213
+ */
214
+ completeAbandonedProposalRecovery(proposalId: string): StoredProposal;
215
+ getEvolutionApplicationReceipt(localProposalId: string): StoredEvolutionApplicationReceipt | undefined;
216
+ /** Independent terminal-presentation outbox; it never scans pending proposals. */
217
+ listPendingEvolutionApplicationReceipts(limit: number): StoredEvolutionApplicationOutboxEntry[];
218
+ settleEvolutionApplicationPublication(input: {
219
+ localProposalId: string;
220
+ receiptDigest: string;
221
+ outcome: 'published' | 'retry';
222
+ error?: string;
223
+ }): StoredEvolutionApplicationOutboxEntry;
129
224
  /** Move an inspected-but-still-pending row behind its peers, durably. */
130
225
  deferPendingProposal(proposalId: string): void;
131
226
  /**