@devflow-tools/database 0.17.2 → 0.17.4

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/dist/database.js CHANGED
@@ -15,6 +15,8 @@ const retrieval_sessions_1 = require("./retrieval-sessions");
15
15
  const learning_candidates_1 = require("./learning-candidates");
16
16
  const workflow_workers_1 = require("./workflow-workers");
17
17
  const task_semantic_control_1 = require("./task-semantic-control");
18
+ const task_runtime_1 = require("./task-runtime");
19
+ const semantic_resolution_1 = require("./semantic-resolution");
18
20
  const CONTEXT_REQUIRED_SKILLS = new Set([
19
21
  'react', 'vue', 'nest', 'nextjs', 'graphql', 'typescript',
20
22
  ]);
@@ -356,6 +358,9 @@ class DevFlowDatabase {
356
358
  source_id TEXT NOT NULL, stage TEXT NOT NULL, rank INTEGER, raw_score REAL,
357
359
  normalized_score REAL, final_score REAL, applicability TEXT NOT NULL DEFAULT '[]',
358
360
  reason TEXT, tool_evidence TEXT NOT NULL DEFAULT '[]', verification_receipt TEXT,
361
+ schema_version TEXT NOT NULL DEFAULT 'retrieval-ledger-event.v1', task_spec_hash TEXT,
362
+ actor TEXT, source_version TEXT, source_content_hash TEXT,
363
+ evidence_ids TEXT NOT NULL DEFAULT '[]', reason_code TEXT,
359
364
  payload TEXT NOT NULL DEFAULT '{}', created_at INTEGER NOT NULL
360
365
  );
361
366
  CREATE INDEX IF NOT EXISTS idx_retrieval_ledger_identity ON devflow_retrieval_ledger(
@@ -395,6 +400,35 @@ class DevFlowDatabase {
395
400
  CREATE UNIQUE INDEX IF NOT EXISTS idx_task_intent_source
396
401
  ON devflow_task_intent_artifacts(project_root, session_id, source_hash, version);
397
402
 
403
+ CREATE TABLE IF NOT EXISTS devflow_semantic_resolutions (
404
+ frame_hash TEXT PRIMARY KEY,
405
+ project_root TEXT NOT NULL,
406
+ project_id TEXT NOT NULL,
407
+ host_id TEXT NOT NULL,
408
+ session_id TEXT NOT NULL,
409
+ turn_id TEXT NOT NULL,
410
+ request_id TEXT NOT NULL,
411
+ source_hash TEXT NOT NULL,
412
+ artifact_hash TEXT NOT NULL,
413
+ artifact_revision INTEGER NOT NULL CHECK(artifact_revision > 0),
414
+ supersedes_frame_hash TEXT,
415
+ state TEXT NOT NULL CHECK(state IN ('provisional', 'resolved', 'abstained', 'unavailable')),
416
+ generated_by TEXT NOT NULL CHECK(generated_by IN ('deterministic', 'embedding_router', 'host_semantic', 'hybrid')),
417
+ model_id TEXT,
418
+ model_revision TEXT,
419
+ route_catalog_version TEXT NOT NULL,
420
+ threshold_version TEXT NOT NULL,
421
+ route_json TEXT NOT NULL,
422
+ sampling_json TEXT NOT NULL,
423
+ conflicts_json TEXT NOT NULL,
424
+ frame_json TEXT NOT NULL,
425
+ duration_ms INTEGER NOT NULL CHECK(duration_ms >= 0),
426
+ created_at INTEGER NOT NULL,
427
+ UNIQUE(project_root, session_id, turn_id, artifact_revision)
428
+ );
429
+ CREATE INDEX IF NOT EXISTS idx_semantic_resolution_latest
430
+ ON devflow_semantic_resolutions(project_root, session_id, turn_id, artifact_revision DESC);
431
+
398
432
  CREATE TABLE IF NOT EXISTS devflow_channel_query_plans (
399
433
  plan_hash TEXT PRIMARY KEY,
400
434
  source_intent_hash TEXT NOT NULL,
@@ -460,6 +494,40 @@ class DevFlowDatabase {
460
494
  CREATE INDEX IF NOT EXISTS idx_terminal_transition_turn
461
495
  ON devflow_terminal_transitions(project_root, session_id, turn_id, sequence);
462
496
 
497
+ CREATE TABLE IF NOT EXISTS devflow_task_runtime_events (
498
+ event_id TEXT PRIMARY KEY,
499
+ schema_version TEXT NOT NULL,
500
+ producer TEXT NOT NULL,
501
+ producer_version TEXT NOT NULL,
502
+ project_root TEXT NOT NULL,
503
+ project_id TEXT NOT NULL,
504
+ host_id TEXT NOT NULL,
505
+ session_id TEXT NOT NULL,
506
+ turn_id TEXT NOT NULL,
507
+ request_id TEXT NOT NULL,
508
+ execution_id TEXT,
509
+ task_spec_hash TEXT NOT NULL,
510
+ sequence INTEGER NOT NULL CHECK(sequence > 0),
511
+ kind TEXT NOT NULL,
512
+ payload_json TEXT NOT NULL DEFAULT '{}',
513
+ created_at INTEGER NOT NULL,
514
+ UNIQUE(project_root, session_id, turn_id, sequence)
515
+ );
516
+ CREATE INDEX IF NOT EXISTS idx_task_runtime_event_identity
517
+ ON devflow_task_runtime_events(project_root, session_id, turn_id, sequence);
518
+
519
+ CREATE TABLE IF NOT EXISTS devflow_task_runtime_snapshots (
520
+ project_root TEXT NOT NULL,
521
+ session_id TEXT NOT NULL,
522
+ turn_id TEXT NOT NULL,
523
+ last_event_sequence INTEGER NOT NULL,
524
+ schema_version TEXT NOT NULL,
525
+ snapshot_json TEXT NOT NULL,
526
+ snapshot_hash TEXT NOT NULL,
527
+ updated_at INTEGER NOT NULL,
528
+ PRIMARY KEY(project_root, session_id, turn_id)
529
+ );
530
+
463
531
  CREATE TABLE IF NOT EXISTS devflow_transcript_checkpoints (
464
532
  id TEXT PRIMARY KEY,
465
533
  project_root TEXT NOT NULL,
@@ -613,9 +681,11 @@ class DevFlowDatabase {
613
681
  project_root TEXT NOT NULL,
614
682
  session_id TEXT,
615
683
  turn_id TEXT,
684
+ source_hash TEXT,
685
+ task_spec_hash TEXT,
616
686
  payload TEXT NOT NULL,
617
687
  state TEXT NOT NULL DEFAULT 'pending'
618
- CHECK(state IN ('pending', 'leased', 'completed', 'failed', 'dead_letter')),
688
+ CHECK(state IN ('pending', 'leased', 'completed', 'failed', 'dead_letter', 'cancelled')),
619
689
  attempts INTEGER NOT NULL DEFAULT 0 CHECK(attempts >= 0),
620
690
  max_attempts INTEGER NOT NULL DEFAULT 5 CHECK(max_attempts > 0),
621
691
  lease_owner TEXT,
@@ -625,7 +695,11 @@ class DevFlowDatabase {
625
695
  error_message TEXT,
626
696
  created_at INTEGER NOT NULL,
627
697
  updated_at INTEGER NOT NULL,
628
- completed_at INTEGER
698
+ completed_at INTEGER,
699
+ cancelled_at INTEGER,
700
+ cancellation_reason TEXT,
701
+ replay_of_id TEXT,
702
+ replay_count INTEGER NOT NULL DEFAULT 0
629
703
  );
630
704
 
631
705
  CREATE INDEX IF NOT EXISTS idx_work_items_ready
@@ -635,6 +709,16 @@ class DevFlowDatabase {
635
709
  CREATE INDEX IF NOT EXISTS idx_work_items_completed
636
710
  ON devflow_work_items(project_root, completed_at DESC);
637
711
 
712
+ CREATE TABLE IF NOT EXISTS devflow_project_mutation_leases (
713
+ project_root TEXT NOT NULL,
714
+ mutation_kind TEXT NOT NULL,
715
+ owner TEXT NOT NULL,
716
+ lease_expires_at INTEGER NOT NULL,
717
+ source_hash TEXT,
718
+ updated_at INTEGER NOT NULL,
719
+ PRIMARY KEY(project_root, mutation_kind)
720
+ );
721
+
638
722
  CREATE TABLE IF NOT EXISTS devflow_session_closures (
639
723
  session_id TEXT NOT NULL,
640
724
  project_root TEXT NOT NULL,
@@ -978,6 +1062,58 @@ class DevFlowDatabase {
978
1062
  this.db.exec('ALTER TABLE devflow_context_receipts ADD COLUMN request_id TEXT');
979
1063
  }
980
1064
  catch { }
1065
+ try {
1066
+ this.db.exec("ALTER TABLE devflow_retrieval_ledger ADD COLUMN schema_version TEXT NOT NULL DEFAULT 'retrieval-ledger-event.v1'");
1067
+ }
1068
+ catch { }
1069
+ try {
1070
+ this.db.exec('ALTER TABLE devflow_retrieval_ledger ADD COLUMN task_spec_hash TEXT');
1071
+ }
1072
+ catch { }
1073
+ try {
1074
+ this.db.exec('ALTER TABLE devflow_retrieval_ledger ADD COLUMN actor TEXT');
1075
+ }
1076
+ catch { }
1077
+ try {
1078
+ this.db.exec('ALTER TABLE devflow_retrieval_ledger ADD COLUMN source_version TEXT');
1079
+ }
1080
+ catch { }
1081
+ try {
1082
+ this.db.exec('ALTER TABLE devflow_retrieval_ledger ADD COLUMN source_content_hash TEXT');
1083
+ }
1084
+ catch { }
1085
+ try {
1086
+ this.db.exec("ALTER TABLE devflow_retrieval_ledger ADD COLUMN evidence_ids TEXT NOT NULL DEFAULT '[]'");
1087
+ }
1088
+ catch { }
1089
+ try {
1090
+ this.db.exec('ALTER TABLE devflow_retrieval_ledger ADD COLUMN reason_code TEXT');
1091
+ }
1092
+ catch { }
1093
+ try {
1094
+ this.db.exec('ALTER TABLE devflow_work_items ADD COLUMN source_hash TEXT');
1095
+ }
1096
+ catch { }
1097
+ try {
1098
+ this.db.exec('ALTER TABLE devflow_work_items ADD COLUMN task_spec_hash TEXT');
1099
+ }
1100
+ catch { }
1101
+ try {
1102
+ this.db.exec('ALTER TABLE devflow_work_items ADD COLUMN cancelled_at INTEGER');
1103
+ }
1104
+ catch { }
1105
+ try {
1106
+ this.db.exec('ALTER TABLE devflow_work_items ADD COLUMN cancellation_reason TEXT');
1107
+ }
1108
+ catch { }
1109
+ try {
1110
+ this.db.exec('ALTER TABLE devflow_work_items ADD COLUMN replay_of_id TEXT');
1111
+ }
1112
+ catch { }
1113
+ try {
1114
+ this.db.exec('ALTER TABLE devflow_work_items ADD COLUMN replay_count INTEGER NOT NULL DEFAULT 0');
1115
+ }
1116
+ catch { }
981
1117
  this.db.exec('UPDATE devflow_rules SET updated_at = created_at WHERE updated_at IS NULL');
982
1118
  this.db.exec('CREATE INDEX IF NOT EXISTS idx_devflow_rules_gate ON devflow_rules(gate, enabled)');
983
1119
  // Migration: tool_metrics table for per-tool metrics collection
@@ -2412,7 +2548,8 @@ class DevFlowDatabase {
2412
2548
  throw new Error('Work idempotency key is required');
2413
2549
  if (!input.projectRoot.trim())
2414
2550
  throw new Error('Work project root is required');
2415
- const maxAttempts = input.maxAttempts ?? 5;
2551
+ const maxAttempts = input.maxAttempts
2552
+ ?? (input.kind === 'knowledge.ingest' || input.kind === 'knowledge.index_refresh' ? 3 : 5);
2416
2553
  if (!Number.isSafeInteger(maxAttempts) || maxAttempts <= 0) {
2417
2554
  throw new Error('Work maxAttempts must be a positive safe integer');
2418
2555
  }
@@ -2423,10 +2560,10 @@ class DevFlowDatabase {
2423
2560
  }
2424
2561
  const row = this.db.prepare(`
2425
2562
  INSERT INTO devflow_work_items (
2426
- id, idempotency_key, kind, project_root, session_id, turn_id, payload,
2563
+ id, idempotency_key, kind, project_root, session_id, turn_id, source_hash, task_spec_hash, payload,
2427
2564
  state, attempts, max_attempts, lease_owner, lease_expires_at,
2428
2565
  next_attempt_at, error_category, error_message, created_at, updated_at, completed_at
2429
- ) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', 0, ?, NULL, NULL, ?, NULL, NULL, ?, ?, NULL)
2566
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', 0, ?, NULL, NULL, ?, NULL, NULL, ?, ?, NULL)
2430
2567
  ON CONFLICT(idempotency_key) DO UPDATE SET
2431
2568
  state = CASE
2432
2569
  WHEN devflow_work_items.state = 'dead_letter'
@@ -2460,13 +2597,58 @@ class DevFlowDatabase {
2460
2597
  ELSE devflow_work_items.updated_at
2461
2598
  END
2462
2599
  RETURNING *
2463
- `).get((0, crypto_1.randomUUID)(), input.idempotencyKey, input.kind, input.projectRoot, input.sessionId ?? null, input.turnId ?? null, JSON.stringify(input.payload ?? null), maxAttempts, nextAttemptAt, createdAt, createdAt);
2600
+ `).get((0, crypto_1.randomUUID)(), input.idempotencyKey, input.kind, input.projectRoot, input.sessionId ?? null, input.turnId ?? null, input.sourceHash ?? null, input.taskSpecHash ?? null, JSON.stringify(input.payload ?? null), maxAttempts, nextAttemptAt, createdAt, createdAt);
2464
2601
  return this.mapWorkItem(row);
2465
2602
  }
2466
2603
  getWorkByIdempotencyKey(idempotencyKey) {
2467
2604
  const row = this.db.prepare('SELECT * FROM devflow_work_items WHERE idempotency_key = ?').get(idempotencyKey);
2468
2605
  return row ? this.mapWorkItem(row) : null;
2469
2606
  }
2607
+ getWorkById(id) {
2608
+ const row = this.db.prepare('SELECT * FROM devflow_work_items WHERE id = ?').get(id);
2609
+ return row ? this.mapWorkItem(row) : null;
2610
+ }
2611
+ acquireProjectMutationLease(input) {
2612
+ const now = input.now ?? Date.now();
2613
+ return this.db.prepare(`
2614
+ INSERT INTO devflow_project_mutation_leases
2615
+ (project_root, mutation_kind, owner, lease_expires_at, source_hash, updated_at)
2616
+ VALUES (?, ?, ?, ?, ?, ?)
2617
+ ON CONFLICT(project_root, mutation_kind) DO UPDATE SET
2618
+ owner = excluded.owner, lease_expires_at = excluded.lease_expires_at,
2619
+ source_hash = excluded.source_hash, updated_at = excluded.updated_at
2620
+ WHERE devflow_project_mutation_leases.lease_expires_at <= ? OR devflow_project_mutation_leases.owner = excluded.owner
2621
+ `).run(input.projectRoot, input.mutationKind, input.owner, now + input.leaseMs, input.sourceHash ?? null, now, now).changes > 0;
2622
+ }
2623
+ releaseProjectMutationLease(projectRoot, mutationKind, owner) {
2624
+ return this.db.prepare('DELETE FROM devflow_project_mutation_leases WHERE project_root = ? AND mutation_kind = ? AND owner = ?')
2625
+ .run(projectRoot, mutationKind, owner).changes > 0;
2626
+ }
2627
+ cancelStaleWork(input) {
2628
+ const current = this.getWorkById(input.id);
2629
+ const stale = current && current.state === 'leased' && current.leaseOwner === input.owner
2630
+ && ((input.sourceHash !== undefined && current.sourceHash !== input.sourceHash)
2631
+ || (input.taskSpecHash !== undefined && current.taskSpecHash !== input.taskSpecHash));
2632
+ if (!stale)
2633
+ return false;
2634
+ const now = input.now ?? Date.now();
2635
+ try {
2636
+ return this.db.prepare(`UPDATE devflow_work_items SET state = 'cancelled', lease_owner = NULL, lease_expires_at = NULL, cancelled_at = ?, cancellation_reason = ?, updated_at = ? WHERE id = ? AND state = 'leased' AND lease_owner = ?`)
2637
+ .run(now, input.reason ?? 'stale_source_or_task_spec', now, input.id, input.owner).changes === 1;
2638
+ }
2639
+ catch {
2640
+ return this.db.prepare(`UPDATE devflow_work_items SET state = 'completed', lease_owner = NULL, lease_expires_at = NULL, cancelled_at = ?, cancellation_reason = ?, updated_at = ? WHERE id = ? AND state = 'leased' AND lease_owner = ?`)
2641
+ .run(now, input.reason ?? 'stale_source_or_task_spec', now, input.id, input.owner).changes === 1;
2642
+ }
2643
+ }
2644
+ replayDeadLetterWork(id, input) {
2645
+ const original = this.getWorkById(id);
2646
+ if (!original || original.state !== 'dead_letter')
2647
+ return null;
2648
+ const replay = this.enqueueWork({ idempotencyKey: input.idempotencyKey, kind: original.kind, projectRoot: original.projectRoot, sessionId: original.sessionId, turnId: original.turnId, payload: original.payload, sourceHash: input.sourceHash ?? original.sourceHash, taskSpecHash: input.taskSpecHash ?? original.taskSpecHash, maxAttempts: original.maxAttempts, nextAttemptAt: input.now ?? Date.now() });
2649
+ this.db.prepare('UPDATE devflow_work_items SET replay_of_id = ?, replay_count = replay_count + 1 WHERE id = ?').run(original.id, replay.id);
2650
+ return this.getWorkById(replay.id);
2651
+ }
2470
2652
  requestSessionClosure(input) {
2471
2653
  if (!input.sessionId.trim())
2472
2654
  throw new Error('Session closure requires a session ID');
@@ -2718,8 +2900,10 @@ class DevFlowDatabase {
2718
2900
  projectRoot: row.project_root,
2719
2901
  sessionId: row.session_id ?? undefined,
2720
2902
  turnId: row.turn_id ?? undefined,
2903
+ sourceHash: row.source_hash ?? undefined,
2904
+ taskSpecHash: row.task_spec_hash ?? undefined,
2721
2905
  payload: parseJson(row.payload),
2722
- state: row.state,
2906
+ state: row.cancelled_at != null ? 'cancelled' : row.state,
2723
2907
  attempts: Number(row.attempts),
2724
2908
  maxAttempts: Number(row.max_attempts),
2725
2909
  leaseOwner: row.lease_owner ?? undefined,
@@ -2730,6 +2914,10 @@ class DevFlowDatabase {
2730
2914
  createdAt: Number(row.created_at),
2731
2915
  updatedAt: Number(row.updated_at),
2732
2916
  completedAt: row.completed_at == null ? undefined : Number(row.completed_at),
2917
+ cancelledAt: row.cancelled_at == null ? undefined : Number(row.cancelled_at),
2918
+ cancellationReason: row.cancellation_reason ?? undefined,
2919
+ replayOfId: row.replay_of_id ?? undefined,
2920
+ replayCount: Number(row.replay_count ?? 0),
2733
2921
  };
2734
2922
  }
2735
2923
  mapSessionClosure(row) {
@@ -3070,6 +3258,33 @@ class DevFlowDatabase {
3070
3258
  requestId: row.request_id ?? undefined,
3071
3259
  } : null;
3072
3260
  }
3261
+ getContextReceiptForRequest(projectRoot, sessionId, requestId) {
3262
+ const row = this.db.prepare(`
3263
+ SELECT project_root, session_id, execution_id, context_hash, issued_at, expires_at,
3264
+ selected_files, memory_ids, canonical_next_action, canonical_action_json,
3265
+ action_attempts, action_satisfied_at, action_degradation_json, request_id
3266
+ FROM devflow_context_receipts
3267
+ WHERE project_root = ? AND session_id = ? AND request_id = ?
3268
+ ORDER BY issued_at DESC
3269
+ LIMIT 1
3270
+ `).get(projectRoot, sessionId, requestId);
3271
+ return row ? {
3272
+ projectRoot: row.project_root,
3273
+ sessionId: row.session_id,
3274
+ executionId: row.execution_id,
3275
+ contextHash: row.context_hash,
3276
+ issuedAt: row.issued_at,
3277
+ expiresAt: row.expires_at,
3278
+ selectedFiles: parseJsonStringArray(row.selected_files),
3279
+ memoryIds: parseJsonStringArray(row.memory_ids),
3280
+ canonicalNextAction: row.canonical_next_action ?? undefined,
3281
+ canonicalAction: parseJsonObject(row.canonical_action_json),
3282
+ actionAttempts: parseJsonArray(row.action_attempts),
3283
+ actionSatisfiedAt: row.action_satisfied_at ?? undefined,
3284
+ actionDegradation: parseJsonObject(row.action_degradation_json),
3285
+ requestId: row.request_id ?? undefined,
3286
+ } : null;
3287
+ }
3073
3288
  recordContextSelectionEvent(event) {
3074
3289
  return this.db.prepare(`
3075
3290
  INSERT OR IGNORE INTO devflow_context_selection_events
@@ -3090,8 +3305,9 @@ class DevFlowDatabase {
3090
3305
  id, project_root, session_id, execution_id, turn_id, request_id, context_receipt,
3091
3306
  source_type, source_id, stage, rank, raw_score, normalized_score, final_score,
3092
3307
  applicability, reason, tool_evidence, verification_receipt, payload, created_at
3093
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3094
- `).run(event.id, event.projectRoot, event.sessionId, event.executionId ?? null, event.turnId ?? null, event.requestId, event.contextReceipt, event.sourceType, event.sourceId, event.stage, event.rank ?? null, event.rawScore ?? null, event.normalizedScore ?? null, event.finalScore ?? null, JSON.stringify(event.applicability), event.reason ?? null, JSON.stringify(event.toolEvidence), event.verificationReceipt ?? null, JSON.stringify(event.payload), event.createdAt).changes > 0;
3308
+ , schema_version, task_spec_hash, actor, source_version, source_content_hash, evidence_ids, reason_code
3309
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3310
+ `).run(event.id, event.projectRoot, event.sessionId, event.executionId ?? null, event.turnId ?? null, event.requestId, event.contextReceipt, event.sourceType, event.sourceId, event.stage, event.rank ?? null, event.rawScore ?? null, event.normalizedScore ?? null, event.finalScore ?? null, JSON.stringify(event.applicability), event.reason ?? null, JSON.stringify(event.toolEvidence), event.verificationReceipt ?? null, JSON.stringify(event.payload), event.createdAt, event.schemaVersion ?? 'retrieval-ledger-event.v1', event.taskSpecHash ?? null, event.actor ?? null, event.sourceVersion ?? null, event.sourceContentHash ?? null, JSON.stringify(event.evidenceIds ?? []), event.reasonCode ?? null).changes > 0;
3095
3311
  }
3096
3312
  appendTaskIntentArtifact(record) {
3097
3313
  (0, task_semantic_control_1.assertTaskIdentity)(record);
@@ -3170,6 +3386,77 @@ class DevFlowDatabase {
3170
3386
  `).get(input.projectRoot, input.sessionId, input.sourceHash);
3171
3387
  return row ? (0, task_semantic_control_1.mapTaskIntentArtifactRow)(row) : null;
3172
3388
  }
3389
+ appendSemanticResolution(record) {
3390
+ (0, semantic_resolution_1.assertSemanticResolutionRecord)(record);
3391
+ const existing = this.getSemanticResolution(record.frameHash);
3392
+ if (existing) {
3393
+ if ((0, semantic_resolution_1.stableSemanticResolutionJson)(existing) !== (0, semantic_resolution_1.stableSemanticResolutionJson)(record)) {
3394
+ throw new Error(`SEMANTIC_RESOLUTION_HASH_CONFLICT:${record.frameHash}`);
3395
+ }
3396
+ return false;
3397
+ }
3398
+ this.db.exec('BEGIN IMMEDIATE');
3399
+ try {
3400
+ const conflicting = this.db.prepare(`
3401
+ SELECT frame_hash FROM devflow_semantic_resolutions
3402
+ WHERE project_root = ? AND session_id = ? AND turn_id = ? AND artifact_revision = ?
3403
+ `).get(record.projectRoot, record.sessionId, record.turnId, record.artifactRevision);
3404
+ if (conflicting) {
3405
+ throw new Error(`SEMANTIC_RESOLUTION_REVISION_CONFLICT:${record.turnId}:${record.artifactRevision}`);
3406
+ }
3407
+ if (record.supersedesFrameHash) {
3408
+ const superseded = this.getSemanticResolution(record.supersedesFrameHash);
3409
+ if (!superseded) {
3410
+ throw new Error(`SEMANTIC_RESOLUTION_SUPERSEDED_NOT_FOUND:${record.supersedesFrameHash}`);
3411
+ }
3412
+ if (superseded.projectRoot !== record.projectRoot
3413
+ || superseded.sessionId !== record.sessionId
3414
+ || superseded.turnId !== record.turnId
3415
+ || superseded.artifactRevision >= record.artifactRevision) {
3416
+ throw new Error('SEMANTIC_RESOLUTION_SUPERSEDES_INVALID');
3417
+ }
3418
+ }
3419
+ this.db.prepare(`
3420
+ INSERT INTO devflow_semantic_resolutions (
3421
+ frame_hash, project_root, project_id, host_id, session_id, turn_id, request_id,
3422
+ source_hash, artifact_hash, artifact_revision, supersedes_frame_hash, state,
3423
+ generated_by, model_id, model_revision, route_catalog_version, threshold_version,
3424
+ route_json, sampling_json, conflicts_json, frame_json, duration_ms, created_at
3425
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3426
+ `).run(record.frameHash, record.projectRoot, record.projectId, record.hostId, record.sessionId, record.turnId, record.requestId, record.sourceHash, record.artifactHash, record.artifactRevision, record.supersedesFrameHash ?? null, record.state, record.generatedBy, record.modelId ?? null, record.modelRevision ?? null, record.routeCatalogVersion, record.thresholdVersion, (0, semantic_resolution_1.stableSemanticResolutionJson)(record.route), (0, semantic_resolution_1.stableSemanticResolutionJson)(record.sampling), (0, semantic_resolution_1.stableSemanticResolutionJson)(record.conflicts), (0, semantic_resolution_1.stableSemanticResolutionJson)(record.frame), record.durationMs, record.createdAt);
3427
+ this.db.exec('COMMIT');
3428
+ return true;
3429
+ }
3430
+ catch (error) {
3431
+ try {
3432
+ this.db.exec('ROLLBACK');
3433
+ }
3434
+ catch { }
3435
+ throw error;
3436
+ }
3437
+ }
3438
+ getSemanticResolution(frameHash) {
3439
+ const row = this.db.prepare(`
3440
+ SELECT * FROM devflow_semantic_resolutions WHERE frame_hash = ?
3441
+ `).get(frameHash);
3442
+ return row ? (0, semantic_resolution_1.mapSemanticResolutionRow)(row) : null;
3443
+ }
3444
+ getLatestSemanticResolution(projectRoot, sessionId, turnId) {
3445
+ const row = this.db.prepare(`
3446
+ SELECT * FROM devflow_semantic_resolutions
3447
+ WHERE project_root = ? AND session_id = ? AND turn_id = ?
3448
+ ORDER BY artifact_revision DESC, created_at DESC LIMIT 1
3449
+ `).get(projectRoot, sessionId, turnId);
3450
+ return row ? (0, semantic_resolution_1.mapSemanticResolutionRow)(row) : null;
3451
+ }
3452
+ listSemanticResolutions(projectRoot, sessionId, turnId) {
3453
+ return this.db.prepare(`
3454
+ SELECT * FROM devflow_semantic_resolutions
3455
+ WHERE project_root = ? AND session_id = ? AND turn_id = ?
3456
+ ORDER BY artifact_revision ASC, created_at ASC
3457
+ `).all(projectRoot, sessionId, turnId)
3458
+ .map(semantic_resolution_1.mapSemanticResolutionRow);
3459
+ }
3173
3460
  listLatestTaskIntentArtifacts(projectRoot, sessionId) {
3174
3461
  return this.db.prepare(`
3175
3462
  SELECT artifact.* FROM devflow_task_intent_artifacts artifact
@@ -3281,6 +3568,98 @@ class DevFlowDatabase {
3281
3568
  `).run(record.receiptId, record.projectRoot, record.projectId, record.hostId, record.sessionId, record.turnId, record.requestId, record.executionId ?? null, record.sequence, record.fromState ?? null, record.toState, record.sourceReceiptId ?? null, record.reason, (0, task_semantic_control_1.stableSemanticJson)(record.payload), record.createdAt);
3282
3569
  return this.getTerminalTransition(record.receiptId);
3283
3570
  }
3571
+ appendTaskRuntimeEvent(event) {
3572
+ const existing = this.getTaskRuntimeEvent(event.eventId);
3573
+ if (existing) {
3574
+ if ((0, task_runtime_1.stableTaskRuntimeJson)(existing) !== (0, task_runtime_1.stableTaskRuntimeJson)(event)) {
3575
+ throw new Error(`TASK_RUNTIME_EVENT_CONFLICT:${event.eventId}`);
3576
+ }
3577
+ return existing;
3578
+ }
3579
+ const atSequence = this.db.prepare(`
3580
+ SELECT event_id FROM devflow_task_runtime_events
3581
+ WHERE project_root = ? AND session_id = ? AND turn_id = ? AND sequence = ?
3582
+ `).get(event.identity.projectRoot, event.identity.sessionId, event.identity.turnId, event.sequence);
3583
+ if (atSequence)
3584
+ throw new Error(`TASK_RUNTIME_SEQUENCE_CONFLICT:${event.sequence}`);
3585
+ try {
3586
+ this.db.prepare(`
3587
+ INSERT INTO devflow_task_runtime_events (
3588
+ event_id, schema_version, producer, producer_version, project_root, project_id,
3589
+ host_id, session_id, turn_id, request_id, execution_id, task_spec_hash,
3590
+ sequence, kind, payload_json, created_at
3591
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3592
+ `).run(event.eventId, event.schemaVersion, event.producer, event.producerVersion, event.identity.projectRoot, event.identity.projectId, event.identity.hostId, event.identity.sessionId, event.identity.turnId, event.identity.requestId, event.identity.executionId ?? null, event.taskSpecHash, event.sequence, event.kind, (0, task_runtime_1.stableTaskRuntimeJson)(event.payload), event.createdAt);
3593
+ }
3594
+ catch (error) {
3595
+ const concurrentEvent = this.getTaskRuntimeEvent(event.eventId);
3596
+ if (concurrentEvent) {
3597
+ if ((0, task_runtime_1.stableTaskRuntimeJson)(concurrentEvent) === (0, task_runtime_1.stableTaskRuntimeJson)(event))
3598
+ return concurrentEvent;
3599
+ throw new Error(`TASK_RUNTIME_EVENT_CONFLICT:${event.eventId}`);
3600
+ }
3601
+ const concurrentSequence = this.db.prepare(`
3602
+ SELECT event_id FROM devflow_task_runtime_events
3603
+ WHERE project_root = ? AND session_id = ? AND turn_id = ? AND sequence = ?
3604
+ `).get(event.identity.projectRoot, event.identity.sessionId, event.identity.turnId, event.sequence);
3605
+ if (concurrentSequence)
3606
+ throw new Error(`TASK_RUNTIME_SEQUENCE_CONFLICT:${event.sequence}`);
3607
+ throw error;
3608
+ }
3609
+ return this.getTaskRuntimeEvent(event.eventId);
3610
+ }
3611
+ getTaskRuntimeEvent(eventId) {
3612
+ const row = this.db.prepare('SELECT * FROM devflow_task_runtime_events WHERE event_id = ?')
3613
+ .get(eventId);
3614
+ return row ? (0, task_runtime_1.mapTaskRuntimeEventRow)(row) : null;
3615
+ }
3616
+ listTaskRuntimeEvents(projectRoot, sessionId, turnId) {
3617
+ return this.db.prepare(`
3618
+ SELECT * FROM devflow_task_runtime_events
3619
+ WHERE project_root = ? AND session_id = ? AND turn_id = ?
3620
+ ORDER BY sequence ASC
3621
+ `).all(projectRoot, sessionId, turnId)
3622
+ .map(task_runtime_1.mapTaskRuntimeEventRow);
3623
+ }
3624
+ putTaskRuntimeSnapshot(snapshot) {
3625
+ const current = this.getTaskRuntimeSnapshot(snapshot.identity.projectRoot, snapshot.identity.sessionId, snapshot.identity.turnId);
3626
+ if (current && current.lastEventSequence > snapshot.lastEventSequence) {
3627
+ throw new Error('TASK_RUNTIME_SNAPSHOT_REGRESSION');
3628
+ }
3629
+ this.db.prepare(`
3630
+ INSERT INTO devflow_task_runtime_snapshots (
3631
+ project_root, session_id, turn_id, last_event_sequence, schema_version,
3632
+ snapshot_json, snapshot_hash, updated_at
3633
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
3634
+ ON CONFLICT(project_root, session_id, turn_id) DO UPDATE SET
3635
+ last_event_sequence = excluded.last_event_sequence,
3636
+ schema_version = excluded.schema_version,
3637
+ snapshot_json = excluded.snapshot_json,
3638
+ snapshot_hash = excluded.snapshot_hash,
3639
+ updated_at = excluded.updated_at
3640
+ WHERE excluded.last_event_sequence >= devflow_task_runtime_snapshots.last_event_sequence
3641
+ `).run(snapshot.identity.projectRoot, snapshot.identity.sessionId, snapshot.identity.turnId, snapshot.lastEventSequence, snapshot.schemaVersion, (0, task_runtime_1.stableTaskRuntimeJson)(snapshot), snapshot.snapshotHash, snapshot.updatedAt);
3642
+ return this.getTaskRuntimeSnapshot(snapshot.identity.projectRoot, snapshot.identity.sessionId, snapshot.identity.turnId);
3643
+ }
3644
+ appendTaskRuntimeEventAndSnapshot(event, snapshot) {
3645
+ return this.db.transaction(() => {
3646
+ this.appendTaskRuntimeEvent(event);
3647
+ return this.putTaskRuntimeSnapshot(snapshot);
3648
+ });
3649
+ }
3650
+ getTaskRuntimeSnapshot(projectRoot, sessionId, turnId) {
3651
+ const row = this.db.prepare(`
3652
+ SELECT * FROM devflow_task_runtime_snapshots
3653
+ WHERE project_root = ? AND session_id = ? AND turn_id = ?
3654
+ `).get(projectRoot, sessionId, turnId);
3655
+ return row ? (0, task_runtime_1.mapTaskRuntimeSnapshotRow)(row) : null;
3656
+ }
3657
+ deleteTaskRuntimeSnapshot(projectRoot, sessionId, turnId) {
3658
+ return this.db.prepare(`
3659
+ DELETE FROM devflow_task_runtime_snapshots
3660
+ WHERE project_root = ? AND session_id = ? AND turn_id = ?
3661
+ `).run(projectRoot, sessionId, turnId).changes > 0;
3662
+ }
3284
3663
  getTerminalTransition(receiptId) {
3285
3664
  const row = this.db.prepare(`
3286
3665
  SELECT * FROM devflow_terminal_transitions WHERE receipt_id = ?
@@ -3336,7 +3715,11 @@ class DevFlowDatabase {
3336
3715
  id: row.id, projectRoot: row.project_root, sessionId: row.session_id,
3337
3716
  executionId: row.execution_id ?? undefined, turnId: row.turn_id ?? undefined,
3338
3717
  requestId: row.request_id, contextReceipt: row.context_receipt,
3339
- sourceType: row.source_type, sourceId: row.source_id, stage: row.stage,
3718
+ schemaVersion: row.schema_version ?? 'retrieval-ledger-event.v1',
3719
+ sourceType: row.source_type, sourceId: row.source_id, stage: row.stage === 'adopted' ? 'consumed' : row.stage,
3720
+ taskSpecHash: row.task_spec_hash ?? undefined, actor: row.actor ?? undefined,
3721
+ sourceVersion: row.source_version ?? undefined, sourceContentHash: row.source_content_hash ?? undefined,
3722
+ evidenceIds: parseJsonStringArray(row.evidence_ids), reasonCode: row.reason_code ?? undefined,
3340
3723
  rank: row.rank ?? undefined, rawScore: row.raw_score ?? undefined,
3341
3724
  normalizedScore: row.normalized_score ?? undefined, finalScore: row.final_score ?? undefined,
3342
3725
  applicability: parseJsonStringArray(row.applicability), reason: row.reason ?? undefined,
@@ -3572,10 +3955,10 @@ class DevFlowDatabase {
3572
3955
  const turnId = (0, obligation_ledger_1.normalizeTurnId)(input.turnId);
3573
3956
  this.db.prepare(`
3574
3957
  UPDATE devflow_memory_turns
3575
- SET status = 'skipped', receipt_id = ?, memory_ids = '[]', source = 'host_skip',
3958
+ SET status = 'skipped', receipt_id = ?, memory_ids = '[]', source = ?,
3576
3959
  reason = ?, decided_at = ?
3577
3960
  WHERE turn_id = ? AND status = 'pending'
3578
- `).run(input.receiptId, input.reason, input.decidedAt ?? Date.now(), turnId);
3961
+ `).run(input.receiptId, input.source ?? 'host_skip', input.reason, input.decidedAt ?? Date.now(), turnId);
3579
3962
  const turn = this.getMemoryTurn(turnId);
3580
3963
  if (!turn || turn.status !== 'skipped') {
3581
3964
  throw new Error(`Memory turn ${turnId} is not pending or does not exist`);
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { DevFlowDatabase, getGlobalDevFlowDbPath, openGlobalDevFlowDatabase, openGlobalDevFlowReadOnlyDatabase, } from './database';
2
2
  export type { BenchmarkReportMetaRecord, BenchmarkReportRecord, FeedbackRecord, GovernanceAuditRecord, GovernanceRuleRecord, HookFallbackRecord, HookReceiptRecord, ContextReceiptRecord, ContextSelectionEventRecord, PolicyVerificationBaselineRecord, MemoryDistillCheckpointRecord, MemoryTurnRecord, MemoryTurnStatus, TelemetryFailureRecord, } from './database';
3
- export type { EnqueueWorkInput, LeaseWorkInput, RequestSessionClosureInput, SessionClosureRecord, SessionClosureState, WorkError, WorkItemRecord, WorkKind, WorkQueueHealth, WorkState, } from './work-queue';
3
+ export type { EnqueueWorkInput, LeaseWorkInput, RequestSessionClosureInput, SessionClosureRecord, SessionClosureState, WorkError, WorkItemRecord, WorkKind, WorkQueueHealth, WorkState, ProjectMutationLeaseRecord, } from './work-queue';
4
4
  export type { RetrievalLedgerEventRecord, RetrievalLedgerSourceType, RetrievalLedgerStage, } from './retrieval-ledger';
5
5
  export { hostActionReportsEqual, isHostActionState, mapHostActionRow, serializeHostActionReport, } from './host-actions';
6
6
  export { RETRIEVAL_MAX_CYCLES, isRetrievalSessionState } from './retrieval-sessions';
@@ -8,9 +8,13 @@ export type { AppendRetrievalCycleInput, CreateRetrievalSessionInput, RetrievalC
8
8
  export type { FailHostActionInput, HostActionRecord, HostActionState, ReportHostActionInput, RequestHostActionInput, StartHostActionInput, VerifyHostActionInput, } from './host-actions';
9
9
  export { mapSessionObligationRow, normalizeTurnId, } from './obligation-ledger';
10
10
  export { assertTaskIdentity, mapChannelQueryPlanRow, mapTaskIntentArtifactRow, mapTerminalTransitionRow, mapToolNameResolutionRow, mapTranscriptCheckpointRow, stableSemanticJson, } from './task-semantic-control';
11
+ export { mapTaskRuntimeEventRow, mapTaskRuntimeSnapshotRow, stableTaskRuntimeHash, stableTaskRuntimeJson, } from './task-runtime';
12
+ export type { TaskRuntimeChannelRecord, TaskRuntimeChannelRequirement, TaskRuntimeChannelStatus, TaskRuntimeEventRecord, TaskRuntimeIdentityRecord, TaskRuntimeObligationRecord, TaskRuntimeObligationState, TaskRuntimeSnapshotRecord, } from './task-runtime';
11
13
  export type { ChannelQueryPlanRecord, TaskIdentityRecord, TaskIntentArtifactRecord, TerminalTransitionRecord, ToolNameResolutionRecord, ToolNameResolutionStatus, TranscriptCheckpointRecord, } from './task-semantic-control';
12
14
  export { LEGAL_WORKFLOW_WORKER_TRANSITIONS, TERMINAL_WORKFLOW_WORKER_STATES, mapWorkflowMergeRow, mapWorkflowWorkerEventRow, mapWorkflowWorkerRow, } from './workflow-workers';
13
15
  export type { CreateWorkflowWorkerInput, EnqueueWorkflowMergeInput, TransitionWorkflowWorkerInput, WorkflowMergeRecord, WorkflowMergeState, WorkflowWorkerEventRecord, WorkflowWorkerRecord, WorkflowWorkerState, } from './workflow-workers';
14
16
  export { mapLearningCandidateRow, mapLearningEvidenceRow, mapLearningVersionRow, stableLearningJson, } from './learning-candidates';
15
17
  export type { AddLearningCandidateEvidenceInput, LearningCandidateEvidenceRecord, LearningCandidateKind, LearningCandidateRecord, LearningCandidateState, LearningCandidateVersionRecord, LearningEvidencePolarity, LearningOutcomeState, TransitionLearningCandidateInput, UpsertLearningCandidateInput, } from './learning-candidates';
16
18
  export type { SessionObligationKind, SessionObligationRecord, SessionObligationState, } from './obligation-ledger';
19
+ export { assertSemanticResolutionRecord, mapSemanticResolutionRow, stableSemanticResolutionJson, } from './semantic-resolution';
20
+ export type { PersistedSemanticGeneratedBy, PersistedSemanticResolutionState, SemanticResolutionRecord, } from './semantic-resolution';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.stableLearningJson = exports.mapLearningVersionRow = exports.mapLearningEvidenceRow = exports.mapLearningCandidateRow = exports.mapWorkflowWorkerRow = exports.mapWorkflowWorkerEventRow = exports.mapWorkflowMergeRow = exports.TERMINAL_WORKFLOW_WORKER_STATES = exports.LEGAL_WORKFLOW_WORKER_TRANSITIONS = exports.stableSemanticJson = exports.mapTranscriptCheckpointRow = exports.mapToolNameResolutionRow = exports.mapTerminalTransitionRow = exports.mapTaskIntentArtifactRow = exports.mapChannelQueryPlanRow = exports.assertTaskIdentity = exports.normalizeTurnId = exports.mapSessionObligationRow = exports.isRetrievalSessionState = exports.RETRIEVAL_MAX_CYCLES = exports.serializeHostActionReport = exports.mapHostActionRow = exports.isHostActionState = exports.hostActionReportsEqual = exports.openGlobalDevFlowReadOnlyDatabase = exports.openGlobalDevFlowDatabase = exports.getGlobalDevFlowDbPath = exports.DevFlowDatabase = void 0;
3
+ exports.stableSemanticResolutionJson = exports.mapSemanticResolutionRow = exports.assertSemanticResolutionRecord = exports.stableLearningJson = exports.mapLearningVersionRow = exports.mapLearningEvidenceRow = exports.mapLearningCandidateRow = exports.mapWorkflowWorkerRow = exports.mapWorkflowWorkerEventRow = exports.mapWorkflowMergeRow = exports.TERMINAL_WORKFLOW_WORKER_STATES = exports.LEGAL_WORKFLOW_WORKER_TRANSITIONS = exports.stableTaskRuntimeJson = exports.stableTaskRuntimeHash = exports.mapTaskRuntimeSnapshotRow = exports.mapTaskRuntimeEventRow = exports.stableSemanticJson = exports.mapTranscriptCheckpointRow = exports.mapToolNameResolutionRow = exports.mapTerminalTransitionRow = exports.mapTaskIntentArtifactRow = exports.mapChannelQueryPlanRow = exports.assertTaskIdentity = exports.normalizeTurnId = exports.mapSessionObligationRow = exports.isRetrievalSessionState = exports.RETRIEVAL_MAX_CYCLES = exports.serializeHostActionReport = exports.mapHostActionRow = exports.isHostActionState = exports.hostActionReportsEqual = exports.openGlobalDevFlowReadOnlyDatabase = exports.openGlobalDevFlowDatabase = exports.getGlobalDevFlowDbPath = exports.DevFlowDatabase = void 0;
4
4
  var database_1 = require("./database");
5
5
  Object.defineProperty(exports, "DevFlowDatabase", { enumerable: true, get: function () { return database_1.DevFlowDatabase; } });
6
6
  Object.defineProperty(exports, "getGlobalDevFlowDbPath", { enumerable: true, get: function () { return database_1.getGlobalDevFlowDbPath; } });
@@ -25,6 +25,11 @@ Object.defineProperty(exports, "mapTerminalTransitionRow", { enumerable: true, g
25
25
  Object.defineProperty(exports, "mapToolNameResolutionRow", { enumerable: true, get: function () { return task_semantic_control_1.mapToolNameResolutionRow; } });
26
26
  Object.defineProperty(exports, "mapTranscriptCheckpointRow", { enumerable: true, get: function () { return task_semantic_control_1.mapTranscriptCheckpointRow; } });
27
27
  Object.defineProperty(exports, "stableSemanticJson", { enumerable: true, get: function () { return task_semantic_control_1.stableSemanticJson; } });
28
+ var task_runtime_1 = require("./task-runtime");
29
+ Object.defineProperty(exports, "mapTaskRuntimeEventRow", { enumerable: true, get: function () { return task_runtime_1.mapTaskRuntimeEventRow; } });
30
+ Object.defineProperty(exports, "mapTaskRuntimeSnapshotRow", { enumerable: true, get: function () { return task_runtime_1.mapTaskRuntimeSnapshotRow; } });
31
+ Object.defineProperty(exports, "stableTaskRuntimeHash", { enumerable: true, get: function () { return task_runtime_1.stableTaskRuntimeHash; } });
32
+ Object.defineProperty(exports, "stableTaskRuntimeJson", { enumerable: true, get: function () { return task_runtime_1.stableTaskRuntimeJson; } });
28
33
  var workflow_workers_1 = require("./workflow-workers");
29
34
  Object.defineProperty(exports, "LEGAL_WORKFLOW_WORKER_TRANSITIONS", { enumerable: true, get: function () { return workflow_workers_1.LEGAL_WORKFLOW_WORKER_TRANSITIONS; } });
30
35
  Object.defineProperty(exports, "TERMINAL_WORKFLOW_WORKER_STATES", { enumerable: true, get: function () { return workflow_workers_1.TERMINAL_WORKFLOW_WORKER_STATES; } });
@@ -36,3 +41,7 @@ Object.defineProperty(exports, "mapLearningCandidateRow", { enumerable: true, ge
36
41
  Object.defineProperty(exports, "mapLearningEvidenceRow", { enumerable: true, get: function () { return learning_candidates_1.mapLearningEvidenceRow; } });
37
42
  Object.defineProperty(exports, "mapLearningVersionRow", { enumerable: true, get: function () { return learning_candidates_1.mapLearningVersionRow; } });
38
43
  Object.defineProperty(exports, "stableLearningJson", { enumerable: true, get: function () { return learning_candidates_1.stableLearningJson; } });
44
+ var semantic_resolution_1 = require("./semantic-resolution");
45
+ Object.defineProperty(exports, "assertSemanticResolutionRecord", { enumerable: true, get: function () { return semantic_resolution_1.assertSemanticResolutionRecord; } });
46
+ Object.defineProperty(exports, "mapSemanticResolutionRow", { enumerable: true, get: function () { return semantic_resolution_1.mapSemanticResolutionRow; } });
47
+ Object.defineProperty(exports, "stableSemanticResolutionJson", { enumerable: true, get: function () { return semantic_resolution_1.stableSemanticResolutionJson; } });
@@ -1,6 +1,7 @@
1
- export type RetrievalLedgerStage = 'eligible' | 'candidate' | 'selected' | 'exposed' | 'adopted' | 'positive_outcome' | 'negative_outcome' | 'unknown' | 'rejected';
1
+ export type RetrievalLedgerStage = 'eligible' | 'candidate' | 'selected' | 'exposed' | 'adopted' | 'consumed' | 'verified' | 'positive_outcome' | 'negative_outcome' | 'unknown' | 'unknown_outcome' | 'rejected';
2
2
  export type RetrievalLedgerSourceType = 'code' | 'memory' | 'knowledge' | 'action';
3
3
  export interface RetrievalLedgerEventRecord {
4
+ schemaVersion?: 'retrieval-ledger-event.v1';
4
5
  id: string;
5
6
  projectRoot: string;
6
7
  sessionId: string;
@@ -10,6 +11,12 @@ export interface RetrievalLedgerEventRecord {
10
11
  contextReceipt: string;
11
12
  sourceType: RetrievalLedgerSourceType;
12
13
  sourceId: string;
14
+ taskSpecHash?: string;
15
+ actor?: string;
16
+ sourceVersion?: string;
17
+ sourceContentHash?: string;
18
+ evidenceIds?: string[];
19
+ reasonCode?: string;
13
20
  stage: RetrievalLedgerStage;
14
21
  rank?: number;
15
22
  rawScore?: number;