@remnic/core 9.63.4 → 9.63.6
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/access-admin-ops-surface.d.ts +11 -11
- package/dist/access-admin-ops-surface.js +23 -23
- package/dist/access-authorization-probe.d.ts +11 -11
- package/dist/access-authorization-probe.js +24 -24
- package/dist/access-boundary.d.ts +11 -11
- package/dist/access-boundary.js +23 -23
- package/dist/access-cli.js +55 -55
- package/dist/access-coding-context-resolution.d.ts +1 -1
- package/dist/access-extraction-force-flush.d.ts +11 -11
- package/dist/access-extraction-force-flush.js +23 -23
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +11 -11
- package/dist/access-http-lifecycle-flush.d.ts +11 -11
- package/dist/access-http-offline-stream.d.ts +11 -11
- package/dist/access-http-query.d.ts +2 -2
- package/dist/access-http-query.js +25 -25
- package/dist/access-http.d.ts +12 -12
- package/dist/access-http.js +34 -34
- package/dist/access-identity-continuity-surface.d.ts +9 -9
- package/dist/access-identity-continuity-surface.js +23 -23
- package/dist/access-lcm-surface.d.ts +11 -11
- package/dist/access-lcm-surface.js +23 -23
- package/dist/access-mcp.d.ts +11 -11
- package/dist/access-mcp.js +28 -28
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-yO4LMGFH.d.ts → access-namespace-preflight-DB0zXFek.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +23 -23
- package/dist/access-observe-write-surface.d.ts +11 -11
- package/dist/access-observe-write-surface.js +23 -23
- package/dist/access-offline-manifest.d.ts +9 -9
- package/dist/access-offline-manifest.js +3 -3
- package/dist/access-operations-batch.js +24 -24
- package/dist/access-operations.d.ts +11 -11
- package/dist/access-operations.js +27 -27
- package/dist/access-recall-concurrency.d.ts +11 -11
- package/dist/access-recall-concurrency.js +23 -23
- package/dist/access-recall-response.d.ts +11 -11
- package/dist/access-recall-response.js +23 -23
- package/dist/access-recall-surface.d.ts +11 -11
- package/dist/access-recall-surface.js +23 -23
- package/dist/{access-service-D-bi3r01.d.ts → access-service-cKQrte9Z.d.ts} +7 -7
- package/dist/access-service-helpers.d.ts +11 -11
- package/dist/access-service.d.ts +11 -11
- package/dist/access-service.js +23 -23
- package/dist/access-surface-catalog.d.ts +11 -11
- package/dist/access-surface-catalog.js +25 -25
- package/dist/access-wearables-meetings-surface.d.ts +3 -3
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.d.ts +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +9 -9
- package/dist/briefing-window.d.ts +2 -2
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +11 -11
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/buffer.js +4 -4
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{capsule-merge-HCJJMLPS.js → capsule-merge-SGIVB3WA.js} +5 -5
- package/dist/{catalog-BYIHQw1l.d.ts → catalog-CCzmf8IH.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +12 -12
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-XFCQIQQU.js → chunk-2UM6WHME.js} +3 -3
- package/dist/{chunk-CKWOMJDY.js → chunk-3Z5TGRFA.js} +8 -8
- package/dist/{chunk-JJX5XEIG.js → chunk-77QZW2D6.js} +4 -4
- package/dist/{chunk-X4MGNVOO.js → chunk-7AF243WZ.js} +1 -1
- package/dist/{chunk-2ASAS3CQ.js → chunk-7KQB4EBS.js} +2 -2
- package/dist/{chunk-3LJ2L3T3.js → chunk-7LF2OHIJ.js} +2 -2
- package/dist/{chunk-VAMQU4W7.js → chunk-AYVCKGA6.js} +2 -2
- package/dist/{chunk-GTRGH4ZT.js → chunk-BB2LH5JM.js} +2 -2
- package/dist/{chunk-XMMESCPD.js → chunk-C64XATK7.js} +17 -27
- package/dist/chunk-C64XATK7.js.map +1 -0
- package/dist/{chunk-DQV3LUQL.js → chunk-CUDSA46O.js} +2 -2
- package/dist/{chunk-PADG72LJ.js → chunk-DXDAQZ2K.js} +2 -2
- package/dist/{chunk-EJCN5ATI.js → chunk-DYZR3Z6D.js} +3 -3
- package/dist/{chunk-VN7IIQGS.js → chunk-E4KMY4KR.js} +2 -2
- package/dist/{chunk-ZQKXRKMR.js → chunk-EFKZT6AY.js} +2 -2
- package/dist/{chunk-DNRTKO2U.js → chunk-EJY3HJMT.js} +2 -2
- package/dist/{chunk-4EDAHS6D.js → chunk-ERPBRXVZ.js} +2 -2
- package/dist/{chunk-ZUZD2DRV.js → chunk-F6JYBVL6.js} +27 -57
- package/dist/{chunk-ZUZD2DRV.js.map → chunk-F6JYBVL6.js.map} +1 -1
- package/dist/{chunk-JWPG65LH.js → chunk-FHKXVTM5.js} +38 -39
- package/dist/chunk-FHKXVTM5.js.map +1 -0
- package/dist/{chunk-RPKJHYVE.js → chunk-FPEZ74F7.js} +2 -2
- package/dist/{chunk-Z334TJRB.js → chunk-GF7RQWXC.js} +2 -2
- package/dist/{chunk-6D7PZKCJ.js → chunk-GG4DN63W.js} +2 -2
- package/dist/{chunk-OR7KEGLR.js → chunk-GTD4Q62X.js} +2 -6
- package/dist/{chunk-QOMUE4FS.js → chunk-I5FLIB2J.js} +2 -2
- package/dist/{chunk-2JL7WPXL.js → chunk-IVXVLDNT.js} +12 -12
- package/dist/{chunk-NRFU5MVH.js → chunk-JOEJG4SD.js} +47 -1
- package/dist/chunk-JOEJG4SD.js.map +1 -0
- package/dist/{chunk-EJLTNPRY.js → chunk-KHCUVYCY.js} +3 -3
- package/dist/{chunk-QSIQVC32.js → chunk-KYTRF64R.js} +2 -2
- package/dist/{chunk-LNFYISZ6.js → chunk-LX4TNSAE.js} +4 -4
- package/dist/{chunk-H6ZXNH5I.js → chunk-MUJ4QFUQ.js} +3 -3
- package/dist/{chunk-JSH2TV34.js → chunk-NA56NSKL.js} +2 -2
- package/dist/{chunk-DFEYRCG2.js → chunk-NKB43PGI.js} +2 -2
- package/dist/{chunk-DLQQU4EG.js → chunk-NS5ETDYD.js} +2 -2
- package/dist/{chunk-VG6DC2GO.js → chunk-OETHJBAL.js} +53 -45
- package/dist/{chunk-VG6DC2GO.js.map → chunk-OETHJBAL.js.map} +1 -1
- package/dist/{chunk-BXOZALJ6.js → chunk-PB4WVYGC.js} +2 -2
- package/dist/{chunk-Q35XGIEM.js → chunk-PBRCYYO7.js} +2 -2
- package/dist/{chunk-QYN5PXDZ.js → chunk-PMVPCZJZ.js} +4 -4
- package/dist/{chunk-3USQWITL.js → chunk-QI5RDDEL.js} +3 -3
- package/dist/{chunk-I6OQCT3Y.js → chunk-QRWMS6SI.js} +2 -2
- package/dist/{chunk-ITYAXU4S.js → chunk-R6UMNP5C.js} +3 -3
- package/dist/{chunk-5W62VEFH.js → chunk-RWMSMTQP.js} +2 -2
- package/dist/{chunk-FKJVEW6O.js → chunk-SYVGVK4S.js} +2 -2
- package/dist/{chunk-GNKY5JEP.js → chunk-TSTI6A3A.js} +8 -8
- package/dist/{chunk-ISFUFLFM.js → chunk-UCLMKNHA.js} +2 -2
- package/dist/{chunk-ZMSZVISA.js → chunk-UFKPQBXH.js} +3 -3
- package/dist/{chunk-B2OOJCUX.js → chunk-UGHCZS6K.js} +2 -2
- package/dist/{chunk-RSLRGRBJ.js → chunk-V3KIRICY.js} +3 -3
- package/dist/{chunk-MRJ43KSG.js → chunk-VPHSMJ2E.js} +2 -2
- package/dist/{chunk-E2GYBTSP.js → chunk-VYEPACWY.js} +2 -2
- package/dist/{chunk-A4HXWNST.js → chunk-X7LEDA74.js} +2 -2
- package/dist/{chunk-KMAP7SNQ.js → chunk-XCB6QDL6.js} +2 -2
- package/dist/{chunk-WDUG2CH3.js → chunk-YEQCMA5L.js} +2 -2
- package/dist/{chunk-LZCSOUJ7.js → chunk-YFCEBB5P.js} +2 -2
- package/dist/{chunk-IKXUG6KC.js → chunk-YXMHUBN2.js} +2 -2
- package/dist/{chunk-GFNS3BHV.js → chunk-ZUPKNWRZ.js} +3 -3
- package/dist/{chunk-GSTIBXBW.js → chunk-ZVPVTPGI.js} +2 -2
- package/dist/{cli-DEoABKXH.d.ts → cli-BFBDYV0D.d.ts} +5 -5
- package/dist/cli.d.ts +13 -13
- package/dist/cli.js +45 -45
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +11 -11
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +11 -11
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +11 -11
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-provenance-check.js +5 -5
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/consolidation-undo.js +4 -4
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +13 -13
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +13 -13
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.d.ts +1 -1
- package/dist/{dependency-propagation-delivery-BxhvAppj.d.ts → dependency-propagation-delivery-DiY5T63p.d.ts} +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-origin-fields.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +11 -11
- package/dist/entity-schema.d.ts +1 -1
- package/dist/episodic-context.d.ts +1 -1
- package/dist/explicit-capture.d.ts +9 -9
- package/dist/explicit-capture.js +5 -5
- package/dist/external-wiki-access.d.ts +11 -11
- package/dist/external-wiki-access.js +24 -24
- package/dist/external-wiki-collection-registration.d.ts +1 -1
- package/dist/external-wiki-collection.d.ts +1 -1
- package/dist/external-wiki-mcp-tools.d.ts +11 -11
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction-liveness.d.ts +1 -1
- package/dist/extraction-normalization.d.ts +1 -1
- package/dist/extraction-prompt.d.ts +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +14 -14
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-path-reconstruction.d.ts +1 -1
- package/dist/graph-path-scoring.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/index.d.ts +21 -21
- package/dist/index.js +55 -55
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +11 -11
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +11 -11
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +12 -12
- package/dist/{maintenance-N5ur13Al.d.ts → maintenance-CaqA4z7V.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +11 -11
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-cache.js +1 -1
- package/dist/memory-corpus-version.js +2 -2
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-snapshot.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +12 -12
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +4 -4
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +11 -11
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +14 -14
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +20 -20
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +17 -17
- package/dist/{orchestrator-ByLrpav4.d.ts → orchestrator-CSc9GfQv.d.ts} +8 -8
- package/dist/orchestrator.d.ts +9 -9
- package/dist/orchestrator.js +55 -55
- package/dist/page-versioning.js +4 -4
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-BdF3ferY.d.ts → pipeline-X606GdRJ.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{public-http-DusietP2.d.ts → public-http-8PcrDIYi.d.ts} +1 -1
- package/dist/{qmd-CBSxevyb.d.ts → qmd-DCKeR-GX.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/qmd.js +2 -2
- package/dist/recall-concurrency-config.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-memory-map.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/reconcile/cursor.d.ts +1 -1
- package/dist/reconcile/manifest.d.ts +1 -1
- package/dist/reconcile/manifest.js +2 -2
- package/dist/reconcile/plan.d.ts +1 -1
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/salvage-envelope.d.ts +1 -1
- package/dist/{scope-profiles-CeMv7pP0.d.ts → scope-profiles-_Y_RHCeE.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +3 -3
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +3 -3
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-B-85brYj.d.ts → semantic-consolidation-DT2VSrU0.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +12 -12
- package/dist/semantic-rule-promotion.js +11 -11
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +11 -11
- package/dist/{service-CoO0HA2E.d.ts → service-BMo-gwDE.d.ts} +3 -3
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +13 -13
- package/dist/{storage-BVAVitkO.d.ts → storage-CGzJGUUu.d.ts} +49 -24
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +10 -10
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/support-passport/index.d.ts +14 -14
- package/dist/support-passport/index.js +26 -26
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/capsule-import.js +5 -5
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-DWHOxlZP.d.ts → types-CBEAYU76.d.ts} +112 -128
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +11 -11
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +2 -2
- package/src/chat/chat-cli.test.ts +53 -0
- package/src/chat/chat-cli.ts +22 -58
- package/src/dedup/index.test.ts +65 -1
- package/src/dedup/index.ts +24 -2
- package/src/meetings/build.test.ts +20 -4
- package/src/meetings/build.ts +2 -2
- package/src/meetings/day-source.test.ts +3 -1
- package/src/meetings/day-source.ts +1 -12
- package/src/meetings/fuse.test.ts +64 -15
- package/src/meetings/fuse.ts +18 -12
- package/src/meetings/types.ts +4 -19
- package/src/memory-cache-derived.test.ts +90 -0
- package/src/memory-cache.ts +40 -42
- package/src/storage/content-hash-index.ts +54 -0
- package/src/storage-contract/content-hash.test.ts +59 -1
- package/src/storage-fact-hash-index-defer.test.ts +9 -9
- package/src/storage.ts +39 -40
- package/dist/chunk-JWPG65LH.js.map +0 -1
- package/dist/chunk-NRFU5MVH.js.map +0 -1
- package/dist/chunk-XMMESCPD.js.map +0 -1
- /package/dist/{capsule-merge-HCJJMLPS.js.map → capsule-merge-SGIVB3WA.js.map} +0 -0
- /package/dist/{chunk-XFCQIQQU.js.map → chunk-2UM6WHME.js.map} +0 -0
- /package/dist/{chunk-CKWOMJDY.js.map → chunk-3Z5TGRFA.js.map} +0 -0
- /package/dist/{chunk-JJX5XEIG.js.map → chunk-77QZW2D6.js.map} +0 -0
- /package/dist/{chunk-X4MGNVOO.js.map → chunk-7AF243WZ.js.map} +0 -0
- /package/dist/{chunk-2ASAS3CQ.js.map → chunk-7KQB4EBS.js.map} +0 -0
- /package/dist/{chunk-3LJ2L3T3.js.map → chunk-7LF2OHIJ.js.map} +0 -0
- /package/dist/{chunk-VAMQU4W7.js.map → chunk-AYVCKGA6.js.map} +0 -0
- /package/dist/{chunk-GTRGH4ZT.js.map → chunk-BB2LH5JM.js.map} +0 -0
- /package/dist/{chunk-DQV3LUQL.js.map → chunk-CUDSA46O.js.map} +0 -0
- /package/dist/{chunk-PADG72LJ.js.map → chunk-DXDAQZ2K.js.map} +0 -0
- /package/dist/{chunk-EJCN5ATI.js.map → chunk-DYZR3Z6D.js.map} +0 -0
- /package/dist/{chunk-VN7IIQGS.js.map → chunk-E4KMY4KR.js.map} +0 -0
- /package/dist/{chunk-ZQKXRKMR.js.map → chunk-EFKZT6AY.js.map} +0 -0
- /package/dist/{chunk-DNRTKO2U.js.map → chunk-EJY3HJMT.js.map} +0 -0
- /package/dist/{chunk-4EDAHS6D.js.map → chunk-ERPBRXVZ.js.map} +0 -0
- /package/dist/{chunk-RPKJHYVE.js.map → chunk-FPEZ74F7.js.map} +0 -0
- /package/dist/{chunk-Z334TJRB.js.map → chunk-GF7RQWXC.js.map} +0 -0
- /package/dist/{chunk-6D7PZKCJ.js.map → chunk-GG4DN63W.js.map} +0 -0
- /package/dist/{chunk-OR7KEGLR.js.map → chunk-GTD4Q62X.js.map} +0 -0
- /package/dist/{chunk-QOMUE4FS.js.map → chunk-I5FLIB2J.js.map} +0 -0
- /package/dist/{chunk-2JL7WPXL.js.map → chunk-IVXVLDNT.js.map} +0 -0
- /package/dist/{chunk-EJLTNPRY.js.map → chunk-KHCUVYCY.js.map} +0 -0
- /package/dist/{chunk-QSIQVC32.js.map → chunk-KYTRF64R.js.map} +0 -0
- /package/dist/{chunk-LNFYISZ6.js.map → chunk-LX4TNSAE.js.map} +0 -0
- /package/dist/{chunk-H6ZXNH5I.js.map → chunk-MUJ4QFUQ.js.map} +0 -0
- /package/dist/{chunk-JSH2TV34.js.map → chunk-NA56NSKL.js.map} +0 -0
- /package/dist/{chunk-DFEYRCG2.js.map → chunk-NKB43PGI.js.map} +0 -0
- /package/dist/{chunk-DLQQU4EG.js.map → chunk-NS5ETDYD.js.map} +0 -0
- /package/dist/{chunk-BXOZALJ6.js.map → chunk-PB4WVYGC.js.map} +0 -0
- /package/dist/{chunk-Q35XGIEM.js.map → chunk-PBRCYYO7.js.map} +0 -0
- /package/dist/{chunk-QYN5PXDZ.js.map → chunk-PMVPCZJZ.js.map} +0 -0
- /package/dist/{chunk-3USQWITL.js.map → chunk-QI5RDDEL.js.map} +0 -0
- /package/dist/{chunk-I6OQCT3Y.js.map → chunk-QRWMS6SI.js.map} +0 -0
- /package/dist/{chunk-ITYAXU4S.js.map → chunk-R6UMNP5C.js.map} +0 -0
- /package/dist/{chunk-5W62VEFH.js.map → chunk-RWMSMTQP.js.map} +0 -0
- /package/dist/{chunk-FKJVEW6O.js.map → chunk-SYVGVK4S.js.map} +0 -0
- /package/dist/{chunk-GNKY5JEP.js.map → chunk-TSTI6A3A.js.map} +0 -0
- /package/dist/{chunk-ISFUFLFM.js.map → chunk-UCLMKNHA.js.map} +0 -0
- /package/dist/{chunk-ZMSZVISA.js.map → chunk-UFKPQBXH.js.map} +0 -0
- /package/dist/{chunk-B2OOJCUX.js.map → chunk-UGHCZS6K.js.map} +0 -0
- /package/dist/{chunk-RSLRGRBJ.js.map → chunk-V3KIRICY.js.map} +0 -0
- /package/dist/{chunk-MRJ43KSG.js.map → chunk-VPHSMJ2E.js.map} +0 -0
- /package/dist/{chunk-E2GYBTSP.js.map → chunk-VYEPACWY.js.map} +0 -0
- /package/dist/{chunk-A4HXWNST.js.map → chunk-X7LEDA74.js.map} +0 -0
- /package/dist/{chunk-KMAP7SNQ.js.map → chunk-XCB6QDL6.js.map} +0 -0
- /package/dist/{chunk-WDUG2CH3.js.map → chunk-YEQCMA5L.js.map} +0 -0
- /package/dist/{chunk-LZCSOUJ7.js.map → chunk-YFCEBB5P.js.map} +0 -0
- /package/dist/{chunk-IKXUG6KC.js.map → chunk-YXMHUBN2.js.map} +0 -0
- /package/dist/{chunk-GFNS3BHV.js.map → chunk-ZUPKNWRZ.js.map} +0 -0
- /package/dist/{chunk-GSTIBXBW.js.map → chunk-ZVPVTPGI.js.map} +0 -0
package/src/memory-cache.ts
CHANGED
|
@@ -33,26 +33,41 @@ function sweepExpiredHotEntries(now: number): void {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Shared read gate for every versioned cache layer (issue #2481): serve an
|
|
38
|
+
* entry only when its version and secure-store keyId match the caller.
|
|
39
|
+
* `currentVersion === 0` means version tracking is unavailable (tests, fresh
|
|
40
|
+
* installs) and always misses so disk is read. The TTL is a safety net for
|
|
41
|
+
* external filesystem edits that bypass the version sentinel (issue #1902):
|
|
42
|
+
* ttlMs <= 0 disables it, and on expiry the entry is evicted — not just
|
|
43
|
+
* skipped — so a stale dir releases its resident corpus instead of lingering
|
|
44
|
+
* until an explicit clear.
|
|
45
|
+
*/
|
|
46
|
+
function getVersionedCacheEntry<K, E extends { version: number; keyId: string; loadedAt: number }>(
|
|
47
|
+
cache: Map<K, E>,
|
|
48
|
+
key: K,
|
|
38
49
|
currentVersion: number,
|
|
39
|
-
keyId
|
|
40
|
-
ttlMs
|
|
41
|
-
):
|
|
42
|
-
// Don't serve from cache when version tracking is unavailable (version=0).
|
|
43
|
-
// This ensures tests and fresh installs without a version file always read disk.
|
|
50
|
+
keyId: string,
|
|
51
|
+
ttlMs: number,
|
|
52
|
+
): E | null {
|
|
44
53
|
if (currentVersion === 0) return null;
|
|
45
|
-
const entry =
|
|
54
|
+
const entry = cache.get(key);
|
|
46
55
|
if (!entry || entry.version !== currentVersion || entry.keyId !== keyId) return null;
|
|
47
|
-
// TTL safety net (issue #1902): bound staleness from external filesystem edits
|
|
48
|
-
// that bypass the version sentinel. ttlMs <= 0 disables the check. On expiry
|
|
49
|
-
// evict the entry (not just return null) so a revisited-but-stale dir releases
|
|
50
|
-
// its resident corpus instead of lingering until an explicit clear.
|
|
51
56
|
if (ttlMs > 0 && Date.now() - entry.loadedAt > ttlMs) {
|
|
52
|
-
|
|
57
|
+
cache.delete(key);
|
|
53
58
|
return null;
|
|
54
59
|
}
|
|
55
|
-
return
|
|
60
|
+
return entry;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function getCachedMemories(
|
|
64
|
+
baseDir: string,
|
|
65
|
+
currentVersion: number,
|
|
66
|
+
keyId = "",
|
|
67
|
+
ttlMs = 0,
|
|
68
|
+
): MemoryFile[] | null {
|
|
69
|
+
const entry = getVersionedCacheEntry(hotCacheByDir, baseDir, currentVersion, keyId, ttlMs);
|
|
70
|
+
return entry ? [...entry.memories.values()] : null;
|
|
56
71
|
}
|
|
57
72
|
|
|
58
73
|
export function setCachedMemories(
|
|
@@ -89,10 +104,10 @@ export function getCachedArchivedMemories(
|
|
|
89
104
|
currentVersion: number,
|
|
90
105
|
keyId = "",
|
|
91
106
|
): MemoryFile[] | null {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return [...entry.memories.values()];
|
|
107
|
+
// ttlMs 0: the archive cache has no age TTL; it is version-keyed and cleared
|
|
108
|
+
// via invalidation.
|
|
109
|
+
const entry = getVersionedCacheEntry(archiveCacheByDir, baseDir, currentVersion, keyId, 0);
|
|
110
|
+
return entry ? [...entry.memories.values()] : null;
|
|
96
111
|
}
|
|
97
112
|
|
|
98
113
|
export function setCachedArchivedMemories(
|
|
@@ -165,7 +180,7 @@ export function invalidateCachedEntities(baseDir: string): void {
|
|
|
165
180
|
// These avoid O(146K) filter+map on every verified recall/rules call.
|
|
166
181
|
interface DerivedCacheEntry<T> {
|
|
167
182
|
data: T;
|
|
168
|
-
|
|
183
|
+
version: number; // matches the hot cache version it was derived from
|
|
169
184
|
keyId: string; // secure-store key identity of the corpus it was derived from (#1902)
|
|
170
185
|
loadedAt: number; // build time — bounds staleness from external edits via ttlMs (#1902)
|
|
171
186
|
}
|
|
@@ -179,17 +194,8 @@ export function getCachedEpisodeMap(
|
|
|
179
194
|
keyId = "",
|
|
180
195
|
ttlMs = 0,
|
|
181
196
|
): Map<string, MemoryFile> | null {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (!entry || entry.sourceVersion !== currentVersion || entry.keyId !== keyId) return null;
|
|
185
|
-
// TTL safety net (issue #1902): the version sentinel doesn't move on a direct
|
|
186
|
-
// external edit, so bound how long a derived view is served before a rebuild
|
|
187
|
-
// (which re-reads via readAllMemories, itself TTL-bounded). ttlMs <= 0 disables.
|
|
188
|
-
if (ttlMs > 0 && Date.now() - entry.loadedAt > ttlMs) {
|
|
189
|
-
episodeMapByDir.delete(baseDir);
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
return entry.data;
|
|
197
|
+
const entry = getVersionedCacheEntry(episodeMapByDir, baseDir, currentVersion, keyId, ttlMs);
|
|
198
|
+
return entry ? entry.data : null;
|
|
193
199
|
}
|
|
194
200
|
|
|
195
201
|
/** Build and cache the episode memory map from the full memory list. */
|
|
@@ -206,7 +212,7 @@ export function setCachedEpisodeMap(
|
|
|
206
212
|
if (m.frontmatter.memoryKind !== "episode") continue;
|
|
207
213
|
map.set(m.frontmatter.id, m);
|
|
208
214
|
}
|
|
209
|
-
if (cache) episodeMapByDir.set(baseDir, { data: map,
|
|
215
|
+
if (cache) episodeMapByDir.set(baseDir, { data: map, version, keyId, loadedAt: Date.now() });
|
|
210
216
|
return map;
|
|
211
217
|
}
|
|
212
218
|
|
|
@@ -217,16 +223,8 @@ export function getCachedRuleMemories(
|
|
|
217
223
|
keyId = "",
|
|
218
224
|
ttlMs = 0,
|
|
219
225
|
): { all: MemoryFile[]; byId: Map<string, MemoryFile> } | null {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (!entry || entry.sourceVersion !== currentVersion || entry.keyId !== keyId) return null;
|
|
223
|
-
// TTL safety net (issue #1902): bound staleness from direct external edits
|
|
224
|
-
// that don't move the version sentinel. ttlMs <= 0 disables.
|
|
225
|
-
if (ttlMs > 0 && Date.now() - entry.loadedAt > ttlMs) {
|
|
226
|
-
ruleMemoriesByDir.delete(baseDir);
|
|
227
|
-
return null;
|
|
228
|
-
}
|
|
229
|
-
return entry.data;
|
|
226
|
+
const entry = getVersionedCacheEntry(ruleMemoriesByDir, baseDir, currentVersion, keyId, ttlMs);
|
|
227
|
+
return entry ? entry.data : null;
|
|
230
228
|
}
|
|
231
229
|
|
|
232
230
|
/** Build and cache the rule memories from the full memory list. */
|
|
@@ -250,7 +248,7 @@ export function setCachedRuleMemories(
|
|
|
250
248
|
}
|
|
251
249
|
}
|
|
252
250
|
const result = { all, byId };
|
|
253
|
-
if (cache) ruleMemoriesByDir.set(baseDir, { data: result,
|
|
251
|
+
if (cache) ruleMemoriesByDir.set(baseDir, { data: result, version, keyId, loadedAt: Date.now() });
|
|
254
252
|
return result;
|
|
255
253
|
}
|
|
256
254
|
|
|
@@ -110,6 +110,20 @@ export interface ContentHashPathEntry {
|
|
|
110
110
|
*/
|
|
111
111
|
export class ContentHashIndex {
|
|
112
112
|
private hashes: Set<string> = new Set();
|
|
113
|
+
/**
|
|
114
|
+
* Fact-ONLY hash partition (issue #2474). `hashes` above is category-blind
|
|
115
|
+
* (every write category registers there); this subset carries only
|
|
116
|
+
* `category === "fact"` hashes so fact-only membership checks
|
|
117
|
+
* (`hasFact*`) can never be satisfied by an unrelated decision/preference
|
|
118
|
+
* sharing the same normalized body. In-memory only — never serialized to
|
|
119
|
+
* fact-hashes.txt; `clear()` drops it and every authoritative rebuild
|
|
120
|
+
* repopulates it via `addFactByHash`. Subset invariant: `factHashes ⊆
|
|
121
|
+
* hashes` — `addFact*` registers in both, and the removal sites that drop
|
|
122
|
+
* a shared hash also drop the partition entry (removal stays caller-paired
|
|
123
|
+
* because shared-index removal is category-blind: archiving a non-fact
|
|
124
|
+
* must not evict an active fact's fact-only membership).
|
|
125
|
+
*/
|
|
126
|
+
private factHashes: Set<string> = new Set();
|
|
113
127
|
private dirty = false;
|
|
114
128
|
/** True when load() found the pre-Unicode, markerless on-disk format. */
|
|
115
129
|
private formatMigrationRequired = false;
|
|
@@ -290,6 +304,9 @@ export class ContentHashIndex {
|
|
|
290
304
|
if (this.hashes.size > 0) {
|
|
291
305
|
this.hashes.clear();
|
|
292
306
|
}
|
|
307
|
+
// The fact-only partition is rebuilt with the shared set on every
|
|
308
|
+
// authoritative corpus rebuild, so it clears here too (issue #2474).
|
|
309
|
+
this.factHashes.clear();
|
|
293
310
|
// A full clear is always paired with a plain overwrite save() (rebuild);
|
|
294
311
|
// pending per-hash add/remove deltas are subsumed by writing the rebuilt set.
|
|
295
312
|
// Cancel any armed deferred-reconcile retry (PR #2016) so it cannot fire in
|
|
@@ -693,6 +710,43 @@ export class ContentHashIndex {
|
|
|
693
710
|
this.dirty = true;
|
|
694
711
|
}
|
|
695
712
|
|
|
713
|
+
// ── Fact-only partition (issue #2474) ─────────────────────────────────
|
|
714
|
+
// Folded here from StorageManager's parallel `factOnlyHashes` set, which had
|
|
715
|
+
// to be kept in lockstep by hand on every add/remove/rebuild site. The
|
|
716
|
+
// partition lives on the index instance, so every path that mutates the
|
|
717
|
+
// shared set and needs fact-only truth mutates it in the same breath.
|
|
718
|
+
|
|
719
|
+
/** Register fact content in BOTH the shared index and the fact-only partition. */
|
|
720
|
+
addFact(content: string): void {
|
|
721
|
+
this.addFactByHash(ContentHashIndex.computeHash(content));
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/** Register a pre-computed fact hash in both the shared index and the fact-only partition. */
|
|
725
|
+
addFactByHash(hash: string): void {
|
|
726
|
+
this.addByHash(hash);
|
|
727
|
+
this.factHashes.add(hash);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/** Fact-ONLY membership: has this content been registered as a fact? */
|
|
731
|
+
hasFact(content: string): boolean {
|
|
732
|
+
return this.factHashes.has(ContentHashIndex.computeHash(content));
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/** Fact-ONLY membership for a pre-computed SHA-256 hash. */
|
|
736
|
+
hasFactByHash(hash: string): boolean {
|
|
737
|
+
return this.factHashes.has(hash);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Drop fact-only partition membership WITHOUT touching the shared index.
|
|
742
|
+
* The shared removal stays caller-owned: a shared hash is dropped only when
|
|
743
|
+
* no other active memory holds it, while fact-only membership follows the
|
|
744
|
+
* fact's own lifecycle (supersede/archive/promotion).
|
|
745
|
+
*/
|
|
746
|
+
removeFactByHash(hash: string): void {
|
|
747
|
+
this.factHashes.delete(hash);
|
|
748
|
+
}
|
|
749
|
+
|
|
696
750
|
/**
|
|
697
751
|
* Resolve a pre-computed semantic hash to one deterministic corpus path.
|
|
698
752
|
*
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import assert from "node:assert/strict";
|
|
12
12
|
import test from "node:test";
|
|
13
13
|
|
|
14
|
-
import { ContentHashIndex } from "../storage.js";
|
|
14
|
+
import { ContentHashIndex, StorageManager } from "../storage.js";
|
|
15
15
|
import { makeStorage } from "./harness.js";
|
|
16
16
|
|
|
17
17
|
test("content-hash: ContentHashIndex.computeHash is deterministic for the same input", () => {
|
|
@@ -158,3 +158,61 @@ test("content-hash: the frontmatter contentHash matches computeHash of the raw c
|
|
|
158
158
|
await cleanup();
|
|
159
159
|
}
|
|
160
160
|
});
|
|
161
|
+
|
|
162
|
+
test("content-hash: fact-only membership across write, supersede, and rebuild — no stale true (#2474)", async () => {
|
|
163
|
+
const { storage, baseDir, cleanup } = await makeStorage();
|
|
164
|
+
try {
|
|
165
|
+
const supersededBody = "the staging region retires on friday";
|
|
166
|
+
const activeBody = "the production region stays";
|
|
167
|
+
|
|
168
|
+
// Write: both facts register fact-only membership on the shared index.
|
|
169
|
+
await storage.writeMemory("fact", supersededBody);
|
|
170
|
+
await storage.writeMemory("fact", activeBody);
|
|
171
|
+
assert.equal(
|
|
172
|
+
await storage.hasFactContentHash(supersededBody),
|
|
173
|
+
true,
|
|
174
|
+
"write registers the fact-only hash",
|
|
175
|
+
);
|
|
176
|
+
assert.equal(await storage.hasFactContentHash(activeBody), true);
|
|
177
|
+
|
|
178
|
+
// Supersede: the frontmatter rewrite runs syncFactHashIndexAfterRewrite →
|
|
179
|
+
// removeFactContentHashesForMemories, which must drop BOTH the shared hash
|
|
180
|
+
// and the fact-only partition. A stale partition entry is the PR #2016
|
|
181
|
+
// stale-true bug class: wearable / explicit-capture / promotion callers
|
|
182
|
+
// would skip a valid re-write.
|
|
183
|
+
const mem = (await storage.readAllMemories()).find((m) =>
|
|
184
|
+
(m.content ?? "").includes(supersededBody),
|
|
185
|
+
);
|
|
186
|
+
assert.ok(mem, "the fact to supersede must exist");
|
|
187
|
+
const ok = await storage.writeMemoryFrontmatter(mem!, { status: "superseded" });
|
|
188
|
+
assert.equal(ok, true, "frontmatter rewrite must succeed");
|
|
189
|
+
assert.equal(
|
|
190
|
+
await storage.hasFactContentHash(supersededBody),
|
|
191
|
+
false,
|
|
192
|
+
"no stale hasFactContentHash true after supersede",
|
|
193
|
+
);
|
|
194
|
+
assert.equal(
|
|
195
|
+
await storage.hasFactContentHash(activeBody),
|
|
196
|
+
true,
|
|
197
|
+
"the untouched fact keeps its fact-only membership",
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
// Rebuild: a fresh instance repopulates the index from the corpus. The
|
|
201
|
+
// superseded fact must stay out of the fact-only partition; the active
|
|
202
|
+
// fact must survive.
|
|
203
|
+
const reopened = new StorageManager(baseDir);
|
|
204
|
+
await reopened.ensureDirectories();
|
|
205
|
+
assert.equal(
|
|
206
|
+
await reopened.hasFactContentHash(supersededBody),
|
|
207
|
+
false,
|
|
208
|
+
"superseded fact stays out of fact-only membership after rebuild",
|
|
209
|
+
);
|
|
210
|
+
assert.equal(
|
|
211
|
+
await reopened.hasFactContentHash(activeBody),
|
|
212
|
+
true,
|
|
213
|
+
"active fact survives the rebuild",
|
|
214
|
+
);
|
|
215
|
+
} finally {
|
|
216
|
+
await cleanup();
|
|
217
|
+
}
|
|
218
|
+
});
|
|
@@ -308,10 +308,10 @@ test("direct writeMemory('fact') without the flag persists the hash via the LOCK
|
|
|
308
308
|
});
|
|
309
309
|
|
|
310
310
|
test("#2016 thread SDzOT: a fact hash added during the authoritative rebuild's corpus scan is not lost", async () => {
|
|
311
|
-
// The rebuild used to build a fresh
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
//
|
|
311
|
+
// The rebuild used to build a fresh fact-only set and publish it with a
|
|
312
|
+
// reassignment, dropping any concurrent in-process writeMemory that added to
|
|
313
|
+
// the LIVE membership during the readAllMemories / readAllColdMemories
|
|
314
|
+
// awaits. The fact-only partition on ContentHashIndex repopulates in place
|
|
315
315
|
// (clear + add), so a concurrent add survives publication — exactly as the
|
|
316
316
|
// shared index preserves concurrent adds by mutating its `hashes` set in place.
|
|
317
317
|
await withMemoryDir(async (dir) => {
|
|
@@ -320,7 +320,7 @@ test("#2016 thread SDzOT: a fact hash added during the authoritative rebuild's c
|
|
|
320
320
|
await storage.writeMemory("fact", "alpha established fact", { source: "extraction" });
|
|
321
321
|
|
|
322
322
|
const s = storage as unknown as {
|
|
323
|
-
|
|
323
|
+
factHashIndex: ContentHashIndex | null;
|
|
324
324
|
factHashIndexAuthoritative: boolean | null;
|
|
325
325
|
readAllColdMemories: () => Promise<unknown[]>;
|
|
326
326
|
ensureFactHashIndexAuthoritative: () => Promise<boolean>;
|
|
@@ -329,13 +329,13 @@ test("#2016 thread SDzOT: a fact hash added during the authoritative rebuild's c
|
|
|
329
329
|
const realCold = s.readAllColdMemories.bind(storage);
|
|
330
330
|
let injected = false;
|
|
331
331
|
// Interpose on the SECOND corpus await inside the rebuild (after clear()):
|
|
332
|
-
// simulate a concurrent writeMemory adding a fact hash to the live
|
|
333
|
-
// the rebuild is mid-scan.
|
|
332
|
+
// simulate a concurrent writeMemory adding a fact hash to the live
|
|
333
|
+
// partition while the rebuild is mid-scan.
|
|
334
334
|
s.readAllColdMemories = async () => {
|
|
335
335
|
const res = await realCold();
|
|
336
336
|
if (!injected) {
|
|
337
337
|
injected = true;
|
|
338
|
-
s.
|
|
338
|
+
s.factHashIndex?.addFactByHash(sentinel);
|
|
339
339
|
}
|
|
340
340
|
return res;
|
|
341
341
|
};
|
|
@@ -345,7 +345,7 @@ test("#2016 thread SDzOT: a fact hash added during the authoritative rebuild's c
|
|
|
345
345
|
assert.equal(await s.ensureFactHashIndexAuthoritative(), true, "rebuild published");
|
|
346
346
|
|
|
347
347
|
assert.equal(
|
|
348
|
-
s.
|
|
348
|
+
s.factHashIndex?.hasFactByHash(sentinel),
|
|
349
349
|
true,
|
|
350
350
|
"a fact hash added during the rebuild scan must survive publication (lost under reassign)"
|
|
351
351
|
);
|
package/src/storage.ts
CHANGED
|
@@ -1867,19 +1867,15 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
1867
1867
|
private factHashIndexAuthoritative: boolean | null = null;
|
|
1868
1868
|
private factHashIndexAuthoritativePromise: Promise<boolean> | null = null;
|
|
1869
1869
|
/**
|
|
1870
|
-
* Fact-ONLY hash membership (PR #2016)
|
|
1871
|
-
*
|
|
1872
|
-
*
|
|
1873
|
-
*
|
|
1874
|
-
* `hasFactContentHash`, so an over-included non-fact body can never
|
|
1875
|
-
* real fact candidate.
|
|
1876
|
-
*
|
|
1877
|
-
* (`
|
|
1878
|
-
* (`removeFactContentHashesForMemories`), AND the orchestrator's archival /
|
|
1879
|
-
* consolidation removal (`removeContentHashForMemory` ->
|
|
1880
|
-
* `removeFactOnlyHashForMemory`). In-memory only; never persisted.
|
|
1870
|
+
* Fact-ONLY hash membership (PR #2016 / issue #2474) lives on the shared
|
|
1871
|
+
* `ContentHashIndex` fact-only partition (`addFact*` / `hasFact*` /
|
|
1872
|
+
* `removeFactByHash`), not a parallel set here. The partition carries only
|
|
1873
|
+
* `category === "fact"` hashes and is the sole source for
|
|
1874
|
+
* `hasFactContentHash`, so an over-included non-fact body can never
|
|
1875
|
+
* suppress a real fact candidate. In-memory only; never persisted — every
|
|
1876
|
+
* authoritative corpus rebuild repopulates it via
|
|
1877
|
+
* `ContentHashIndex.clear()` + `addFactByHash`.
|
|
1881
1878
|
*/
|
|
1882
|
-
private factOnlyHashes: Set<string> = new Set();
|
|
1883
1879
|
/** Optional lock/retry tuning for the fact-hash index cross-process lock (PR #2016; tests inject tight budgets). */
|
|
1884
1880
|
factHashIndexLockOptions: ContentHashIndexLockOptions = {};
|
|
1885
1881
|
private readonly secureAppendChains = new Map<string, Promise<void>>();
|
|
@@ -3328,15 +3324,14 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3328
3324
|
*/
|
|
3329
3325
|
private async rebuildFactHashIndexFromCorpus(factHashIndex: ContentHashIndex): Promise<void> {
|
|
3330
3326
|
factHashIndex.clear();
|
|
3331
|
-
// Fact-ONLY membership rebuilt in lockstep (PR #2016):
|
|
3332
|
-
// reads
|
|
3333
|
-
// over-included non-fact body can
|
|
3334
|
-
//
|
|
3335
|
-
//
|
|
3336
|
-
//
|
|
3337
|
-
//
|
|
3338
|
-
// by mutating its `hashes` set in place.
|
|
3339
|
-
this.factOnlyHashes.clear();
|
|
3327
|
+
// Fact-ONLY membership is rebuilt in lockstep (PR #2016 / issue #2474):
|
|
3328
|
+
// hasFactContentHash reads the index's fact-only partition, never the
|
|
3329
|
+
// category-agnostic shared set, so an over-included non-fact body can
|
|
3330
|
+
// never satisfy a fact-hash check. `factHashIndex.clear()` above cleared
|
|
3331
|
+
// the partition too, and it repopulates in place below — a concurrent
|
|
3332
|
+
// in-process writeMemory that adds a fact hash during the corpus-read
|
|
3333
|
+
// awaits survives publication (PR #2016 thread SDzOT), exactly as the
|
|
3334
|
+
// shared index preserves by mutating its `hashes` set in place.
|
|
3340
3335
|
// #1909 review round 14: index the HOT and COLD tiers together. A fact or
|
|
3341
3336
|
// procedure demoted to cold/ is still active and its content-hash must
|
|
3342
3337
|
// survive the corpus rebuild, or a restart would drop the hash and let the
|
|
@@ -3371,8 +3366,11 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3371
3366
|
continue;
|
|
3372
3367
|
}
|
|
3373
3368
|
for (const hash of hashes) {
|
|
3374
|
-
|
|
3375
|
-
|
|
3369
|
+
if (memory.frontmatter.category === "fact") {
|
|
3370
|
+
factHashIndex.addFactByHash(hash);
|
|
3371
|
+
} else {
|
|
3372
|
+
factHashIndex.addByHash(hash);
|
|
3373
|
+
}
|
|
3376
3374
|
}
|
|
3377
3375
|
}
|
|
3378
3376
|
if (legacyRecovered > 0) {
|
|
@@ -3896,8 +3894,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3896
3894
|
options.contentHashSource !== undefined && options.contentHashSource.length > 0
|
|
3897
3895
|
? sanitizeMemoryContent(options.contentHashSource).text
|
|
3898
3896
|
: sanitized.text;
|
|
3899
|
-
factHashIndex.
|
|
3900
|
-
this.factOnlyHashes.add(ContentHashIndex.computeHash(hashText));
|
|
3897
|
+
factHashIndex.addFact(hashText);
|
|
3901
3898
|
// Gate only the flush (issue #1909): the `.add(...)` above already set
|
|
3902
3899
|
// dirty=true. When the caller defers, it owns the batch save
|
|
3903
3900
|
// (extraction persist -> saveContentHashIndexes()). Single-write callers
|
|
@@ -3973,7 +3970,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3973
3970
|
// upkeep); otherwise the snapshot may be stale, so verify against the durable
|
|
3974
3971
|
// fact corpus (ground truth) so a lock-contended read never suppresses a fact.
|
|
3975
3972
|
if (authoritative) {
|
|
3976
|
-
|
|
3973
|
+
const factHashIndex = await this.getFactHashIndex();
|
|
3974
|
+
return factHashIndex.hasFact(sanitized.text);
|
|
3977
3975
|
}
|
|
3978
3976
|
return await this.factContentHashPresentInCorpus(hash);
|
|
3979
3977
|
}
|
|
@@ -4002,8 +4000,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4002
4000
|
await this.ensureFactHashIndexAuthoritative();
|
|
4003
4001
|
const factHashIndex = await this.getFactHashIndex();
|
|
4004
4002
|
for (const hash of hashes) {
|
|
4005
|
-
factHashIndex.
|
|
4006
|
-
this.factOnlyHashes.add(hash);
|
|
4003
|
+
factHashIndex.addFactByHash(hash);
|
|
4007
4004
|
}
|
|
4008
4005
|
// PR #2016 thread SDzOP: flush through the SAME cross-process locked
|
|
4009
4006
|
// reconcile the write/batch/rebuild paths use, never the unlocked whole-file
|
|
@@ -4089,7 +4086,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4089
4086
|
for (const hash of removedHashes) {
|
|
4090
4087
|
if (!remainingActiveHashes.has(hash)) {
|
|
4091
4088
|
factHashIndex.removeByHash(hash);
|
|
4092
|
-
|
|
4089
|
+
factHashIndex.removeFactByHash(hash);
|
|
4093
4090
|
}
|
|
4094
4091
|
}
|
|
4095
4092
|
// PR #2016 thread SDzOP: serialize the removal with the per-index lock via
|
|
@@ -4102,21 +4099,23 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4102
4099
|
}
|
|
4103
4100
|
|
|
4104
4101
|
/**
|
|
4105
|
-
* Remove a memory's fact-ONLY
|
|
4106
|
-
* category-agnostic index removal the orchestrator's
|
|
4107
|
-
* `removeContentHashForMemory` performs on archival / semantic
|
|
4108
|
-
* (PR #2016 threads SDzOP / SDzOR). Without this,
|
|
4109
|
-
* removed/superseded fact's hash and `hasFactContentHash`
|
|
4110
|
-
* `true` until the next corpus rebuild, so wearable /
|
|
4111
|
-
* promotion callers skipped a valid write.
|
|
4112
|
-
*
|
|
4113
|
-
*
|
|
4114
|
-
*
|
|
4102
|
+
* Remove a memory's fact-ONLY partition membership in lockstep with the
|
|
4103
|
+
* shared, category-agnostic index removal the orchestrator's
|
|
4104
|
+
* `removeContentHashForMemory` performs on archival / semantic
|
|
4105
|
+
* consolidation (PR #2016 threads SDzOP / SDzOR). Without this, the
|
|
4106
|
+
* partition kept a removed/superseded fact's hash and `hasFactContentHash`
|
|
4107
|
+
* returned a stale `true` until the next corpus rebuild, so wearable /
|
|
4108
|
+
* explicit-capture / promotion callers skipped a valid write. No-op when
|
|
4109
|
+
* the fact-hash index has not been loaded in this process yet (the
|
|
4110
|
+
* partition is empty then and the corpus rebuild excludes the removed
|
|
4111
|
+
* memory). No-op for non-facts.
|
|
4115
4112
|
*/
|
|
4116
4113
|
removeFactOnlyHashForMemory(memory: MemoryFile): void {
|
|
4117
4114
|
if (memory.frontmatter.category !== "fact") return;
|
|
4115
|
+
const factHashIndex = this.factHashIndex;
|
|
4116
|
+
if (!factHashIndex) return;
|
|
4118
4117
|
for (const hash of this.factContentHashesForRemoval(memory)) {
|
|
4119
|
-
|
|
4118
|
+
factHashIndex.removeFactByHash(hash);
|
|
4120
4119
|
}
|
|
4121
4120
|
}
|
|
4122
4121
|
|