@equationalapplications/core-llm-wiki 7.0.0 → 7.1.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.
@@ -729,6 +729,22 @@ var JobManager = class {
729
729
  _isReembedActive(entityId) {
730
730
  return this.activeMaintenanceJobs.has(this._reembedKey(entityId)) || this.activeMaintenanceJobs.has(this._globalReembedKey());
731
731
  }
732
+ /**
733
+ * True while any reembed sweep is in flight — per-entity or global.
734
+ *
735
+ * Read-only; acquires nothing. Callers that mutate embedding failure
736
+ * markers across ALL entities (the dimension-promotion clear) must gate on
737
+ * this and defer, rather than resurrect rows an in-flight sweep already
738
+ * classified. See spec 2026-09-05-reembed-lock-scope-design.md §2.
739
+ *
740
+ * The global key `${prefix}:reembed` also ends in ':reembed', so the suffix
741
+ * scan alone would already match it. The explicit check is kept because it
742
+ * documents the intent and survives any future change to the global key's
743
+ * format.
744
+ */
745
+ isAnyReembedActive() {
746
+ return this.activeMaintenanceJobs.has(this._globalReembedKey()) || this._isAnyMaintenanceActiveWithSuffix(":reembed");
747
+ }
732
748
  _isImportActiveFor(entityId) {
733
749
  return this.activeMaintenanceJobs.has(this._importKey(entityId)) || this.activeMaintenanceJobs.has(this._globalImportKey());
734
750
  }
@@ -902,10 +918,13 @@ var JobManager = class {
902
918
  }
903
919
  }
904
920
  /**
905
- * Auto-heal historically only gated on the heal self-key. Keep that behavior
906
- * for write() auto-trigger paths while preserving stricter checks in acquireLock().
921
+ * Auto-heal historically only gated on the heal self-key. Keep that
922
+ * permissiveness for write() auto-trigger paths — stricter checks stay in
923
+ * acquireLock() — with one exception: reembed sweeps, which are excluded
924
+ * structurally rather than by accident (see below).
907
925
  */
908
926
  tryAcquireAutoHealLock(entityId) {
927
+ if (this.isAnyReembedActive()) return false;
909
928
  const healKey = this._healKey(entityId);
910
929
  if (this.activeMaintenanceJobs.has(healKey)) return false;
911
930
  this.activeMaintenanceJobs.add(healKey);
@@ -2681,6 +2700,15 @@ var MaintenanceService = class {
2681
2700
  * sets embedding_dimension_mismatch, so promotion never fires and markers
2682
2701
  * survive the swap. Use `runReembed({ force: true })` to clear that state —
2683
2702
  * `force` bypasses classification entirely and retries every row.
2703
+ *
2704
+ * Lock scope (spec 2026-09-05 §2): a marker mutation is legal while a sweep
2705
+ * is in flight if and only if it cannot resurrect a row the sweep has
2706
+ * classified. Mutations scoped to entities not under an active sweep key are
2707
+ * legal — the entity-scoped ingest/import lock checks enforce that. The one
2708
+ * mutation that spans every entity, `reconcileEmbeddingDimension`'s marker
2709
+ * clear, is made legal by DEFERRING (importDump gates on
2710
+ * `JobManager.isAnyReembedActive()`), never by widening a lock. Auto-heal is
2711
+ * excluded from sweeps for the same reason.
2684
2712
  */
2685
2713
  async runReembed(entityId, opts) {
2686
2714
  const embedFn = this.options.llmProvider.embed;
@@ -3828,7 +3856,13 @@ var ImportExportService = class {
3828
3856
  this.db
3829
3857
  );
3830
3858
  }
3831
- await this.embeddingService.reconcileEmbeddingDimension();
3859
+ if (this.jobManager.isAnyReembedActive()) {
3860
+ console.info(
3861
+ "[WikiMemory] importDump: embedding-dimension promotion deferred; a reembed sweep is in flight"
3862
+ );
3863
+ } else {
3864
+ await this.embeddingService.reconcileEmbeddingDimension();
3865
+ }
3832
3866
  } else {
3833
3867
  await this.metadataRepo.setMeta(
3834
3868
  "embedding_dimension_mismatch",
@@ -3935,6 +3969,19 @@ var EmbeddingService = class {
3935
3969
  * Revived rows are NOT embedded here. They become eligible and are picked up
3936
3970
  * by the NEXT sweep, because runReembed calls this after its candidates were
3937
3971
  * already classified; same-sweep revival would be re-entrant.
3972
+ *
3973
+ * Caller contract (spec 2026-09-05 §3.2): callers must not invoke this while
3974
+ * a reembed sweep is in flight unless they hold that sweep's lock, because
3975
+ * the marker clear spans every entity. `runReembed`'s tail call is exempt —
3976
+ * by the tail, the sweep's classification phase is complete, so the clear
3977
+ * cannot resurrect a row THIS sweep classified; any overlap with a
3978
+ * concurrent import's entity-scoped, blob-guarded writes (an importDump of a
3979
+ * different entity can run during a per-entity sweep) is bounded redundant
3980
+ * work. External callers
3981
+ * gate on `JobManager.isAnyReembedActive()` and defer. This service
3982
+ * deliberately holds no `JobManager` reference: gating here instead of at
3983
+ * the call site would make `runReembed`'s own tail call see its own lock and
3984
+ * defer forever.
3938
3985
  */
3939
3986
  async reconcileEmbeddingDimension() {
3940
3987
  const mismatchValue = await this.metadataRepo.getMeta("embedding_dimension_mismatch");
@@ -4867,5 +4914,5 @@ var WriteService = class {
4867
4914
  };
4868
4915
 
4869
4916
  export { BaseRepository, DEFAULT_CHUNK_OVERLAP, DEFAULT_MAX_CHUNK_LENGTH, DEFAULT_MAX_EMBED_CHARS, EMBED_CHARS_CEILING, EmbeddingService, HEAL_ANCHORS_PER_CANDIDATE, HEAL_BATCH_SIZE, HEAL_MAX_FACT_BODY_CHARS_L3, HEAL_MAX_TASKS, HEAL_RECHECK_MS, HOOK_TIMEOUT_MARKER, ImportExportService, IngestionService, JobManager, MaintenanceService, MetadataRepository, ONTOLOGY_BACKFILL_BATCH_SIZE, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, ONTOLOGY_BACKFILL_RECHECK_MS, ONTOLOGY_BACKFILL_SYSTEM_PROMPT, PromptService, PrunePartialFailureError, RetrievalService, SearchService, WikiBusyError, WikiDuplicateHashError, WikiIngestEmptyError, WikiInvalidReadOptions, WikiParseError, WikiSourceRefHashCollision, WikiStrictOntologyViolation, WikiTransactionError, WriteService, __privateAdd, __privateGet, __privateSet, chunkText, configureRandomSource, emptyManifest, entitySummaryMetaKey, extractSqliteCode, generateId, normalizeSourceHash, normalizeSourceRef, normalizeTitleKey, parseEmbedding, resolveEdgeDefinitions, resolveNodeType, safeSlice, typeSatisfies, validateInlineEdges, validateManifest };
4870
- //# sourceMappingURL=chunk-YNFYSLR6.mjs.map
4871
- //# sourceMappingURL=chunk-YNFYSLR6.mjs.map
4917
+ //# sourceMappingURL=chunk-ZU7K6NAU.mjs.map
4918
+ //# sourceMappingURL=chunk-ZU7K6NAU.mjs.map