@remnic/core 9.45.3 → 9.45.5
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/abort-error.d.ts +2 -1
- package/dist/abort-error.js +3 -1
- package/dist/access-admin-ops-surface.d.ts +14 -10
- package/dist/access-admin-ops-surface.js +84 -75
- package/dist/access-audit.js +2 -2
- package/dist/access-authorization-probe.d.ts +14 -10
- package/dist/access-authorization-probe.js +85 -76
- package/dist/access-boundary.d.ts +15 -11
- package/dist/access-boundary.js +84 -75
- package/dist/access-citation-namespace.js +2 -2
- package/dist/access-cli.js +191 -177
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +16 -0
- package/dist/access-coding-context-resolution.js +13 -0
- package/dist/access-coding-context-resolution.js.map +1 -0
- package/dist/access-extraction-force-flush.d.ts +14 -10
- package/dist/access-extraction-force-flush.js +84 -75
- package/dist/access-health-types.d.ts +2 -1
- package/dist/access-http-lcm-compaction.d.ts +16 -12
- package/dist/access-http-lcm-compaction.js +3 -3
- package/dist/access-http-lifecycle-flush.d.ts +14 -10
- package/dist/access-http-lifecycle-flush.js +2 -2
- package/dist/access-http-offline-stream.d.ts +123 -0
- package/dist/access-http-offline-stream.js +10 -0
- package/dist/access-http-offline-stream.js.map +1 -0
- package/dist/access-http-query.js +84 -75
- package/dist/access-http.d.ts +15 -11
- package/dist/access-http.js +104 -90
- package/dist/access-identity-continuity-surface.d.ts +9 -8
- package/dist/access-identity-continuity-surface.js +84 -75
- package/dist/access-lcm-surface.d.ts +14 -10
- package/dist/access-lcm-surface.js +84 -75
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +14 -10
- package/dist/access-mcp.js +95 -82
- package/dist/access-memory-search-fanout.d.ts +3 -2
- package/dist/{access-namespace-preflight-5yZ4g6F8.d.ts → access-namespace-preflight-CWUDwB4M.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +4 -3
- package/dist/access-namespace-preflight.js +84 -75
- package/dist/access-observe-helpers.d.ts +1 -0
- package/dist/access-observe-helpers.js +1 -1
- package/dist/access-observe-write-surface.d.ts +16 -10
- package/dist/access-observe-write-surface.js +84 -75
- package/dist/access-offline-manifest.d.ts +104 -0
- package/dist/access-offline-manifest.js +45 -0
- package/dist/access-offline-manifest.js.map +1 -0
- package/dist/access-operations-batch.js +86 -77
- package/dist/access-operations.d.ts +18 -14
- package/dist/access-operations.js +91 -79
- package/dist/access-recall-concurrency.d.ts +16 -26
- package/dist/access-recall-concurrency.js +86 -76
- package/dist/access-recall-response.d.ts +18 -14
- package/dist/access-recall-response.js +84 -75
- package/dist/access-recall-surface.d.ts +29 -24
- package/dist/access-recall-surface.js +84 -75
- package/dist/access-schema.d.ts +84 -84
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-CiJRsgAB.d.ts → access-service-CNN89xyn.d.ts} +25 -16
- package/dist/access-service-helpers.d.ts +14 -10
- package/dist/access-service.d.ts +14 -10
- package/dist/access-service.js +84 -75
- package/dist/access-surface-catalog.d.ts +14 -10
- package/dist/access-surface-catalog.js +4 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +4 -3
- package/dist/action-confidence.d.ts +2 -1
- package/dist/active-memory-bridge.d.ts +2 -1
- package/dist/active-recall.d.ts +2 -1
- package/dist/active-recall.js +10 -8
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/{auto-sync-5OE5QOZB.js → auto-sync-UPTUVE4X.js} +6 -6
- package/dist/behavior-learner.d.ts +2 -1
- package/dist/behavior-learner.js +1 -1
- package/dist/behavior-signals.d.ts +2 -1
- package/dist/bootstrap.d.ts +9 -8
- package/dist/briefing.d.ts +3 -2
- package/dist/briefing.js +24 -22
- package/dist/buffer-surprise-report.d.ts +2 -1
- package/dist/buffer-turn-helpers.d.ts +2 -1
- package/dist/buffer.d.ts +3 -2
- package/dist/buffer.js +12 -11
- package/dist/bulk-import/index.d.ts +4 -3
- package/dist/calibration.d.ts +2 -1
- package/dist/capabilities.d.ts +2 -1
- package/dist/{capsule-merge-IDWJPCWK.js → capsule-merge-Q6AR3XL7.js} +67 -54
- package/dist/capsule-merge-Q6AR3XL7.js.map +1 -0
- package/dist/{catalog-scBmy0sO.d.ts → catalog-bctMURhN.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +2 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +2 -1
- package/dist/causal-consolidation.js +28 -26
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +2 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-E5UK4VPE.js → chunk-2FSTB6BJ.js} +5 -5
- package/dist/{chunk-5ZE7QHTK.js → chunk-2X2T2UVE.js} +5 -5
- package/dist/{chunk-P4DRWEYC.js → chunk-3COYXTGM.js} +2 -2
- package/dist/{chunk-5IVLTFOV.js → chunk-44N6ESJ4.js} +2 -2
- package/dist/{chunk-DL7ZD3JH.js → chunk-4FBVAGV3.js} +14 -9
- package/dist/chunk-4FBVAGV3.js.map +1 -0
- package/dist/{chunk-WOCNN776.js → chunk-4POAMKV6.js} +100 -41
- package/dist/chunk-4POAMKV6.js.map +1 -0
- package/dist/{chunk-HO3QBJEY.js → chunk-5546W5SI.js} +2 -2
- package/dist/{chunk-AAIUERNB.js → chunk-5QJQHBLE.js} +6 -6
- package/dist/{chunk-6CZPDBJS.js → chunk-5U7ID3EZ.js} +3 -3
- package/dist/{chunk-RN7DY3FC.js → chunk-6ISC4AVB.js} +31 -12
- package/dist/chunk-6ISC4AVB.js.map +1 -0
- package/dist/chunk-773TRRGT.js +36 -0
- package/dist/chunk-773TRRGT.js.map +1 -0
- package/dist/chunk-7T4TOGMS.js +242 -0
- package/dist/chunk-7T4TOGMS.js.map +1 -0
- package/dist/{chunk-DLVPUX7U.js → chunk-7YKVM5H3.js} +8 -6
- package/dist/chunk-7YKVM5H3.js.map +1 -0
- package/dist/chunk-7YQ6ESEA.js +322 -0
- package/dist/chunk-7YQ6ESEA.js.map +1 -0
- package/dist/{chunk-DNWXFTLD.js → chunk-A4IJCD2Z.js} +2 -2
- package/dist/{chunk-3CE77VAP.js → chunk-A4JMGKCD.js} +87 -74
- package/dist/chunk-A4JMGKCD.js.map +1 -0
- package/dist/chunk-A5KNZSNA.js +26 -0
- package/dist/chunk-A5KNZSNA.js.map +1 -0
- package/dist/{chunk-PKNLM44P.js → chunk-AC5OWJLV.js} +9 -9
- package/dist/{chunk-LZ4LDKHZ.js → chunk-AMAUBUKY.js} +6 -6
- package/dist/{chunk-CUM2BBPN.js → chunk-AUMWZSE7.js} +19 -10
- package/dist/chunk-AUMWZSE7.js.map +1 -0
- package/dist/{chunk-BUE5E2HL.js → chunk-BGLY7EEM.js} +5 -314
- package/dist/chunk-BGLY7EEM.js.map +1 -0
- package/dist/chunk-BIPBQQFI.js +44 -0
- package/dist/chunk-BIPBQQFI.js.map +1 -0
- package/dist/{chunk-S5SLVSVY.js → chunk-BQIFZ2MP.js} +5 -5
- package/dist/chunk-BTTPKDIL.js +34 -0
- package/dist/{chunk-PVGDJXVK.js.map → chunk-BTTPKDIL.js.map} +1 -1
- package/dist/chunk-CK5KOVHW.js +69 -0
- package/dist/chunk-CK5KOVHW.js.map +1 -0
- package/dist/{chunk-Q6IP2ARR.js → chunk-CSOYVTRX.js} +2 -2
- package/dist/{chunk-XOQSEF7X.js → chunk-CVILPI77.js} +6 -6
- package/dist/{chunk-VWAXN2BN.js → chunk-CX4ZUMC6.js} +91 -83
- package/dist/chunk-CX4ZUMC6.js.map +1 -0
- package/dist/{chunk-NVRYW264.js → chunk-DAJPRXBR.js} +16 -13
- package/dist/chunk-DAJPRXBR.js.map +1 -0
- package/dist/{chunk-J7VGGECD.js → chunk-DZPFMQZ7.js} +1 -1
- package/dist/chunk-DZPFMQZ7.js.map +1 -0
- package/dist/{chunk-4LMA77JH.js → chunk-E5XQIWAL.js} +3 -3
- package/dist/{chunk-WUNIWKY4.js → chunk-ELIL2A37.js} +6 -6
- package/dist/{chunk-OQ5PRDDS.js → chunk-ERZ2R42X.js} +6 -6
- package/dist/{chunk-U7GW7NE7.js → chunk-FIK3CQNA.js} +10 -10
- package/dist/{chunk-D3J5SLQK.js → chunk-FR27HBBA.js} +81 -20
- package/dist/chunk-FR27HBBA.js.map +1 -0
- package/dist/{chunk-E6PNLPGJ.js → chunk-FUCYDRE5.js} +838 -480
- package/dist/chunk-FUCYDRE5.js.map +1 -0
- package/dist/{chunk-HZFHQ4AQ.js → chunk-G7A5HLUS.js} +23 -17
- package/dist/chunk-G7A5HLUS.js.map +1 -0
- package/dist/{chunk-33PLLLL7.js → chunk-GFCVUY6G.js} +6 -6
- package/dist/{chunk-HREE4JHI.js → chunk-GODSPTOT.js} +477 -278
- package/dist/chunk-GODSPTOT.js.map +1 -0
- package/dist/{chunk-S2NCTZGJ.js → chunk-GRUYA45P.js} +15 -15
- package/dist/chunk-GRUYA45P.js.map +1 -0
- package/dist/{chunk-VUPTKTDV.js → chunk-GUAL4PQH.js} +3 -3
- package/dist/{chunk-CINZGPSJ.js → chunk-GUMZC2BO.js} +2 -2
- package/dist/{chunk-H24WNPA2.js → chunk-GWFSVJ4P.js} +3 -3
- package/dist/{chunk-7XC2HX75.js → chunk-GYPQL6XN.js} +157 -16
- package/dist/chunk-GYPQL6XN.js.map +1 -0
- package/dist/{chunk-TSH56VPU.js → chunk-HAYSYUAB.js} +2 -2
- package/dist/{chunk-PDLBLTOK.js → chunk-HC3PBX23.js} +9 -9
- package/dist/{chunk-TDHTVMPG.js → chunk-HFPASSFV.js} +7 -2
- package/dist/chunk-HFPASSFV.js.map +1 -0
- package/dist/chunk-J2WC5LF4.js +395 -0
- package/dist/chunk-J2WC5LF4.js.map +1 -0
- package/dist/{chunk-KXB4VXHY.js → chunk-JIYDRBVZ.js} +2 -2
- package/dist/chunk-JV3C2MNQ.js +74 -0
- package/dist/chunk-JV3C2MNQ.js.map +1 -0
- package/dist/{chunk-HLPD7B7P.js → chunk-JZH4LWHB.js} +2 -2
- package/dist/{chunk-AV5ZEH4M.js → chunk-KVJRXN2E.js} +2 -2
- package/dist/{chunk-WFTIGIIS.js → chunk-L6CQ7WIW.js} +5 -5
- package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
- package/dist/{chunk-EJUEXZHX.js → chunk-LLJMAULE.js} +2 -2
- package/dist/{chunk-N5Z4EVOR.js → chunk-LNEWDF2A.js} +36 -11
- package/dist/chunk-LNEWDF2A.js.map +1 -0
- package/dist/{chunk-QN25OCUF.js → chunk-LPYDOLSM.js} +5 -5
- package/dist/{chunk-AS7YMSL6.js → chunk-M23RF3LJ.js} +4 -4
- package/dist/{chunk-OAEQLRCY.js → chunk-MO4HSXHZ.js} +5 -5
- package/dist/{chunk-ECK75GDJ.js → chunk-N3LL5NEU.js} +43 -24
- package/dist/chunk-N3LL5NEU.js.map +1 -0
- package/dist/chunk-NEF7LR5J.js +29 -0
- package/dist/chunk-NEF7LR5J.js.map +1 -0
- package/dist/{chunk-3F2LKUMU.js → chunk-NIS256NW.js} +2 -2
- package/dist/{chunk-YIAA2X3D.js → chunk-NK5RGJ65.js} +3 -3
- package/dist/chunk-NLDVVWCL.js +84 -0
- package/dist/chunk-NLDVVWCL.js.map +1 -0
- package/dist/{chunk-4J7G5SY4.js → chunk-NZBZ7IS2.js} +72 -24
- package/dist/chunk-NZBZ7IS2.js.map +1 -0
- package/dist/{chunk-3TBLDMJA.js → chunk-O4KMGRXE.js} +5 -2
- package/dist/chunk-O4KMGRXE.js.map +1 -0
- package/dist/{chunk-7TWUCYER.js → chunk-PNRA7FAD.js} +7 -7
- package/dist/{chunk-5I4M26Q7.js → chunk-QBSFOKY6.js} +4 -4
- package/dist/{chunk-E53DSZEN.js → chunk-QR6G5KF4.js} +3 -3
- package/dist/{chunk-CJ2ZR7UA.js → chunk-QUENPGWZ.js} +261 -211
- package/dist/chunk-QUENPGWZ.js.map +1 -0
- package/dist/{chunk-4UH4BTGK.js → chunk-QVJPH7SH.js} +84 -84
- package/dist/{chunk-UYLMNVY6.js → chunk-R3KHKU7M.js} +16 -9
- package/dist/chunk-R3KHKU7M.js.map +1 -0
- package/dist/{chunk-JBPKEARU.js → chunk-RKNJBZ55.js} +4 -4
- package/dist/{chunk-WDISJRMG.js → chunk-RMMVQQA6.js} +2 -2
- package/dist/{chunk-JVLCVFQ4.js → chunk-RNHVVMFN.js} +3 -3
- package/dist/{chunk-QJAQNXWI.js → chunk-RVO6TCTU.js} +81 -84
- package/dist/chunk-RVO6TCTU.js.map +1 -0
- package/dist/chunk-S2HLHAZ4.js +16 -0
- package/dist/chunk-S2HLHAZ4.js.map +1 -0
- package/dist/{chunk-KWMXR7XS.js → chunk-S2V7RUCL.js} +8 -1
- package/dist/{chunk-KWMXR7XS.js.map → chunk-S2V7RUCL.js.map} +1 -1
- package/dist/{chunk-5SM35XZR.js → chunk-S5NZBKKQ.js} +2 -2
- package/dist/{chunk-VNA7W7QF.js → chunk-SVH57F5Z.js} +12 -4
- package/dist/chunk-SVH57F5Z.js.map +1 -0
- package/dist/{chunk-WIPEXG6R.js → chunk-SXIMQLGV.js} +2 -2
- package/dist/{chunk-RVLJEII5.js → chunk-SYUBB3WM.js} +256 -187
- package/dist/chunk-SYUBB3WM.js.map +1 -0
- package/dist/{chunk-VCD4PSK2.js → chunk-TQZ4DVBC.js} +7 -4
- package/dist/chunk-TQZ4DVBC.js.map +1 -0
- package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
- package/dist/{chunk-YV32N67O.js → chunk-URS5GSM7.js} +1 -1
- package/dist/chunk-URS5GSM7.js.map +1 -0
- package/dist/{chunk-4B77XSG5.js → chunk-UV72DEZD.js} +5 -5
- package/dist/{chunk-BJKPPZ6Z.js → chunk-UW66OZTD.js} +2 -2
- package/dist/{chunk-XYTOI63Z.js → chunk-V2TNYF6Q.js} +19 -11
- package/dist/chunk-V2TNYF6Q.js.map +1 -0
- package/dist/{chunk-S2BBISHU.js → chunk-VANZKHTN.js} +3 -3
- package/dist/chunk-VHFXP27N.js +250 -0
- package/dist/chunk-VHFXP27N.js.map +1 -0
- package/dist/chunk-VL35ZFSZ.js +102 -0
- package/dist/chunk-VL35ZFSZ.js.map +1 -0
- package/dist/{chunk-3Y224NYC.js → chunk-VYISFWVX.js} +2 -2
- package/dist/{chunk-JE7EK33X.js → chunk-W2V7UESE.js} +2 -2
- package/dist/{chunk-TIHMZFIV.js → chunk-W3IC7QOY.js} +3 -3
- package/dist/{chunk-NRV4Y3PM.js → chunk-W4FBGYGK.js} +1 -1
- package/dist/{chunk-P2BM76KT.js → chunk-WAS4HV46.js} +174 -43
- package/dist/chunk-WAS4HV46.js.map +1 -0
- package/dist/{chunk-57QKLRBV.js → chunk-WB7JSQCP.js} +2 -1
- package/dist/chunk-WB7JSQCP.js.map +1 -0
- package/dist/{chunk-A5OJCXZL.js → chunk-WZ3TOIDW.js} +15 -4
- package/dist/chunk-WZ3TOIDW.js.map +1 -0
- package/dist/{chunk-MU7ZHSZE.js → chunk-WZFAPHIK.js} +2 -2
- package/dist/{chunk-T2TTP3KU.js → chunk-X4IDNPOS.js} +2 -2
- package/dist/{chunk-UVIKWC7M.js → chunk-XAGYS7X6.js} +17 -17
- package/dist/{chunk-BLAKS3CP.js → chunk-XL3TATMJ.js} +3 -3
- package/dist/{chunk-W4XJFLAL.js → chunk-XPRJSHNI.js} +2 -2
- package/dist/{chunk-5TFP4CUL.js → chunk-XQ3HXAQH.js} +14 -11
- package/dist/chunk-XQ3HXAQH.js.map +1 -0
- package/dist/{chunk-E6EE5B67.js → chunk-YK6BDDHP.js} +4 -4
- package/dist/{chunk-ES36HTSC.js → chunk-YLHM5BQQ.js} +3 -3
- package/dist/{chunk-ULARSG5Z.js → chunk-YN6ASZUG.js} +10 -8
- package/dist/{chunk-ULARSG5Z.js.map → chunk-YN6ASZUG.js.map} +1 -1
- package/dist/{chunk-VOUOLGIP.js → chunk-YRFAYOFQ.js} +11 -13
- package/dist/chunk-YRFAYOFQ.js.map +1 -0
- package/dist/{chunk-IKKWIPYN.js → chunk-YYQAKIDJ.js} +37 -1
- package/dist/chunk-YYQAKIDJ.js.map +1 -0
- package/dist/{chunk-GF22HWS2.js → chunk-Z54EM5YZ.js} +4 -4
- package/dist/{chunk-64UDOIMI.js → chunk-ZLQ37WJX.js} +2 -2
- package/dist/{cli-BUGN3d6_.d.ts → cli-BHBswmUa.d.ts} +5 -5
- package/dist/cli.d.ts +16 -12
- package/dist/cli.js +138 -123
- package/dist/compounding/engine.d.ts +3 -2
- package/dist/compounding/engine.js +25 -23
- package/dist/compounding/preference-consolidator.d.ts +2 -1
- package/dist/compression-optimizer.d.ts +2 -1
- package/dist/config.d.ts +2 -1
- package/dist/config.js +10 -8
- package/dist/connectors/codex-materialize-runner.d.ts +2 -1
- package/dist/connectors/codex-materialize-runner.js +24 -22
- package/dist/connectors/codex-materialize.d.ts +2 -1
- package/dist/connectors/index.d.ts +2 -1
- package/dist/connectors/index.js +27 -25
- package/dist/consolidation-provenance-check.d.ts +3 -2
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.d.ts +3 -2
- package/dist/consolidation-undo.js +10 -7
- package/dist/consolidation-undo.js.map +1 -1
- package/dist/contradiction/index.d.ts +3 -2
- package/dist/converge-config.d.ts +2 -1
- package/dist/convergence-refresh.d.ts +4 -3
- package/dist/convergence-refresh.js +28 -26
- package/dist/conversation-index/backend.d.ts +2 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +2 -1
- package/dist/conversation-index/faiss-adapter.d.ts +2 -1
- package/dist/conversation-index/indexer.d.ts +2 -1
- package/dist/conversation-index/search.d.ts +2 -1
- package/dist/corpus-watermark.d.ts +2 -1
- package/dist/corpus-watermark.js +43 -41
- package/dist/day-summary.d.ts +2 -1
- package/dist/delinearize.d.ts +2 -1
- package/dist/direct-answer-wiring.d.ts +2 -1
- package/dist/direct-answer-wiring.js +2 -2
- package/dist/direct-answer.d.ts +2 -1
- package/dist/embedding-fallback.d.ts +2 -1
- package/dist/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +2 -1
- package/dist/entity-retrieval-boundaries.js +1 -1
- package/dist/entity-retrieval.d.ts +3 -2
- package/dist/entity-retrieval.js +25 -23
- package/dist/entity-schema.d.ts +2 -1
- package/dist/explicit-capture.d.ts +9 -8
- package/dist/explicit-capture.js +11 -9
- package/dist/external-wiki-access.d.ts +127 -0
- package/dist/external-wiki-access.js +187 -0
- package/dist/external-wiki-access.js.map +1 -0
- package/dist/external-wiki-cli.d.ts +13 -0
- package/dist/external-wiki-cli.js +10 -0
- package/dist/external-wiki-cli.js.map +1 -0
- package/dist/external-wiki-collection-registration.d.ts +39 -0
- package/dist/external-wiki-collection-registration.js +79 -0
- package/dist/external-wiki-collection-registration.js.map +1 -0
- package/dist/external-wiki-collection.d.ts +50 -0
- package/dist/external-wiki-collection.js +387 -0
- package/dist/external-wiki-collection.js.map +1 -0
- package/dist/external-wiki-config.d.ts +13 -0
- package/dist/external-wiki-config.js +13 -0
- package/dist/external-wiki-config.js.map +1 -0
- package/dist/external-wiki-guard.d.ts +11 -0
- package/dist/external-wiki-guard.js +18 -0
- package/dist/external-wiki-guard.js.map +1 -0
- package/dist/external-wiki-mcp-tools.d.ts +123 -0
- package/dist/external-wiki-mcp-tools.js +8 -0
- package/dist/external-wiki-mcp-tools.js.map +1 -0
- package/dist/external-wiki-search.d.ts +42 -0
- package/dist/external-wiki-search.js +11 -0
- package/dist/external-wiki-search.js.map +1 -0
- package/dist/external-wiki.d.ts +39 -0
- package/dist/external-wiki.js +14 -0
- package/dist/external-wiki.js.map +1 -0
- package/dist/extraction-error-classification.d.ts +2 -1
- package/dist/extraction-faithfulness.d.ts +2 -1
- package/dist/extraction-judge-telemetry.d.ts +2 -1
- package/dist/extraction-judge-training.d.ts +2 -1
- package/dist/extraction-judge.d.ts +2 -1
- package/dist/extraction-liveness.d.ts +2 -1
- package/dist/extraction-source-grounding-helpers.d.ts +5 -3
- package/dist/extraction-source-grounding-helpers.js +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +2 -1
- package/dist/extraction-source-grounding-rules.js +2 -2
- package/dist/extraction-source-grounding.d.ts +2 -1
- package/dist/extraction-source-grounding.js +5 -5
- package/dist/extraction.d.ts +2 -1
- package/dist/extraction.js +46 -43
- package/dist/fallback-llm.d.ts +2 -1
- package/dist/{first-start-migration-F2QJD66E.js → first-start-migration-ZSHEFEI3.js} +10 -12
- package/dist/{first-start-migration-F2QJD66E.js.map → first-start-migration-ZSHEFEI3.js.map} +1 -1
- package/dist/graph-dashboard-diff.d.ts +2 -1
- package/dist/graph-dashboard-key.d.ts +2 -1
- package/dist/graph-dashboard-parser.d.ts +2 -1
- package/dist/graph-edge-reinforcement.d.ts +2 -1
- package/dist/graph-snapshot.d.ts +2 -1
- package/dist/graph.d.ts +2 -1
- package/dist/harmonic-retrieval.js +2 -2
- package/dist/importance.d.ts +2 -1
- package/dist/importers/index.d.ts +2 -1
- package/dist/in-flight-reads.d.ts +2 -1
- package/dist/index.d.ts +443 -430
- package/dist/index.js +304 -269
- package/dist/intent.d.ts +2 -1
- package/dist/lcm/engine.d.ts +2 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +2 -1
- package/dist/lcm/index.js +7 -7
- package/dist/lcm/tools.d.ts +2 -1
- package/dist/lifecycle.d.ts +2 -1
- package/dist/live-connectors-runner.d.ts +2 -1
- package/dist/local-llm.d.ts +2 -1
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +2 -1
- package/dist/maintenance/memory-governance.d.ts +2 -1
- package/dist/maintenance/memory-governance.js +25 -23
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +25 -23
- package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-projection.js +27 -25
- package/dist/{maintenance-LbuS2rUA.d.ts → maintenance-CoRikzIt.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +14 -10
- package/dist/mcp-read-only-tools.js +1 -1
- package/dist/memory-action-policy.d.ts +2 -1
- package/dist/memory-cache.d.ts +2 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
- package/dist/memory-projection-store.d.ts +2 -1
- package/dist/memory-provenance.d.ts +2 -1
- package/dist/memory-snapshot.d.ts +10 -0
- package/dist/memory-snapshot.js +8 -0
- package/dist/memory-snapshot.js.map +1 -0
- package/dist/memory-worth-outcomes.d.ts +3 -2
- package/dist/models-json.d.ts +2 -1
- package/dist/namespaces/migrate.d.ts +4 -3
- package/dist/namespaces/migrate.js +41 -39
- package/dist/namespaces/principal.d.ts +2 -1
- package/dist/namespaces/search.d.ts +2 -1
- package/dist/namespaces/search.js +18 -18
- package/dist/namespaces/storage.d.ts +4 -3
- package/dist/namespaces/storage.js +24 -22
- package/dist/native-knowledge.d.ts +2 -1
- package/dist/offline-sync-impression-drain.d.ts +2 -1
- package/dist/offline-sync-impression-drain.js +11 -9
- package/dist/offline-sync.d.ts +29 -3
- package/dist/offline-sync.js +6 -2
- package/dist/operator-doctor-corpus.d.ts +2 -1
- package/dist/operator-doctor-corpus.js +46 -44
- package/dist/operator-doctor-replica.d.ts +2 -1
- package/dist/operator-doctor-replica.js +3 -3
- package/dist/operator-toolkit.d.ts +4 -3
- package/dist/operator-toolkit.js +60 -55
- package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
- package/dist/orchestration/maintenance.d.ts +5 -4
- package/dist/orchestration/maintenance.js +37 -33
- package/dist/{orchestrator-rHiWt32X.d.ts → orchestrator-BJeq7Pw1.d.ts} +14 -7
- package/dist/orchestrator.d.ts +9 -8
- package/dist/orchestrator.js +200 -186
- package/dist/page-versioning.js +3 -3
- package/dist/patterns-cli.d.ts +2 -1
- package/dist/{pipeline-W_97O8BV.d.ts → pipeline-CNjY4wk3.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +2 -1
- package/dist/policy-runtime.js +1 -1
- package/dist/proactive-contention.d.ts +2 -1
- package/dist/provenance.d.ts +2 -1
- package/dist/provenance.js +2 -2
- package/dist/{qmd-LWtMofAf.d.ts → qmd-C0UDZidt.d.ts} +9 -7
- package/dist/qmd-preflight.d.ts +5 -4
- package/dist/qmd-preflight.js +2 -2
- package/dist/qmd-recall-cache.d.ts +2 -1
- package/dist/qmd.d.ts +4 -3
- package/dist/qmd.js +8 -8
- package/dist/recall-concurrency-config.d.ts +2 -1
- package/dist/recall-disclosure-escalation.d.ts +2 -1
- package/dist/recall-explain-renderer.d.ts +2 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +2 -1
- package/dist/recall-planner-llm.d.ts +2 -1
- package/dist/recall-state.d.ts +2 -1
- package/dist/recall-tag-filter.d.ts +2 -1
- package/dist/recall-timings.d.ts +2 -1
- package/dist/recall-xray-cli.d.ts +2 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +2 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +8 -1
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.d.ts +12 -2
- package/dist/reconcile/cursor.js +46 -7
- package/dist/reconcile/cursor.js.map +1 -1
- package/dist/reconcile/manifest.d.ts +9 -2
- package/dist/reconcile/manifest.js +15 -268
- package/dist/reconcile/manifest.js.map +1 -1
- package/dist/reconcile/plan.d.ts +4 -1
- package/dist/reconcile/plan.js +4 -4
- package/dist/replay/normalizers/chatgpt.d.ts +2 -1
- package/dist/replay/normalizers/claude.d.ts +2 -1
- package/dist/replay/normalizers/openclaw.d.ts +2 -1
- package/dist/replay/normalizers/shared.d.ts +2 -1
- package/dist/replay/runner.d.ts +2 -1
- package/dist/replay/types.d.ts +2 -1
- package/dist/replica-divergence.d.ts +2 -1
- package/dist/replica-divergence.js +2 -2
- package/dist/replica-peers-config.d.ts +2 -1
- package/dist/resolve-auth-token.d.ts +2 -1
- package/dist/resume-bundles.js +12 -10
- package/dist/retrieval-agents.d.ts +4 -3
- package/dist/retrieval-agents.js +2 -2
- package/dist/retrieval-tiers.d.ts +2 -1
- package/dist/routing/engine.d.ts +2 -1
- package/dist/routing/store.d.ts +2 -1
- package/dist/salvage-envelope.d.ts +2 -1
- package/dist/schemas.d.ts +54 -54
- package/dist/{scope-profiles-BiQKOE-p.d.ts → scope-profiles-BJzp2F5A.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +2 -1
- package/dist/search/embed-helper.js +3 -3
- package/dist/search/factory.d.ts +4 -2
- package/dist/search/factory.js +20 -18
- package/dist/search/index.d.ts +2 -1
- package/dist/search/index.js +20 -20
- package/dist/search/lancedb-backend.d.ts +2 -1
- package/dist/search/lancedb-backend.js +4 -4
- package/dist/search/meilisearch-backend.d.ts +2 -1
- package/dist/search/meilisearch-backend.js +4 -4
- package/dist/search/noop-backend.d.ts +2 -1
- package/dist/search/orama-backend.d.ts +2 -1
- package/dist/search/orama-backend.js +4 -4
- package/dist/search/port.d.ts +18 -1
- package/dist/search/port.js +1 -1
- package/dist/search/remote-backend.d.ts +2 -1
- package/dist/search/remote-backend.js +2 -2
- package/dist/secure-store/index.js +2 -2
- package/dist/{semantic-consolidation-dHYCyqgh.d.ts → semantic-consolidation-D4KAZO2G.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +3 -2
- package/dist/semantic-consolidation.js +26 -24
- package/dist/semantic-rule-promotion.js +24 -22
- package/dist/semantic-rule-verifier.d.ts +2 -1
- package/dist/semantic-rule-verifier.js +25 -23
- package/dist/{service-DJG3KCQ4.d.ts → service-DWC4tq7p.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +2 -1
- package/dist/session-observer-state.d.ts +2 -1
- package/dist/shared-context/manager.d.ts +10 -9
- package/dist/shared-context/manager.js +2 -2
- package/dist/signal.d.ts +2 -1
- package/dist/source-agent-qualifier.d.ts +2 -1
- package/dist/source-agent-qualifier.js +43 -40
- package/dist/{storage-F9FVh-w9.d.ts → storage-DPGjB-8e.d.ts} +28 -13
- package/dist/storage.d.ts +3 -2
- package/dist/storage.js +26 -24
- package/dist/summarizer.d.ts +2 -1
- package/dist/summarizer.js +5 -5
- package/dist/summary-snapshot.d.ts +2 -1
- package/dist/temporal-supersession.d.ts +3 -2
- package/dist/temporal-timeline-recall.d.ts +2 -1
- package/dist/temporal-validity.d.ts +2 -1
- package/dist/threading.d.ts +2 -1
- package/dist/tier-migration.d.ts +3 -2
- package/dist/tier-migration.js +1 -1
- package/dist/tier-routing.d.ts +2 -1
- package/dist/tool-scoped-memory.d.ts +5 -1
- package/dist/tool-scoped-memory.js +3 -1
- package/dist/topics.d.ts +2 -1
- package/dist/transcript.d.ts +2 -1
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/transfer/types.d.ts +66 -66
- package/dist/trust-score-stage.d.ts +2 -1
- package/dist/trust-score.d.ts +2 -1
- package/dist/{types-rEwubvim.d.ts → types-yX_FwERf.d.ts} +8 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +2 -1
- package/dist/verified-recall.js +25 -23
- package/dist/write-envelope.d.ts +2 -1
- package/package.json +2 -2
- package/src/abort-error.ts +17 -0
- package/src/access-admin-ops-surface.ts +1 -0
- package/src/access-boundary.ts +1 -0
- package/src/access-coding-context-resolution.ts +42 -0
- package/src/access-extraction-force-flush.ts +38 -2
- package/src/access-http-lcm-compaction.ts +5 -2
- package/src/access-http-offline-stream.ts +80 -0
- package/src/access-http.test.ts +310 -3
- package/src/access-http.ts +84 -77
- package/src/access-mcp-output-schemas.ts +36 -0
- package/src/access-mcp.test.ts +95 -1
- package/src/access-mcp.ts +7 -9
- package/src/access-observe-helpers.ts +64 -22
- package/src/access-observe-write-surface.ts +8 -0
- package/src/access-offline-manifest.ts +54 -0
- package/src/access-operations-batch.ts +3 -3
- package/src/access-operations.ts +13 -7
- package/src/access-recall-concurrency.ts +3 -27
- package/src/access-recall-surface.ts +3 -0
- package/src/access-service-health.test.ts +32 -7
- package/src/access-service-namespace.test.ts +55 -0
- package/src/access-service-observe-idempotency.test.ts +34 -2
- package/src/access-service-observe-lcm-parity.test.ts +183 -23
- package/src/access-service-observe-scope.test.ts +160 -1
- package/src/access-service-offline-file-content.test.ts +345 -1
- package/src/access-service.ts +88 -62
- package/src/access-surface-catalog.ts +4 -0
- package/src/admin/admin-surfaces.ts +2 -0
- package/src/binary-lifecycle/pipeline.test.ts +106 -1
- package/src/binary-lifecycle/pipeline.ts +3 -0
- package/src/coding/git-context.test.ts +47 -0
- package/src/coding/git-context.ts +129 -27
- package/src/config.test.ts +24 -0
- package/src/config.ts +9 -12
- package/src/connector-provenance.test.ts +101 -0
- package/src/consolidation-undo.ts +3 -0
- package/src/convergence-refresh.ts +14 -2
- package/src/correction/correction-access-wiring.ts +9 -7
- package/src/correction/correction-executor.test.ts +206 -2
- package/src/correction/correction-executor.ts +29 -20
- package/src/correction/correction-planner.test.ts +36 -0
- package/src/correction/correction-planner.ts +9 -15
- package/src/correction/correction-service.ts +3 -1
- package/src/correction/correction-storage-integration.test.ts +77 -0
- package/src/correction/correction-surfaces.test.ts +41 -28
- package/src/correction/passive-capture.test.ts +59 -0
- package/src/correction/passive-capture.ts +4 -1
- package/src/entity-retrieval-boundaries.ts +17 -4
- package/src/entity-retrieval.ts +27 -6
- package/src/external-wiki-access.test.ts +65 -0
- package/src/external-wiki-access.ts +31 -0
- package/src/external-wiki-cli.ts +100 -0
- package/src/external-wiki-collection-registration.test.ts +163 -0
- package/src/external-wiki-collection-registration.ts +101 -0
- package/src/external-wiki-collection.test.ts +502 -0
- package/src/external-wiki-collection.ts +503 -0
- package/src/external-wiki-config.test.ts +135 -0
- package/src/external-wiki-config.ts +100 -0
- package/src/external-wiki-guard.ts +83 -0
- package/src/external-wiki-mcp-tools.ts +23 -0
- package/src/external-wiki-search.test.ts +367 -0
- package/src/external-wiki-search.ts +362 -0
- package/src/external-wiki.test.ts +240 -0
- package/src/external-wiki.ts +427 -0
- package/src/extraction-scope-source-agent.test.ts +21 -0
- package/src/extraction-source-grounding-helpers.ts +243 -53
- package/src/extraction-source-grounding-rules.ts +133 -39
- package/src/extraction-source-grounding.test.ts +363 -33
- package/src/extraction-timeout.test.ts +1 -0
- package/src/extraction-watermark.test.ts +150 -7
- package/src/extraction.ts +8 -1
- package/src/index.ts +9 -5
- package/src/maintenance/first-start-migration.ts +11 -11
- package/src/mcp-read-only-tools.ts +1 -0
- package/src/memory-snapshot.ts +15 -0
- package/src/offline-sync.test.ts +194 -0
- package/src/offline-sync.ts +217 -13
- package/src/orchestration/external-wiki-recall-guard.test.ts +94 -0
- package/src/orchestration/extraction-persist.ts +19 -2
- package/src/orchestration/extraction-run-helpers.ts +37 -19
- package/src/orchestration/extraction-run.test.ts +171 -2
- package/src/orchestration/extraction-run.ts +11 -13
- package/src/orchestration/extraction-watermark.ts +106 -17
- package/src/orchestration/generic-recall-paths.ts +14 -0
- package/src/orchestration/orchestrator-helpers.ts +2 -0
- package/src/orchestration/orchestrator-init.ts +9 -0
- package/src/orchestration/recall-internal-deps.ts +6 -0
- package/src/orchestration/recall-internal.ts +154 -33
- package/src/orchestration/recall-rerank-coordinator.ts +60 -25
- package/src/orchestration/recall-search-pipeline.test.ts +75 -1
- package/src/orchestration/recall-search-pipeline.ts +50 -10
- package/src/orchestrator-convergence-refresh.test.ts +36 -2
- package/src/orchestrator.ts +13 -3
- package/src/page-versioning.ts +5 -19
- package/src/procedural/procedure-recall.ts +5 -1
- package/src/provenance-surfaces.test.ts +3 -0
- package/src/qmd-client.test.ts +78 -17
- package/src/qmd.test.ts +24 -0
- package/src/qmd.ts +224 -315
- package/src/recall-explain-renderer.ts +3 -0
- package/src/recall-rerank-coordinator.test.ts +61 -0
- package/src/recall-xray-renderer.test.ts +6 -0
- package/src/recall-xray.test.ts +88 -1
- package/src/recall-xray.ts +15 -0
- package/src/reconcile/cursor.test.ts +48 -0
- package/src/reconcile/cursor.ts +58 -11
- package/src/reconcile/manifest.test.ts +4 -0
- package/src/reconcile/manifest.ts +41 -51
- package/src/reconcile/plan.test.ts +4 -0
- package/src/reconcile/plan.ts +28 -16
- package/src/search/factory.ts +6 -6
- package/src/search/port.ts +25 -9
- package/src/secure-store/secure-fs.ts +20 -12
- package/src/secure-store/secure-store.test.ts +41 -2
- package/src/spaces/index.test.ts +61 -2
- package/src/spaces/index.ts +44 -18
- package/src/storage/entity-alias-config.ts +97 -0
- package/src/storage/entity-canonical-id-lock.ts +53 -23
- package/src/storage/entity-canonical-id-migration.ts +53 -22
- package/src/storage/entity-canonical-id-references.ts +3 -0
- package/src/storage/entity-id-safety.ts +7 -0
- package/src/storage/entity-store.ts +6 -2
- package/src/storage/memory-frontmatter-metadata.ts +4 -9
- package/src/storage/memory-migration-serialization.ts +10 -15
- package/src/storage/tombstone-blocked-capture-mutation.ts +52 -64
- package/src/storage/tombstone-blocked-capture-sync.ts +244 -199
- package/src/storage-contract/cache-coherence.test.ts +99 -0
- package/src/storage-deletion-revisions.test.ts +91 -0
- package/src/storage-fact-hash-index-defer.test.ts +460 -170
- package/src/storage.ts +572 -284
- package/src/testing/subjects/first-start-tier-migration.test.ts +75 -0
- package/src/tier-migration.ts +10 -12
- package/src/tool-scoped-memory.ts +10 -0
- package/src/transfer/capsule-import.ts +13 -0
- package/src/transfer/capsule-merge.ts +13 -0
- package/src/trust-score-recall-paths.test.ts +75 -1
- package/src/types.ts +7 -3
- package/dist/capsule-merge-IDWJPCWK.js.map +0 -1
- package/dist/chunk-3CE77VAP.js.map +0 -1
- package/dist/chunk-3TBLDMJA.js.map +0 -1
- package/dist/chunk-4J7G5SY4.js.map +0 -1
- package/dist/chunk-57QKLRBV.js.map +0 -1
- package/dist/chunk-5TFP4CUL.js.map +0 -1
- package/dist/chunk-7XC2HX75.js.map +0 -1
- package/dist/chunk-A5OJCXZL.js.map +0 -1
- package/dist/chunk-BUE5E2HL.js.map +0 -1
- package/dist/chunk-CJ2ZR7UA.js.map +0 -1
- package/dist/chunk-CUM2BBPN.js.map +0 -1
- package/dist/chunk-D3J5SLQK.js.map +0 -1
- package/dist/chunk-DL7ZD3JH.js.map +0 -1
- package/dist/chunk-DLVPUX7U.js.map +0 -1
- package/dist/chunk-E6PNLPGJ.js.map +0 -1
- package/dist/chunk-ECK75GDJ.js.map +0 -1
- package/dist/chunk-HREE4JHI.js.map +0 -1
- package/dist/chunk-HZFHQ4AQ.js.map +0 -1
- package/dist/chunk-IKKWIPYN.js.map +0 -1
- package/dist/chunk-J7VGGECD.js.map +0 -1
- package/dist/chunk-N5Z4EVOR.js.map +0 -1
- package/dist/chunk-NVRYW264.js.map +0 -1
- package/dist/chunk-P2BM76KT.js.map +0 -1
- package/dist/chunk-PVGDJXVK.js +0 -21
- package/dist/chunk-QJAQNXWI.js.map +0 -1
- package/dist/chunk-RN7DY3FC.js.map +0 -1
- package/dist/chunk-RVLJEII5.js.map +0 -1
- package/dist/chunk-S2NCTZGJ.js.map +0 -1
- package/dist/chunk-TDHTVMPG.js.map +0 -1
- package/dist/chunk-UYLMNVY6.js.map +0 -1
- package/dist/chunk-VCD4PSK2.js.map +0 -1
- package/dist/chunk-VNA7W7QF.js.map +0 -1
- package/dist/chunk-VOUOLGIP.js.map +0 -1
- package/dist/chunk-VWAXN2BN.js.map +0 -1
- package/dist/chunk-WOCNN776.js.map +0 -1
- package/dist/chunk-XYTOI63Z.js.map +0 -1
- package/dist/chunk-YV32N67O.js.map +0 -1
- /package/dist/{auto-sync-5OE5QOZB.js.map → auto-sync-UPTUVE4X.js.map} +0 -0
- /package/dist/{chunk-E5UK4VPE.js.map → chunk-2FSTB6BJ.js.map} +0 -0
- /package/dist/{chunk-5ZE7QHTK.js.map → chunk-2X2T2UVE.js.map} +0 -0
- /package/dist/{chunk-P4DRWEYC.js.map → chunk-3COYXTGM.js.map} +0 -0
- /package/dist/{chunk-5IVLTFOV.js.map → chunk-44N6ESJ4.js.map} +0 -0
- /package/dist/{chunk-HO3QBJEY.js.map → chunk-5546W5SI.js.map} +0 -0
- /package/dist/{chunk-AAIUERNB.js.map → chunk-5QJQHBLE.js.map} +0 -0
- /package/dist/{chunk-6CZPDBJS.js.map → chunk-5U7ID3EZ.js.map} +0 -0
- /package/dist/{chunk-DNWXFTLD.js.map → chunk-A4IJCD2Z.js.map} +0 -0
- /package/dist/{chunk-PKNLM44P.js.map → chunk-AC5OWJLV.js.map} +0 -0
- /package/dist/{chunk-LZ4LDKHZ.js.map → chunk-AMAUBUKY.js.map} +0 -0
- /package/dist/{chunk-S5SLVSVY.js.map → chunk-BQIFZ2MP.js.map} +0 -0
- /package/dist/{chunk-Q6IP2ARR.js.map → chunk-CSOYVTRX.js.map} +0 -0
- /package/dist/{chunk-XOQSEF7X.js.map → chunk-CVILPI77.js.map} +0 -0
- /package/dist/{chunk-4LMA77JH.js.map → chunk-E5XQIWAL.js.map} +0 -0
- /package/dist/{chunk-WUNIWKY4.js.map → chunk-ELIL2A37.js.map} +0 -0
- /package/dist/{chunk-OQ5PRDDS.js.map → chunk-ERZ2R42X.js.map} +0 -0
- /package/dist/{chunk-U7GW7NE7.js.map → chunk-FIK3CQNA.js.map} +0 -0
- /package/dist/{chunk-33PLLLL7.js.map → chunk-GFCVUY6G.js.map} +0 -0
- /package/dist/{chunk-VUPTKTDV.js.map → chunk-GUAL4PQH.js.map} +0 -0
- /package/dist/{chunk-CINZGPSJ.js.map → chunk-GUMZC2BO.js.map} +0 -0
- /package/dist/{chunk-H24WNPA2.js.map → chunk-GWFSVJ4P.js.map} +0 -0
- /package/dist/{chunk-TSH56VPU.js.map → chunk-HAYSYUAB.js.map} +0 -0
- /package/dist/{chunk-PDLBLTOK.js.map → chunk-HC3PBX23.js.map} +0 -0
- /package/dist/{chunk-KXB4VXHY.js.map → chunk-JIYDRBVZ.js.map} +0 -0
- /package/dist/{chunk-HLPD7B7P.js.map → chunk-JZH4LWHB.js.map} +0 -0
- /package/dist/{chunk-AV5ZEH4M.js.map → chunk-KVJRXN2E.js.map} +0 -0
- /package/dist/{chunk-WFTIGIIS.js.map → chunk-L6CQ7WIW.js.map} +0 -0
- /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-EJUEXZHX.js.map → chunk-LLJMAULE.js.map} +0 -0
- /package/dist/{chunk-QN25OCUF.js.map → chunk-LPYDOLSM.js.map} +0 -0
- /package/dist/{chunk-AS7YMSL6.js.map → chunk-M23RF3LJ.js.map} +0 -0
- /package/dist/{chunk-OAEQLRCY.js.map → chunk-MO4HSXHZ.js.map} +0 -0
- /package/dist/{chunk-3F2LKUMU.js.map → chunk-NIS256NW.js.map} +0 -0
- /package/dist/{chunk-YIAA2X3D.js.map → chunk-NK5RGJ65.js.map} +0 -0
- /package/dist/{chunk-7TWUCYER.js.map → chunk-PNRA7FAD.js.map} +0 -0
- /package/dist/{chunk-5I4M26Q7.js.map → chunk-QBSFOKY6.js.map} +0 -0
- /package/dist/{chunk-E53DSZEN.js.map → chunk-QR6G5KF4.js.map} +0 -0
- /package/dist/{chunk-4UH4BTGK.js.map → chunk-QVJPH7SH.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-RKNJBZ55.js.map} +0 -0
- /package/dist/{chunk-WDISJRMG.js.map → chunk-RMMVQQA6.js.map} +0 -0
- /package/dist/{chunk-JVLCVFQ4.js.map → chunk-RNHVVMFN.js.map} +0 -0
- /package/dist/{chunk-5SM35XZR.js.map → chunk-S5NZBKKQ.js.map} +0 -0
- /package/dist/{chunk-WIPEXG6R.js.map → chunk-SXIMQLGV.js.map} +0 -0
- /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
- /package/dist/{chunk-4B77XSG5.js.map → chunk-UV72DEZD.js.map} +0 -0
- /package/dist/{chunk-BJKPPZ6Z.js.map → chunk-UW66OZTD.js.map} +0 -0
- /package/dist/{chunk-S2BBISHU.js.map → chunk-VANZKHTN.js.map} +0 -0
- /package/dist/{chunk-3Y224NYC.js.map → chunk-VYISFWVX.js.map} +0 -0
- /package/dist/{chunk-JE7EK33X.js.map → chunk-W2V7UESE.js.map} +0 -0
- /package/dist/{chunk-TIHMZFIV.js.map → chunk-W3IC7QOY.js.map} +0 -0
- /package/dist/{chunk-NRV4Y3PM.js.map → chunk-W4FBGYGK.js.map} +0 -0
- /package/dist/{chunk-MU7ZHSZE.js.map → chunk-WZFAPHIK.js.map} +0 -0
- /package/dist/{chunk-T2TTP3KU.js.map → chunk-X4IDNPOS.js.map} +0 -0
- /package/dist/{chunk-UVIKWC7M.js.map → chunk-XAGYS7X6.js.map} +0 -0
- /package/dist/{chunk-BLAKS3CP.js.map → chunk-XL3TATMJ.js.map} +0 -0
- /package/dist/{chunk-W4XJFLAL.js.map → chunk-XPRJSHNI.js.map} +0 -0
- /package/dist/{chunk-E6EE5B67.js.map → chunk-YK6BDDHP.js.map} +0 -0
- /package/dist/{chunk-ES36HTSC.js.map → chunk-YLHM5BQQ.js.map} +0 -0
- /package/dist/{chunk-GF22HWS2.js.map → chunk-Z54EM5YZ.js.map} +0 -0
- /package/dist/{chunk-64UDOIMI.js.map → chunk-ZLQ37WJX.js.map} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import assert from "node:assert/strict";
|
|
2
3
|
import { mkdtemp, mkdir, readFile, readdir, rename, rm, stat, utimes, writeFile } from "node:fs/promises";
|
|
3
4
|
import { existsSync } from "node:fs";
|
|
@@ -10,8 +11,12 @@ import {
|
|
|
10
11
|
buildExplicitCaptureDedupKey,
|
|
11
12
|
TombstoneBlockedCaptureIndex,
|
|
12
13
|
} from "./storage/tombstone-blocked-capture-index.js";
|
|
13
|
-
import {
|
|
14
|
-
|
|
14
|
+
import {
|
|
15
|
+
buildCapturePathLockIdentity,
|
|
16
|
+
runTombstoneBlockedMutation,
|
|
17
|
+
TombstoneBlockedCaptureWriteLock,
|
|
18
|
+
} from "./storage/tombstone-blocked-capture-mutation.js";
|
|
19
|
+
import { isEncryptedFile, SECURE_STORE_ENVELOPE_OVERHEAD_BYTES } from "./secure-store/secure-fs.js";
|
|
15
20
|
import type { MemoryFile } from "./types.js";
|
|
16
21
|
|
|
17
22
|
// Issue #1909 (Part B): writeMemory("fact") used to rewrite the whole
|
|
@@ -26,7 +31,7 @@ async function withMemoryDir(run: (dir: string) => Promise<void>): Promise<void>
|
|
|
26
31
|
try {
|
|
27
32
|
await run(dir);
|
|
28
33
|
} finally {
|
|
29
|
-
await rm(dir, { recursive: true, force: true });
|
|
34
|
+
await rm(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
|
|
@@ -54,6 +59,171 @@ test("capture write locks combine streamed hashes in canonical order", async ()
|
|
|
54
59
|
);
|
|
55
60
|
});
|
|
56
61
|
});
|
|
62
|
+
test("active mutations recheck queued-review replacements inside coordinated identity locks", async () => {
|
|
63
|
+
const pathname = "/memory/facts/active.md";
|
|
64
|
+
const active = {
|
|
65
|
+
path: pathname,
|
|
66
|
+
content: "active content",
|
|
67
|
+
frontmatter: { id: "active", category: "fact", status: "active" },
|
|
68
|
+
} as MemoryFile;
|
|
69
|
+
const queued = {
|
|
70
|
+
path: pathname,
|
|
71
|
+
content: "queued content",
|
|
72
|
+
frontmatter: {
|
|
73
|
+
id: "queued",
|
|
74
|
+
category: "fact",
|
|
75
|
+
status: "pending_review",
|
|
76
|
+
tags: ["queued-review"],
|
|
77
|
+
sourceConnector: "provider-a",
|
|
78
|
+
},
|
|
79
|
+
} as MemoryFile;
|
|
80
|
+
const activeIdentity = buildExplicitCaptureDedupKey(
|
|
81
|
+
active.content,
|
|
82
|
+
active.frontmatter.category,
|
|
83
|
+
active.frontmatter.sourceConnector
|
|
84
|
+
);
|
|
85
|
+
const queuedIdentity = buildExplicitCaptureDedupKey(
|
|
86
|
+
queued.content,
|
|
87
|
+
queued.frontmatter.category,
|
|
88
|
+
queued.frontmatter.sourceConnector
|
|
89
|
+
);
|
|
90
|
+
let current = active;
|
|
91
|
+
const lockIdentities: string[][] = [];
|
|
92
|
+
let writes = 0;
|
|
93
|
+
|
|
94
|
+
await runTombstoneBlockedMutation(
|
|
95
|
+
{
|
|
96
|
+
readCurrent: async () => current,
|
|
97
|
+
isBlocked: () => false,
|
|
98
|
+
isQueuedReview: (memory) => memory?.frontmatter.id === queued.frontmatter.id,
|
|
99
|
+
memoryIdentity: (memory) => (memory.frontmatter.id === active.frontmatter.id ? activeIdentity : queuedIdentity),
|
|
100
|
+
prepareWrite: async () => "marker",
|
|
101
|
+
commitWrite: async () => {},
|
|
102
|
+
discardWrite: async () => {},
|
|
103
|
+
markUntrusted: () => {},
|
|
104
|
+
writeStorageSecureFile: async () => {
|
|
105
|
+
assert.equal(lockIdentities.length, 2);
|
|
106
|
+
assert.ok(lockIdentities[1]?.includes(queuedIdentity));
|
|
107
|
+
writes += 1;
|
|
108
|
+
},
|
|
109
|
+
withCaptureWriteLock: async (task, identity) => {
|
|
110
|
+
const identities = Array.isArray(identity) ? [...identity] : [identity];
|
|
111
|
+
lockIdentities.push(identities);
|
|
112
|
+
if (lockIdentities.length === 1) current = queued;
|
|
113
|
+
await task();
|
|
114
|
+
},
|
|
115
|
+
logWarning: () => {},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
blocked: false,
|
|
119
|
+
pathname,
|
|
120
|
+
fileContent: "replacement",
|
|
121
|
+
identity: [
|
|
122
|
+
buildCapturePathLockIdentity(pathname),
|
|
123
|
+
activeIdentity,
|
|
124
|
+
buildExplicitCaptureDedupKey("replacement", "fact", undefined),
|
|
125
|
+
],
|
|
126
|
+
updateIndex: async () => {},
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
assert.equal(writes, 1);
|
|
131
|
+
assert.equal(lockIdentities.length, 2);
|
|
132
|
+
assert.ok(lockIdentities[0]?.includes(activeIdentity));
|
|
133
|
+
assert.ok(lockIdentities[0]?.includes(buildCapturePathLockIdentity(pathname)));
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("shared memory writes include their pathname in the capture lock union", async () => {
|
|
137
|
+
await withMemoryDir(async (dir) => {
|
|
138
|
+
const storage = new StorageManager(dir);
|
|
139
|
+
await storage.ensureDirectories();
|
|
140
|
+
const storageWithOverride = storage as unknown as {
|
|
141
|
+
withTombstoneBlockedCaptureWriteLock: (
|
|
142
|
+
task: () => Promise<unknown>,
|
|
143
|
+
identity?: string | readonly string[]
|
|
144
|
+
) => Promise<unknown>;
|
|
145
|
+
};
|
|
146
|
+
const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
|
|
147
|
+
const captured: Array<string | readonly string[] | undefined> = [];
|
|
148
|
+
storageWithOverride.withTombstoneBlockedCaptureWriteLock = async (task, identity) => {
|
|
149
|
+
captured.push(identity);
|
|
150
|
+
return await originalLock(task, identity);
|
|
151
|
+
};
|
|
152
|
+
try {
|
|
153
|
+
const written = await storage.writeMemory("fact", "Every writer shares the deterministic pathname lock.", {
|
|
154
|
+
source: "test",
|
|
155
|
+
});
|
|
156
|
+
const memory = await storage.getMemoryById(written.id);
|
|
157
|
+
assert.ok(memory);
|
|
158
|
+
const pathIdentity = buildCapturePathLockIdentity(memory.path);
|
|
159
|
+
assert.ok(captured.some((identity) => (Array.isArray(identity) ? identity : [identity]).includes(pathIdentity)));
|
|
160
|
+
} finally {
|
|
161
|
+
storageWithOverride.withTombstoneBlockedCaptureWriteLock = originalLock;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("offline sync reserves a marker when its locked snapshot became blocked with the same identity", async () => {
|
|
167
|
+
await withMemoryDir(async (dir) => {
|
|
168
|
+
const storage = new StorageManager(dir);
|
|
169
|
+
await storage.ensureDirectories();
|
|
170
|
+
const target = path.join(dir, "memory", "facts", "same-identity.md");
|
|
171
|
+
const active = {
|
|
172
|
+
path: target,
|
|
173
|
+
content: "Same identity, different review state.",
|
|
174
|
+
frontmatter: {
|
|
175
|
+
id: "same-identity",
|
|
176
|
+
category: "fact",
|
|
177
|
+
status: "active",
|
|
178
|
+
sourceConnector: "provider-a",
|
|
179
|
+
},
|
|
180
|
+
} as MemoryFile;
|
|
181
|
+
const blocked = {
|
|
182
|
+
...active,
|
|
183
|
+
frontmatter: {
|
|
184
|
+
...active.frontmatter,
|
|
185
|
+
status: "pending_review",
|
|
186
|
+
blockedBy: "same-identity-tombstone",
|
|
187
|
+
},
|
|
188
|
+
} as MemoryFile;
|
|
189
|
+
let readCount = 0;
|
|
190
|
+
let prepared = 0;
|
|
191
|
+
const fakeIndex = {
|
|
192
|
+
withCaptureWriteLock: async <T>(task: () => Promise<T>) => await task(),
|
|
193
|
+
prepareWrite: async () => {
|
|
194
|
+
prepared += 1;
|
|
195
|
+
return "same-identity-marker";
|
|
196
|
+
},
|
|
197
|
+
commitWrite: async () => {},
|
|
198
|
+
discardWrite: async () => {},
|
|
199
|
+
markUntrusted: () => {},
|
|
200
|
+
};
|
|
201
|
+
const storageWithOverrides = storage as unknown as {
|
|
202
|
+
readMemoryByPath: (pathname: string) => Promise<MemoryFile | null>;
|
|
203
|
+
getTombstoneBlockedCaptureIndex: () => typeof fakeIndex;
|
|
204
|
+
invalidateAfterOfflineSyncMutation: (pathname: string, marker?: string) => Promise<void>;
|
|
205
|
+
runTombstoneBlockedOfflineSyncMutation: (
|
|
206
|
+
pathname: string,
|
|
207
|
+
after: MemoryFile | null,
|
|
208
|
+
write: () => Promise<void>
|
|
209
|
+
) => Promise<void>;
|
|
210
|
+
};
|
|
211
|
+
const originalRead = storageWithOverrides.readMemoryByPath.bind(storage);
|
|
212
|
+
const originalIndex = storageWithOverrides.getTombstoneBlockedCaptureIndex.bind(storage);
|
|
213
|
+
const originalInvalidate = storageWithOverrides.invalidateAfterOfflineSyncMutation.bind(storage);
|
|
214
|
+
storageWithOverrides.readMemoryByPath = async () => (readCount++ === 0 ? active : blocked);
|
|
215
|
+
storageWithOverrides.getTombstoneBlockedCaptureIndex = () => fakeIndex;
|
|
216
|
+
storageWithOverrides.invalidateAfterOfflineSyncMutation = async () => {};
|
|
217
|
+
try {
|
|
218
|
+
await storageWithOverrides.runTombstoneBlockedOfflineSyncMutation(target, active, async () => {});
|
|
219
|
+
assert.equal(prepared, 1);
|
|
220
|
+
} finally {
|
|
221
|
+
storageWithOverrides.readMemoryByPath = originalRead;
|
|
222
|
+
storageWithOverrides.getTombstoneBlockedCaptureIndex = originalIndex;
|
|
223
|
+
storageWithOverrides.invalidateAfterOfflineSyncMutation = originalInvalidate;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
});
|
|
57
227
|
|
|
58
228
|
test("deferred fact writes do NO per-fact index saves; a single flush persists all", async () => {
|
|
59
229
|
await withMemoryDir(async (dir) => {
|
|
@@ -1662,6 +1832,45 @@ test("blocked chunk writes recheck identity after waiting on the capture lock",
|
|
|
1662
1832
|
});
|
|
1663
1833
|
});
|
|
1664
1834
|
|
|
1835
|
+
test("chunk rewrites reacquire discovered identities in canonical lock order", async () => {
|
|
1836
|
+
await withMemoryDir(async (dir) => {
|
|
1837
|
+
const storage = new StorageManager(dir);
|
|
1838
|
+
await storage.ensureDirectories();
|
|
1839
|
+
let queuedContent = "";
|
|
1840
|
+
let blockedContent = "";
|
|
1841
|
+
for (let index = 0; index < 100 && queuedContent.length === 0; index += 1) {
|
|
1842
|
+
const queuedCandidate = `queued identity ${index}`;
|
|
1843
|
+
const blockedCandidate = `blocked identity ${index}`;
|
|
1844
|
+
const queuedHash = createHash("sha256")
|
|
1845
|
+
.update(buildExplicitCaptureDedupKey(queuedCandidate, "fact", "provider-a"))
|
|
1846
|
+
.digest("hex");
|
|
1847
|
+
const blockedHash = createHash("sha256")
|
|
1848
|
+
.update(buildExplicitCaptureDedupKey(blockedCandidate, "fact", "provider-a"))
|
|
1849
|
+
.digest("hex");
|
|
1850
|
+
if (queuedHash < blockedHash) {
|
|
1851
|
+
queuedContent = queuedCandidate;
|
|
1852
|
+
blockedContent = blockedCandidate;
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
assert.ok(queuedContent.length > 0);
|
|
1856
|
+
|
|
1857
|
+
await storage.writeChunk("nested-lock-order", 0, 1, "fact", queuedContent, {
|
|
1858
|
+
source: "explicit-inline-review",
|
|
1859
|
+
sourceConnector: "provider-a",
|
|
1860
|
+
status: "pending_review",
|
|
1861
|
+
tags: ["queued-review"],
|
|
1862
|
+
});
|
|
1863
|
+
const id = await storage.writeChunk("nested-lock-order", 0, 1, "fact", blockedContent, {
|
|
1864
|
+
source: "offline-sync",
|
|
1865
|
+
sourceConnector: "provider-a",
|
|
1866
|
+
status: "pending_review",
|
|
1867
|
+
blockedBy: "tombstone-lock-order",
|
|
1868
|
+
});
|
|
1869
|
+
|
|
1870
|
+
assert.equal((await storage.getMemoryById(id))?.content, blockedContent);
|
|
1871
|
+
});
|
|
1872
|
+
});
|
|
1873
|
+
|
|
1665
1874
|
test("offline sync rechecks blocked identity after waiting on the capture lock", async () => {
|
|
1666
1875
|
await withMemoryDir(async (dir) => {
|
|
1667
1876
|
const storage = new StorageManager(dir);
|
|
@@ -1725,6 +1934,84 @@ test("offline sync rechecks blocked identity after waiting on the capture lock",
|
|
|
1725
1934
|
assert.equal(matches[0]?.frontmatter.id, captureResult.id);
|
|
1726
1935
|
});
|
|
1727
1936
|
});
|
|
1937
|
+
test("offline sync locks queued-review target identities before replacement", async () => {
|
|
1938
|
+
await withMemoryDir(async (dir) => {
|
|
1939
|
+
const storage = new StorageManager(dir);
|
|
1940
|
+
await storage.ensureDirectories();
|
|
1941
|
+
const queuedContent = "A queued review must not disappear during capture dedupe.";
|
|
1942
|
+
const queuedResult = await storage.writeMemory("fact", queuedContent, {
|
|
1943
|
+
source: "explicit-inline-review",
|
|
1944
|
+
sourceConnector: "provider-a",
|
|
1945
|
+
status: "pending_review",
|
|
1946
|
+
tags: ["explicit-capture", "queued-review"],
|
|
1947
|
+
});
|
|
1948
|
+
const queuedMemory = await storage.getMemoryById(queuedResult.id);
|
|
1949
|
+
assert.ok(queuedMemory);
|
|
1950
|
+
const queuedIdentity = buildExplicitCaptureDedupKey(queuedContent, "fact", "provider-a");
|
|
1951
|
+
const entered = Promise.withResolvers<void>();
|
|
1952
|
+
const release = Promise.withResolvers<void>();
|
|
1953
|
+
const held = storage.withTombstoneBlockedCaptureWriteLock(async () => {
|
|
1954
|
+
entered.resolve();
|
|
1955
|
+
await release.promise;
|
|
1956
|
+
}, queuedIdentity);
|
|
1957
|
+
await entered.promise;
|
|
1958
|
+
const storageWithOverride = storage as unknown as {
|
|
1959
|
+
withTombstoneBlockedCaptureWriteLock: (
|
|
1960
|
+
task: () => Promise<unknown>,
|
|
1961
|
+
identity?: string | readonly string[]
|
|
1962
|
+
) => Promise<unknown>;
|
|
1963
|
+
};
|
|
1964
|
+
const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
|
|
1965
|
+
const coordinationAttempted = Promise.withResolvers<void>();
|
|
1966
|
+
storageWithOverride.withTombstoneBlockedCaptureWriteLock = async (task, identity) => {
|
|
1967
|
+
if ((Array.isArray(identity) ? identity : [identity]).includes(queuedIdentity)) {
|
|
1968
|
+
coordinationAttempted.resolve();
|
|
1969
|
+
}
|
|
1970
|
+
return await originalLock(task, identity);
|
|
1971
|
+
};
|
|
1972
|
+
|
|
1973
|
+
const replacementContent = "The reviewed replacement is now active.";
|
|
1974
|
+
const replacementFile = [
|
|
1975
|
+
"---",
|
|
1976
|
+
"id: queued-review-replacement",
|
|
1977
|
+
"category: fact",
|
|
1978
|
+
"created: 2026-01-01T00:00:00.000Z",
|
|
1979
|
+
"updated: 2026-01-01T00:00:00.000Z",
|
|
1980
|
+
"source: offline-sync",
|
|
1981
|
+
"confidence: 0.8",
|
|
1982
|
+
"confidenceTier: implied",
|
|
1983
|
+
"tags: []",
|
|
1984
|
+
"status: active",
|
|
1985
|
+
"---",
|
|
1986
|
+
"",
|
|
1987
|
+
replacementContent,
|
|
1988
|
+
"",
|
|
1989
|
+
].join("\n");
|
|
1990
|
+
let completed = false;
|
|
1991
|
+
let replacement: Promise<void> | undefined;
|
|
1992
|
+
try {
|
|
1993
|
+
replacement = storage.writeOfflineSyncFile(queuedMemory.path, Buffer.from(replacementFile, "utf8")).then(() => {
|
|
1994
|
+
completed = true;
|
|
1995
|
+
});
|
|
1996
|
+
const first = await Promise.race([
|
|
1997
|
+
coordinationAttempted.promise.then(() => "coordinated" as const),
|
|
1998
|
+
replacement.then(() => "completed" as const),
|
|
1999
|
+
]);
|
|
2000
|
+
assert.equal(first, "coordinated");
|
|
2001
|
+
assert.equal(completed, false, "offline sync must wait for the queued-review identity lock");
|
|
2002
|
+
release.resolve();
|
|
2003
|
+
await held;
|
|
2004
|
+
await replacement;
|
|
2005
|
+
assert.equal((await storage.getMemoryById("queued-review-replacement"))?.content, replacementContent);
|
|
2006
|
+
} finally {
|
|
2007
|
+
release.resolve();
|
|
2008
|
+
storageWithOverride.withTombstoneBlockedCaptureWriteLock = originalLock;
|
|
2009
|
+
await held.catch(() => undefined);
|
|
2010
|
+
await replacement?.catch(() => undefined);
|
|
2011
|
+
}
|
|
2012
|
+
});
|
|
2013
|
+
});
|
|
2014
|
+
|
|
1728
2015
|
test("offline sync reacquires a rewritten blocked target identity", async () => {
|
|
1729
2016
|
await withMemoryDir(async (dir) => {
|
|
1730
2017
|
const storage = new StorageManager(dir);
|
|
@@ -1776,9 +2063,7 @@ test("offline sync reacquires a rewritten blocked target identity", async () =>
|
|
|
1776
2063
|
contentA,
|
|
1777
2064
|
"",
|
|
1778
2065
|
].join("\n");
|
|
1779
|
-
const targetMemory = (await storage.readAllMemories()).find(
|
|
1780
|
-
(memory) => memory.frontmatter.id === target.id
|
|
1781
|
-
);
|
|
2066
|
+
const targetMemory = (await storage.readAllMemories()).find((memory) => memory.frontmatter.id === target.id);
|
|
1782
2067
|
assert.ok(targetMemory);
|
|
1783
2068
|
const identityA = buildExplicitCaptureDedupKey(contentA, "fact", "provider-a");
|
|
1784
2069
|
const identityB = buildExplicitCaptureDedupKey(contentB, "fact", "provider-a");
|
|
@@ -1786,7 +2071,7 @@ test("offline sync reacquires a rewritten blocked target identity", async () =>
|
|
|
1786
2071
|
const storageWithOverride = storage as unknown as {
|
|
1787
2072
|
withTombstoneBlockedCaptureWriteLock: (
|
|
1788
2073
|
task: () => Promise<unknown>,
|
|
1789
|
-
identity?: string | readonly string[]
|
|
2074
|
+
identity?: string | readonly string[]
|
|
1790
2075
|
) => Promise<unknown>;
|
|
1791
2076
|
};
|
|
1792
2077
|
const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
|
|
@@ -1816,7 +2101,7 @@ test("offline sync reacquires a rewritten blocked target identity", async () =>
|
|
|
1816
2101
|
await releaseMarker.promise;
|
|
1817
2102
|
}
|
|
1818
2103
|
return marker;
|
|
1819
|
-
}
|
|
2104
|
+
}
|
|
1820
2105
|
);
|
|
1821
2106
|
|
|
1822
2107
|
const sync = storage.writeOfflineSyncFile(targetMemory.path, Buffer.from(incomingFile, "utf8"));
|
|
@@ -1826,11 +2111,11 @@ test("offline sync reacquires a rewritten blocked target identity", async () =>
|
|
|
1826
2111
|
const secondKeys = capturedIdentities[1];
|
|
1827
2112
|
assert.ok(
|
|
1828
2113
|
(Array.isArray(firstKeys) ? firstKeys : [firstKeys]).includes(identityB),
|
|
1829
|
-
"sync must first observe the original target identity"
|
|
2114
|
+
"sync must first observe the original target identity"
|
|
1830
2115
|
);
|
|
1831
2116
|
assert.ok(
|
|
1832
2117
|
(Array.isArray(secondKeys) ? secondKeys : [secondKeys]).includes(identityC),
|
|
1833
|
-
"sync must reacquire the rewritten target identity"
|
|
2118
|
+
"sync must reacquire the rewritten target identity"
|
|
1834
2119
|
);
|
|
1835
2120
|
let recaptureCompleted = false;
|
|
1836
2121
|
const recapture = peer
|
|
@@ -1852,7 +2137,7 @@ test("offline sync reacquires a rewritten blocked target identity", async () =>
|
|
|
1852
2137
|
assert.equal(
|
|
1853
2138
|
after.find((memory) => memory.path === targetMemory.path)?.content,
|
|
1854
2139
|
contentA,
|
|
1855
|
-
"offline sync must replace the target after holding its current identity lock"
|
|
2140
|
+
"offline sync must replace the target after holding its current identity lock"
|
|
1856
2141
|
);
|
|
1857
2142
|
assert.equal(after.filter((memory) => memory.content === contentC).length, 1);
|
|
1858
2143
|
} finally {
|
|
@@ -2247,7 +2532,7 @@ test("chunked offline sync scans oversized frontmatter before locking its identi
|
|
|
2247
2532
|
semanticThreshold: 0.9,
|
|
2248
2533
|
namespace: "default",
|
|
2249
2534
|
});
|
|
2250
|
-
const content =
|
|
2535
|
+
const content = "Oversized frontmatter sync";
|
|
2251
2536
|
const tombstoneId = await storage.appendTombstone({
|
|
2252
2537
|
reason: "correction",
|
|
2253
2538
|
createdBy: "user_correction",
|
|
@@ -2263,7 +2548,7 @@ test("chunked offline sync scans oversized frontmatter before locking its identi
|
|
|
2263
2548
|
const memory = (await storage.readAllMemories()).find((candidate) => candidate.frontmatter.id === result.id);
|
|
2264
2549
|
assert.ok(memory);
|
|
2265
2550
|
|
|
2266
|
-
const largeTags = Array.from({ length:
|
|
2551
|
+
const largeTags = Array.from({ length: 100_000 }, (_, index) => `"tag-${index}"`).join(", ");
|
|
2267
2552
|
const updatedFile = [
|
|
2268
2553
|
"---",
|
|
2269
2554
|
`id: ${memory.frontmatter.id}`,
|
|
@@ -2282,6 +2567,10 @@ test("chunked offline sync scans oversized frontmatter before locking its identi
|
|
|
2282
2567
|
content,
|
|
2283
2568
|
"",
|
|
2284
2569
|
].join("\n");
|
|
2570
|
+
assert.ok(
|
|
2571
|
+
updatedFile.indexOf("\n---\n") > 1_048_576,
|
|
2572
|
+
"the streamed body delimiter must appear after the chunk buffer limit",
|
|
2573
|
+
);
|
|
2285
2574
|
const chunks = (async function* (): AsyncIterable<Buffer> {
|
|
2286
2575
|
for (let offset = 0; offset < updatedFile.length; offset += 32 * 1024) {
|
|
2287
2576
|
yield Buffer.from(updatedFile.slice(offset, offset + 32 * 1024), "utf8");
|
|
@@ -2309,6 +2598,52 @@ test("chunked offline sync scans oversized frontmatter before locking its identi
|
|
|
2309
2598
|
});
|
|
2310
2599
|
});
|
|
2311
2600
|
|
|
2601
|
+
test("chunked offline sync lowercases contextual Unicode across staged read boundaries", async () => {
|
|
2602
|
+
await withMemoryDir(async (dir) => {
|
|
2603
|
+
const storage = new StorageManager(dir);
|
|
2604
|
+
await storage.ensureDirectories();
|
|
2605
|
+
const header = (id: string) =>
|
|
2606
|
+
[
|
|
2607
|
+
"---",
|
|
2608
|
+
`id: ${id}`,
|
|
2609
|
+
"category: fact",
|
|
2610
|
+
"created: 2026-01-01T00:00:00.000Z",
|
|
2611
|
+
"updated: 2026-01-01T00:00:00.000Z",
|
|
2612
|
+
"source: offline-sync",
|
|
2613
|
+
"confidence: 0.8",
|
|
2614
|
+
"confidenceTier: implied",
|
|
2615
|
+
"tags: []",
|
|
2616
|
+
"sourceConnector: provider-a",
|
|
2617
|
+
"status: pending_review",
|
|
2618
|
+
"blockedBy: tombstone-unicode-boundary",
|
|
2619
|
+
"---",
|
|
2620
|
+
].join("\n");
|
|
2621
|
+
const incomingHeader = header("unicode-boundary-incoming");
|
|
2622
|
+
const firstReadBoundary = SECURE_STORE_ENVELOPE_OVERHEAD_BYTES + 64 * 1024;
|
|
2623
|
+
const bodyOffset = Buffer.byteLength(`${incomingHeader}\n`);
|
|
2624
|
+
const prefixLength = firstReadBoundary - bodyOffset - Buffer.byteLength("\nΟΣ", "utf8");
|
|
2625
|
+
assert.ok(prefixLength > 0);
|
|
2626
|
+
const content = `${"x".repeat(prefixLength)}ΟΣΑ${"z".repeat(1_050_000)}`;
|
|
2627
|
+
assert.equal(Buffer.byteLength(`${incomingHeader}\n\n${"x".repeat(prefixLength)}ΟΣ`, "utf8"), firstReadBoundary);
|
|
2628
|
+
const memoryFile = (id: string) => `${header(id)}\n\n${content}\n`;
|
|
2629
|
+
const existingPath = path.join(dir, "facts", "2026-01-01", "unicode-boundary-existing.md");
|
|
2630
|
+
await storage.writeOfflineSyncFile(existingPath, Buffer.from(memoryFile("unicode-boundary-existing"), "utf8"));
|
|
2631
|
+
|
|
2632
|
+
const incomingPath = path.join(dir, "facts", "2026-01-01", "unicode-boundary-incoming.md");
|
|
2633
|
+
const incoming = Buffer.from(memoryFile("unicode-boundary-incoming"), "utf8");
|
|
2634
|
+
const chunks = (async function* (): AsyncIterable<Buffer> {
|
|
2635
|
+
for (let offset = 0; offset < incoming.length; offset += 32 * 1024) {
|
|
2636
|
+
yield incoming.subarray(offset, offset + 32 * 1024);
|
|
2637
|
+
}
|
|
2638
|
+
})();
|
|
2639
|
+
await storage.writeOfflineSyncFileChunks(incomingPath, chunks);
|
|
2640
|
+
|
|
2641
|
+
assert.equal(existsSync(incomingPath), false, "the normalized duplicate must not be published");
|
|
2642
|
+
const matches = (await storage.readAllMemories()).filter((memory) => memory.content === content);
|
|
2643
|
+
assert.equal(matches.length, 1);
|
|
2644
|
+
});
|
|
2645
|
+
});
|
|
2646
|
+
|
|
2312
2647
|
test("chunked offline sync encrypts oversized staging files when secure storage is enabled", async () => {
|
|
2313
2648
|
await withMemoryDir(async (dir) => {
|
|
2314
2649
|
const storage = new StorageManager(dir);
|
|
@@ -2320,7 +2655,7 @@ test("chunked offline sync encrypts oversized staging files when secure storage
|
|
|
2320
2655
|
semanticThreshold: 0.9,
|
|
2321
2656
|
namespace: "default",
|
|
2322
2657
|
});
|
|
2323
|
-
const content =
|
|
2658
|
+
const content = "Oversized encrypted staging content";
|
|
2324
2659
|
const tombstoneId = await storage.appendTombstone({
|
|
2325
2660
|
reason: "correction",
|
|
2326
2661
|
createdBy: "user_correction",
|
|
@@ -2335,6 +2670,7 @@ test("chunked offline sync encrypts oversized staging files when secure storage
|
|
|
2335
2670
|
assert.equal(result.tombstoneBlocked, true);
|
|
2336
2671
|
const memory = (await storage.readAllMemories()).find((candidate) => candidate.frontmatter.id === result.id);
|
|
2337
2672
|
assert.ok(memory);
|
|
2673
|
+
const largeTags = Array.from({ length: 100_000 }, (_, index) => `"tag-${index}"`).join(", ");
|
|
2338
2674
|
|
|
2339
2675
|
const incomingFile = [
|
|
2340
2676
|
"---",
|
|
@@ -2345,7 +2681,7 @@ test("chunked offline sync encrypts oversized staging files when secure storage
|
|
|
2345
2681
|
`source: ${memory.frontmatter.source}`,
|
|
2346
2682
|
`confidence: ${memory.frontmatter.confidence}`,
|
|
2347
2683
|
`confidenceTier: ${memory.frontmatter.confidenceTier}`,
|
|
2348
|
-
|
|
2684
|
+
`tags: [${largeTags}]`,
|
|
2349
2685
|
"sourceConnector: provider-a",
|
|
2350
2686
|
"status: pending_review",
|
|
2351
2687
|
`blockedBy: ${memory.frontmatter.blockedBy}`,
|
|
@@ -2354,6 +2690,7 @@ test("chunked offline sync encrypts oversized staging files when secure storage
|
|
|
2354
2690
|
content,
|
|
2355
2691
|
"",
|
|
2356
2692
|
].join("\n");
|
|
2693
|
+
assert.ok(incomingFile.length > 1_048_576, "the encrypted staging fixture must exceed the chunk buffer limit");
|
|
2357
2694
|
const chunks = (async function* (): AsyncIterable<Buffer> {
|
|
2358
2695
|
for (let offset = 0; offset < incomingFile.length; offset += 32 * 1024) {
|
|
2359
2696
|
yield Buffer.from(incomingFile.slice(offset, offset + 32 * 1024), "utf8");
|
|
@@ -2481,9 +2818,7 @@ test("chunked offline sync acquires a target identity discovered in a nested rec
|
|
|
2481
2818
|
});
|
|
2482
2819
|
assert.ok(targetTombstone);
|
|
2483
2820
|
assert.equal(target.tombstoneBlocked, false);
|
|
2484
|
-
const targetMemory = (await storage.readAllMemories()).find(
|
|
2485
|
-
(memory) => memory.frontmatter.id === target.id
|
|
2486
|
-
);
|
|
2821
|
+
const targetMemory = (await storage.readAllMemories()).find((memory) => memory.frontmatter.id === target.id);
|
|
2487
2822
|
assert.ok(targetMemory);
|
|
2488
2823
|
const incomingFile = [
|
|
2489
2824
|
"---",
|
|
@@ -2512,13 +2847,13 @@ test("chunked offline sync acquires a target identity discovered in a nested rec
|
|
|
2512
2847
|
const storageWithOverrides = storage as unknown as {
|
|
2513
2848
|
withTombstoneBlockedCaptureWriteLock: (
|
|
2514
2849
|
task: () => Promise<unknown>,
|
|
2515
|
-
identity?: string | readonly string[]
|
|
2850
|
+
identity?: string | readonly string[]
|
|
2516
2851
|
) => Promise<unknown>;
|
|
2517
2852
|
runTombstoneBlockedOfflineSyncMutation: (
|
|
2518
2853
|
target: string,
|
|
2519
2854
|
after: MemoryFile | null,
|
|
2520
2855
|
write: () => Promise<void>,
|
|
2521
|
-
coordinate?: boolean
|
|
2856
|
+
coordinate?: boolean
|
|
2522
2857
|
) => Promise<void>;
|
|
2523
2858
|
};
|
|
2524
2859
|
const originalLock = storageWithOverrides.withTombstoneBlockedCaptureWriteLock.bind(storage);
|
|
@@ -2532,17 +2867,10 @@ test("chunked offline sync acquires a target identity discovered in a nested rec
|
|
|
2532
2867
|
let pauseNextPrepare = false;
|
|
2533
2868
|
const markerEntered = Promise.withResolvers<void>();
|
|
2534
2869
|
const releaseMarker = Promise.withResolvers<void>();
|
|
2535
|
-
storageWithOverrides.runTombstoneBlockedOfflineSyncMutation = async (
|
|
2536
|
-
syncTarget,
|
|
2537
|
-
after,
|
|
2538
|
-
write,
|
|
2539
|
-
coordinate,
|
|
2540
|
-
) => {
|
|
2870
|
+
storageWithOverrides.runTombstoneBlockedOfflineSyncMutation = async (syncTarget, after, write, coordinate) => {
|
|
2541
2871
|
if (!rewroteTarget) {
|
|
2542
2872
|
rewroteTarget = true;
|
|
2543
|
-
const current = (await peer.readAllMemories()).find(
|
|
2544
|
-
(memory) => memory.frontmatter.id === target.id
|
|
2545
|
-
);
|
|
2873
|
+
const current = (await peer.readAllMemories()).find((memory) => memory.frontmatter.id === target.id);
|
|
2546
2874
|
assert.ok(current);
|
|
2547
2875
|
await peer.writeMemoryFrontmatter(current, {
|
|
2548
2876
|
status: "pending_review",
|
|
@@ -2564,17 +2892,15 @@ test("chunked offline sync acquires a target identity discovered in a nested rec
|
|
|
2564
2892
|
await releaseMarker.promise;
|
|
2565
2893
|
}
|
|
2566
2894
|
return marker;
|
|
2567
|
-
}
|
|
2895
|
+
}
|
|
2568
2896
|
);
|
|
2569
2897
|
|
|
2570
2898
|
const sync = storage.writeOfflineSyncFileChunks(targetMemory.path, chunks);
|
|
2571
2899
|
try {
|
|
2572
2900
|
await markerEntered.promise;
|
|
2573
2901
|
assert.ok(
|
|
2574
|
-
capturedIdentities.some((identity) =>
|
|
2575
|
-
|
|
2576
|
-
),
|
|
2577
|
-
"nested chunk sync must acquire the identity discovered after the outer recheck",
|
|
2902
|
+
capturedIdentities.some((identity) => (Array.isArray(identity) ? identity : [identity]).includes(identityC)),
|
|
2903
|
+
"nested chunk sync must acquire the identity discovered after the outer recheck"
|
|
2578
2904
|
);
|
|
2579
2905
|
let recaptureCompleted = false;
|
|
2580
2906
|
const recapture = peer
|
|
@@ -2596,7 +2922,7 @@ test("chunked offline sync acquires a target identity discovered in a nested rec
|
|
|
2596
2922
|
assert.equal(
|
|
2597
2923
|
after.find((memory) => memory.path === targetMemory.path)?.content,
|
|
2598
2924
|
incomingContent,
|
|
2599
|
-
"chunk sync must replace the target only while holding its current identity lock"
|
|
2925
|
+
"chunk sync must replace the target only while holding its current identity lock"
|
|
2600
2926
|
);
|
|
2601
2927
|
assert.equal(after.filter((memory) => memory.content === targetContent).length, 1);
|
|
2602
2928
|
} finally {
|
|
@@ -2640,7 +2966,8 @@ test("large blocked offline sync streams through bounded staging and deduplicate
|
|
|
2640
2966
|
semanticThreshold: 0.9,
|
|
2641
2967
|
namespace: "default",
|
|
2642
2968
|
});
|
|
2643
|
-
const largeContent = "large stream duplicate
|
|
2969
|
+
const largeContent = "large stream duplicate";
|
|
2970
|
+
const largeTags = Array.from({ length: 100_000 }, (_, index) => `"tag-${index}"`).join(", ");
|
|
2644
2971
|
const tombstoneId = await storage.appendTombstone({
|
|
2645
2972
|
reason: "correction",
|
|
2646
2973
|
createdBy: "user_correction",
|
|
@@ -2663,7 +2990,7 @@ test("large blocked offline sync streams through bounded staging and deduplicate
|
|
|
2663
2990
|
"source: offline-sync",
|
|
2664
2991
|
"confidence: 0.8",
|
|
2665
2992
|
"confidenceTier: implied",
|
|
2666
|
-
|
|
2993
|
+
`tags: [${largeTags}]`,
|
|
2667
2994
|
"sourceConnector: provider-a",
|
|
2668
2995
|
"status: pending_review",
|
|
2669
2996
|
`blockedBy: ${tombstoneId}`,
|
|
@@ -2672,7 +2999,7 @@ test("large blocked offline sync streams through bounded staging and deduplicate
|
|
|
2672
2999
|
largeContent,
|
|
2673
3000
|
"",
|
|
2674
3001
|
].join("\n"),
|
|
2675
|
-
"utf8"
|
|
3002
|
+
"utf8"
|
|
2676
3003
|
);
|
|
2677
3004
|
assert.ok(incomingFile.byteLength > 1_048_576);
|
|
2678
3005
|
const target = path.join(dir, "cold", "large-stream-incoming.md");
|
|
@@ -2689,10 +3016,9 @@ test("large blocked offline sync streams through bounded staging and deduplicate
|
|
|
2689
3016
|
|
|
2690
3017
|
assert.equal(consumedBytes, incomingFile.byteLength);
|
|
2691
3018
|
assert.equal(existsSync(target), false, "a streamed blocked duplicate must not publish a new row");
|
|
2692
|
-
const matches = [
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
].filter((memory) => memory.frontmatter.id === existing.id);
|
|
3019
|
+
const matches = [...(await storage.readAllMemories()), ...(await storage.readAllColdMemories())].filter(
|
|
3020
|
+
(memory) => memory.frontmatter.id === existing.id
|
|
3021
|
+
);
|
|
2696
3022
|
assert.equal(matches.length, 1, "the existing blocked row remains the sole durable duplicate");
|
|
2697
3023
|
});
|
|
2698
3024
|
});
|
|
@@ -2827,10 +3153,7 @@ test("frontmatter rewrites invalidate cold cache before blocked index sync", asy
|
|
|
2827
3153
|
);
|
|
2828
3154
|
assert.ok(coldMemory, "migrated blocked memory must be readable from cold tier");
|
|
2829
3155
|
|
|
2830
|
-
assert.equal(
|
|
2831
|
-
await storage.writeMemoryFrontmatter(coldMemory, { sourceConnector: "provider-b" }),
|
|
2832
|
-
true
|
|
2833
|
-
);
|
|
3156
|
+
assert.equal(await storage.writeMemoryFrontmatter(coldMemory, { sourceConnector: "provider-b" }), true);
|
|
2834
3157
|
assert.equal(
|
|
2835
3158
|
await storage.hasTombstoneBlockedExplicitCapture(content, "fact", "provider-a"),
|
|
2836
3159
|
false,
|
|
@@ -3207,7 +3530,7 @@ test("blocked invalidation reserves the index marker before deleting under the i
|
|
|
3207
3530
|
const storageWithOverride = storage as unknown as {
|
|
3208
3531
|
withTombstoneBlockedCaptureWriteLock: (
|
|
3209
3532
|
task: () => Promise<boolean>,
|
|
3210
|
-
identity?: string | readonly string[]
|
|
3533
|
+
identity?: string | readonly string[]
|
|
3211
3534
|
) => Promise<boolean>;
|
|
3212
3535
|
};
|
|
3213
3536
|
let capturedIdentity: string | readonly string[] | undefined;
|
|
@@ -3229,7 +3552,7 @@ test("blocked invalidation reserves the index marker before deleting under the i
|
|
|
3229
3552
|
await release.promise;
|
|
3230
3553
|
}
|
|
3231
3554
|
return marker;
|
|
3232
|
-
}
|
|
3555
|
+
}
|
|
3233
3556
|
);
|
|
3234
3557
|
|
|
3235
3558
|
const invalidation = storage.invalidateMemory(first.id);
|
|
@@ -3238,15 +3561,12 @@ test("blocked invalidation reserves the index marker before deleting under the i
|
|
|
3238
3561
|
entered.promise.then(() => true),
|
|
3239
3562
|
new Promise<boolean>((resolve) => setTimeout(() => resolve(false), 100)),
|
|
3240
3563
|
]);
|
|
3241
|
-
assert.equal(
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
"blocked invalidation must reserve its rebuild marker before unlinking",
|
|
3245
|
-
);
|
|
3246
|
-
assert.equal(capturedIdentity, identity);
|
|
3564
|
+
assert.equal(enteredBeforeTimeout, true, "blocked invalidation must reserve its rebuild marker before unlinking");
|
|
3565
|
+
assert.ok(Array.isArray(capturedIdentity) && capturedIdentity.includes(identity));
|
|
3566
|
+
assert.ok(Array.isArray(capturedIdentity) && capturedIdentity.some((key) => key.startsWith("path ")));
|
|
3247
3567
|
assert.ok(
|
|
3248
3568
|
(await readdir(path.join(dir, "state", "tombstone-blocked-capture", "rebuild-required"))).length > 0,
|
|
3249
|
-
"blocked invalidation must publish its rebuild marker before unlinking"
|
|
3569
|
+
"blocked invalidation must publish its rebuild marker before unlinking"
|
|
3250
3570
|
);
|
|
3251
3571
|
|
|
3252
3572
|
let peerCompleted = false;
|
|
@@ -3266,10 +3586,7 @@ test("blocked invalidation reserves the index marker before deleting under the i
|
|
|
3266
3586
|
const second = await recapture;
|
|
3267
3587
|
assert.equal(second.tombstoneBlocked, true);
|
|
3268
3588
|
assert.notEqual(second.id, first.id);
|
|
3269
|
-
assert.equal(
|
|
3270
|
-
(await peer.readAllMemories()).filter((memory) => memory.content === content).length,
|
|
3271
|
-
1,
|
|
3272
|
-
);
|
|
3589
|
+
assert.equal((await peer.readAllMemories()).filter((memory) => memory.content === content).length, 1);
|
|
3273
3590
|
} finally {
|
|
3274
3591
|
release.resolve();
|
|
3275
3592
|
prepareSpy.mock.restore();
|
|
@@ -3313,7 +3630,7 @@ test("blocked archive serializes capture scans with the archive transition", asy
|
|
|
3313
3630
|
const storageWithOverride = storage as unknown as {
|
|
3314
3631
|
withTombstoneBlockedCaptureWriteLock: (
|
|
3315
3632
|
task: () => Promise<unknown>,
|
|
3316
|
-
identity?: string | readonly string[]
|
|
3633
|
+
identity?: string | readonly string[]
|
|
3317
3634
|
) => Promise<unknown>;
|
|
3318
3635
|
};
|
|
3319
3636
|
const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
|
|
@@ -3338,7 +3655,7 @@ test("blocked archive serializes capture scans with the archive transition", asy
|
|
|
3338
3655
|
await releaseMarker.promise;
|
|
3339
3656
|
}
|
|
3340
3657
|
return marker;
|
|
3341
|
-
}
|
|
3658
|
+
}
|
|
3342
3659
|
);
|
|
3343
3660
|
|
|
3344
3661
|
const archive = storage.archiveMemory(firstMemory);
|
|
@@ -3348,7 +3665,8 @@ test("blocked archive serializes capture scans with the archive transition", asy
|
|
|
3348
3665
|
new Promise<boolean>((resolve) => setTimeout(() => resolve(false), 100)),
|
|
3349
3666
|
]);
|
|
3350
3667
|
assert.equal(enteredBeforeTimeout, true, "archive must reserve its marker under the capture lock");
|
|
3351
|
-
assert.
|
|
3668
|
+
assert.ok(Array.isArray(capturedIdentity) && capturedIdentity.includes(identity));
|
|
3669
|
+
assert.ok(Array.isArray(capturedIdentity) && capturedIdentity.some((key) => key.startsWith("path ")));
|
|
3352
3670
|
|
|
3353
3671
|
let recaptureCompleted = false;
|
|
3354
3672
|
const recapture = peer
|
|
@@ -3372,12 +3690,12 @@ test("blocked archive serializes capture scans with the archive transition", asy
|
|
|
3372
3690
|
assert.equal(
|
|
3373
3691
|
(await peer.readAllMemories()).filter((memory) => memory.content === content).length,
|
|
3374
3692
|
1,
|
|
3375
|
-
"recapture must recreate the review row after archive removes the old row"
|
|
3693
|
+
"recapture must recreate the review row after archive removes the old row"
|
|
3376
3694
|
);
|
|
3377
3695
|
assert.equal(
|
|
3378
3696
|
await peer.hasTombstoneBlockedExplicitCapture(content, "fact", "provider-a"),
|
|
3379
3697
|
true,
|
|
3380
|
-
"the recreated review row must remain indexed"
|
|
3698
|
+
"the recreated review row must remain indexed"
|
|
3381
3699
|
);
|
|
3382
3700
|
} finally {
|
|
3383
3701
|
releaseMarker.resolve();
|
|
@@ -3396,7 +3714,7 @@ test("blocked archive failures discard their uncommitted rebuild marker", async
|
|
|
3396
3714
|
protected override writeStorageSecureFile(
|
|
3397
3715
|
filePath: string,
|
|
3398
3716
|
content: string | Buffer,
|
|
3399
|
-
forceEncrypt = false
|
|
3717
|
+
forceEncrypt = false
|
|
3400
3718
|
): Promise<void> {
|
|
3401
3719
|
if (this.failArchiveWrites && filePath.includes(`${path.sep}archive${path.sep}`)) {
|
|
3402
3720
|
return Promise.reject(new Error("simulated archive write failure"));
|
|
@@ -3476,7 +3794,7 @@ test("blocked invalidation reacquires the reloaded identity lock", async () => {
|
|
|
3476
3794
|
const storageWithOverride = storage as unknown as {
|
|
3477
3795
|
withTombstoneBlockedCaptureWriteLock: (
|
|
3478
3796
|
task: () => Promise<unknown>,
|
|
3479
|
-
identity?: string | readonly string[]
|
|
3797
|
+
identity?: string | readonly string[]
|
|
3480
3798
|
) => Promise<unknown>;
|
|
3481
3799
|
};
|
|
3482
3800
|
const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
|
|
@@ -3506,13 +3824,23 @@ test("blocked invalidation reacquires the reloaded identity lock", async () => {
|
|
|
3506
3824
|
await releaseMarker.promise;
|
|
3507
3825
|
}
|
|
3508
3826
|
return marker;
|
|
3509
|
-
}
|
|
3827
|
+
}
|
|
3510
3828
|
);
|
|
3511
3829
|
|
|
3512
3830
|
const invalidation = storage.invalidateMemory(first.id);
|
|
3513
3831
|
try {
|
|
3514
3832
|
await markerEntered.promise;
|
|
3515
|
-
assert.deepEqual(
|
|
3833
|
+
assert.deepEqual(
|
|
3834
|
+
capturedIdentities.map((identity) =>
|
|
3835
|
+
(Array.isArray(identity) ? identity : [identity]).filter((key) => key?.startsWith("category "))
|
|
3836
|
+
),
|
|
3837
|
+
[[identityA], [identityA, identityB]]
|
|
3838
|
+
);
|
|
3839
|
+
assert.ok(
|
|
3840
|
+
capturedIdentities.every((identity) =>
|
|
3841
|
+
(Array.isArray(identity) ? identity : [identity]).some((key) => key?.startsWith("path "))
|
|
3842
|
+
)
|
|
3843
|
+
);
|
|
3516
3844
|
let recaptureCompleted = false;
|
|
3517
3845
|
const recapture = peer
|
|
3518
3846
|
.writeMemory("fact", contentB, {
|
|
@@ -3530,10 +3858,7 @@ test("blocked invalidation reacquires the reloaded identity lock", async () => {
|
|
|
3530
3858
|
const second = await recapture;
|
|
3531
3859
|
assert.equal(second.tombstoneBlocked, true);
|
|
3532
3860
|
assert.notEqual(second.id, first.id);
|
|
3533
|
-
assert.equal(
|
|
3534
|
-
(await peer.readAllMemories()).filter((memory) => memory.content === contentB).length,
|
|
3535
|
-
1,
|
|
3536
|
-
);
|
|
3861
|
+
assert.equal((await peer.readAllMemories()).filter((memory) => memory.content === contentB).length, 1);
|
|
3537
3862
|
} finally {
|
|
3538
3863
|
releaseMarker.resolve();
|
|
3539
3864
|
prepareSpy.mock.restore();
|
|
@@ -3570,7 +3895,7 @@ test("blocked rewrites reacquire a target identity changed before update", async
|
|
|
3570
3895
|
createdBy: "user_correction",
|
|
3571
3896
|
sourceMemoryId,
|
|
3572
3897
|
rawContent,
|
|
3573
|
-
})
|
|
3898
|
+
})
|
|
3574
3899
|
);
|
|
3575
3900
|
}
|
|
3576
3901
|
const target = await storage.writeMemory("fact", contentA, {
|
|
@@ -3578,9 +3903,7 @@ test("blocked rewrites reacquire a target identity changed before update", async
|
|
|
3578
3903
|
sourceConnector: "provider-a",
|
|
3579
3904
|
});
|
|
3580
3905
|
assert.equal(target.tombstoneBlocked, true);
|
|
3581
|
-
const targetMemory = (await storage.readAllMemories()).find(
|
|
3582
|
-
(memory) => memory.frontmatter.id === target.id
|
|
3583
|
-
);
|
|
3906
|
+
const targetMemory = (await storage.readAllMemories()).find((memory) => memory.frontmatter.id === target.id);
|
|
3584
3907
|
assert.ok(targetMemory);
|
|
3585
3908
|
const identityA = buildExplicitCaptureDedupKey(contentA, "fact", "provider-a");
|
|
3586
3909
|
const identityB = buildExplicitCaptureDedupKey(contentB, "fact", "provider-a");
|
|
@@ -3588,7 +3911,7 @@ test("blocked rewrites reacquire a target identity changed before update", async
|
|
|
3588
3911
|
const storageWithOverride = storage as unknown as {
|
|
3589
3912
|
withTombstoneBlockedCaptureWriteLock: (
|
|
3590
3913
|
task: () => Promise<unknown>,
|
|
3591
|
-
identity?: string | readonly string[]
|
|
3914
|
+
identity?: string | readonly string[]
|
|
3592
3915
|
) => Promise<unknown>;
|
|
3593
3916
|
};
|
|
3594
3917
|
const originalLock = storageWithOverride.withTombstoneBlockedCaptureWriteLock.bind(storage);
|
|
@@ -3618,7 +3941,7 @@ test("blocked rewrites reacquire a target identity changed before update", async
|
|
|
3618
3941
|
await releaseMarker.promise;
|
|
3619
3942
|
}
|
|
3620
3943
|
return marker;
|
|
3621
|
-
}
|
|
3944
|
+
}
|
|
3622
3945
|
);
|
|
3623
3946
|
|
|
3624
3947
|
const update = storage.updateMemory(target.id, contentC, { sourceConnector: "provider-a" });
|
|
@@ -3629,11 +3952,11 @@ test("blocked rewrites reacquire a target identity changed before update", async
|
|
|
3629
3952
|
const secondKeys = capturedIdentities[1];
|
|
3630
3953
|
assert.ok(
|
|
3631
3954
|
(Array.isArray(firstKeys) ? firstKeys : [firstKeys]).includes(identityA),
|
|
3632
|
-
"update must first lock the identity read before the peer rewrite"
|
|
3955
|
+
"update must first lock the identity read before the peer rewrite"
|
|
3633
3956
|
);
|
|
3634
3957
|
assert.ok(
|
|
3635
3958
|
(Array.isArray(secondKeys) ? secondKeys : [secondKeys]).includes(identityB),
|
|
3636
|
-
"update must reacquire the rewritten target identity"
|
|
3959
|
+
"update must reacquire the rewritten target identity"
|
|
3637
3960
|
);
|
|
3638
3961
|
let recaptureCompleted = false;
|
|
3639
3962
|
const recapture = peer
|
|
@@ -3655,7 +3978,7 @@ test("blocked rewrites reacquire a target identity changed before update", async
|
|
|
3655
3978
|
assert.equal(
|
|
3656
3979
|
after.find((memory) => memory.path === targetMemory.path)?.content,
|
|
3657
3980
|
contentC,
|
|
3658
|
-
"update must write only after holding the current target identity lock"
|
|
3981
|
+
"update must write only after holding the current target identity lock"
|
|
3659
3982
|
);
|
|
3660
3983
|
assert.equal(after.filter((memory) => memory.content === contentB).length, 1);
|
|
3661
3984
|
} finally {
|
|
@@ -3914,130 +4237,97 @@ test("queued-review dispositions coordinate with explicit capture dedupe", async
|
|
|
3914
4237
|
});
|
|
3915
4238
|
});
|
|
3916
4239
|
|
|
3917
|
-
test("active rewrites
|
|
4240
|
+
test("active rewrites serialize the target path across their read and write", async () => {
|
|
3918
4241
|
await withMemoryDir(async (dir) => {
|
|
3919
4242
|
const storage = new StorageManager(dir);
|
|
3920
4243
|
const peer = new StorageManager(dir);
|
|
3921
4244
|
await storage.ensureDirectories();
|
|
3922
4245
|
await peer.ensureDirectories();
|
|
3923
|
-
const
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
semanticThreshold: 0.9,
|
|
3927
|
-
namespace: "default",
|
|
3928
|
-
};
|
|
3929
|
-
storage.setTombstonesConfig(tombstoneConfig);
|
|
3930
|
-
peer.setTombstonesConfig(tombstoneConfig);
|
|
3931
|
-
const contentA = "An active target becomes blocked before an update writes.";
|
|
3932
|
-
const contentB = "The rewritten blocked target identity must be locked.";
|
|
3933
|
-
const contentC = "The stale update must publish only after locking identity B.";
|
|
3934
|
-
const tombstoneId = await peer.appendTombstone({
|
|
3935
|
-
reason: "correction",
|
|
3936
|
-
createdBy: "user_correction",
|
|
3937
|
-
sourceMemoryId: "active-rewrite-recheck",
|
|
3938
|
-
rawContent: contentB,
|
|
3939
|
-
});
|
|
3940
|
-
assert.ok(tombstoneId);
|
|
4246
|
+
const contentA = "An active target is read before a concurrent update.";
|
|
4247
|
+
const contentB = "The concurrent update must run after the in-flight write.";
|
|
4248
|
+
const contentC = "The in-flight update holds the path through persistence.";
|
|
3941
4249
|
const target = await storage.writeMemory("fact", contentA, {
|
|
3942
4250
|
source: "test",
|
|
3943
4251
|
sourceConnector: "provider-a",
|
|
3944
4252
|
});
|
|
3945
4253
|
const targetMemory = await storage.getMemoryById(target.id);
|
|
3946
4254
|
assert.ok(targetMemory);
|
|
3947
|
-
assert.equal(targetMemory.frontmatter.status, "active");
|
|
3948
|
-
const identityB = buildExplicitCaptureDedupKey(contentB, "fact", "provider-a");
|
|
3949
|
-
await storage.hasTombstoneBlockedExplicitCapture(contentB, "fact", "provider-a");
|
|
3950
4255
|
|
|
4256
|
+
const readPaused = Promise.withResolvers<void>();
|
|
4257
|
+
const releaseRead = Promise.withResolvers<void>();
|
|
3951
4258
|
const storageWithOverrides = storage as unknown as {
|
|
3952
4259
|
readMemoryByPath: (filePath: string) => Promise<MemoryFile | null>;
|
|
3953
4260
|
withTombstoneBlockedCaptureWriteLock: (
|
|
3954
4261
|
task: () => Promise<unknown>,
|
|
3955
|
-
identity?: string | readonly string[]
|
|
4262
|
+
identity?: string | readonly string[]
|
|
3956
4263
|
) => Promise<unknown>;
|
|
3957
4264
|
};
|
|
3958
4265
|
const originalRead = storageWithOverrides.readMemoryByPath.bind(storage);
|
|
3959
|
-
let
|
|
4266
|
+
let pauseRead = true;
|
|
3960
4267
|
storageWithOverrides.readMemoryByPath = async (filePath) => {
|
|
3961
4268
|
const current = await originalRead(filePath);
|
|
3962
|
-
if (
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
const rewritten = await peer.getMemoryById(target.id);
|
|
3967
|
-
assert.ok(rewritten);
|
|
3968
|
-
assert.equal(
|
|
3969
|
-
await peer.writeMemoryFrontmatter(rewritten, {
|
|
3970
|
-
status: "pending_review",
|
|
3971
|
-
blockedBy: tombstoneId,
|
|
3972
|
-
}),
|
|
3973
|
-
true,
|
|
3974
|
-
);
|
|
3975
|
-
pauseNextPrepare = true;
|
|
3976
|
-
return await originalRead(filePath);
|
|
4269
|
+
if (pauseRead && filePath === targetMemory.path) {
|
|
4270
|
+
pauseRead = false;
|
|
4271
|
+
readPaused.resolve();
|
|
4272
|
+
await releaseRead.promise;
|
|
3977
4273
|
}
|
|
3978
4274
|
return current;
|
|
3979
4275
|
};
|
|
3980
|
-
const
|
|
3981
|
-
const
|
|
4276
|
+
const originalStorageLock = storageWithOverrides.withTombstoneBlockedCaptureWriteLock.bind(storage);
|
|
4277
|
+
const storageIdentities: Array<string | readonly string[] | undefined> = [];
|
|
3982
4278
|
storageWithOverrides.withTombstoneBlockedCaptureWriteLock = async (task, identity) => {
|
|
3983
|
-
|
|
3984
|
-
return await
|
|
4279
|
+
storageIdentities.push(identity);
|
|
4280
|
+
return await originalStorageLock(task, identity);
|
|
4281
|
+
};
|
|
4282
|
+
|
|
4283
|
+
const peerWithOverride = peer as unknown as {
|
|
4284
|
+
withTombstoneBlockedCaptureWriteLock: (
|
|
4285
|
+
task: () => Promise<unknown>,
|
|
4286
|
+
identity?: string | readonly string[]
|
|
4287
|
+
) => Promise<unknown>;
|
|
4288
|
+
};
|
|
4289
|
+
const originalPeerLock = peerWithOverride.withTombstoneBlockedCaptureWriteLock.bind(peer);
|
|
4290
|
+
const peerLockRequested = Promise.withResolvers<void>();
|
|
4291
|
+
const peerIdentities: Array<string | readonly string[] | undefined> = [];
|
|
4292
|
+
peerWithOverride.withTombstoneBlockedCaptureWriteLock = async (task, identity) => {
|
|
4293
|
+
peerIdentities.push(identity);
|
|
4294
|
+
peerLockRequested.resolve();
|
|
4295
|
+
return await originalPeerLock(task, identity);
|
|
3985
4296
|
};
|
|
3986
|
-
const releaseMarker = Promise.withResolvers<void>();
|
|
3987
|
-
const markerEntered = Promise.withResolvers<void>();
|
|
3988
|
-
let pauseNextPrepare = false;
|
|
3989
|
-
const originalPrepare = TombstoneBlockedCaptureIndex.prototype.prepareWrite;
|
|
3990
|
-
const prepareSpy = mock.method(
|
|
3991
|
-
TombstoneBlockedCaptureIndex.prototype,
|
|
3992
|
-
"prepareWrite",
|
|
3993
|
-
async function (this: TombstoneBlockedCaptureIndex) {
|
|
3994
|
-
const marker = await originalPrepare.call(this);
|
|
3995
|
-
if (pauseNextPrepare) {
|
|
3996
|
-
pauseNextPrepare = false;
|
|
3997
|
-
markerEntered.resolve();
|
|
3998
|
-
await releaseMarker.promise;
|
|
3999
|
-
}
|
|
4000
|
-
return marker;
|
|
4001
|
-
}
|
|
4002
|
-
);
|
|
4003
4297
|
|
|
4004
4298
|
const update = storage.updateMemory(target.id, contentC, { sourceConnector: "provider-a" });
|
|
4299
|
+
let competingUpdate: Promise<boolean> | undefined;
|
|
4300
|
+
let competingFinished = false;
|
|
4005
4301
|
try {
|
|
4006
|
-
await
|
|
4302
|
+
await readPaused.promise;
|
|
4303
|
+
competingUpdate = peer.updateMemory(target.id, contentB, { sourceConnector: "provider-a" }).then((updated) => {
|
|
4304
|
+
competingFinished = true;
|
|
4305
|
+
return updated;
|
|
4306
|
+
});
|
|
4307
|
+
await peerLockRequested.promise;
|
|
4308
|
+
const contentionWindow = Promise.withResolvers<void>();
|
|
4309
|
+
setTimeout(contentionWindow.resolve, 50);
|
|
4310
|
+
await contentionWindow.promise;
|
|
4311
|
+
const pathIdentity = buildCapturePathLockIdentity(targetMemory.path);
|
|
4007
4312
|
assert.ok(
|
|
4008
|
-
|
|
4009
|
-
(Array.isArray(identity) ? identity : [identity]).includes(identityB)
|
|
4010
|
-
),
|
|
4011
|
-
"active rewrite must reacquire the current blocked target identity",
|
|
4313
|
+
storageIdentities.some((identity) => (Array.isArray(identity) ? identity : [identity]).includes(pathIdentity))
|
|
4012
4314
|
);
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
.writeMemory("fact", contentB, {
|
|
4016
|
-
source: "test",
|
|
4017
|
-
sourceConnector: "provider-a",
|
|
4018
|
-
})
|
|
4019
|
-
.then((result) => {
|
|
4020
|
-
recaptureCompleted = true;
|
|
4021
|
-
return result;
|
|
4022
|
-
});
|
|
4023
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
4024
|
-
assert.equal(recaptureCompleted, false, "recapture must wait for the current target identity lock");
|
|
4025
|
-
releaseMarker.resolve();
|
|
4026
|
-
assert.equal(await update, true);
|
|
4027
|
-
assert.equal((await recapture).tombstoneBlocked, true);
|
|
4028
|
-
const after = await peer.readAllMemories();
|
|
4029
|
-
assert.equal(
|
|
4030
|
-
after.find((memory) => memory.path === targetMemory.path)?.content,
|
|
4031
|
-
contentC,
|
|
4032
|
-
"the stale update must write the requested content",
|
|
4315
|
+
assert.ok(
|
|
4316
|
+
peerIdentities.some((identity) => (Array.isArray(identity) ? identity : [identity]).includes(pathIdentity))
|
|
4033
4317
|
);
|
|
4034
|
-
assert.equal(
|
|
4318
|
+
assert.equal(competingFinished, false, "the peer must wait while the first writer holds the target path");
|
|
4319
|
+
|
|
4320
|
+
releaseRead.resolve();
|
|
4321
|
+
assert.equal(await update, true);
|
|
4322
|
+
assert.equal(await competingUpdate, true);
|
|
4323
|
+
assert.equal((await peer.getMemoryById(target.id))?.content, contentB);
|
|
4035
4324
|
} finally {
|
|
4036
|
-
|
|
4037
|
-
prepareSpy.mock.restore();
|
|
4325
|
+
releaseRead.resolve();
|
|
4038
4326
|
storageWithOverrides.readMemoryByPath = originalRead;
|
|
4039
|
-
storageWithOverrides.withTombstoneBlockedCaptureWriteLock =
|
|
4327
|
+
storageWithOverrides.withTombstoneBlockedCaptureWriteLock = originalStorageLock;
|
|
4328
|
+
peerWithOverride.withTombstoneBlockedCaptureWriteLock = originalPeerLock;
|
|
4040
4329
|
await update.catch(() => false);
|
|
4330
|
+
await competingUpdate?.catch(() => false);
|
|
4041
4331
|
}
|
|
4042
4332
|
});
|
|
4043
4333
|
});
|