@remnic/core 9.3.728 → 9.3.730
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-boundary.d.ts +6 -5
- package/dist/access-boundary.js +13 -13
- package/dist/access-cli.js +34 -33
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +6 -5
- package/dist/access-http.js +19 -19
- package/dist/access-mcp.d.ts +6 -5
- package/dist/access-mcp.js +18 -18
- package/dist/access-operations-batch.js +16 -16
- package/dist/access-operations.d.ts +7 -6
- package/dist/access-operations.js +17 -17
- package/dist/access-schema.d.ts +4 -4
- package/dist/{access-service-Bgpjxo4f.d.ts → access-service-Byoe3HsT.d.ts} +18 -3
- package/dist/access-service.d.ts +6 -5
- package/dist/access-service.js +12 -12
- package/dist/access-surface-catalog.d.ts +6 -5
- 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/active-recall.js +2 -2
- package/dist/{auto-sync-F3KCSQFJ.js → auto-sync-G3V5AN4C.js} +2 -2
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +5 -4
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +3 -3
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +55 -2
- package/dist/capabilities.js +5 -1
- package/dist/{catalog-bMczlO2G.d.ts → catalog-DM1nk7cM.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 +4 -4
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-4NOI577P.js → chunk-24ZLC5QN.js} +2 -2
- package/dist/{chunk-DMQWV6SQ.js → chunk-5RZOFIDL.js} +2 -2
- package/dist/{chunk-UM5AWJNQ.js → chunk-646B5ERJ.js} +62 -37
- package/dist/chunk-646B5ERJ.js.map +1 -0
- package/dist/{chunk-H5BWGCRZ.js → chunk-6TUWSUUD.js} +51 -47
- package/dist/{chunk-H5BWGCRZ.js.map → chunk-6TUWSUUD.js.map} +1 -1
- package/dist/{chunk-36SEDFAU.js → chunk-C5WN74HH.js} +2 -2
- package/dist/{chunk-MLKWJOAJ.js → chunk-CGPHMNL4.js} +2 -2
- package/dist/{chunk-R6OVFAX6.js → chunk-DJECGBBM.js} +7 -2
- package/dist/{chunk-R6OVFAX6.js.map → chunk-DJECGBBM.js.map} +1 -1
- package/dist/{chunk-3RCBIOOJ.js → chunk-ESF7TRYJ.js} +18 -2
- package/dist/{chunk-3RCBIOOJ.js.map → chunk-ESF7TRYJ.js.map} +1 -1
- package/dist/{chunk-EY6MDMHK.js → chunk-F6OEXJQQ.js} +2 -2
- package/dist/{chunk-M4V2JVSZ.js → chunk-FFUCCKPN.js} +2 -2
- package/dist/{chunk-O6YH5F47.js → chunk-FYWUNVFZ.js} +8 -8
- package/dist/{chunk-37436GML.js → chunk-GEXI357K.js} +2 -2
- package/dist/{chunk-YGIQORJ3.js → chunk-GGL34GCW.js} +3 -3
- package/dist/{chunk-4H4F3BFL.js → chunk-GXTYEG7Q.js} +3 -3
- package/dist/{chunk-4H4F3BFL.js.map → chunk-GXTYEG7Q.js.map} +1 -1
- package/dist/{chunk-WAS3NV46.js → chunk-H3MB3F62.js} +2 -2
- package/dist/{chunk-UTHQPSRC.js → chunk-HHNSLPX7.js} +11 -8
- package/dist/chunk-HHNSLPX7.js.map +1 -0
- package/dist/{chunk-76NHR6ZL.js → chunk-HJWQJUKQ.js} +4 -4
- package/dist/{chunk-Y4YD5TYW.js → chunk-IIBFCZA7.js} +3 -3
- package/dist/{chunk-UVPL565C.js → chunk-IQOEW5YV.js} +2 -2
- package/dist/{chunk-V4GNSDFH.js → chunk-KQYGNGON.js} +2 -2
- package/dist/{chunk-CBWI22JN.js → chunk-KSJCXXOU.js} +2 -2
- package/dist/{chunk-M4AYVEWS.js → chunk-LUCARK4W.js} +12 -11
- package/dist/chunk-LUCARK4W.js.map +1 -0
- package/dist/{chunk-I5REUWLH.js → chunk-NIZQH6AU.js} +3 -3
- package/dist/{chunk-4ESAR77N.js → chunk-NOU77OHX.js} +2 -2
- package/dist/{chunk-BQCHEV7O.js → chunk-O4ZIBPIW.js} +3 -3
- package/dist/{chunk-HOHVIVDR.js → chunk-OBJUKYDO.js} +2 -2
- package/dist/{chunk-YKBHOBJK.js → chunk-OEHCMALU.js} +56 -4
- package/dist/chunk-OEHCMALU.js.map +1 -0
- package/dist/{chunk-YOLZS7NY.js → chunk-OTQE66IX.js} +2 -2
- package/dist/{chunk-QNEUZIAH.js → chunk-OUITHS6V.js} +381 -433
- package/dist/chunk-OUITHS6V.js.map +1 -0
- package/dist/{chunk-4T3BMHKD.js → chunk-OZECYVGI.js} +20 -7
- package/dist/chunk-OZECYVGI.js.map +1 -0
- package/dist/{chunk-C2PG7IEH.js → chunk-P3VJCTVE.js} +2 -2
- package/dist/{chunk-EH5ED3C6.js → chunk-PMAQRUN4.js} +4 -4
- package/dist/chunk-PMAQRUN4.js.map +1 -0
- package/dist/{chunk-7RLCCNHU.js → chunk-Q6BAA57B.js} +4 -3
- package/dist/chunk-Q6BAA57B.js.map +1 -0
- package/dist/{chunk-HGNOCPZX.js → chunk-QZHF4BWN.js} +6 -6
- package/dist/chunk-SYX73XD7.js +283 -0
- package/dist/chunk-SYX73XD7.js.map +1 -0
- package/dist/{chunk-ASKXIAHD.js → chunk-WDJCZQB4.js} +2 -2
- package/dist/{chunk-AQLOP5F4.js → chunk-WNGXQMRI.js} +95 -6
- package/dist/chunk-WNGXQMRI.js.map +1 -0
- package/dist/{chunk-JYLFZWUX.js → chunk-XYUFGHUW.js} +2 -2
- package/dist/{chunk-3TSTGI6F.js → chunk-ZQUAVZNG.js} +2 -2
- package/dist/{chunk-4NR2PDZ5.js → chunk-ZVHRSR2R.js} +14 -4
- package/dist/chunk-ZVHRSR2R.js.map +1 -0
- package/dist/{cli-BLME420h.d.ts → cli-Dt-tuiYH.d.ts} +3 -3
- package/dist/cli.d.ts +7 -6
- package/dist/cli.js +35 -35
- package/dist/compounding/engine.d.ts +12 -1
- package/dist/compounding/engine.js +3 -3
- 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/config.js +2 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/contradiction/index.js +1 -1
- 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/day-summary.d.ts +1 -1
- package/dist/delinearize.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/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +6 -4
- package/dist/explicit-capture.js +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.d.ts +1 -1
- package/dist/extraction.js +3 -3
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-22LPFHD5.js → first-start-migration-OOR57AYR.js} +2 -2
- 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-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +296 -11
- package/dist/index.js +359 -47
- package/dist/index.js.map +1 -1
- 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 +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +6 -5
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- 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-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +2 -2
- package/dist/namespaces/migrate.js +9 -9
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +5 -5
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +3 -3
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +14 -14
- package/dist/orchestration/compression-guideline-coordinator.d.ts +105 -0
- package/dist/orchestration/compression-guideline-coordinator.js +12 -0
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +5 -5
- package/dist/{orchestrator-DqPAz8ot.d.ts → orchestrator-B4KjaOtY.d.ts} +128 -34
- package/dist/orchestrator.d.ts +5 -4
- package/dist/orchestrator.js +28 -26
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/provenance.js +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.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-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-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/{resolution-MN36NW5P.js → resolution-33PIX3TT.js} +2 -2
- package/dist/resolution-33PIX3TT.js.map +1 -0
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +3 -3
- package/dist/retrieval-agents.d.ts +1 -1
- 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/schemas.d.ts +32 -32
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/embed-helper.js +2 -2
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +4 -4
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +8 -8
- 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-Cl15ksZy.d.ts → semantic-consolidation-CstTvHPo.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +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/storage.d.ts +22 -3
- package/dist/storage.js +2 -2
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.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 +1 -1
- 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/types.d.ts +22 -22
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-ChQb9D6s.d.ts → types-VkxElCHR.d.ts} +8 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +3 -3
- package/package.json +12 -2
- package/src/access-service-coding-write.test.ts +2 -2
- package/src/access-service.ts +33 -14
- package/src/bitemporal-dedup-backfill.test.ts +10 -10
- package/src/bitemporal-frontmatter.test.ts +3 -3
- package/src/capabilities.test.ts +185 -0
- package/src/capabilities.ts +110 -0
- package/src/cli/creation-ledger-commands.ts +22 -21
- package/src/coding/architecture-surfaces.test.ts +25 -1
- package/src/coding/architecture-surfaces.ts +47 -19
- package/src/coding/decision-surfaces.ts +12 -3
- package/src/coding/review-context-structural.test.ts +303 -0
- package/src/coding/review-context.ts +79 -0
- package/src/coding/structural-context.test.ts +259 -0
- package/src/coding/structural-context.ts +315 -0
- package/src/coding/structural-subprocess-provider.test.ts +430 -0
- package/src/coding/structural-subprocess-provider.ts +355 -0
- package/src/compounding/engine.test.ts +90 -0
- package/src/compounding/engine.ts +25 -1
- package/src/contradiction/contradiction.test.ts +1 -1
- package/src/contradiction/resolution.ts +9 -1
- package/src/correction/correction-access-wiring.ts +21 -3
- package/src/correction/correction-contract.ts +7 -0
- package/src/correction/correction-planner.test.ts +231 -0
- package/src/correction/correction-planner.ts +73 -0
- package/src/correction/correction-service.ts +29 -0
- package/src/correction/correction-storage-integration.test.ts +2 -2
- package/src/dedup/semantic.test.ts +1 -1
- package/src/explicit-capture.ts +7 -4
- package/src/extraction-eventtime-wiring.test.ts +3 -3
- package/src/extraction-redaction-rules.test.ts +172 -0
- package/src/index.ts +29 -0
- package/src/maintenance/forget.test.ts +1 -1
- package/src/maintenance/memory-governance.test.ts +1 -1
- package/src/maintenance/pattern-reinforcement.test.ts +2 -2
- package/src/operator-toolkit.ts +4 -3
- package/src/orchestration/compression-guideline-coordinator.ts +449 -0
- package/src/orchestration/extraction-queue-coordinator.ts +175 -0
- package/src/orchestrator-extraction-queue.test.ts +26 -38
- package/src/orchestrator-flush.test.ts +10 -15
- package/src/orchestrator.ts +359 -542
- package/src/procedural/procedure-miner.test.ts +2 -2
- package/src/provenance-extraction.test.ts +382 -4
- package/src/provenance.ts +158 -22
- package/src/recall-handles-wiring.test.ts +1 -1
- package/src/search/factory.ts +4 -3
- package/src/semantic-rule-promotion.ts +1 -1
- package/src/source-attribution-roundtrip.test.ts +2 -2
- package/src/storage-contract/atomicity.test.ts +1 -1
- package/src/storage-contract/cache-coherence.test.ts +2 -2
- package/src/storage-contract/content-hash.test.ts +1 -1
- package/src/storage-contract/namespace-routing.test.ts +1 -1
- package/src/storage-contract/round-trip.test.ts +3 -3
- package/src/storage.ts +23 -2
- package/src/temporal-supersession.test.ts +12 -11
- package/src/temporal-validity.test.ts +11 -11
- package/src/wearables/cli.test.ts +30 -0
- package/src/wearables/cli.ts +3 -0
- package/src/wearables/memory-gen.test.ts +57 -1
- package/src/wearables/memory-gen.ts +31 -7
- package/src/wearables/pipeline.test.ts +40 -1
- package/src/wearables/pipeline.ts +4 -0
- package/src/wearables/service.test.ts +2 -2
- package/src/wearables/storage-io.test.ts +3 -3
- package/src/wearables/types.ts +7 -0
- package/dist/chunk-4NR2PDZ5.js.map +0 -1
- package/dist/chunk-4T3BMHKD.js.map +0 -1
- package/dist/chunk-7RLCCNHU.js.map +0 -1
- package/dist/chunk-AQLOP5F4.js.map +0 -1
- package/dist/chunk-EH5ED3C6.js.map +0 -1
- package/dist/chunk-M4AYVEWS.js.map +0 -1
- package/dist/chunk-QNEUZIAH.js.map +0 -1
- package/dist/chunk-UM5AWJNQ.js.map +0 -1
- package/dist/chunk-UTHQPSRC.js.map +0 -1
- package/dist/chunk-YKBHOBJK.js.map +0 -1
- /package/dist/{auto-sync-F3KCSQFJ.js.map → auto-sync-G3V5AN4C.js.map} +0 -0
- /package/dist/{chunk-4NOI577P.js.map → chunk-24ZLC5QN.js.map} +0 -0
- /package/dist/{chunk-DMQWV6SQ.js.map → chunk-5RZOFIDL.js.map} +0 -0
- /package/dist/{chunk-36SEDFAU.js.map → chunk-C5WN74HH.js.map} +0 -0
- /package/dist/{chunk-MLKWJOAJ.js.map → chunk-CGPHMNL4.js.map} +0 -0
- /package/dist/{chunk-EY6MDMHK.js.map → chunk-F6OEXJQQ.js.map} +0 -0
- /package/dist/{chunk-M4V2JVSZ.js.map → chunk-FFUCCKPN.js.map} +0 -0
- /package/dist/{chunk-O6YH5F47.js.map → chunk-FYWUNVFZ.js.map} +0 -0
- /package/dist/{chunk-37436GML.js.map → chunk-GEXI357K.js.map} +0 -0
- /package/dist/{chunk-YGIQORJ3.js.map → chunk-GGL34GCW.js.map} +0 -0
- /package/dist/{chunk-WAS3NV46.js.map → chunk-H3MB3F62.js.map} +0 -0
- /package/dist/{chunk-76NHR6ZL.js.map → chunk-HJWQJUKQ.js.map} +0 -0
- /package/dist/{chunk-Y4YD5TYW.js.map → chunk-IIBFCZA7.js.map} +0 -0
- /package/dist/{chunk-UVPL565C.js.map → chunk-IQOEW5YV.js.map} +0 -0
- /package/dist/{chunk-V4GNSDFH.js.map → chunk-KQYGNGON.js.map} +0 -0
- /package/dist/{chunk-CBWI22JN.js.map → chunk-KSJCXXOU.js.map} +0 -0
- /package/dist/{chunk-I5REUWLH.js.map → chunk-NIZQH6AU.js.map} +0 -0
- /package/dist/{chunk-4ESAR77N.js.map → chunk-NOU77OHX.js.map} +0 -0
- /package/dist/{chunk-BQCHEV7O.js.map → chunk-O4ZIBPIW.js.map} +0 -0
- /package/dist/{chunk-HOHVIVDR.js.map → chunk-OBJUKYDO.js.map} +0 -0
- /package/dist/{chunk-YOLZS7NY.js.map → chunk-OTQE66IX.js.map} +0 -0
- /package/dist/{chunk-C2PG7IEH.js.map → chunk-P3VJCTVE.js.map} +0 -0
- /package/dist/{chunk-HGNOCPZX.js.map → chunk-QZHF4BWN.js.map} +0 -0
- /package/dist/{chunk-ASKXIAHD.js.map → chunk-WDJCZQB4.js.map} +0 -0
- /package/dist/{chunk-JYLFZWUX.js.map → chunk-XYUFGHUW.js.map} +0 -0
- /package/dist/{chunk-3TSTGI6F.js.map → chunk-ZQUAVZNG.js.map} +0 -0
- /package/dist/{first-start-migration-22LPFHD5.js.map → first-start-migration-OOR57AYR.js.map} +0 -0
- /package/dist/{resolution-MN36NW5P.js.map → orchestration/compression-guideline-coordinator.js.map} +0 -0
package/src/search/factory.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { EmbedHelper } from "./embed-helper.js";
|
|
|
10
10
|
import { QmdClient, type QmdClientOptions } from "../qmd.js";
|
|
11
11
|
import { log } from "../logger.js";
|
|
12
12
|
import { FaissConversationIndexAdapter } from "../conversation-index/faiss-adapter.js";
|
|
13
|
+
import { resolveIndexingCapabilities } from "../capabilities.js";
|
|
13
14
|
import {
|
|
14
15
|
createConversationIndexBackend,
|
|
15
16
|
type ConversationIndexBackend,
|
|
@@ -135,7 +136,7 @@ export function createSearchBackend(config: PluginConfig): SearchBackend {
|
|
|
135
136
|
* Returns undefined if conversation index is not enabled or not using qmd backend.
|
|
136
137
|
*/
|
|
137
138
|
export function createConversationSearchBackend(config: PluginConfig): SearchBackend | undefined {
|
|
138
|
-
if (!config.
|
|
139
|
+
if (!resolveIndexingCapabilities(config).conversationIndex || config.conversationIndexBackend !== "qmd") {
|
|
139
140
|
return undefined;
|
|
140
141
|
}
|
|
141
142
|
|
|
@@ -169,7 +170,7 @@ export function createConversationIndexRuntime(
|
|
|
169
170
|
): ConversationIndexRuntime {
|
|
170
171
|
const qmd = createConversationSearchBackend(config) as ConversationQmdRuntime | undefined;
|
|
171
172
|
let faiss: FaissConversationIndexAdapter | undefined;
|
|
172
|
-
if (config.
|
|
173
|
+
if (resolveIndexingCapabilities(config).conversationIndex && config.conversationIndexBackend === "faiss") {
|
|
173
174
|
try {
|
|
174
175
|
faiss = new FaissConversationIndexAdapter({
|
|
175
176
|
memoryDir: config.memoryDir,
|
|
@@ -189,7 +190,7 @@ export function createConversationIndexRuntime(
|
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
const backend = createConversationIndexBackend({
|
|
192
|
-
enabled: config.
|
|
193
|
+
enabled: resolveIndexingCapabilities(config).conversationIndex,
|
|
193
194
|
backend: config.conversationIndexBackend,
|
|
194
195
|
getQmd: () => overrides?.getQmd?.() ?? qmd,
|
|
195
196
|
getFaiss: () => overrides?.getFaiss?.() ?? faiss,
|
|
@@ -630,7 +630,7 @@ export async function promoteSemanticRuleFromMemory(options: {
|
|
|
630
630
|
}
|
|
631
631
|
|
|
632
632
|
await lock.beforePromotedRuleWrite();
|
|
633
|
-
const id = await storage.writeMemory("rule", content, {
|
|
633
|
+
const { id: id } = await storage.writeMemory("rule", content, {
|
|
634
634
|
confidence,
|
|
635
635
|
tags: candidateBase.tags,
|
|
636
636
|
source: "semantic-rule-promotion",
|
|
@@ -41,7 +41,7 @@ test("round-trip: citation-enriched fact content survives writeMemory → readAl
|
|
|
41
41
|
|
|
42
42
|
assert.ok(hasCitation(enriched), "attachCitation must emit a marker");
|
|
43
43
|
|
|
44
|
-
const id = await storage.writeMemory("fact", enriched, {
|
|
44
|
+
const { id: id } = await storage.writeMemory("fact", enriched, {
|
|
45
45
|
confidence: 0.8,
|
|
46
46
|
tags: ["test"],
|
|
47
47
|
});
|
|
@@ -76,7 +76,7 @@ test("legacy fact memories without a citation marker still read cleanly", async
|
|
|
76
76
|
await storage.ensureDirectories();
|
|
77
77
|
|
|
78
78
|
const legacyBody = "Legacy fact without inline provenance.";
|
|
79
|
-
const id = await storage.writeMemory("fact", legacyBody, {
|
|
79
|
+
const { id: id } = await storage.writeMemory("fact", legacyBody, {
|
|
80
80
|
confidence: 0.8,
|
|
81
81
|
tags: ["legacy"],
|
|
82
82
|
});
|
|
@@ -82,7 +82,7 @@ test("atomicity: StorageManager.updateMemory preserves the original on overwrite
|
|
|
82
82
|
const { makeStorage } = await import("./harness.js");
|
|
83
83
|
const { storage, cleanup } = await makeStorage();
|
|
84
84
|
try {
|
|
85
|
-
const id = await storage.writeMemory("fact", "version one");
|
|
85
|
+
const { id: id } = await storage.writeMemory("fact", "version one");
|
|
86
86
|
const before = await storage.getMemoryById(id);
|
|
87
87
|
assert.ok(before);
|
|
88
88
|
assert.equal(before!.content, "version one");
|
|
@@ -24,7 +24,7 @@ test("cache-coherence: write via instance A, read via fresh instance B → B see
|
|
|
24
24
|
const smA = new StorageManager(dir);
|
|
25
25
|
await smA.ensureDirectories();
|
|
26
26
|
|
|
27
|
-
const id = await smA.writeMemory("fact", "written by A");
|
|
27
|
+
const { id: id } = await smA.writeMemory("fact", "written by A");
|
|
28
28
|
|
|
29
29
|
// Fresh instance over the same dir
|
|
30
30
|
const smB = new StorageManager(dir);
|
|
@@ -47,7 +47,7 @@ test("cache-coherence: delete via instance A is reflected in fresh instance B",
|
|
|
47
47
|
resetStaticCaches();
|
|
48
48
|
const smA = new StorageManager(dir);
|
|
49
49
|
await smA.ensureDirectories();
|
|
50
|
-
const id = await smA.writeMemory("fact", "to be deleted");
|
|
50
|
+
const { id: id } = await smA.writeMemory("fact", "to be deleted");
|
|
51
51
|
|
|
52
52
|
// Confirm B sees it
|
|
53
53
|
const smB = new StorageManager(dir);
|
|
@@ -87,7 +87,7 @@ test("content-hash: the frontmatter contentHash matches computeHash of the raw c
|
|
|
87
87
|
const { storage, cleanup } = await makeStorage();
|
|
88
88
|
try {
|
|
89
89
|
const rawFact = "deterministic hash check";
|
|
90
|
-
const id = await storage.writeMemory("fact", rawFact);
|
|
90
|
+
const { id: id } = await storage.writeMemory("fact", rawFact);
|
|
91
91
|
const memory = await storage.getMemoryById(id);
|
|
92
92
|
assert.ok(memory);
|
|
93
93
|
assert.ok(memory!.frontmatter.contentHash, "frontmatter must carry a contentHash for facts");
|
|
@@ -69,7 +69,7 @@ test("namespace-routing: writes in one namespace are invisible to another (isola
|
|
|
69
69
|
const { router, cleanup } = await makeNamespaceRouter();
|
|
70
70
|
try {
|
|
71
71
|
const sm1 = await router.storageFor("team-alpha");
|
|
72
|
-
const id = await sm1.writeMemory("fact", "alpha-only fact");
|
|
72
|
+
const { id: id } = await sm1.writeMemory("fact", "alpha-only fact");
|
|
73
73
|
|
|
74
74
|
const sm2 = await router.storageFor("team-beta");
|
|
75
75
|
const found = await sm2.getMemoryById(id);
|
|
@@ -38,7 +38,7 @@ const ROUND_TRIP_CATEGORIES = ALL_CATEGORY_KEYS.filter(
|
|
|
38
38
|
test("round-trip: writeMemory returns a stable id and persists to the category dir", async () => {
|
|
39
39
|
const { storage, cleanup } = await makeStorage();
|
|
40
40
|
try {
|
|
41
|
-
const id = await storage.writeMemory("fact", "The sky is blue", {
|
|
41
|
+
const { id: id } = await storage.writeMemory("fact", "The sky is blue", {
|
|
42
42
|
tags: ["contract"],
|
|
43
43
|
});
|
|
44
44
|
assert.equal(typeof id, "string");
|
|
@@ -58,7 +58,7 @@ test("round-trip: readAllMemories returns written memories from every category d
|
|
|
58
58
|
try {
|
|
59
59
|
const written: string[] = [];
|
|
60
60
|
for (const category of ROUND_TRIP_CATEGORIES) {
|
|
61
|
-
const id = await storage.writeMemory(
|
|
61
|
+
const { id: id } = await storage.writeMemory(
|
|
62
62
|
category,
|
|
63
63
|
`content for ${category}`,
|
|
64
64
|
{ confidence: 0.9 },
|
|
@@ -81,7 +81,7 @@ for (const category of ROUND_TRIP_CATEGORIES) {
|
|
|
81
81
|
const { storage, cleanup } = await makeStorage();
|
|
82
82
|
try {
|
|
83
83
|
const content = `fact body for category ${category}`;
|
|
84
|
-
const id = await storage.writeMemory(category, content, {
|
|
84
|
+
const { id: id } = await storage.writeMemory(category, content, {
|
|
85
85
|
tags: ["round-trip"],
|
|
86
86
|
});
|
|
87
87
|
|
package/src/storage.ts
CHANGED
|
@@ -2244,6 +2244,19 @@ function isValidBufferSurpriseEvent(value: unknown): value is BufferSurpriseEven
|
|
|
2244
2244
|
return true;
|
|
2245
2245
|
}
|
|
2246
2246
|
|
|
2247
|
+
/** Result of {@link StorageManager.writeMemory} (issue #1645). Carries the
|
|
2248
|
+
* persisted id PLUS the non-resurrection tombstone-block outcome (#1579) so
|
|
2249
|
+
* post-write callers can observe it — NEVER a silent no-op (rule 34). */
|
|
2250
|
+
export interface MemoryWriteResult {
|
|
2251
|
+
/** The persisted memory id. */
|
|
2252
|
+
id: string;
|
|
2253
|
+
/** True when the #1579 tombstone chokepoint downgraded this write to
|
|
2254
|
+
* `pending_review` + `blockedBy`. Callers gate active post-write work on this. */
|
|
2255
|
+
tombstoneBlocked: boolean;
|
|
2256
|
+
/** The tombstone id that blocked the write, when `tombstoneBlocked`. */
|
|
2257
|
+
blockedBy?: string;
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2247
2260
|
export class StorageManager {
|
|
2248
2261
|
private knowledgeIndexCache: { result: string; builtAt: number } | null = null;
|
|
2249
2262
|
private static readonly KNOWLEDGE_INDEX_CACHE_TTL_MS = 600_000; // 10 minutes (entity mutations invalidate)
|
|
@@ -3625,7 +3638,7 @@ export class StorageManager {
|
|
|
3625
3638
|
sources?: ProvenanceSource[];
|
|
3626
3639
|
provenance?: "verified" | "unverified" | "none";
|
|
3627
3640
|
} = {},
|
|
3628
|
-
): Promise<
|
|
3641
|
+
): Promise<MemoryWriteResult> {
|
|
3629
3642
|
await this.ensureDirectories();
|
|
3630
3643
|
const now = new Date();
|
|
3631
3644
|
const today = now.toISOString().slice(0, 10);
|
|
@@ -3835,7 +3848,7 @@ export class StorageManager {
|
|
|
3835
3848
|
}
|
|
3836
3849
|
}
|
|
3837
3850
|
log.debug(`wrote memory ${id} to ${filePath}`);
|
|
3838
|
-
return id;
|
|
3851
|
+
return { id, tombstoneBlocked, ...(fm.blockedBy ? { blockedBy: fm.blockedBy } : {}) };
|
|
3839
3852
|
}
|
|
3840
3853
|
|
|
3841
3854
|
async hasFactContentHash(content: string): Promise<boolean> {
|
|
@@ -7359,6 +7372,13 @@ export class StorageManager {
|
|
|
7359
7372
|
validAt?: string;
|
|
7360
7373
|
/** Lifecycle status (issue #1576): pending_review chunks stay out of active recall. */
|
|
7361
7374
|
status?: import("./types.js").MemoryStatus;
|
|
7375
|
+
/**
|
|
7376
|
+
* Tombstone block provenance (issue #1645): when the parent fact was
|
|
7377
|
+
* tombstone-blocked, propagate the tombstone id onto each chunk so an
|
|
7378
|
+
* independently-surfaced chunk (memory_get/x-ray/doctor) reveals the block
|
|
7379
|
+
* and the chunk stays pending_review, never an active resurrection.
|
|
7380
|
+
*/
|
|
7381
|
+
blockedBy?: string;
|
|
7362
7382
|
/** Faithfulness gate verdict (issue #1576), propagated from the parent fact. */
|
|
7363
7383
|
faithfulness?: import("./types.js").FaithfulnessFrontmatter;
|
|
7364
7384
|
/** Claim-level provenance spans (issue #1575 PR 2), propagated from the parent fact so a chunk surfaced independently (memory_get/x-ray) preserves them (chatgpt-codex-connector thread Ocvmo). */
|
|
@@ -7406,6 +7426,7 @@ export class StorageManager {
|
|
|
7406
7426
|
observedAt: chunkObservedAt,
|
|
7407
7427
|
eventTimeSource: options.eventTimeSource,
|
|
7408
7428
|
...(options.status ? { status: options.status } : {}),
|
|
7429
|
+
...(options.blockedBy ? { blockedBy: options.blockedBy } : {}),
|
|
7409
7430
|
...(options.faithfulness ? { faithfulness: options.faithfulness } : {}),
|
|
7410
7431
|
...(options.sources ? { sources: options.sources } : {}),
|
|
7411
7432
|
...(options.provenance ? { provenance: options.provenance } : {}),
|
|
@@ -46,13 +46,14 @@ async function writeFact(
|
|
|
46
46
|
entityRef: string,
|
|
47
47
|
attrs: Record<string, string>,
|
|
48
48
|
): Promise<string> {
|
|
49
|
-
|
|
49
|
+
const { id } = await storage.writeMemory("fact", content, {
|
|
50
50
|
entityRef,
|
|
51
51
|
structuredAttributes: attrs,
|
|
52
52
|
source: "test",
|
|
53
53
|
confidence: 0.9,
|
|
54
54
|
tags: [],
|
|
55
55
|
});
|
|
56
|
+
return id;
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
async function readFrontmatterById(
|
|
@@ -328,7 +329,7 @@ test("applyTemporalSupersession: retires child chunks with superseded parent", a
|
|
|
328
329
|
try {
|
|
329
330
|
const oldValidAt = "2026-01-01T00:00:00.000Z";
|
|
330
331
|
const newValidAt = "2026-02-01T00:00:00.000Z";
|
|
331
|
-
const oldParent = await storage.writeMemory(
|
|
332
|
+
const { id: oldParent } = await storage.writeMemory(
|
|
332
333
|
"fact",
|
|
333
334
|
"project X is based in Austin. ".repeat(40),
|
|
334
335
|
{
|
|
@@ -355,7 +356,7 @@ test("applyTemporalSupersession: retires child chunks with superseded parent", a
|
|
|
355
356
|
},
|
|
356
357
|
);
|
|
357
358
|
|
|
358
|
-
const newParent = await storage.writeMemory(
|
|
359
|
+
const { id: newParent } = await storage.writeMemory(
|
|
359
360
|
"fact",
|
|
360
361
|
"project X relocated to NYC",
|
|
361
362
|
{
|
|
@@ -396,7 +397,7 @@ test("applyTemporalSupersession: retires child chunks with superseded parent", a
|
|
|
396
397
|
test("applyTemporalSupersession: no structured attributes is a no-op", async () => {
|
|
397
398
|
const { storage, cleanup } = await makeStorage();
|
|
398
399
|
try {
|
|
399
|
-
const oldFact = await storage.writeMemory(
|
|
400
|
+
const { id: oldFact } = await storage.writeMemory(
|
|
400
401
|
"fact",
|
|
401
402
|
"project X is based in Austin",
|
|
402
403
|
{
|
|
@@ -407,7 +408,7 @@ test("applyTemporalSupersession: no structured attributes is a no-op", async ()
|
|
|
407
408
|
},
|
|
408
409
|
);
|
|
409
410
|
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
410
|
-
const newFact = await storage.writeMemory(
|
|
411
|
+
const { id: newFact } = await storage.writeMemory(
|
|
411
412
|
"fact",
|
|
412
413
|
"project X uses vim",
|
|
413
414
|
{
|
|
@@ -2419,7 +2420,7 @@ test("StorageManager: writing same enriched content twice does not create duplic
|
|
|
2419
2420
|
const attrs = { city: "Denver" };
|
|
2420
2421
|
|
|
2421
2422
|
// First write.
|
|
2422
|
-
const id1 = await storage.writeMemory("fact", rawContent, {
|
|
2423
|
+
const { id: id1 } = await storage.writeMemory("fact", rawContent, {
|
|
2423
2424
|
entityRef: TEST_ENTITY,
|
|
2424
2425
|
structuredAttributes: attrs,
|
|
2425
2426
|
source: "test",
|
|
@@ -2491,7 +2492,7 @@ test("StorageManager: hash-dedup catch fall-through — write proceeds when look
|
|
|
2491
2492
|
|
|
2492
2493
|
// Simulate the fall-through path: when lookup fails the orchestrator falls
|
|
2493
2494
|
// through to writeMemory. Write the fact directly as the orchestrator would.
|
|
2494
|
-
const id = await storage.writeMemory("fact", rawContent, {
|
|
2495
|
+
const { id: id } = await storage.writeMemory("fact", rawContent, {
|
|
2495
2496
|
entityRef: TEST_ENTITY,
|
|
2496
2497
|
structuredAttributes: attrs,
|
|
2497
2498
|
source: "test",
|
|
@@ -2546,14 +2547,14 @@ test("StorageManager: enriched-hash matching selects correct candidate when two
|
|
|
2546
2547
|
const enrichedB = `${rawContent}\n[Attributes: ${Object.entries(attrsB).map(([k, v]) => `${k}: ${v}`).join("; ")}]`;
|
|
2547
2548
|
|
|
2548
2549
|
// Write both facts.
|
|
2549
|
-
const idA = await storage.writeMemory("fact", rawContent, {
|
|
2550
|
+
const { id: idA } = await storage.writeMemory("fact", rawContent, {
|
|
2550
2551
|
entityRef: TEST_ENTITY,
|
|
2551
2552
|
structuredAttributes: attrsA,
|
|
2552
2553
|
source: "test",
|
|
2553
2554
|
confidence: 0.9,
|
|
2554
2555
|
tags: [],
|
|
2555
2556
|
});
|
|
2556
|
-
const idB = await storage.writeMemory("fact", rawContent, {
|
|
2557
|
+
const { id: idB } = await storage.writeMemory("fact", rawContent, {
|
|
2557
2558
|
entityRef: TEST_ENTITY,
|
|
2558
2559
|
structuredAttributes: attrsB,
|
|
2559
2560
|
source: "test",
|
|
@@ -2663,7 +2664,7 @@ test("normalizeAttributePairs: writeMemory hash-dedup stable across key orders",
|
|
|
2663
2664
|
const attrsFwd = { city: "Seattle", country: "USA" };
|
|
2664
2665
|
const attrsRev = { country: "USA", city: "Seattle" }; // reversed
|
|
2665
2666
|
|
|
2666
|
-
const id1 = await storage.writeMemory("fact", content, {
|
|
2667
|
+
const { id: id1 } = await storage.writeMemory("fact", content, {
|
|
2667
2668
|
entityRef: TEST_ENTITY,
|
|
2668
2669
|
structuredAttributes: attrsFwd,
|
|
2669
2670
|
source: "test",
|
|
@@ -2728,7 +2729,7 @@ test("normalizeAttributePairs + sanitizeMemoryContent: normalizedIncoming uses s
|
|
|
2728
2729
|
const cleanContent = "Alice lives in Seattle";
|
|
2729
2730
|
const attrs = { city: "Seattle", state: "WA" };
|
|
2730
2731
|
|
|
2731
|
-
const id1 = await storage.writeMemory("fact", cleanContent, {
|
|
2732
|
+
const { id: id1 } = await storage.writeMemory("fact", cleanContent, {
|
|
2732
2733
|
entityRef: TEST_ENTITY,
|
|
2733
2734
|
structuredAttributes: attrs,
|
|
2734
2735
|
source: "test",
|
|
@@ -66,7 +66,7 @@ test("storage: valid_at / invalid_at round-trip exactly when set", async () => {
|
|
|
66
66
|
try {
|
|
67
67
|
const validAt = "2025-01-01T00:00:00.000Z";
|
|
68
68
|
const invalidAt = "2026-01-01T00:00:00.000Z";
|
|
69
|
-
const id = await storage.writeMemory("fact", "project X is based in Austin", {
|
|
69
|
+
const { id: id } = await storage.writeMemory("fact", "project X is based in Austin", {
|
|
70
70
|
entityRef: TEST_ENTITY,
|
|
71
71
|
structuredAttributes: { city: "Austin" },
|
|
72
72
|
source: "test",
|
|
@@ -95,7 +95,7 @@ test("storage: valid_at / invalid_at round-trip exactly when set", async () => {
|
|
|
95
95
|
test("storage: writeMemory persists explicit validAt as valid_at", async () => {
|
|
96
96
|
const { storage, cleanup } = await makeStorage();
|
|
97
97
|
try {
|
|
98
|
-
const id = await storage.writeMemory(
|
|
98
|
+
const { id: id } = await storage.writeMemory(
|
|
99
99
|
"fact",
|
|
100
100
|
"project X launched from the source transcript",
|
|
101
101
|
{
|
|
@@ -135,7 +135,7 @@ test("storage: writeMemory rejects invalid validAt values", async () => {
|
|
|
135
135
|
test("storage: legacy memories without valid_at parse as undefined (no backfill)", async () => {
|
|
136
136
|
const { storage, cleanup } = await makeStorage();
|
|
137
137
|
try {
|
|
138
|
-
const id = await storage.writeMemory("fact", "legacy memory", {
|
|
138
|
+
const { id: id } = await storage.writeMemory("fact", "legacy memory", {
|
|
139
139
|
entityRef: TEST_ENTITY,
|
|
140
140
|
source: "test",
|
|
141
141
|
confidence: 0.9,
|
|
@@ -176,7 +176,7 @@ test("effectiveValidAt: whitespace-only valid_at falls back to created", () => {
|
|
|
176
176
|
test("supersession: new fact propagates valid_at to old fact's invalid_at", async () => {
|
|
177
177
|
const { storage, cleanup } = await makeStorage();
|
|
178
178
|
try {
|
|
179
|
-
const oldId = await storage.writeMemory(
|
|
179
|
+
const { id: oldId } = await storage.writeMemory(
|
|
180
180
|
"fact",
|
|
181
181
|
"project X is based in Austin",
|
|
182
182
|
{
|
|
@@ -188,7 +188,7 @@ test("supersession: new fact propagates valid_at to old fact's invalid_at", asyn
|
|
|
188
188
|
},
|
|
189
189
|
);
|
|
190
190
|
await new Promise((r) => setTimeout(r, 5));
|
|
191
|
-
const newId = await storage.writeMemory(
|
|
191
|
+
const { id: newId } = await storage.writeMemory(
|
|
192
192
|
"fact",
|
|
193
193
|
"project X relocated to NYC",
|
|
194
194
|
{
|
|
@@ -242,7 +242,7 @@ test("supersession: older source-valid replay fact does not supersede newer sour
|
|
|
242
242
|
const newerValidAt = "2025-01-02T00:00:00.000Z";
|
|
243
243
|
const olderValidAt = "2025-01-01T00:00:00.000Z";
|
|
244
244
|
|
|
245
|
-
const newerId = await storage.writeMemory(
|
|
245
|
+
const { id: newerId } = await storage.writeMemory(
|
|
246
246
|
"fact",
|
|
247
247
|
"project X moved to NYC",
|
|
248
248
|
{
|
|
@@ -255,7 +255,7 @@ test("supersession: older source-valid replay fact does not supersede newer sour
|
|
|
255
255
|
},
|
|
256
256
|
);
|
|
257
257
|
await new Promise((r) => setTimeout(r, 5));
|
|
258
|
-
const olderId = await storage.writeMemory(
|
|
258
|
+
const { id: olderId } = await storage.writeMemory(
|
|
259
259
|
"fact",
|
|
260
260
|
"project X was previously based in Austin",
|
|
261
261
|
{
|
|
@@ -292,7 +292,7 @@ test("supersession: older source-valid replay fact does not supersede newer sour
|
|
|
292
292
|
test("supersession: when superseder has no valid_at, falls back to persisted created", async () => {
|
|
293
293
|
const { storage, cleanup } = await makeStorage();
|
|
294
294
|
try {
|
|
295
|
-
const oldId = await storage.writeMemory(
|
|
295
|
+
const { id: oldId } = await storage.writeMemory(
|
|
296
296
|
"fact",
|
|
297
297
|
"project X is based in Austin",
|
|
298
298
|
{
|
|
@@ -304,7 +304,7 @@ test("supersession: when superseder has no valid_at, falls back to persisted cre
|
|
|
304
304
|
},
|
|
305
305
|
);
|
|
306
306
|
await new Promise((r) => setTimeout(r, 5));
|
|
307
|
-
const newId = await storage.writeMemory(
|
|
307
|
+
const { id: newId } = await storage.writeMemory(
|
|
308
308
|
"fact",
|
|
309
309
|
"project X relocated to NYC",
|
|
310
310
|
{
|
|
@@ -341,7 +341,7 @@ test("supersession: when superseder has no valid_at, falls back to persisted cre
|
|
|
341
341
|
test("supersession: existing invalid_at is preserved (idempotent)", async () => {
|
|
342
342
|
const { storage, cleanup } = await makeStorage();
|
|
343
343
|
try {
|
|
344
|
-
const oldId = await storage.writeMemory("fact", "old fact", {
|
|
344
|
+
const { id: oldId } = await storage.writeMemory("fact", "old fact", {
|
|
345
345
|
entityRef: TEST_ENTITY,
|
|
346
346
|
structuredAttributes: { city: "Austin" },
|
|
347
347
|
source: "test",
|
|
@@ -359,7 +359,7 @@ test("supersession: existing invalid_at is preserved (idempotent)", async () =>
|
|
|
359
359
|
});
|
|
360
360
|
|
|
361
361
|
await new Promise((r) => setTimeout(r, 5));
|
|
362
|
-
const newId = await storage.writeMemory("fact", "new fact", {
|
|
362
|
+
const { id: newId } = await storage.writeMemory("fact", "new fact", {
|
|
363
363
|
entityRef: TEST_ENTITY,
|
|
364
364
|
structuredAttributes: { city: "NYC" },
|
|
365
365
|
source: "test",
|
|
@@ -52,6 +52,7 @@ function stubService(overrides: Partial<Record<keyof WearablesService, unknown>>
|
|
|
52
52
|
transcriptsWritten: ["2026-06-11"],
|
|
53
53
|
memoriesCreated: 2,
|
|
54
54
|
memoriesSkipped: 4,
|
|
55
|
+
memoriesBlocked: 0,
|
|
55
56
|
nativeMemoriesImported: 0,
|
|
56
57
|
warnings: ["something minor"],
|
|
57
58
|
},
|
|
@@ -114,6 +115,35 @@ test("status renders sources and respects --json", async () => {
|
|
|
114
115
|
assert.equal(parsed.enabled, true);
|
|
115
116
|
});
|
|
116
117
|
|
|
118
|
+
test("sync renders a memories blocked line when writes are tombstone-blocked (#1645)", async () => {
|
|
119
|
+
const { io, out } = makeIo();
|
|
120
|
+
const service = stubService({
|
|
121
|
+
sync: async () => [
|
|
122
|
+
{
|
|
123
|
+
source: "limitless",
|
|
124
|
+
days: ["2026-06-11"],
|
|
125
|
+
conversations: 1,
|
|
126
|
+
segmentsKept: 4,
|
|
127
|
+
segmentsDropped: 0,
|
|
128
|
+
redactions: 0,
|
|
129
|
+
correctionsApplied: 0,
|
|
130
|
+
transcriptsWritten: ["2026-06-11"],
|
|
131
|
+
memoriesCreated: 0,
|
|
132
|
+
memoriesPromoted: 0,
|
|
133
|
+
memoriesDemoted: 0,
|
|
134
|
+
memoriesSkipped: 0,
|
|
135
|
+
memoriesBlocked: 2,
|
|
136
|
+
nativeMemoriesImported: 0,
|
|
137
|
+
warnings: [],
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
});
|
|
141
|
+
assert.equal(await runWearablesCliCommand(service, ["sync"], io), 0);
|
|
142
|
+
const text = out.join("");
|
|
143
|
+
assert.match(text, /memories blocked:\s+2/);
|
|
144
|
+
assert.doesNotMatch(text, /memories created:\s+[1-9]/, "no blocked write counted as created");
|
|
145
|
+
});
|
|
146
|
+
|
|
117
147
|
test("sync renders the summary including warnings", async () => {
|
|
118
148
|
const { io, out } = makeIo();
|
|
119
149
|
assert.equal(await runWearablesCliCommand(stubService(), ["sync"], io), 0);
|
package/src/wearables/cli.ts
CHANGED
|
@@ -131,6 +131,9 @@ function renderSyncSummary(summary: WearableSyncSummary): string {
|
|
|
131
131
|
if (summary.memoriesDemoted > 0) {
|
|
132
132
|
lines.push(` memories demoted: ${summary.memoriesDemoted}`);
|
|
133
133
|
}
|
|
134
|
+
if (summary.memoriesBlocked > 0) {
|
|
135
|
+
lines.push(` memories blocked: ${summary.memoriesBlocked}`);
|
|
136
|
+
}
|
|
134
137
|
if (summary.nativeMemoriesImported > 0) {
|
|
135
138
|
lines.push(` native memories queued: ${summary.nativeMemoriesImported}`);
|
|
136
139
|
}
|
|
@@ -79,7 +79,7 @@ function makeWriter(existingHashes: string[] = []): {
|
|
|
79
79
|
writer: {
|
|
80
80
|
async writeMemory(category, content, options) {
|
|
81
81
|
writes.push({ category, content, options: options as Record<string, unknown> });
|
|
82
|
-
return `id-${writes.length}
|
|
82
|
+
return { id: `id-${writes.length}`, tombstoneBlocked: false };
|
|
83
83
|
},
|
|
84
84
|
async hasFactContentHash(content) {
|
|
85
85
|
return existing.has(content);
|
|
@@ -755,3 +755,59 @@ test("native memories always import as pending_review and respect prior imports"
|
|
|
755
755
|
assert.equal(writes[0].options.source, "wearable:bee:native");
|
|
756
756
|
assert.deepEqual(result.importedIds.sort(), ["n1", "n2", "n3"]);
|
|
757
757
|
});
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
test("#1645: a tombstone-blocked wearable write counts as blocked, not created", async () => {
|
|
761
|
+
// The writer returns tombstoneBlocked: true — the #1579 chokepoint downgraded
|
|
762
|
+
// the write to pending_review (no active copy). The day-write loop must count
|
|
763
|
+
// it as blocked, NOT created, so the sync summary and callers don't report
|
|
764
|
+
// blocked content as successfully created active memories.
|
|
765
|
+
const writes: Array<{ category: string; content: string; options: Record<string, unknown> }> = [];
|
|
766
|
+
const writer: WearableMemoryWriter = {
|
|
767
|
+
async writeMemory(category, content, options) {
|
|
768
|
+
writes.push({ category, content, options: options as Record<string, unknown> });
|
|
769
|
+
return { id: `id-${writes.length}`, tombstoneBlocked: true, blockedBy: "tomb-1" };
|
|
770
|
+
},
|
|
771
|
+
async hasFactContentHash() {
|
|
772
|
+
return false;
|
|
773
|
+
},
|
|
774
|
+
};
|
|
775
|
+
const result = await generateWearableMemories(
|
|
776
|
+
"limitless",
|
|
777
|
+
"2026-06-10",
|
|
778
|
+
[LONG_CONVERSATION],
|
|
779
|
+
settings(),
|
|
780
|
+
REGISTRY,
|
|
781
|
+
{
|
|
782
|
+
extract: extractionReturning([
|
|
783
|
+
{ category: "decision", content: "Launch moved to September 12.", confidence: 0.9, tags: ["launch"] },
|
|
784
|
+
]),
|
|
785
|
+
writer,
|
|
786
|
+
},
|
|
787
|
+
);
|
|
788
|
+
assert.equal(writes.length, 1, "the write still happens (pending_review row)");
|
|
789
|
+
assert.equal(result.created, 0, "blocked write must NOT count as created");
|
|
790
|
+
assert.equal(result.tombstoneBlocked, 1, "blocked write counted separately");
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
test("#1645: a tombstone-blocked native import counts as blocked, not imported", async () => {
|
|
795
|
+
const writer: WearableMemoryWriter = {
|
|
796
|
+
async writeMemory() {
|
|
797
|
+
return { id: "blocked-native-1", tombstoneBlocked: true, blockedBy: "tomb-1" };
|
|
798
|
+
},
|
|
799
|
+
async hasFactContentHash() {
|
|
800
|
+
return false;
|
|
801
|
+
},
|
|
802
|
+
};
|
|
803
|
+
const result = await importNativeMemories(
|
|
804
|
+
"bee",
|
|
805
|
+
[{ id: "n1", content: "A native fact that matches a tombstone.", createdIso: "2026-06-10T10:00:00Z" }],
|
|
806
|
+
new Set(),
|
|
807
|
+
settings({ importNativeMemories: "review" }),
|
|
808
|
+
{ extract: extractionReturning([]), writer },
|
|
809
|
+
);
|
|
810
|
+
assert.equal(result.imported, 0, "blocked native import must NOT count as imported");
|
|
811
|
+
assert.equal(result.tombstoneBlocked, 1, "blocked native import counted separately");
|
|
812
|
+
assert.deepEqual(result.importedIds, ["n1"], "provider id still recorded to prevent duplicate re-import");
|
|
813
|
+
});
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
import { scoreImportance } from "../importance.js";
|
|
31
|
+
import type { MemoryWriteResult } from "../storage.js";
|
|
31
32
|
import type { JudgeBatchResult, JudgeCandidate } from "../extraction-judge.js";
|
|
32
33
|
import { getVerdictKind } from "../extraction-judge.js";
|
|
33
34
|
import { describeErrorForOperator } from "./errors.js";
|
|
@@ -82,7 +83,7 @@ export interface WearableMemoryWriter {
|
|
|
82
83
|
status?: MemoryStatus;
|
|
83
84
|
memoryKind?: "episode" | "note" | "box" | "dream" | "procedural";
|
|
84
85
|
},
|
|
85
|
-
): Promise<
|
|
86
|
+
): Promise<MemoryWriteResult>;
|
|
86
87
|
hasFactContentHash(content: string): Promise<boolean>;
|
|
87
88
|
/**
|
|
88
89
|
* Locate an earlier wearable write of the same content (any status).
|
|
@@ -131,6 +132,12 @@ export interface WearableMemoryGenDeps {
|
|
|
131
132
|
|
|
132
133
|
export interface WearableMemoryGenResult {
|
|
133
134
|
created: number;
|
|
135
|
+
/**
|
|
136
|
+
* Writes the #1579 tombstone chokepoint downgraded to pending_review (no
|
|
137
|
+
* active copy). Surfaced distinctly from `created` so sync summaries and
|
|
138
|
+
* callers don't count blocked content as successfully created (#1645).
|
|
139
|
+
*/
|
|
140
|
+
tombstoneBlocked: number;
|
|
134
141
|
/** Earlier borderline writes promoted to active by new evidence. */
|
|
135
142
|
promoted: number;
|
|
136
143
|
/** Earlier pending writes retired by a fresh judge-reject verdict. */
|
|
@@ -309,6 +316,7 @@ export async function generateWearableMemories(
|
|
|
309
316
|
): Promise<WearableMemoryGenResult> {
|
|
310
317
|
const result: WearableMemoryGenResult = {
|
|
311
318
|
created: 0,
|
|
319
|
+
tombstoneBlocked: 0,
|
|
312
320
|
promoted: 0,
|
|
313
321
|
demoted: 0,
|
|
314
322
|
skipped: 0,
|
|
@@ -565,7 +573,7 @@ export async function generateWearableMemories(
|
|
|
565
573
|
wearableDayTag(date),
|
|
566
574
|
]),
|
|
567
575
|
];
|
|
568
|
-
await deps.writer.writeMemory(candidate.fact.category, candidate.fact.content, {
|
|
576
|
+
const writeResult = await deps.writer.writeMemory(candidate.fact.category, candidate.fact.content, {
|
|
569
577
|
confidence:
|
|
570
578
|
settings.memoryMode === "smart"
|
|
571
579
|
? trustById.get(index)?.trust
|
|
@@ -584,7 +592,14 @@ export async function generateWearableMemories(
|
|
|
584
592
|
contentHashSource: candidate.fact.content,
|
|
585
593
|
status,
|
|
586
594
|
});
|
|
587
|
-
|
|
595
|
+
// #1645: a tombstone-blocked wearable write lands pending_review (no active
|
|
596
|
+
// copy) — count it as blocked, NOT created, so the sync summary and callers
|
|
597
|
+
// don't report blocked content as successfully created active memories.
|
|
598
|
+
if (writeResult.tombstoneBlocked) {
|
|
599
|
+
result.tombstoneBlocked += 1;
|
|
600
|
+
} else {
|
|
601
|
+
result.created += 1;
|
|
602
|
+
}
|
|
588
603
|
}
|
|
589
604
|
return result;
|
|
590
605
|
}
|
|
@@ -654,8 +669,9 @@ export async function importNativeMemories(
|
|
|
654
669
|
alreadyImportedIds: ReadonlySet<string>,
|
|
655
670
|
settings: WearableSourceSettings,
|
|
656
671
|
deps: WearableMemoryGenDeps,
|
|
657
|
-
): Promise<{ imported: number; importedIds: string[]; warnings: string[] }> {
|
|
672
|
+
): Promise<{ imported: number; tombstoneBlocked: number; importedIds: string[]; warnings: string[] }> {
|
|
658
673
|
let imported = 0;
|
|
674
|
+
let tombstoneBlocked = 0;
|
|
659
675
|
const importedIds: string[] = [];
|
|
660
676
|
const warnings: string[] = [];
|
|
661
677
|
const seenContent = new Set<string>();
|
|
@@ -743,7 +759,7 @@ export async function importNativeMemories(
|
|
|
743
759
|
: {}),
|
|
744
760
|
};
|
|
745
761
|
}
|
|
746
|
-
await deps.writer.writeMemory("fact", content, {
|
|
762
|
+
const nativeWriteResult = await deps.writer.writeMemory("fact", content, {
|
|
747
763
|
confidence,
|
|
748
764
|
tags: [
|
|
749
765
|
...new Set([
|
|
@@ -764,8 +780,16 @@ export async function importNativeMemories(
|
|
|
764
780
|
contentHashSource: content,
|
|
765
781
|
status,
|
|
766
782
|
});
|
|
767
|
-
|
|
783
|
+
// #1645: a tombstone-blocked native import lands pending_review (no active
|
|
784
|
+
// copy) — count it as blocked, NOT imported. Still record the provider id in
|
|
785
|
+
// importedIds so the next sync doesn't re-import and duplicate the pending
|
|
786
|
+
// row; the block is permanent for this content.
|
|
787
|
+
if (nativeWriteResult.tombstoneBlocked) {
|
|
788
|
+
tombstoneBlocked += 1;
|
|
789
|
+
} else {
|
|
790
|
+
imported += 1;
|
|
791
|
+
}
|
|
768
792
|
importedIds.push(memory.id);
|
|
769
793
|
}
|
|
770
|
-
return { imported, importedIds, warnings };
|
|
794
|
+
return { imported, tombstoneBlocked, importedIds, warnings };
|
|
771
795
|
}
|