@equationalapplications/core-llm-wiki 5.2.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/{chunk-J3N3WRK7.mjs → chunk-KIJINNYU.mjs} +367 -84
- package/dist/chunk-KIJINNYU.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +664 -103
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +300 -24
- package/dist/index.mjs.map +1 -1
- package/dist/{testing-DyXISRwS.d.mts → testing-zf3Jp_RL.d.mts} +336 -29
- package/dist/{testing-DyXISRwS.d.ts → testing-zf3Jp_RL.d.ts} +336 -29
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +378 -74
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-J3N3WRK7.mjs.map +0 -1
|
@@ -560,6 +560,42 @@ declare class WikiDuplicateHashError extends Error {
|
|
|
560
560
|
entityId: string;
|
|
561
561
|
});
|
|
562
562
|
}
|
|
563
|
+
/**
|
|
564
|
+
* Thrown by `WikiMemory.upsertGraph` when the persisted ontology mode for the
|
|
565
|
+
* entity is `'strict'` and a caller-supplied node or edge `type` does not
|
|
566
|
+
* resolve against the entity's manifest. Mirrors {@link WikiBusyError}'s
|
|
567
|
+
* anchoring of canonical metadata on the error instance for stable
|
|
568
|
+
* observability. Per C4, the check is pre-flight and all-or-nothing — the
|
|
569
|
+
* first invalid item throws; NONE are written.
|
|
570
|
+
*/
|
|
571
|
+
declare class WikiStrictOntologyViolation extends Error {
|
|
572
|
+
readonly entityId: string;
|
|
573
|
+
readonly kind: 'node' | 'edge';
|
|
574
|
+
readonly type: string;
|
|
575
|
+
readonly code: "WIKI_STRICT_ONTOLOGY_VIOLATION";
|
|
576
|
+
constructor(entityId: string, kind: 'node' | 'edge', type: string);
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Thrown by `WikiMemory.upsertGraph`'s C2 probe when the supplied
|
|
580
|
+
* `sourceHash` is already mapped to a *different* `sourceRef` for the same
|
|
581
|
+
* entity. Indicates either a caller-side id-derivation collision, a race with
|
|
582
|
+
* another writer, or — per the C2 known-limitation note in the spec — two
|
|
583
|
+
* source files with genuinely identical content (byte-identical barrel
|
|
584
|
+
* re-exports, blank stubs, vendored boilerplate). In all cases: fail loud.
|
|
585
|
+
*/
|
|
586
|
+
declare class WikiSourceRefHashCollision extends Error {
|
|
587
|
+
readonly entityId: string;
|
|
588
|
+
readonly sourceHash: string;
|
|
589
|
+
readonly existingSourceRef: string;
|
|
590
|
+
readonly attemptedSourceRef: string;
|
|
591
|
+
readonly code: "WIKI_SOURCE_REF_HASH_COLLISION";
|
|
592
|
+
constructor(params: {
|
|
593
|
+
entityId: string;
|
|
594
|
+
sourceHash: string;
|
|
595
|
+
existingSourceRef: string;
|
|
596
|
+
attemptedSourceRef: string;
|
|
597
|
+
});
|
|
598
|
+
}
|
|
563
599
|
/**
|
|
564
600
|
* Thrown by the serialized transaction wrapper when a SQLite driver error
|
|
565
601
|
* escapes a transaction callback (nested BEGIN, SQLITE_BUSY, constraint
|
|
@@ -734,8 +770,16 @@ declare class EntryRepository extends BaseRepository {
|
|
|
734
770
|
/**
|
|
735
771
|
* Fetch recent non-deleted entries for an entity (limited), ordered by updated_at DESC.
|
|
736
772
|
* Used by MaintenanceService.doRunLibrarian().
|
|
773
|
+
*
|
|
774
|
+
* When `excludeSourceRef` is supplied, the WHERE clause filters out that
|
|
775
|
+
* sourceRef BEFORE applying LIMIT. The caller in IngestionService is
|
|
776
|
+
* `findRecentByEntityId(entityId, 500, tx)` — it discards same-sourceRef
|
|
777
|
+
* rows after the read to build a cross-sourceRef title index. If those
|
|
778
|
+
* rows are filtered out in SQL, the limit applies to usable rows only
|
|
779
|
+
* and a re-ingest where the caller's sourceRef owns most recent facts
|
|
780
|
+
* still leaves cross-sourceRef entries in the index.
|
|
737
781
|
*/
|
|
738
|
-
findRecentByEntityId(entityId: string, limit: number, tx?: SQLiteAdapter): Promise<WikiFact[]>;
|
|
782
|
+
findRecentByEntityId(entityId: string, limit: number, tx?: SQLiteAdapter, excludeSourceRef?: string): Promise<WikiFact[]>;
|
|
739
783
|
/**
|
|
740
784
|
* Fetch all non-deleted entries for an entity with embedding blobs preserved.
|
|
741
785
|
* Used by ImportExportService for export/import round-tripping.
|
|
@@ -943,6 +987,49 @@ declare class EntryRepository extends BaseRepository {
|
|
|
943
987
|
}>>;
|
|
944
988
|
}
|
|
945
989
|
|
|
990
|
+
/**
|
|
991
|
+
* Per-(entity_id, source_hash) record of the canonical sourceRef currently
|
|
992
|
+
* holding that hash. The partial UNIQUE index on (entity_id, source_hash)
|
|
993
|
+
* WHERE deleted_at IS NULL enforces the sourceRef-level TOCTOU-race invariant
|
|
994
|
+
* for the #79 fix. See
|
|
995
|
+
* docs/superpowers/specs/2026-08-07-dependabot-concurrency-release-hygiene-design.md §B1.
|
|
996
|
+
*
|
|
997
|
+
* The entries table cannot express this invariant directly because a single
|
|
998
|
+
* `ingestDocument` call writes N facts that all share
|
|
999
|
+
* (entity_id, source_ref, source_hash); a UNIQUE index on
|
|
1000
|
+
* `entries(entity_id, source_hash)` would block the 2nd–Nth fact inserts in
|
|
1001
|
+
* the normal multi-fact path. The per-(entity, hash) granularity of
|
|
1002
|
+
* source_ref_index matches the TOCTOU invariant exactly.
|
|
1003
|
+
*
|
|
1004
|
+
* No outbox events: this is an internal index table whose state is fully
|
|
1005
|
+
* derivable from `entries`. Hosts that need CDC continue to read `entries`
|
|
1006
|
+
* outbox events; the index is not part of the user-visible contract.
|
|
1007
|
+
*/
|
|
1008
|
+
declare class SourceRefIndexRepository extends BaseRepository {
|
|
1009
|
+
/**
|
|
1010
|
+
* Idempotent insert: the partial UNIQUE index catches concurrent inserts for
|
|
1011
|
+
* the same (entity_id, source_hash). The caller (IngestionService) catches
|
|
1012
|
+
* the resulting SQLITE_CONSTRAINT_UNIQUE and translates it to the per-mode
|
|
1013
|
+
* duplicate-hash outcome. Runtime IDs use the `sri_` prefix to avoid
|
|
1014
|
+
* collision with the deterministic `sri:<entity>:<hash>` IDs used by the v9
|
|
1015
|
+
* backfill (the colon separator keeps the two ID spaces disjoint).
|
|
1016
|
+
*/
|
|
1017
|
+
upsert(entityId: string, sourceHash: string, sourceRef: string, tx: SQLiteAdapter): Promise<void>;
|
|
1018
|
+
/**
|
|
1019
|
+
* Idempotent soft-delete of the live row for (entity_id, source_ref).
|
|
1020
|
+
* Called at the start of every ingestDocument to remove the prior run's
|
|
1021
|
+
* index row, so the new upsert doesn't collide with itself. No-op when the
|
|
1022
|
+
* row is already soft-deleted or never existed.
|
|
1023
|
+
*/
|
|
1024
|
+
softDeleteByEntityAndSourceRef(entityId: string, sourceRef: string, tx: SQLiteAdapter): Promise<number>;
|
|
1025
|
+
/**
|
|
1026
|
+
* Returns the live sourceRef holding the given hash, or null when no live
|
|
1027
|
+
* row exists. Used by the IngestionService pre-check (line 82) and the
|
|
1028
|
+
* catch-and-translate canonical lookup (line 212).
|
|
1029
|
+
*/
|
|
1030
|
+
findActiveByEntityAndHash(entityId: string, sourceHash: string, tx?: SQLiteAdapter): Promise<string | null>;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
946
1033
|
declare class MetadataRepository extends BaseRepository {
|
|
947
1034
|
getCheckpoint(entityId: string, tx: SQLiteAdapter): Promise<{
|
|
948
1035
|
memory?: number;
|
|
@@ -960,6 +1047,15 @@ declare class MetadataRepository extends BaseRepository {
|
|
|
960
1047
|
tableExists(tableName: string, tx?: SQLiteAdapter): Promise<boolean>;
|
|
961
1048
|
getTableDdl(tableName: string, tx?: SQLiteAdapter): Promise<string | null>;
|
|
962
1049
|
vacuum(): Promise<void>;
|
|
1050
|
+
/**
|
|
1051
|
+
* Returns the set of distinct `entity_id` values across entries/tasks/events.
|
|
1052
|
+
*
|
|
1053
|
+
* Deliberately widened from a prior `WHERE deleted_at IS NULL` form: the
|
|
1054
|
+
* returned set intentionally includes entities whose only rows are
|
|
1055
|
+
* soft-deleted, so the host's maintenance sweep can visit such
|
|
1056
|
+
* "decommissioned-scope" namespaces and reap the soft-deleted rows. Sorting
|
|
1057
|
+
* is `entity_id COLLATE BINARY` for stable, locale-independent ordering.
|
|
1058
|
+
*/
|
|
963
1059
|
getDistinctEntityIds(tx?: SQLiteAdapter): Promise<string[]>;
|
|
964
1060
|
getManifest(entityId: string, tx?: SQLiteAdapter): Promise<{
|
|
965
1061
|
mode: OntologyMode;
|
|
@@ -1065,8 +1161,46 @@ declare class JobManager {
|
|
|
1065
1161
|
private prefix;
|
|
1066
1162
|
private activeMaintenanceJobs;
|
|
1067
1163
|
private activeIngestJobs;
|
|
1164
|
+
/**
|
|
1165
|
+
* Per-(entityId, sourceHash) promise-chain lock. Serializes ingest races
|
|
1166
|
+
* at the application level (the v9 partial UNIQUE index enforces it at
|
|
1167
|
+
* the DB level as defense-in-depth). Two callers holding the same hash
|
|
1168
|
+
* see FIFO order; different hashes never block one another.
|
|
1169
|
+
*
|
|
1170
|
+
* Keyed `${entityId}\0${sourceHash}` so distinct (entityId, sourceHash)
|
|
1171
|
+
* pairs can never share a lock. A raw concatenation would let
|
|
1172
|
+
* ("ab", "c…") collide with ("a", "bc…"); the NUL separator makes that
|
|
1173
|
+
* impossible because neither component can contain NUL (entityIds are
|
|
1174
|
+
* user-supplied identifiers; sourceHashes are hex digests).
|
|
1175
|
+
*/
|
|
1176
|
+
private hashLocks;
|
|
1068
1177
|
private statusSubscribers;
|
|
1069
1178
|
constructor(prefix: string);
|
|
1179
|
+
private _hashLockKey;
|
|
1180
|
+
/**
|
|
1181
|
+
* Acquire a promise-chain lock scoped to one `(entityId, sourceHash)` pair.
|
|
1182
|
+
* Returns a zero-argument release closure that removes the current tail
|
|
1183
|
+
* from the chain. Releasing is idempotent so a holder that double-fires
|
|
1184
|
+
* (e.g. on a finally that races an explicit release) cannot unblock
|
|
1185
|
+
* the next holder prematurely.
|
|
1186
|
+
*
|
|
1187
|
+
* Documented ordering: ingest acquires the hash lock FIRST, then the
|
|
1188
|
+
* synchronous sourceRef ingest lock, and the release closure unwinds in
|
|
1189
|
+
* the opposite order (sourceRef first, hash second). Hash-then-sourceRef
|
|
1190
|
+
* is required because the v9 partial UNIQUE index conflicts on the
|
|
1191
|
+
* (entity_id, source_hash) pair regardless of source_ref, so two callers
|
|
1192
|
+
* with DIFFERENT source_refs racing the same hash are the exact case the
|
|
1193
|
+
* TOCTOU race fix needs to serialize.
|
|
1194
|
+
*
|
|
1195
|
+
* Mechanics: each holder owns a private `released` promise that resolves
|
|
1196
|
+
* only when THIS holder calls release(). The map stores the holder's
|
|
1197
|
+
* `released` promise as the "tail" — the NEXT caller awaits that tail
|
|
1198
|
+
* via `previous = this.hashLocks.get(key)`. The current caller gets
|
|
1199
|
+
* their unique release function once `previous` (the prior holder's
|
|
1200
|
+
* release signal) settles, so each holder is guaranteed a UNIQUE release
|
|
1201
|
+
* closure bound to their own `released` promise.
|
|
1202
|
+
*/
|
|
1203
|
+
acquireHashLock(entityId: string, sourceHash: string): Promise<() => void>;
|
|
1070
1204
|
private _pruneKey;
|
|
1071
1205
|
private _reembedKey;
|
|
1072
1206
|
private _globalReembedKey;
|
|
@@ -1103,6 +1237,21 @@ declare class JobManager {
|
|
|
1103
1237
|
* for write() auto-trigger paths while preserving stricter checks in acquireLock().
|
|
1104
1238
|
*/
|
|
1105
1239
|
tryAcquireAutoHealLock(entityId: string): boolean;
|
|
1240
|
+
/**
|
|
1241
|
+
* Centralized ingest lock acquisition. Acquires the hash lock FIRST
|
|
1242
|
+
* (FIFO across callers racing the same hash), then the synchronous
|
|
1243
|
+
* sourceRef ingest lock (rejects cross-entity conflicts and busy
|
|
1244
|
+
* operations). Returns a single zero-argument release closure that
|
|
1245
|
+
* unwinds in the opposite order — sourceRef first, hash second — so
|
|
1246
|
+
* the sourceRef lock is freed the instant its work is done and only
|
|
1247
|
+
* the hash lock keeps serializing the duplicate-content race window.
|
|
1248
|
+
*
|
|
1249
|
+
* On a sourceRef conflict (WikiBusyError thrown synchronously by the
|
|
1250
|
+
* underlying acquireLock) the hash lock is released BEFORE the error
|
|
1251
|
+
* propagates, so the next caller in the hash chain is not held up by
|
|
1252
|
+
* a request that never reached the DB.
|
|
1253
|
+
*/
|
|
1254
|
+
acquireIngestLocks(entityId: string, sourceRef: string, sourceHash: string): Promise<() => void>;
|
|
1106
1255
|
/**
|
|
1107
1256
|
* Validates then acquires global + per-entity import locks atomically.
|
|
1108
1257
|
* Validates all entities before acquiring any lock (same as current importDump semantics).
|
|
@@ -1115,26 +1264,6 @@ declare class JobManager {
|
|
|
1115
1264
|
private _notifyStatusSubscribers;
|
|
1116
1265
|
}
|
|
1117
1266
|
|
|
1118
|
-
declare class EmbeddingService {
|
|
1119
|
-
private db;
|
|
1120
|
-
private options;
|
|
1121
|
-
private entryRepo;
|
|
1122
|
-
private metadataRepo;
|
|
1123
|
-
constructor(db: SQLiteAdapter, options: WikiOptions, entryRepo: EntryRepository, metadataRepo: MetadataRepository);
|
|
1124
|
-
storeEmbeddingDimension(dim: number): Promise<void>;
|
|
1125
|
-
/** Promotes embedding_dimension_mismatch to canonical embedding_dimension when safe. */
|
|
1126
|
-
reconcileEmbeddingDimension(): Promise<void>;
|
|
1127
|
-
embedFact(fact: {
|
|
1128
|
-
id: string;
|
|
1129
|
-
entity_id: string;
|
|
1130
|
-
title: string;
|
|
1131
|
-
body: string;
|
|
1132
|
-
tags: string | string[];
|
|
1133
|
-
}): Promise<boolean>;
|
|
1134
|
-
notifyEmbeddingPersisted(entityId: string, factId: string, vector: Float32Array | null): Promise<void>;
|
|
1135
|
-
notifyEmbeddingPersistedOrThrow(entityId: string, factId: string, vector: Float32Array | null): Promise<void>;
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
1267
|
interface NeighborhoodQueryOptions {
|
|
1139
1268
|
maxDepth: number;
|
|
1140
1269
|
direction: 'inbound' | 'outbound' | 'both';
|
|
@@ -1153,6 +1282,18 @@ declare class EdgeRepository extends BaseRepository {
|
|
|
1153
1282
|
getByEntityId(entityId: string, tx?: SQLiteAdapter): Promise<WikiEdge[]>;
|
|
1154
1283
|
/** Hard delete — edges have no soft-delete concept, only presence/absence. `tx` is REQUIRED. */
|
|
1155
1284
|
bulkDeleteByEntityId(entityId: string, tx: SQLiteAdapter): Promise<void>;
|
|
1285
|
+
/**
|
|
1286
|
+
* Hard-delete every edge whose `source_id` is in `sourceFactIds`, scoped to
|
|
1287
|
+
* `entityId`. Returns the number of rows deleted. Edges have no soft-delete
|
|
1288
|
+
* concept; this method is named `softDeleteBySourceFactIds` for symmetry with
|
|
1289
|
+
* `EntryRepository.softDeleteBySource` (which IS a soft delete), but its
|
|
1290
|
+
* semantics are immediate presence/absence removal. Use ONLY inside an open
|
|
1291
|
+
* transaction — the method requires `tx` and performs no autocommit.
|
|
1292
|
+
*
|
|
1293
|
+
* Used by `IngestionService.upsertGraphCore` to retire the prior parse's
|
|
1294
|
+
* edges whose source facts are being superseded by `softDeleteBySource`.
|
|
1295
|
+
*/
|
|
1296
|
+
softDeleteBySourceFactIds(entityId: string, sourceFactIds: readonly string[], tx: SQLiteAdapter): Promise<number>;
|
|
1156
1297
|
/**
|
|
1157
1298
|
* Multi-hop traversal from `sourceId` via SQLite `WITH RECURSIVE`. All filtering,
|
|
1158
1299
|
* dead-ending, cycle-guarding, capping, and ordering happens in this one query.
|
|
@@ -1165,6 +1306,26 @@ declare class EdgeRepository extends BaseRepository {
|
|
|
1165
1306
|
}>;
|
|
1166
1307
|
}
|
|
1167
1308
|
|
|
1309
|
+
declare class EmbeddingService {
|
|
1310
|
+
private db;
|
|
1311
|
+
private options;
|
|
1312
|
+
private entryRepo;
|
|
1313
|
+
private metadataRepo;
|
|
1314
|
+
constructor(db: SQLiteAdapter, options: WikiOptions, entryRepo: EntryRepository, metadataRepo: MetadataRepository);
|
|
1315
|
+
storeEmbeddingDimension(dim: number): Promise<void>;
|
|
1316
|
+
/** Promotes embedding_dimension_mismatch to canonical embedding_dimension when safe. */
|
|
1317
|
+
reconcileEmbeddingDimension(): Promise<void>;
|
|
1318
|
+
embedFact(fact: {
|
|
1319
|
+
id: string;
|
|
1320
|
+
entity_id: string;
|
|
1321
|
+
title: string;
|
|
1322
|
+
body: string;
|
|
1323
|
+
tags: string | string[];
|
|
1324
|
+
}): Promise<boolean>;
|
|
1325
|
+
notifyEmbeddingPersisted(entityId: string, factId: string, vector: Float32Array | null): Promise<void>;
|
|
1326
|
+
notifyEmbeddingPersistedOrThrow(entityId: string, factId: string, vector: Float32Array | null): Promise<void>;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1168
1329
|
type TitleIndexEntry = {
|
|
1169
1330
|
id: string;
|
|
1170
1331
|
okf_type: string | null;
|
|
@@ -1187,10 +1348,28 @@ declare class OntologyService {
|
|
|
1187
1348
|
}>;
|
|
1188
1349
|
buildPromptContext(entityId: string): Promise<OntologyPromptContext | null>;
|
|
1189
1350
|
mergeEmergentUpdates(entityId: string, updates: OntologyUpdates, tx: SQLiteAdapter): Promise<OntologyManifest>;
|
|
1190
|
-
validateAndNormalizeFact(fact: ExtractedFactWithOntology, manifest: OntologyManifest
|
|
1351
|
+
validateAndNormalizeFact(fact: ExtractedFactWithOntology, manifest: OntologyManifest, opts?: {
|
|
1352
|
+
strict?: boolean;
|
|
1353
|
+
entityId?: string;
|
|
1354
|
+
}): {
|
|
1191
1355
|
okf_type: string | null;
|
|
1192
1356
|
edges: ExtractedFactEdge[];
|
|
1193
1357
|
};
|
|
1358
|
+
/**
|
|
1359
|
+
* Pure resolver: given a source type, LLM-supplied edges, the manifest,
|
|
1360
|
+
* and a title index, return a list of concrete `WikiEdge` objects ready
|
|
1361
|
+
* for persistence. Performs no DB writes. Used by callers that batch edge
|
|
1362
|
+
* writes inside their own transaction (e.g. `IngestionService.ingestDocument`
|
|
1363
|
+
* when delegating to `upsertGraphCore`).
|
|
1364
|
+
*/
|
|
1365
|
+
resolveEdges(entityId: string, sourceId: string, sourceType: string | null, edges: ExtractedFactEdge[], manifest: OntologyManifest, titleIndex: Map<string, TitleIndexEntry>, now: number): WikiEdge[];
|
|
1366
|
+
/**
|
|
1367
|
+
* Backwards-compatible wrapper: resolves edges via {@link resolveEdges},
|
|
1368
|
+
* then persists each via `edgeRepo.addIgnoreDuplicate` in the supplied
|
|
1369
|
+
* transaction. Returns the number of edges persisted. Used by paths that
|
|
1370
|
+
* want self-contained edge persistence (e.g. MaintenanceService heal /
|
|
1371
|
+
* backfill callers that do not have a separate edge-write step).
|
|
1372
|
+
*/
|
|
1194
1373
|
resolveAndPersistEdges(entityId: string, sourceId: string, sourceType: string | null, edges: ExtractedFactEdge[], manifest: OntologyManifest, titleIndex: Map<string, TitleIndexEntry>, tx: SQLiteAdapter, now: number): Promise<number>;
|
|
1195
1374
|
}
|
|
1196
1375
|
|
|
@@ -1224,12 +1403,15 @@ declare class IngestionService {
|
|
|
1224
1403
|
private prefix;
|
|
1225
1404
|
private options;
|
|
1226
1405
|
private entryRepo;
|
|
1406
|
+
private sourceRefIndexRepo;
|
|
1407
|
+
private metadataRepo;
|
|
1408
|
+
private edgeRepo;
|
|
1227
1409
|
private searchService;
|
|
1228
1410
|
private jobManager;
|
|
1229
1411
|
private embeddingService;
|
|
1230
1412
|
private ontologyService?;
|
|
1231
1413
|
private promptService;
|
|
1232
|
-
constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService, ontologyService?: OntologyService | undefined);
|
|
1414
|
+
constructor(db: SQLiteAdapter, prefix: string, options: WikiOptions, entryRepo: EntryRepository, sourceRefIndexRepo: SourceRefIndexRepository, metadataRepo: MetadataRepository, edgeRepo: EdgeRepository, searchService: SearchService, jobManager: JobManager, embeddingService: EmbeddingService, promptService?: PromptService, ontologyService?: OntologyService | undefined);
|
|
1233
1415
|
ingestDocument(entityId: string, params: {
|
|
1234
1416
|
sourceRef: string;
|
|
1235
1417
|
sourceHash: string;
|
|
@@ -1245,6 +1427,49 @@ declare class IngestionService {
|
|
|
1245
1427
|
chunks: number;
|
|
1246
1428
|
duplicateOf?: string;
|
|
1247
1429
|
}>;
|
|
1430
|
+
/**
|
|
1431
|
+
* Implements spec §2 data flow steps a–j with the host-facing
|
|
1432
|
+
* `{sourceRef, sourceHash, nodes, edges}` parameter shape. Shared between
|
|
1433
|
+
* `ingestDocument` (with `{ strict: false }` to preserve current behavior)
|
|
1434
|
+
* and `WikiMemory.upsertGraph` (which lets the persisted ontology mode
|
|
1435
|
+
* decide strictness).
|
|
1436
|
+
*
|
|
1437
|
+
* Runs ENTIRELY inside the supplied `tx`. Does not acquire locks, does not
|
|
1438
|
+
* open a nested transaction, does not perform post-commit work (search
|
|
1439
|
+
* sync, embedding, cache eviction). Those concerns remain in `ingestDocument`.
|
|
1440
|
+
*
|
|
1441
|
+
* The pre-flight validation (steps a–c) lives INSIDE this method per the
|
|
1442
|
+
* spec, so the public `WikiMemory.upsertGraph` can be a thin wrapper that
|
|
1443
|
+
* performs only the C2 probe before delegating.
|
|
1444
|
+
*
|
|
1445
|
+
* @returns Counts: nodesWritten (validated nodes persisted), edgesWritten
|
|
1446
|
+
* (manifest-valid edges persisted), superseded (prior facts soft-deleted
|
|
1447
|
+
* plus prior source-ref edges hard-deleted).
|
|
1448
|
+
*/
|
|
1449
|
+
upsertGraphCore(entityId: string, params: {
|
|
1450
|
+
sourceRef: string;
|
|
1451
|
+
sourceHash: string;
|
|
1452
|
+
nodes: readonly {
|
|
1453
|
+
id: string;
|
|
1454
|
+
type: string;
|
|
1455
|
+
title: string;
|
|
1456
|
+
body?: string;
|
|
1457
|
+
tags?: readonly string[];
|
|
1458
|
+
confidence?: 'certain' | 'inferred' | 'tentative';
|
|
1459
|
+
}[];
|
|
1460
|
+
edges: readonly {
|
|
1461
|
+
type: string;
|
|
1462
|
+
sourceId: string;
|
|
1463
|
+
targetId: string;
|
|
1464
|
+
id?: string;
|
|
1465
|
+
}[];
|
|
1466
|
+
}, tx: SQLiteAdapter, opts?: {
|
|
1467
|
+
strict?: boolean;
|
|
1468
|
+
}): Promise<{
|
|
1469
|
+
nodesWritten: number;
|
|
1470
|
+
edgesWritten: number;
|
|
1471
|
+
superseded: number;
|
|
1472
|
+
}>;
|
|
1248
1473
|
}
|
|
1249
1474
|
|
|
1250
1475
|
declare class TaskRepository extends BaseRepository {
|
|
@@ -1361,6 +1586,7 @@ declare class MaintenanceService {
|
|
|
1361
1586
|
private prefix;
|
|
1362
1587
|
private options;
|
|
1363
1588
|
private entryRepo;
|
|
1589
|
+
private sourceRefIndexRepo;
|
|
1364
1590
|
private taskRepo;
|
|
1365
1591
|
private eventRepo;
|
|
1366
1592
|
private metadataRepo;
|
|
@@ -1369,7 +1595,7 @@ declare class MaintenanceService {
|
|
|
1369
1595
|
private embeddingService;
|
|
1370
1596
|
private ontologyService?;
|
|
1371
1597
|
private promptService;
|
|
1372
|
-
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);
|
|
1598
|
+
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);
|
|
1373
1599
|
runPrune(entityId: string, options?: {
|
|
1374
1600
|
retainSoftDeletedFor?: number | null;
|
|
1375
1601
|
retainEventsFor?: number | null;
|
|
@@ -1582,6 +1808,7 @@ interface WikiMemoryTestAccess {
|
|
|
1582
1808
|
promptService: PromptService;
|
|
1583
1809
|
graphTraversalService: GraphTraversalService;
|
|
1584
1810
|
entryRepo: EntryRepository;
|
|
1811
|
+
sourceRefIndexRepo: SourceRefIndexRepository;
|
|
1585
1812
|
metadataRepo: MetadataRepository;
|
|
1586
1813
|
jobManager: JobManager;
|
|
1587
1814
|
}
|
|
@@ -1592,6 +1819,7 @@ declare class WikiMemory {
|
|
|
1592
1819
|
private options;
|
|
1593
1820
|
private entryRepo;
|
|
1594
1821
|
private outboxRepo;
|
|
1822
|
+
private sourceRefIndexRepo;
|
|
1595
1823
|
private taskRepo;
|
|
1596
1824
|
private eventRepo;
|
|
1597
1825
|
private edgeRepo;
|
|
@@ -1647,12 +1875,43 @@ declare class WikiMemory {
|
|
|
1647
1875
|
lastIngestedAt: number;
|
|
1648
1876
|
}>>;
|
|
1649
1877
|
/**
|
|
1650
|
-
* Returns the live source_refs for an entity that hold the given source_hash
|
|
1651
|
-
*
|
|
1652
|
-
*
|
|
1653
|
-
*
|
|
1878
|
+
* Returns the live source_refs for an entity that hold the given source_hash.
|
|
1879
|
+
* With v9, source_ref_index is the source of truth for the sourceRef-level
|
|
1880
|
+
* TOCTOU-race invariant: at most one sourceRef can hold a given
|
|
1881
|
+
* (entity_id, source_hash). The result is either a single-element array
|
|
1882
|
+
* (one canonical ref) or empty (no live ref holds the hash). Returned as
|
|
1883
|
+
* an array to preserve the existing public-API shape used by hosts
|
|
1884
|
+
* auditing duplicate-content collisions.
|
|
1654
1885
|
*/
|
|
1655
1886
|
findSourceRefsByHash(entityId: string, sourceHash: string): Promise<string[]>;
|
|
1887
|
+
/**
|
|
1888
|
+
* Returns the set of `entity_id` values with at least one row in this
|
|
1889
|
+
* database, INCLUDING entities whose only remaining rows are soft-deleted
|
|
1890
|
+
* — sorted ascending `entity_id COLLATE BINARY`. Empty array when the
|
|
1891
|
+
* database has no entities.
|
|
1892
|
+
*
|
|
1893
|
+
* The deliberate inclusion of soft-deleted-only entities closes the
|
|
1894
|
+
* decommissioned-scope leak: a scoped namespace whose documents have all
|
|
1895
|
+
* been forgotten or superseded must still appear so host maintenance
|
|
1896
|
+
* sweeps (`runLibrarian`, `runHeal`, `runOntologyBackfill`, `runPrune`)
|
|
1897
|
+
* can visit it and reap the soft-deleted rows.
|
|
1898
|
+
*
|
|
1899
|
+
* Read-only. Never acquires a lock. Never opens a transaction. Propagates
|
|
1900
|
+
* underlying read errors.
|
|
1901
|
+
*
|
|
1902
|
+
* @param options.prefix - Optional string filter applied as
|
|
1903
|
+
* `id.startsWith(prefix)`. O(n) over distinct ids because the
|
|
1904
|
+
* `(entity_id, source_ref)` index is not seekable on `entity_id`-only
|
|
1905
|
+
* prefix. Empty-string prefix matches every id.
|
|
1906
|
+
*
|
|
1907
|
+
* Note: this widens the coverage of `exportDump` (which delegates to
|
|
1908
|
+
* `MetadataRepository.getDistinctEntityIds`); exported dumps now include
|
|
1909
|
+
* orphaned entities. This is a deliberate widening for backup/migration
|
|
1910
|
+
* coverage, not a breaking change to `exportDump`'s return shape.
|
|
1911
|
+
*/
|
|
1912
|
+
listEntityIds(options?: {
|
|
1913
|
+
prefix?: string;
|
|
1914
|
+
}): Promise<string[]>;
|
|
1656
1915
|
runPrune(entityId: string, options?: {
|
|
1657
1916
|
retainSoftDeletedFor?: number | null;
|
|
1658
1917
|
retainEventsFor?: number | null;
|
|
@@ -1768,6 +2027,54 @@ declare class WikiMemory {
|
|
|
1768
2027
|
chunks: number;
|
|
1769
2028
|
duplicateOf?: string;
|
|
1770
2029
|
}>;
|
|
2030
|
+
/**
|
|
2031
|
+
* Deterministic write path into the graph. Accepts caller-supplied
|
|
2032
|
+
* `(nodes, edges)` and writes them under `(sourceRef, sourceHash)`
|
|
2033
|
+
* semantics identical to `ingestDocument`, minus the LLM extraction step.
|
|
2034
|
+
*
|
|
2035
|
+
* MUST be called from inside an open `db.withTransactionAsync` callback —
|
|
2036
|
+
* the third argument is the caller's `tx`. The method does not open a
|
|
2037
|
+
* nested transaction, does not acquire any lock, and does not perform
|
|
2038
|
+
* post-commit work (search sync, embedding, cache eviction). Hosts that
|
|
2039
|
+
* want embeddings synced should drive the existing maintenance sweep
|
|
2040
|
+
* (`runLibrarian` / `runHeal` / `runOntologyBackfill` / `runPrune`,
|
|
2041
|
+
* scoped via `listEntityIds`).
|
|
2042
|
+
*
|
|
2043
|
+
* Contract (full pre-flight validation lives inside
|
|
2044
|
+
* `IngestionService.upsertGraphCore`, which this method delegates to):
|
|
2045
|
+
* - C2: no-op when `(entityId, sourceHash)` is already mapped to
|
|
2046
|
+
* `params.sourceRef`; throws `WikiSourceRefHashCollision` if mapped to
|
|
2047
|
+
* a different `sourceRef`.
|
|
2048
|
+
* - C3: edges with dangling `targetId` are stored verbatim (no FK, no
|
|
2049
|
+
* resolution).
|
|
2050
|
+
* - C4: under persisted ontology mode `'strict'`, an out-of-manifest node
|
|
2051
|
+
* or edge `type` throws `WikiStrictOntologyViolation` (pre-flight,
|
|
2052
|
+
* all-or-nothing — NONE written on failure).
|
|
2053
|
+
*
|
|
2054
|
+
* @returns Counts: nodesWritten (validated nodes persisted), edgesWritten
|
|
2055
|
+
* (manifest-valid edges persisted), superseded (prior facts soft-deleted
|
|
2056
|
+
* plus prior source-ref edges hard-deleted).
|
|
2057
|
+
*/
|
|
2058
|
+
upsertGraph(entityId: string, params: {
|
|
2059
|
+
sourceRef: string;
|
|
2060
|
+
sourceHash: string;
|
|
2061
|
+
nodes: readonly {
|
|
2062
|
+
id: string;
|
|
2063
|
+
type: string;
|
|
2064
|
+
title: string;
|
|
2065
|
+
body?: string;
|
|
2066
|
+
}[];
|
|
2067
|
+
edges: readonly {
|
|
2068
|
+
type: string;
|
|
2069
|
+
sourceId: string;
|
|
2070
|
+
targetId: string;
|
|
2071
|
+
id?: string;
|
|
2072
|
+
}[];
|
|
2073
|
+
}, adapter: SQLiteAdapter): Promise<{
|
|
2074
|
+
nodesWritten: number;
|
|
2075
|
+
edgesWritten: number;
|
|
2076
|
+
superseded: number;
|
|
2077
|
+
}>;
|
|
1771
2078
|
/**
|
|
1772
2079
|
* Returns up to `limit` unprocessed outbox events, oldest first.
|
|
1773
2080
|
* Works regardless of enableOutbox value — allows draining after disabling.
|
|
@@ -1796,4 +2103,4 @@ declare class WikiMemory {
|
|
|
1796
2103
|
}): Promise<void>;
|
|
1797
2104
|
}
|
|
1798
2105
|
|
|
1799
|
-
export {
|
|
2106
|
+
export { ImportExportService 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, WikiSourceRefHashCollision as U, type VectorRanker as V, type WikiOptions as W, WikiStrictOntologyViolation as X, type WikiTask as Y, WikiTransactionError as Z, EmbeddingService as _, type MemoryDump as a, IngestionService as a0, JobManager as a1, MaintenanceService as a2, RetrievalService as a3, SearchService as a4, WriteService as a5, 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 };
|
package/dist/testing.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { _ as EmbeddingService, $ as ImportExportService, a0 as IngestionService, a1 as JobManager, a1 as JobManagerType, a2 as MaintenanceService, a3 as RetrievalService, a4 as SearchService, a4 as SearchServiceType, Q as WikiMemoryTestAccess, a5 as WriteService } from './testing-zf3Jp_RL.mjs';
|
|
2
2
|
import 'minisearch';
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { _ as EmbeddingService, $ as ImportExportService, a0 as IngestionService, a1 as JobManager, a1 as JobManagerType, a2 as MaintenanceService, a3 as RetrievalService, a4 as SearchService, a4 as SearchServiceType, Q as WikiMemoryTestAccess, a5 as WriteService } from './testing-zf3Jp_RL.js';
|
|
2
2
|
import 'minisearch';
|