@equationalapplications/core-llm-wiki 7.1.2 → 7.1.3

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/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, O as OntologyManifest, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-CA7723qk.mjs';
2
- export { C as ChunkFailure, D as DegradedRecord, E as EmbedFactResult, d as EmbedFailureKind, e as EmbeddingMarkerKind, f as EntityStatus, g as ExtractedFact, h as ExtractedFactEdge, i as ExtractedFactWithOntology, j as ExtractedTask, k as GraphTraversalOptions, H as HEAL_BATCH_SIZE, l as HEAL_RECHECK_MS, m as HOOK_TIMEOUT_MARKER, n as HealResult, I as IngestDocumentResult, L as LLMProvider, o as ONTOLOGY_BACKFILL_BATCH_SIZE, p as ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, q as ONTOLOGY_BACKFILL_RECHECK_MS, r as OntologyBackfillResult, s as OntologyConfig, t as OntologyEdgeType, u as OntologyMode, v as OntologyNodeType, w as OntologyPromptContext, x as OntologyUpdates, P as PromptOverrides, y as PromptService, z as PrunePartialFailureError, A as ReembedResult, V as VectorRanker, B as VectorRankerFallback, J as VectorRankerRankArgs, K as VectorRankerSemanticResult, N as WikiBusyError, Q as WikiBusyOperation, T as WikiCheckpoint, U as WikiConfig, X as WikiDuplicateHashError, Y as WikiEdge, Z as WikiEvent, _ as WikiFact, $ as WikiIngestEmptyError, a0 as WikiInvalidReadOptions, a1 as WikiMemoryTestAccess, a2 as WikiOutboxEvent, a3 as WikiParseError, a4 as WikiSourceRefHashCollision, a5 as WikiStrictOntologyViolation, a6 as WikiTask, a7 as WikiTransactionError } from './testing-CA7723qk.mjs';
1
+ import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, O as OntologyManifest, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-DYeMd9d1.mjs';
2
+ export { C as ChunkFailure, D as DegradedRecord, E as EmbedFactResult, d as EmbedFailureKind, e as EmbeddingMarkerKind, f as EntityStatus, g as ExtractedFact, h as ExtractedFactEdge, i as ExtractedFactWithOntology, j as ExtractedTask, k as GraphTraversalOptions, H as HEAL_BATCH_SIZE, l as HEAL_RECHECK_MS, m as HOOK_TIMEOUT_MARKER, n as HealResult, I as IngestDocumentResult, L as LLMProvider, o as ONTOLOGY_BACKFILL_BATCH_SIZE, p as ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, q as ONTOLOGY_BACKFILL_RECHECK_MS, r as OntologyBackfillResult, s as OntologyConfig, t as OntologyEdgeType, u as OntologyMode, v as OntologyNodeType, w as OntologyPromptContext, x as OntologyUpdates, P as PromptOverrides, y as PromptService, z as PrunePartialFailureError, A as ReembedResult, V as VectorRanker, B as VectorRankerFallback, J as VectorRankerRankArgs, K as VectorRankerSemanticResult, N as WikiBusyError, Q as WikiBusyOperation, T as WikiCheckpoint, U as WikiConfig, X as WikiDuplicateHashError, Y as WikiEdge, Z as WikiEvent, _ as WikiFact, $ as WikiGraphNodeOwnershipConflict, a0 as WikiIngestEmptyError, a1 as WikiInvalidReadOptions, a2 as WikiMemoryTestAccess, a3 as WikiOutboxEvent, a4 as WikiParseError, a5 as WikiSourceRefHashCollision, a6 as WikiStrictOntologyViolation, a7 as WikiTask, a8 as WikiTransactionError } from './testing-DYeMd9d1.mjs';
3
3
  import { OkfFile } from '@equationalapplications/core-okf';
4
4
  import 'minisearch';
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, O as OntologyManifest, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-CA7723qk.js';
2
- export { C as ChunkFailure, D as DegradedRecord, E as EmbedFactResult, d as EmbedFailureKind, e as EmbeddingMarkerKind, f as EntityStatus, g as ExtractedFact, h as ExtractedFactEdge, i as ExtractedFactWithOntology, j as ExtractedTask, k as GraphTraversalOptions, H as HEAL_BATCH_SIZE, l as HEAL_RECHECK_MS, m as HOOK_TIMEOUT_MARKER, n as HealResult, I as IngestDocumentResult, L as LLMProvider, o as ONTOLOGY_BACKFILL_BATCH_SIZE, p as ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, q as ONTOLOGY_BACKFILL_RECHECK_MS, r as OntologyBackfillResult, s as OntologyConfig, t as OntologyEdgeType, u as OntologyMode, v as OntologyNodeType, w as OntologyPromptContext, x as OntologyUpdates, P as PromptOverrides, y as PromptService, z as PrunePartialFailureError, A as ReembedResult, V as VectorRanker, B as VectorRankerFallback, J as VectorRankerRankArgs, K as VectorRankerSemanticResult, N as WikiBusyError, Q as WikiBusyOperation, T as WikiCheckpoint, U as WikiConfig, X as WikiDuplicateHashError, Y as WikiEdge, Z as WikiEvent, _ as WikiFact, $ as WikiIngestEmptyError, a0 as WikiInvalidReadOptions, a1 as WikiMemoryTestAccess, a2 as WikiOutboxEvent, a3 as WikiParseError, a4 as WikiSourceRefHashCollision, a5 as WikiStrictOntologyViolation, a6 as WikiTask, a7 as WikiTransactionError } from './testing-CA7723qk.js';
1
+ import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, O as OntologyManifest, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-DYeMd9d1.js';
2
+ export { C as ChunkFailure, D as DegradedRecord, E as EmbedFactResult, d as EmbedFailureKind, e as EmbeddingMarkerKind, f as EntityStatus, g as ExtractedFact, h as ExtractedFactEdge, i as ExtractedFactWithOntology, j as ExtractedTask, k as GraphTraversalOptions, H as HEAL_BATCH_SIZE, l as HEAL_RECHECK_MS, m as HOOK_TIMEOUT_MARKER, n as HealResult, I as IngestDocumentResult, L as LLMProvider, o as ONTOLOGY_BACKFILL_BATCH_SIZE, p as ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, q as ONTOLOGY_BACKFILL_RECHECK_MS, r as OntologyBackfillResult, s as OntologyConfig, t as OntologyEdgeType, u as OntologyMode, v as OntologyNodeType, w as OntologyPromptContext, x as OntologyUpdates, P as PromptOverrides, y as PromptService, z as PrunePartialFailureError, A as ReembedResult, V as VectorRanker, B as VectorRankerFallback, J as VectorRankerRankArgs, K as VectorRankerSemanticResult, N as WikiBusyError, Q as WikiBusyOperation, T as WikiCheckpoint, U as WikiConfig, X as WikiDuplicateHashError, Y as WikiEdge, Z as WikiEvent, _ as WikiFact, $ as WikiGraphNodeOwnershipConflict, a0 as WikiIngestEmptyError, a1 as WikiInvalidReadOptions, a2 as WikiMemoryTestAccess, a3 as WikiOutboxEvent, a4 as WikiParseError, a5 as WikiSourceRefHashCollision, a6 as WikiStrictOntologyViolation, a7 as WikiTask, a8 as WikiTransactionError } from './testing-DYeMd9d1.js';
3
3
  import { OkfFile } from '@equationalapplications/core-okf';
4
4
  import 'minisearch';
5
5
 
package/dist/index.js CHANGED
@@ -270,6 +270,21 @@ var WikiSourceRefHashCollision = class extends Error {
270
270
  this.name = "WikiSourceRefHashCollision";
271
271
  }
272
272
  };
273
+ var WikiGraphNodeOwnershipConflict = class extends Error {
274
+ /**
275
+ * Privacy-preserving constructor: accepts no arguments, so neither the foreign
276
+ * owner, the conflicting node ID, the stored content, nor any provenance can
277
+ * leak through this error. The fixed message and `code` are the entire signal.
278
+ *
279
+ * @returns a contextless `WikiGraphNodeOwnershipConflict` instance. See the
280
+ * class-level JSDoc for the privacy rationale.
281
+ */
282
+ constructor() {
283
+ super("Graph write rejected because a node ID is unavailable for this entity.");
284
+ this.code = "WIKI_GRAPH_NODE_OWNERSHIP_CONFLICT";
285
+ this.name = "WikiGraphNodeOwnershipConflict";
286
+ }
287
+ };
273
288
  var WikiTransactionError = class extends Error {
274
289
  constructor(message, options) {
275
290
  super(message, options);
@@ -764,6 +779,26 @@ var EntryRepository = class extends BaseRepository {
764
779
  * diagnostic that inflates runReembed's permanentlyFailed counter. A conflict
765
780
  * with no blob leaves marker state alone, matching the "absent means don't
766
781
  * touch" semantics used for embedding_blob itself.
782
+ *
783
+ * Graph node ownership (spec §2.4 + §3, REQ-OWN-01 + REQ-GRAPH-01): entry
784
+ * IDs share one database-wide namespace, so an ID stays owned by its
785
+ * existing entity for as long as the row exists — soft deletion included.
786
+ * The pre-write lookup already reads the existing row for OKF metadata; we
787
+ * project `entity_id` off that same SELECT and reject the write before
788
+ * any outbox payload construction when the stored owner differs from
789
+ * `fact.entity_id`. Soft-deleted foreign rows keep their IDs reserved;
790
+ * permanent reservation is NOT introduced, so a physically absent ID may
791
+ * still be inserted under the requested entity. The ON CONFLICT UPDATE SET
792
+ * clause carries a final `WHERE entries.entity_id = excluded.entity_id`
793
+ * guard so the database itself refuses a cross-owner row overwrite even if
794
+ * a future caller bypasses the pre-write check. When `runAsync` reports
795
+ * 0 changes (a legitimate conflict-suppressed write, OR an adapter that
796
+ * under-reports a permitted write) we re-read the stored owner; only a
797
+ * foreign owner throws — this is local defensive behavior, not permission
798
+ * for adapters to under-report. The thrown error is
799
+ * `WikiGraphNodeOwnershipConflict` (no owner, node ID, or stored content
800
+ * is disclosed). Upserts that pass both gates retain existing same-entity
801
+ * update + resurrection semantics.
767
802
  */
768
803
  async upsert(fact, tx) {
769
804
  const executor = this.getExecutor(tx);
@@ -771,12 +806,15 @@ var EntryRepository = class extends BaseRepository {
771
806
  const tagsJson = JSON.stringify(fact.tags);
772
807
  const embeddingBlob = this.normalizeEmbeddingBlob(fact.embedding_blob);
773
808
  const existingRow = await executor.getFirstAsync(
774
- `SELECT id, lifecycle_status, stale_after, generated_by,
809
+ `SELECT id, entity_id, lifecycle_status, stale_after, generated_by,
775
810
  okf_sources, okf_verified, okf_usage_window,
776
811
  last_verified_at, last_verified_by
777
812
  FROM ${this.prefix}entries WHERE id = ?`,
778
813
  [fact.id]
779
814
  );
815
+ if (existingRow && existingRow.entity_id !== fact.entity_id) {
816
+ throw new WikiGraphNodeOwnershipConflict();
817
+ }
780
818
  const operation = fact.deleted_at ? "DELETE" : existingRow ? "UPDATE" : "INSERT";
781
819
  const result = await executor.runAsync(
782
820
  `INSERT INTO ${this.prefix}entries (
@@ -787,7 +825,6 @@ var EntryRepository = class extends BaseRepository {
787
825
  okf_sources, okf_verified, okf_usage_window
788
826
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
789
827
  ON CONFLICT(id) DO UPDATE SET
790
- entity_id = excluded.entity_id,
791
828
  title = excluded.title,
792
829
  body = excluded.body,
793
830
  tags = excluded.tags,
@@ -804,7 +841,8 @@ var EntryRepository = class extends BaseRepository {
804
841
  embedding_failed_at = CASE WHEN excluded.embedding_blob IS NOT NULL THEN NULL ELSE embedding_failed_at END,
805
842
  embedding_failure_kind = CASE WHEN excluded.embedding_blob IS NOT NULL THEN NULL ELSE embedding_failure_kind END,
806
843
  embedding_attempts = CASE WHEN excluded.embedding_blob IS NOT NULL THEN 0 ELSE embedding_attempts END,
807
- okf_type = excluded.okf_type`,
844
+ okf_type = excluded.okf_type
845
+ WHERE ${this.prefix}entries.entity_id = excluded.entity_id`,
808
846
  [
809
847
  fact.id,
810
848
  fact.entity_id,
@@ -836,6 +874,18 @@ var EntryRepository = class extends BaseRepository {
836
874
  fact.okf_usage_window ? JSON.stringify(fact.okf_usage_window) : null
837
875
  ]
838
876
  );
877
+ if (result.changes === 0) {
878
+ const stored = await tx.getFirstAsync(
879
+ `SELECT entity_id FROM ${this.prefix}entries WHERE id = ?`,
880
+ [fact.id]
881
+ );
882
+ if (!stored) {
883
+ throw new Error("Entry upsert reported no change and stored no row; the SQLiteAdapter did not perform the write");
884
+ }
885
+ if (stored.entity_id !== fact.entity_id) {
886
+ throw new WikiGraphNodeOwnershipConflict();
887
+ }
888
+ }
839
889
  const persistedOkf = existingRow ? {
840
890
  lifecycle_status: existingRow.lifecycle_status ?? "stable",
841
891
  stale_after: existingRow.stale_after != null ? Number(existingRow.stale_after) : null,
@@ -4510,6 +4560,36 @@ var IngestionService = class {
4510
4560
  releaseIngestLocks();
4511
4561
  }
4512
4562
  }
4563
+ /**
4564
+ * Reject the whole write when any incoming node ID is already owned by a
4565
+ * different entity. Runs entirely inside the supplied `tx`, through the
4566
+ * repository abstraction, and — being the first thing `upsertGraphCore`
4567
+ * does — before ontology resolution, which can itself persist a configured
4568
+ * seed manifest.
4569
+ *
4570
+ * The lookup has no deleted-row filter, so a soft-deleted foreign row keeps
4571
+ * its ID reserved. Only the lookup IDs are deduplicated; `params.nodes` and
4572
+ * the later write loops keep their ordering and counts.
4573
+ *
4574
+ * The error is deliberately contextless — see WikiGraphNodeOwnershipConflict.
4575
+ *
4576
+ * @param entityId - the entity the caller is writing on behalf of. Foreign
4577
+ * rows under a different entity trigger the rejection.
4578
+ * @param nodes - incoming node set; only the IDs are inspected, so callers
4579
+ * may pass the public `params.nodes` shape directly without slicing.
4580
+ * @param tx - the open transaction. Reuses the same handle every later
4581
+ * statement in `upsertGraphCore` runs against, so atomicity is enforced
4582
+ * by the host transaction's commit/rollback, not by this method.
4583
+ */
4584
+ async assertGraphNodeOwnership(entityId, nodes, tx) {
4585
+ const ids = [...new Set(nodes.map((node) => node.id))];
4586
+ const existing = await this.entryRepo.findExistingMetadataByIds(ids, tx);
4587
+ for (const row of existing) {
4588
+ if (row.entity_id !== entityId) {
4589
+ throw new WikiGraphNodeOwnershipConflict();
4590
+ }
4591
+ }
4592
+ }
4513
4593
  /**
4514
4594
  * Implements spec §2 data flow steps a–j with the host-facing
4515
4595
  * `{sourceRef, sourceHash, nodes, edges}` parameter shape. Shared between
@@ -4528,8 +4608,19 @@ var IngestionService = class {
4528
4608
  * @returns Counts: nodesWritten (validated nodes persisted), edgesWritten
4529
4609
  * (manifest-valid edges persisted), superseded (prior facts soft-deleted
4530
4610
  * plus prior source-ref edges hard-deleted).
4611
+ *
4612
+ * Node-ownership pre-flight (spec §3, REQ-GRAPH-01): the first statement
4613
+ * is `assertGraphNodeOwnership(entityId, params.nodes, tx)`, which runs
4614
+ * before ontology resolution, seed-manifest persistence, and every other
4615
+ * write. A foreign-owned ID throws `WikiGraphNodeOwnershipConflict` with
4616
+ * no disclosed owner, node ID, or content; the caller's transaction
4617
+ * remains open and must be rolled back by the host. Soft-deleted foreign
4618
+ * rows keep their IDs reserved. Duplicate incoming IDs are deduplicated
4619
+ * only for the lookup; `params.nodes` and the write loops keep their
4620
+ * ordering and counts so success counts match the pre-change contract.
4531
4621
  */
4532
4622
  async upsertGraphCore(entityId, params, tx, opts) {
4623
+ await this.assertGraphNodeOwnership(entityId, params.nodes, tx);
4533
4624
  const now = Date.now();
4534
4625
  const ontologyState = await this.ontologyService?.getEffectiveState(entityId, tx) ?? { mode: "off", manifest: { node_types: [], edge_types: [] } };
4535
4626
  let { mode, manifest } = ontologyState;
@@ -7975,6 +8066,11 @@ var WikiMemory = class {
7975
8066
  return this.maintenanceService.forget(entityId, params, opts);
7976
8067
  }
7977
8068
  /**
8069
+ * Full and partial ingestion both reject foreign-owned generated fact IDs with
8070
+ * `WikiGraphNodeOwnershipConflict`. Such collisions are unexpected. Ingestion
8071
+ * may already have persisted ontology or other state before rejection; unlike
8072
+ * direct graph preflight, it relies on transaction rollback for atomicity.
8073
+ *
7978
8074
  * @param params.promptOverride - Overrides the system prompt for this ingest call only.
7979
8075
  * For persistent customization, set `options.config.prompts.ingestSystemPrompt` at
7980
8076
  * WikiMemory construction time.
@@ -8006,6 +8102,19 @@ var WikiMemory = class {
8006
8102
  * or edge `type` throws `WikiStrictOntologyViolation` (pre-flight,
8007
8103
  * all-or-nothing — NONE written on failure).
8008
8104
  *
8105
+ * Entry IDs share one database-wide namespace. Existing rows, including
8106
+ * soft-deleted rows, reserve their IDs for their entity; same-entity updates
8107
+ * and resurrection remain supported. Hosts authenticate callers and select
8108
+ * the authorized entity ID; entity-qualified IDs are optional, not required.
8109
+ * After the live-only C2 probe above, a foreign node ID throws the fixed,
8110
+ * privacy-preserving `WikiGraphNodeOwnershipConflict` before persistent writes
8111
+ * (including seed manifests). Deleted source mappings do not trigger C2.
8112
+ *
8113
+ * Propagate later failures to roll back the host transaction. In particular,
8114
+ * foreign edge-ID collisions remain late bare `Error`s: the foreign edge is
8115
+ * not overwritten, but catching and committing can retain earlier writes.
8116
+ * This method neither commits nor rolls back the caller's transaction.
8117
+ *
8009
8118
  * @returns Counts: nodesWritten (validated nodes persisted), edgesWritten
8010
8119
  * (manifest-valid edges persisted), superseded (prior facts soft-deleted
8011
8120
  * plus prior source-ref edges hard-deleted).
@@ -9100,6 +9209,7 @@ exports.PromptService = PromptService;
9100
9209
  exports.PrunePartialFailureError = PrunePartialFailureError;
9101
9210
  exports.WikiBusyError = WikiBusyError;
9102
9211
  exports.WikiDuplicateHashError = WikiDuplicateHashError;
9212
+ exports.WikiGraphNodeOwnershipConflict = WikiGraphNodeOwnershipConflict;
9103
9213
  exports.WikiIngestEmptyError = WikiIngestEmptyError;
9104
9214
  exports.WikiInvalidReadOptions = WikiInvalidReadOptions;
9105
9215
  exports.WikiMemory = WikiMemory;