@equationalapplications/core-llm-wiki 5.1.1 → 5.2.1

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.
@@ -544,6 +544,22 @@ declare class WikiBusyError extends Error {
544
544
  readonly entityId: string;
545
545
  constructor(operation: WikiBusyOperation, entityId: string);
546
546
  }
547
+ /**
548
+ * Thrown by `ingestDocument({ onDuplicateHash: 'throw' })` when a different
549
+ * source_ref in the same entity already holds the supplied source_hash against
550
+ * a live row. Mirrors {@link WikiBusyError}'s anchoring of canonical metadata
551
+ * on the error instance for stable observability.
552
+ */
553
+ declare class WikiDuplicateHashError extends Error {
554
+ readonly canonical: string;
555
+ readonly sourceHash: string;
556
+ readonly entityId: string;
557
+ constructor(params: {
558
+ canonical: string;
559
+ sourceHash: string;
560
+ entityId: string;
561
+ });
562
+ }
547
563
  /**
548
564
  * Thrown by the serialized transaction wrapper when a SQLite driver error
549
565
  * escapes a transaction callback (nested BEGIN, SQLITE_BUSY, constraint
@@ -796,6 +812,59 @@ declare class EntryRepository extends BaseRepository {
796
812
  }>>;
797
813
  updateSourceRefByRowid(rowid: number, sourceRef: string | null, tx: SQLiteAdapter): Promise<void>;
798
814
  findLatestSourceHash(entityId: string, sourceRef: string, tx?: SQLiteAdapter): Promise<string | null>;
815
+ /**
816
+ * Batch version of {@link findLatestSourceHash}. Returns a Map covering every
817
+ * requested ref, where the value is the source_hash from the row with the
818
+ * most-recently-updated live fact for that ref, or null when no live row exists.
819
+ *
820
+ * The SQL uses ROW_NUMBER() OVER (PARTITION BY source_ref ORDER BY updated_at
821
+ * DESC, id ASC) — NOT MAX(source_hash). Aggregation with MAX(source_hash) is
822
+ * wrong because MAX computes independently across grouped rows; the hash must
823
+ * come from the exact row that wins MAX(updated_at). The `id ASC` tie-break
824
+ * keeps selection deterministic when two live rows share `updated_at`.
825
+ *
826
+ * Source refs are de-duplicated and processed in chunks so the per-query bind
827
+ * parameter count stays under SQLite's `SQLITE_MAX_VARIABLE_NUMBER` (default
828
+ * 999, leaving one slot for `entity_id`).
829
+ *
830
+ * Empty input is a synchronous early return with zero SQL calls.
831
+ */
832
+ findLatestSourceHashes(entityId: string, sourceRefs: readonly string[], tx?: SQLiteAdapter): Promise<Map<string, string | null>>;
833
+ /**
834
+ * Return the live source_refs for an entity that hold the given source_hash.
835
+ * Used by the ingestDocument duplicate-hash guard and by hosts auditing
836
+ * duplicate-content collisions. Sorted `COLLATE BINARY` so the canonical
837
+ * ref (the code-unit-minimum of the set) is stable across deploys.
838
+ */
839
+ findSourceRefsByHash(entityId: string, sourceHash: string, tx?: SQLiteAdapter): Promise<string[]>;
840
+ /**
841
+ * Per-sourceRef rollup for an entity: one row per live source_ref, with the
842
+ * most-recently-updated live hash (NOT the lexically-max hash) and a live
843
+ * fact count.
844
+ *
845
+ * The hash comes from the same row that wins ROW_NUMBER() over updated_at
846
+ * DESC, so a ref with multiple live hashes (e.g. from import) reports the
847
+ * latest one — matching single-doc `findLatestSourceHash` semantics.
848
+ *
849
+ * Sort is COLLATE BINARY: locale-dependent ordering re-mints identity on
850
+ * every deploy, which is the bug this whole section exists to prevent.
851
+ */
852
+ listSourceRefs(entityId: string, tx?: SQLiteAdapter): Promise<Array<{
853
+ sourceRef: string;
854
+ sourceHash: string | null;
855
+ factCount: number;
856
+ lastIngestedAt: number;
857
+ }>>;
858
+ /**
859
+ * Count live entries for an entity across all source_refs/source_hashes.
860
+ * Used by forget({ dryRun, clearAll: true }).
861
+ */
862
+ countLiveByEntityId(entityId: string, tx?: SQLiteAdapter): Promise<number>;
863
+ /**
864
+ * Count live entries matching a source filter (either or both may be null).
865
+ * Used by forget({ dryRun: true }) with sourceRef/sourceHash.
866
+ */
867
+ countLiveBySource(entityId: string, sourceRef: string | null, sourceHash: string | null, tx?: SQLiteAdapter): Promise<number>;
799
868
  findMetadataByIds(ids: readonly string[], tx?: SQLiteAdapter): Promise<EntryRowMetadata[]>;
800
869
  findWithEmbeddingsByIds(ids: readonly string[], tx?: SQLiteAdapter): Promise<EntryRowWithEmbeddings[]>;
801
870
  findMetadataByEntityIds(entityIds: readonly string[], tx?: SQLiteAdapter): Promise<EntryRowMetadata[]>;
@@ -874,6 +943,49 @@ declare class EntryRepository extends BaseRepository {
874
943
  }>>;
875
944
  }
876
945
 
946
+ /**
947
+ * Per-(entity_id, source_hash) record of the canonical sourceRef currently
948
+ * holding that hash. The partial UNIQUE index on (entity_id, source_hash)
949
+ * WHERE deleted_at IS NULL enforces the sourceRef-level TOCTOU-race invariant
950
+ * for the #79 fix. See
951
+ * docs/superpowers/specs/2026-08-07-dependabot-concurrency-release-hygiene-design.md §B1.
952
+ *
953
+ * The entries table cannot express this invariant directly because a single
954
+ * `ingestDocument` call writes N facts that all share
955
+ * (entity_id, source_ref, source_hash); a UNIQUE index on
956
+ * `entries(entity_id, source_hash)` would block the 2nd–Nth fact inserts in
957
+ * the normal multi-fact path. The per-(entity, hash) granularity of
958
+ * source_ref_index matches the TOCTOU invariant exactly.
959
+ *
960
+ * No outbox events: this is an internal index table whose state is fully
961
+ * derivable from `entries`. Hosts that need CDC continue to read `entries`
962
+ * outbox events; the index is not part of the user-visible contract.
963
+ */
964
+ declare class SourceRefIndexRepository extends BaseRepository {
965
+ /**
966
+ * Idempotent insert: the partial UNIQUE index catches concurrent inserts for
967
+ * the same (entity_id, source_hash). The caller (IngestionService) catches
968
+ * the resulting SQLITE_CONSTRAINT_UNIQUE and translates it to the per-mode
969
+ * duplicate-hash outcome. Runtime IDs use the `sri_` prefix to avoid
970
+ * collision with the deterministic `sri:<entity>:<hash>` IDs used by the v9
971
+ * backfill (the colon separator keeps the two ID spaces disjoint).
972
+ */
973
+ upsert(entityId: string, sourceHash: string, sourceRef: string, tx: SQLiteAdapter): Promise<void>;
974
+ /**
975
+ * Idempotent soft-delete of the live row for (entity_id, source_ref).
976
+ * Called at the start of every ingestDocument to remove the prior run's
977
+ * index row, so the new upsert doesn't collide with itself. No-op when the
978
+ * row is already soft-deleted or never existed.
979
+ */
980
+ softDeleteByEntityAndSourceRef(entityId: string, sourceRef: string, tx: SQLiteAdapter): Promise<number>;
981
+ /**
982
+ * Returns the live sourceRef holding the given hash, or null when no live
983
+ * row exists. Used by the IngestionService pre-check (line 82) and the
984
+ * catch-and-translate canonical lookup (line 212).
985
+ */
986
+ findActiveByEntityAndHash(entityId: string, sourceHash: string, tx?: SQLiteAdapter): Promise<string | null>;
987
+ }
988
+
877
989
  declare class MetadataRepository extends BaseRepository {
878
990
  getCheckpoint(entityId: string, tx: SQLiteAdapter): Promise<{
879
991
  memory?: number;
@@ -996,8 +1108,46 @@ declare class JobManager {
996
1108
  private prefix;
997
1109
  private activeMaintenanceJobs;
998
1110
  private activeIngestJobs;
1111
+ /**
1112
+ * Per-(entityId, sourceHash) promise-chain lock. Serializes ingest races
1113
+ * at the application level (the v9 partial UNIQUE index enforces it at
1114
+ * the DB level as defense-in-depth). Two callers holding the same hash
1115
+ * see FIFO order; different hashes never block one another.
1116
+ *
1117
+ * Keyed `${entityId}\0${sourceHash}` so distinct (entityId, sourceHash)
1118
+ * pairs can never share a lock. A raw concatenation would let
1119
+ * ("ab", "c…") collide with ("a", "bc…"); the NUL separator makes that
1120
+ * impossible because neither component can contain NUL (entityIds are
1121
+ * user-supplied identifiers; sourceHashes are hex digests).
1122
+ */
1123
+ private hashLocks;
999
1124
  private statusSubscribers;
1000
1125
  constructor(prefix: string);
1126
+ private _hashLockKey;
1127
+ /**
1128
+ * Acquire a promise-chain lock scoped to one `(entityId, sourceHash)` pair.
1129
+ * Returns a zero-argument release closure that removes the current tail
1130
+ * from the chain. Releasing is idempotent so a holder that double-fires
1131
+ * (e.g. on a finally that races an explicit release) cannot unblock
1132
+ * the next holder prematurely.
1133
+ *
1134
+ * Documented ordering: ingest acquires the hash lock FIRST, then the
1135
+ * synchronous sourceRef ingest lock, and the release closure unwinds in
1136
+ * the opposite order (sourceRef first, hash second). Hash-then-sourceRef
1137
+ * is required because the v9 partial UNIQUE index conflicts on the
1138
+ * (entity_id, source_hash) pair regardless of source_ref, so two callers
1139
+ * with DIFFERENT source_refs racing the same hash are the exact case the
1140
+ * TOCTOU race fix needs to serialize.
1141
+ *
1142
+ * Mechanics: each holder owns a private `released` promise that resolves
1143
+ * only when THIS holder calls release(). The map stores the holder's
1144
+ * `released` promise as the "tail" — the NEXT caller awaits that tail
1145
+ * via `previous = this.hashLocks.get(key)`. The current caller gets
1146
+ * their unique release function once `previous` (the prior holder's
1147
+ * release signal) settles, so each holder is guaranteed a UNIQUE release
1148
+ * closure bound to their own `released` promise.
1149
+ */
1150
+ acquireHashLock(entityId: string, sourceHash: string): Promise<() => void>;
1001
1151
  private _pruneKey;
1002
1152
  private _reembedKey;
1003
1153
  private _globalReembedKey;
@@ -1034,6 +1184,21 @@ declare class JobManager {
1034
1184
  * for write() auto-trigger paths while preserving stricter checks in acquireLock().
1035
1185
  */
1036
1186
  tryAcquireAutoHealLock(entityId: string): boolean;
1187
+ /**
1188
+ * Centralized ingest lock acquisition. Acquires the hash lock FIRST
1189
+ * (FIFO across callers racing the same hash), then the synchronous
1190
+ * sourceRef ingest lock (rejects cross-entity conflicts and busy
1191
+ * operations). Returns a single zero-argument release closure that
1192
+ * unwinds in the opposite order — sourceRef first, hash second — so
1193
+ * the sourceRef lock is freed the instant its work is done and only
1194
+ * the hash lock keeps serializing the duplicate-content race window.
1195
+ *
1196
+ * On a sourceRef conflict (WikiBusyError thrown synchronously by the
1197
+ * underlying acquireLock) the hash lock is released BEFORE the error
1198
+ * propagates, so the next caller in the hash chain is not held up by
1199
+ * a request that never reached the DB.
1200
+ */
1201
+ acquireIngestLocks(entityId: string, sourceRef: string, sourceHash: string): Promise<() => void>;
1037
1202
  /**
1038
1203
  * Validates then acquires global + per-entity import locks atomically.
1039
1204
  * Validates all entities before acquiring any lock (same as current importDump semantics).
@@ -1155,12 +1320,13 @@ declare class IngestionService {
1155
1320
  private prefix;
1156
1321
  private options;
1157
1322
  private entryRepo;
1323
+ private sourceRefIndexRepo;
1158
1324
  private searchService;
1159
1325
  private jobManager;
1160
1326
  private embeddingService;
1161
1327
  private ontologyService?;
1162
1328
  private promptService;
1163
- constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService, ontologyService?: OntologyService | undefined);
1329
+ constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, sourceRefIndexRepo: SourceRefIndexRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService, ontologyService?: OntologyService | undefined);
1164
1330
  ingestDocument(entityId: string, params: {
1165
1331
  sourceRef: string;
1166
1332
  sourceHash: string;
@@ -1169,9 +1335,12 @@ declare class IngestionService {
1169
1335
  chunkOverlap?: number;
1170
1336
  chunkConcurrency?: number;
1171
1337
  promptOverride?: string;
1338
+ }, opts?: {
1339
+ onDuplicateHash?: 'ingest' | 'skip' | 'throw';
1172
1340
  }): Promise<{
1173
1341
  truncated: boolean;
1174
1342
  chunks: number;
1343
+ duplicateOf?: string;
1175
1344
  }>;
1176
1345
  }
1177
1346
 
@@ -1230,6 +1399,10 @@ declare class TaskRepository extends BaseRepository {
1230
1399
  * `tx` is REQUIRED.
1231
1400
  */
1232
1401
  bulkSoftDeleteByEntityId(entityId: string, tx: SQLiteAdapter): Promise<number>;
1402
+ /**
1403
+ * Count live tasks for an entity. Used by forget({ dryRun, clearAll: true }).
1404
+ */
1405
+ countLiveByEntityId(entityId: string, tx?: SQLiteAdapter): Promise<number>;
1233
1406
  }
1234
1407
 
1235
1408
  declare class EventRepository extends BaseRepository {
@@ -1285,6 +1458,7 @@ declare class MaintenanceService {
1285
1458
  private prefix;
1286
1459
  private options;
1287
1460
  private entryRepo;
1461
+ private sourceRefIndexRepo;
1288
1462
  private taskRepo;
1289
1463
  private eventRepo;
1290
1464
  private metadataRepo;
@@ -1293,7 +1467,7 @@ declare class MaintenanceService {
1293
1467
  private embeddingService;
1294
1468
  private ontologyService?;
1295
1469
  private promptService;
1296
- constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, taskRepo: TaskRepository, eventRepo: EventRepository, metadataRepo: MetadataRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService, ontologyService?: OntologyService | undefined);
1470
+ constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, sourceRefIndexRepo: SourceRefIndexRepository, taskRepo: TaskRepository, eventRepo: EventRepository, metadataRepo: MetadataRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService, ontologyService?: OntologyService | undefined);
1297
1471
  runPrune(entityId: string, options?: {
1298
1472
  retainSoftDeletedFor?: number | null;
1299
1473
  retainEventsFor?: number | null;
@@ -1328,12 +1502,28 @@ declare class MaintenanceService {
1328
1502
  sourceRef?: string;
1329
1503
  sourceHash?: string;
1330
1504
  clearAll?: boolean;
1505
+ }, opts?: {
1506
+ dryRun?: boolean;
1331
1507
  }): Promise<{
1332
1508
  deleted: {
1333
1509
  entries: number;
1334
1510
  tasks: number;
1335
1511
  };
1512
+ metadataReset?: boolean;
1336
1513
  }>;
1514
+ /**
1515
+ * Read-only dry-run preview of {@link forget}. Returns the same shape as a
1516
+ * real call would, without acquiring the lock, opening a transaction, staging
1517
+ * outbox events, or firing embedding hooks. Counts may be off-by-N during a
1518
+ * concurrent real forget — this is accepted, not considered a bug.
1519
+ *
1520
+ * `metadataReset` mirrors the real call: only `clearAll: true` returns true,
1521
+ * because only `clearAll` actually resets the metadata checkpoint.
1522
+ * `standard` (sourceRef/sourceHash) returns no metadataReset field, just like
1523
+ * the real call. `entryId`/`taskId` selectors are rejected with a clear error
1524
+ * (the spec keeps dry-run narrow).
1525
+ */
1526
+ private forgetDryRun;
1337
1527
  /** Core librarian pass (locks handled by {@link runLibrarian}). Package-internal orchestration hook. */
1338
1528
  doRunLibrarian(entityId: string, promptOverride?: string): Promise<void>;
1339
1529
  /**
@@ -1490,6 +1680,7 @@ interface WikiMemoryTestAccess {
1490
1680
  promptService: PromptService;
1491
1681
  graphTraversalService: GraphTraversalService;
1492
1682
  entryRepo: EntryRepository;
1683
+ sourceRefIndexRepo: SourceRefIndexRepository;
1493
1684
  metadataRepo: MetadataRepository;
1494
1685
  jobManager: JobManager;
1495
1686
  }
@@ -1500,6 +1691,7 @@ declare class WikiMemory {
1500
1691
  private options;
1501
1692
  private entryRepo;
1502
1693
  private outboxRepo;
1694
+ private sourceRefIndexRepo;
1503
1695
  private taskRepo;
1504
1696
  private eventRepo;
1505
1697
  private edgeRepo;
@@ -1523,6 +1715,47 @@ declare class WikiMemory {
1523
1715
  get __testAccess(): WikiMemoryTestAccess;
1524
1716
  setup(): Promise<void>;
1525
1717
  hasChanged(entityId: string, sourceRef: string, sourceHash: string): Promise<boolean>;
1718
+ /**
1719
+ * Batched overload.
1720
+ *
1721
+ * `duplicateOf`, when present, is the canonical stored DIFFERENT `source_ref`
1722
+ * holding the same hash — never the incoming ref itself (the incoming ref is
1723
+ * excluded from the canonical-sort set so a self-reference is impossible).
1724
+ * `duplicateOf` reflects the *DB-side* normalized spelling; `sourceRef` in
1725
+ * each result echoes the raw caller value. Hosts should not compare these
1726
+ * two fields directly to infer canonical status.
1727
+ */
1728
+ hasChanged(entityId: string, entries: Array<{
1729
+ sourceRef: string;
1730
+ sourceHash: string;
1731
+ }>): Promise<Array<{
1732
+ sourceRef: string;
1733
+ changed: boolean;
1734
+ duplicateOf?: string;
1735
+ }>>;
1736
+ /**
1737
+ * Returns the live source_refs for an entity, one row per ref, with the most
1738
+ * recently-updated live `source_hash` and a live fact count. Refs are sorted
1739
+ * `COLLATE BINARY` (no locale dependency). Used by hosts to reconcile stored
1740
+ * state against a live source, or audit duplicate-hash collisions via
1741
+ * `findSourceRefsByHash`.
1742
+ */
1743
+ listSourceRefs(entityId: string): Promise<Array<{
1744
+ sourceRef: string;
1745
+ sourceHash: string | null;
1746
+ factCount: number;
1747
+ lastIngestedAt: number;
1748
+ }>>;
1749
+ /**
1750
+ * Returns the live source_refs for an entity that hold the given source_hash.
1751
+ * With v9, source_ref_index is the source of truth for the sourceRef-level
1752
+ * TOCTOU-race invariant: at most one sourceRef can hold a given
1753
+ * (entity_id, source_hash). The result is either a single-element array
1754
+ * (one canonical ref) or empty (no live ref holds the hash). Returned as
1755
+ * an array to preserve the existing public-API shape used by hosts
1756
+ * auditing duplicate-content collisions.
1757
+ */
1758
+ findSourceRefsByHash(entityId: string, sourceHash: string): Promise<string[]>;
1526
1759
  runPrune(entityId: string, options?: {
1527
1760
  retainSoftDeletedFor?: number | null;
1528
1761
  retainEventsFor?: number | null;
@@ -1609,11 +1842,14 @@ declare class WikiMemory {
1609
1842
  sourceRef?: string;
1610
1843
  sourceHash?: string;
1611
1844
  clearAll?: boolean;
1845
+ }, opts?: {
1846
+ dryRun?: boolean;
1612
1847
  }): Promise<{
1613
1848
  deleted: {
1614
1849
  entries: number;
1615
1850
  tasks: number;
1616
1851
  };
1852
+ metadataReset?: boolean;
1617
1853
  }>;
1618
1854
  /**
1619
1855
  * @param params.promptOverride - Overrides the system prompt for this ingest call only.
@@ -1628,9 +1864,12 @@ declare class WikiMemory {
1628
1864
  chunkOverlap?: number;
1629
1865
  chunkConcurrency?: number;
1630
1866
  promptOverride?: string;
1867
+ }, opts?: {
1868
+ onDuplicateHash?: 'ingest' | 'skip' | 'throw';
1631
1869
  }): Promise<{
1632
1870
  truncated: boolean;
1633
1871
  chunks: number;
1872
+ duplicateOf?: string;
1634
1873
  }>;
1635
1874
  /**
1636
1875
  * Returns up to `limit` unprocessed outbox events, oldest first.
@@ -1660,4 +1899,4 @@ declare class WikiMemory {
1660
1899
  }): Promise<void>;
1661
1900
  }
1662
1901
 
1663
- export { MaintenanceService as $, WikiBusyError as A, type WikiBusyOperation as B, type WikiCheckpoint as C, type WikiConfig as D, type EntityStatus as E, type FormatContextOptions as F, type GraphNeighborhood as G, HEAL_BATCH_SIZE as H, type WikiEdge as I, type WikiEvent as J, type WikiFact as K, type LLMProvider as L, type MemoryBundle as M, type WikiMemoryTestAccess as N, type OntologyManifest as O, type PromptOverrides as P, type WikiOutboxEvent as Q, type ReadOptions as R, type SQLiteAdapter as S, type WikiTask as T, WikiTransactionError as U, type VectorRanker as V, type WikiOptions as W, EmbeddingService as X, ImportExportService as Y, IngestionService as Z, JobManager as _, type MemoryDump as a, RetrievalService as a0, SearchService as a1, WriteService as a2, type FormattedMemoryDump as b, WikiMemory as c, type ExtractedFact as d, type ExtractedFactEdge as e, type ExtractedFactWithOntology as f, type ExtractedTask as g, type GraphTraversalOptions as h, HEAL_RECHECK_MS as i, HOOK_TIMEOUT_MARKER as j, type HealResult as k, ONTOLOGY_BACKFILL_BATCH_SIZE as l, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS as m, ONTOLOGY_BACKFILL_RECHECK_MS as n, type OntologyBackfillResult as o, type OntologyConfig as p, type OntologyEdgeType as q, type OntologyMode as r, type OntologyNodeType as s, type OntologyPromptContext as t, type OntologyUpdates as u, PromptService as v, PrunePartialFailureError as w, type VectorRankerFallback as x, type VectorRankerRankArgs as y, type VectorRankerSemanticResult as z };
1902
+ export { JobManager as $, WikiBusyError as A, type WikiBusyOperation as B, type WikiCheckpoint as C, type WikiConfig as D, type EntityStatus as E, type FormatContextOptions as F, type GraphNeighborhood as G, HEAL_BATCH_SIZE as H, WikiDuplicateHashError as I, type WikiEdge as J, type WikiEvent as K, type LLMProvider as L, type MemoryBundle as M, type WikiFact as N, type OntologyManifest as O, type PromptOverrides as P, type WikiMemoryTestAccess as Q, type ReadOptions as R, type SQLiteAdapter as S, type WikiOutboxEvent as T, type WikiTask as U, type VectorRanker as V, type WikiOptions as W, WikiTransactionError as X, EmbeddingService as Y, ImportExportService as Z, IngestionService as _, type MemoryDump as a, MaintenanceService as a0, RetrievalService as a1, SearchService as a2, WriteService as a3, type FormattedMemoryDump as b, WikiMemory as c, type ExtractedFact as d, type ExtractedFactEdge as e, type ExtractedFactWithOntology as f, type ExtractedTask as g, type GraphTraversalOptions as h, HEAL_RECHECK_MS as i, HOOK_TIMEOUT_MARKER as j, type HealResult as k, ONTOLOGY_BACKFILL_BATCH_SIZE as l, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS as m, ONTOLOGY_BACKFILL_RECHECK_MS as n, type OntologyBackfillResult as o, type OntologyConfig as p, type OntologyEdgeType as q, type OntologyMode as r, type OntologyNodeType as s, type OntologyPromptContext as t, type OntologyUpdates as u, PromptService as v, PrunePartialFailureError as w, type VectorRankerFallback as x, type VectorRankerRankArgs as y, type VectorRankerSemanticResult as z };