@remnic/core 10.0.3 → 10.0.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/access-admin-ops-surface.js +62 -62
- package/dist/access-authorization-probe.js +63 -63
- package/dist/access-boundary.js +62 -62
- package/dist/access-cli.d.ts.map +1 -1
- package/dist/access-cli.js +146 -139
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +62 -62
- package/dist/access-http-briefing.js +63 -63
- package/dist/access-http-query.js +64 -64
- package/dist/access-http.d.ts.map +1 -1
- package/dist/access-http.js +86 -85
- package/dist/access-identity-continuity-surface.js +62 -62
- package/dist/access-lcm-surface.js +62 -62
- package/dist/access-mcp-correction-tools.d.ts +10 -0
- package/dist/access-mcp-correction-tools.d.ts.map +1 -0
- package/dist/access-mcp-correction-tools.js +8 -0
- package/dist/access-mcp.d.ts.map +1 -1
- package/dist/access-mcp.js +76 -75
- package/dist/access-namespace-preflight.js +62 -62
- package/dist/access-observe-write-category.js +5 -5
- package/dist/access-observe-write-surface.js +62 -62
- package/dist/access-offline-manifest.js +8 -8
- package/dist/access-operations-batch.js +65 -65
- package/dist/access-operations.d.ts +1 -0
- package/dist/access-operations.d.ts.map +1 -1
- package/dist/access-operations.js +72 -72
- package/dist/access-recall-concurrency.js +62 -62
- package/dist/access-recall-diagnostics.js +2 -2
- package/dist/access-recall-response.js +62 -62
- package/dist/access-recall-surface.js +62 -62
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +62 -62
- package/dist/access-surface-catalog.js +64 -64
- package/dist/active-recall.js +31 -30
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/{auto-sync-PAWBFQWL.js → auto-sync-FN7E3OTO.js} +6 -6
- package/dist/briefing.js +26 -26
- package/dist/buffer.js +8 -8
- package/dist/causal-consolidation.js +26 -26
- package/dist/{chunk-YQSWNFZE.js → chunk-2CP577K6.js} +2 -2
- package/dist/{chunk-6JIHC5AS.js → chunk-37HCPM56.js} +78 -67
- package/dist/chunk-37HCPM56.js.map +1 -0
- package/dist/{chunk-345MEMRU.js → chunk-3OUGSOJP.js} +2 -2
- package/dist/{chunk-CHI37EHP.js → chunk-4CWUZBPF.js} +8 -6
- package/dist/chunk-4CWUZBPF.js.map +1 -0
- package/dist/{chunk-G2STTRYB.js → chunk-4D2YH47Z.js} +2 -2
- package/dist/{chunk-IXYIW3MZ.js → chunk-4K2H4KTR.js} +5 -5
- package/dist/{chunk-UVVSOSHL.js → chunk-52CQKST6.js} +53 -53
- package/dist/{chunk-H7BZBSP6.js → chunk-52II7PB6.js} +4 -4
- package/dist/{chunk-BLHPADUX.js → chunk-5BPXMAUP.js} +22 -78
- package/dist/chunk-5BPXMAUP.js.map +1 -0
- package/dist/{chunk-ZS7RK6H6.js → chunk-5BY3IA2U.js} +16 -53
- package/dist/chunk-5BY3IA2U.js.map +1 -0
- package/dist/{chunk-2QZFZNXO.js → chunk-5CQO6LVM.js} +2 -2
- package/dist/{chunk-NLDMTXWV.js → chunk-5LNPW7NE.js} +2 -2
- package/dist/{chunk-WHTMVTU4.js → chunk-5X4ZJESN.js} +2 -2
- package/dist/{chunk-WI37MWRZ.js → chunk-63UNVGZW.js} +5 -5
- package/dist/{chunk-G3T6YMBO.js → chunk-64S6X4IU.js} +7 -7
- package/dist/{chunk-CFCEJNOE.js → chunk-6KHF6PAB.js} +2 -2
- package/dist/{chunk-5GINB5LC.js → chunk-6MKLMEBE.js} +1 -1
- package/dist/{chunk-5GINB5LC.js.map → chunk-6MKLMEBE.js.map} +1 -1
- package/dist/{chunk-35A7GCHG.js → chunk-6T42L5FI.js} +2 -2
- package/dist/{chunk-JDOBIFBK.js → chunk-7CXL25AA.js} +2 -2
- package/dist/{chunk-YLBE6PLR.js → chunk-7IGMKQWK.js} +2 -2
- package/dist/{chunk-CSLK7BN6.js → chunk-7LYRFI5A.js} +2 -2
- package/dist/{chunk-IB63OVUB.js → chunk-AJ6ORARY.js} +6 -6
- package/dist/{chunk-CGOKNQDK.js → chunk-ANZXWOYD.js} +2 -2
- package/dist/{chunk-5QXMESS7.js → chunk-AXC7UTLM.js} +2 -2
- package/dist/{chunk-RFIJRZ4K.js → chunk-B657ZGDH.js} +2 -2
- package/dist/{chunk-AW4QUFQF.js → chunk-BTNNL7ZW.js} +3 -2
- package/dist/{chunk-AW4QUFQF.js.map → chunk-BTNNL7ZW.js.map} +1 -1
- package/dist/{chunk-MY7B3HYC.js → chunk-CLCMDKTB.js} +2 -2
- package/dist/{chunk-QPWUG2S3.js → chunk-CYEK6Z3P.js} +4 -4
- package/dist/{chunk-IHCYCE6D.js → chunk-DJMVSUPK.js} +4 -4
- package/dist/{chunk-HP4CU2ZA.js → chunk-DST7HRSG.js} +2 -2
- package/dist/{chunk-IIFFC3RL.js → chunk-EDR6CVWZ.js} +2 -2
- package/dist/{chunk-AUWMKDKL.js → chunk-EMVJU7WC.js} +2 -2
- package/dist/{chunk-O6AYMAPJ.js → chunk-ENNC3RZ6.js} +2 -2
- package/dist/{chunk-2JRB3Z5N.js → chunk-EP5WXE2G.js} +3 -3
- package/dist/{chunk-QLK3SL7Q.js → chunk-ETSJD5IV.js} +131 -12
- package/dist/chunk-ETSJD5IV.js.map +1 -0
- package/dist/chunk-EWMRFW3F.js +38 -0
- package/dist/chunk-EWMRFW3F.js.map +1 -0
- package/dist/{chunk-I2KEH2LS.js → chunk-FC6RCOIU.js} +2 -2
- package/dist/{chunk-OZVHLBH6.js → chunk-FLV7M7CT.js} +2 -2
- package/dist/{chunk-Q6GI7HEC.js → chunk-FRH2UC7Q.js} +2 -2
- package/dist/{chunk-3SL52JKD.js → chunk-FZVROZKC.js} +5 -5
- package/dist/{chunk-2EZB2DL5.js → chunk-GE6HETIF.js} +3 -3
- package/dist/{chunk-2DHJTJIY.js → chunk-GEGUBU3D.js} +2 -2
- package/dist/{chunk-6AA7XFMO.js → chunk-GF4H3B3R.js} +8 -8
- package/dist/{chunk-NGOZH7R5.js → chunk-GVUW5XK5.js} +311 -142
- package/dist/chunk-GVUW5XK5.js.map +1 -0
- package/dist/{chunk-ME2LMFHF.js → chunk-HPAOMYKM.js} +92 -92
- package/dist/{chunk-4NRZ7BRS.js → chunk-I25RINZK.js} +2 -2
- package/dist/{chunk-XG4XXI66.js → chunk-I25RQA65.js} +2 -2
- package/dist/chunk-I56MTWE7.js +80 -0
- package/dist/chunk-I56MTWE7.js.map +1 -0
- package/dist/{chunk-EJJMDLVB.js → chunk-IJ4FEGZR.js} +2 -2
- package/dist/{chunk-EUL3S3LE.js → chunk-J5WI4QRP.js} +4 -4
- package/dist/{chunk-LMMC55WM.js → chunk-JA54KIYD.js} +4 -4
- package/dist/{chunk-5FLFPTDK.js → chunk-JA72X46J.js} +2 -2
- package/dist/{chunk-6GU3TNJJ.js → chunk-JMF5Q4JY.js} +246 -49
- package/dist/chunk-JMF5Q4JY.js.map +1 -0
- package/dist/{chunk-IDSSDL4W.js → chunk-JXSYWTFK.js} +21 -4
- package/dist/{chunk-IDSSDL4W.js.map → chunk-JXSYWTFK.js.map} +1 -1
- package/dist/{chunk-NLYOOGZ7.js → chunk-KE5PWLI6.js} +3 -3
- package/dist/chunk-KIUVEMBI.js +49 -0
- package/dist/chunk-KIUVEMBI.js.map +1 -0
- package/dist/{chunk-4DDIWRT7.js → chunk-KQI2PKYP.js} +2 -2
- package/dist/{chunk-Y2ADLCB3.js → chunk-KSUOM3YU.js} +9 -9
- package/dist/{chunk-BTOHGPHC.js → chunk-KZEMFD6E.js} +3 -3
- package/dist/{chunk-NXVD46HT.js → chunk-L2VS27PZ.js} +4 -4
- package/dist/{chunk-MYYHACOW.js → chunk-L34W4W4I.js} +2 -2
- package/dist/{chunk-KRTIHXWC.js → chunk-L3PWXD73.js} +2 -2
- package/dist/{chunk-NQHSXHJP.js → chunk-L6GNS5GB.js} +2 -2
- package/dist/{chunk-44PBRUXB.js → chunk-M47Q6566.js} +2 -2
- package/dist/{chunk-E7FN5N5E.js → chunk-MQNOIH2C.js} +7 -7
- package/dist/{chunk-IDSZNHIP.js → chunk-MULNBSPP.js} +4 -4
- package/dist/{chunk-RKSGUMVL.js → chunk-NBQIFCJE.js} +2 -2
- package/dist/{chunk-I6WFBNA4.js → chunk-NHSVW7UT.js} +15 -15
- package/dist/{chunk-32HO62I4.js → chunk-OFEHITAZ.js} +2 -2
- package/dist/{chunk-PCO3P7WJ.js → chunk-OGVJXIHX.js} +2 -2
- package/dist/{chunk-RYN4AIRM.js → chunk-OZABSIOV.js} +4 -4
- package/dist/{chunk-HO7IQP7G.js → chunk-QMFKW4OU.js} +3 -3
- package/dist/{chunk-34G4U6HS.js → chunk-QRZMJ2WN.js} +2 -2
- package/dist/{chunk-RKDSELA3.js → chunk-QWWMS4AE.js} +1 -1
- package/dist/chunk-QWWMS4AE.js.map +1 -0
- package/dist/{chunk-GUD6FYQG.js → chunk-RSMIRLKM.js} +2 -2
- package/dist/{chunk-TNVZCLJU.js → chunk-S5TGRZWY.js} +2 -2
- package/dist/{chunk-O24EWFPQ.js → chunk-SNXBXYUE.js} +3 -3
- package/dist/{chunk-KW77LGDX.js → chunk-SUAX5JWY.js} +2 -2
- package/dist/{chunk-PNFWIB4X.js → chunk-SWRN6U7Q.js} +2 -2
- package/dist/{chunk-X6X4UASX.js → chunk-SZXPKUMN.js} +232 -83
- package/dist/chunk-SZXPKUMN.js.map +1 -0
- package/dist/{chunk-R4NGLTUS.js → chunk-TDMNADPI.js} +2 -2
- package/dist/{chunk-QCP75JGO.js → chunk-TFA6HPOA.js} +5 -5
- package/dist/{chunk-LI76ESJL.js → chunk-TZQOCQXB.js} +2 -2
- package/dist/{chunk-OV7EYM6M.js → chunk-U6OXJQEH.js} +12 -12
- package/dist/{chunk-OWHPA4JS.js → chunk-V32NHP2R.js} +2 -2
- package/dist/{chunk-JSUA4YFE.js → chunk-WG4TMZJ2.js} +2 -2
- package/dist/{chunk-DQTCGVFK.js → chunk-WHCD4Z3D.js} +2 -2
- package/dist/{chunk-GBA4N2SG.js → chunk-WRICYGYG.js} +27 -26
- package/dist/chunk-WRICYGYG.js.map +1 -0
- package/dist/{chunk-KATEWTQJ.js → chunk-X7J56GPG.js} +2 -2
- package/dist/{chunk-7KICGR5W.js → chunk-XPRAOTJY.js} +2 -2
- package/dist/{chunk-2NV7MMMM.js → chunk-XQSJXNWC.js} +2 -2
- package/dist/{chunk-22DYJLFN.js → chunk-XVC7JU2N.js} +39 -18
- package/dist/chunk-XVC7JU2N.js.map +1 -0
- package/dist/{chunk-RXT6UB25.js → chunk-YJAOYEWI.js} +2 -2
- package/dist/{chunk-L6DJJEFW.js → chunk-YJEUHGZZ.js} +2 -2
- package/dist/{chunk-AXFWMRKI.js → chunk-YQJCWR4R.js} +2 -2
- package/dist/cli.js +110 -108
- package/dist/coding/export-okf-codegraph.js +25 -25
- package/dist/compounding/engine.js +25 -25
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +31 -30
- package/dist/connectors/codex-materialize-runner.js +25 -25
- package/dist/connectors/index.js +25 -25
- package/dist/consolidation-provenance-check.js +2 -2
- package/dist/contradiction/index.js +7 -7
- package/dist/convergence-refresh.js +27 -27
- package/dist/conversation-index/backend.js +2 -2
- package/dist/corpus-read-cancellation.d.ts +7 -0
- package/dist/corpus-read-cancellation.d.ts.map +1 -1
- package/dist/corpus-read-cancellation.js +1 -1
- package/dist/corpus-watermark.js +27 -27
- package/dist/correction/correction-access-wiring.d.ts +6 -6
- package/dist/correction/correction-access-wiring.d.ts.map +1 -1
- package/dist/correction/correction-classify.d.ts +25 -0
- package/dist/correction/correction-classify.d.ts.map +1 -0
- package/dist/correction/correction-config.d.ts +11 -0
- package/dist/correction/correction-config.d.ts.map +1 -0
- package/dist/correction/correction-contract.d.ts +13 -1
- package/dist/correction/correction-contract.d.ts.map +1 -1
- package/dist/correction/correction-executor.d.ts +2 -0
- package/dist/correction/correction-executor.d.ts.map +1 -1
- package/dist/correction/correction-planner.d.ts +24 -3
- package/dist/correction/correction-planner.d.ts.map +1 -1
- package/dist/directory-sidecars.js +2 -2
- package/dist/entity-retrieval.js +25 -25
- package/dist/event-order-recall.js +2 -2
- package/dist/explicit-capture.js +2 -2
- package/dist/external-wiki-access.js +63 -63
- package/dist/extraction-span-materialize.js +2 -2
- package/dist/extraction.js +34 -34
- package/dist/harmonic-retrieval.js +25 -25
- package/dist/index.js +221 -218
- package/dist/lcm/index.js +3 -3
- package/dist/local-llm.d.ts.map +1 -1
- package/dist/local-llm.js +1 -1
- package/dist/location/index.js +28 -28
- package/dist/maintenance/archive-observations.js +2 -2
- package/dist/maintenance/atomic-file.d.ts +1 -1
- package/dist/maintenance/atomic-file.d.ts.map +1 -1
- package/dist/maintenance/atomic-file.js +1 -1
- package/dist/maintenance/memory-governance.js +25 -25
- package/dist/maintenance/migrate-observations.js +3 -3
- package/dist/maintenance/observation-ledger-utils.js +2 -2
- package/dist/maintenance/projection-rebuild-abort.d.ts +17 -0
- package/dist/maintenance/projection-rebuild-abort.d.ts.map +1 -0
- package/dist/maintenance/projection-timeline.d.ts +19 -0
- package/dist/maintenance/projection-timeline.d.ts.map +1 -0
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +25 -25
- package/dist/maintenance/rebuild-memory-projection-runner.d.ts +8 -0
- package/dist/maintenance/rebuild-memory-projection-runner.d.ts.map +1 -0
- package/dist/maintenance/rebuild-memory-projection-runner.js +113 -0
- package/dist/maintenance/rebuild-memory-projection-runner.js.map +1 -0
- package/dist/maintenance/rebuild-memory-projection.d.ts +8 -0
- package/dist/maintenance/rebuild-memory-projection.d.ts.map +1 -1
- package/dist/maintenance/rebuild-memory-projection.js +26 -26
- package/dist/maintenance/rebuild-observations.js +3 -3
- package/dist/memory-browse-operations.js +63 -63
- package/dist/memory-browse.js +7 -7
- package/dist/memory-subject.js +1 -1
- package/dist/namespaces/migrate.js +26 -26
- package/dist/namespaces/search.js +10 -10
- package/dist/namespaces/storage.js +25 -25
- package/dist/offline-sync-impression-drain.js +3 -3
- package/dist/operator-doctor-corpus.js +28 -28
- package/dist/operator-toolkit.js +41 -40
- package/dist/orchestration/full-corpus-heap-guard.d.ts +25 -0
- package/dist/orchestration/full-corpus-heap-guard.d.ts.map +1 -0
- package/dist/orchestration/maintenance.d.ts.map +1 -1
- package/dist/orchestration/maintenance.js +38 -36
- package/dist/orchestration/projection-rebuild-schedule.d.ts +40 -0
- package/dist/orchestration/projection-rebuild-schedule.d.ts.map +1 -1
- package/dist/orchestration/session-context.d.ts.map +1 -1
- package/dist/orchestrator.js +142 -139
- package/dist/projection-rebuild-config.d.ts +52 -0
- package/dist/projection-rebuild-config.d.ts.map +1 -0
- package/dist/projection-rebuild-config.js +14 -0
- package/dist/projection-rebuild-config.js.map +1 -0
- package/dist/qmd.js +4 -4
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-navigate-access.js +2 -2
- package/dist/recall-navigate-disclosure.js +2 -2
- package/dist/recall-navigate.js +2 -2
- package/dist/recall-navigation-operations.js +63 -63
- package/dist/recall-navigation.js +62 -62
- package/dist/recall-state-view-admission.js +7 -7
- package/dist/recall-state.js +2 -2
- package/dist/recall-why-service.js +8 -8
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/manifest.js +3 -3
- package/dist/relevance.js +2 -2
- package/dist/{resolution-RSG4HZTL.js → resolution-TV3F7ZTH.js} +7 -7
- package/dist/resolution-TV3F7ZTH.js.map +1 -0
- package/dist/resume-bundles.js +32 -31
- package/dist/salvage-envelope.js +1 -1
- package/dist/search/factory.js +9 -9
- package/dist/search/index.js +17 -17
- package/dist/semantic-consolidation.js +31 -31
- package/dist/semantic-rule-promotion.js +25 -25
- package/dist/semantic-rule-verifier.js +25 -25
- package/dist/source-agent-qualifier.js +29 -29
- package/dist/standup/build.js +25 -25
- package/dist/storage/memory-lifecycle-ledger-access.d.ts +5 -3
- package/dist/storage/memory-lifecycle-ledger-access.d.ts.map +1 -1
- package/dist/storage/memory-read-store.d.ts +2 -2
- package/dist/storage/memory-read-store.d.ts.map +1 -1
- package/dist/storage.d.ts +4 -2
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +24 -24
- package/dist/subject-config.js +1 -1
- package/dist/summarizer.js +3 -3
- package/dist/support-passport/index.js +78 -78
- package/dist/transfer/export-okf.js +26 -26
- package/dist/types.d.ts +8 -40
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/verified-recall.js +25 -25
- package/dist/who-knows-cli.js +26 -26
- package/dist/who-knows.js +25 -25
- package/dist/write-envelope.js +1 -1
- package/package.json +2 -2
- package/src/access-cli.ts +4 -0
- package/src/access-http.ts +1 -0
- package/src/access-mcp-correction-tools.ts +56 -0
- package/src/access-mcp.ts +4 -49
- package/src/access-operations.ts +3 -0
- package/src/access-service.ts +12 -21
- package/src/config.test.ts +35 -0
- package/src/config.ts +6 -65
- package/src/corpus-read-cancellation.ts +7 -0
- package/src/correction/correction-access-wiring.ts +56 -16
- package/src/correction/correction-classify.test.ts +185 -0
- package/src/correction/correction-classify.ts +157 -0
- package/src/correction/correction-config.ts +93 -0
- package/src/correction/correction-contract.ts +61 -14
- package/src/correction/correction-executor.test.ts +102 -2
- package/src/correction/correction-executor.ts +19 -1
- package/src/correction/correction-planner.test.ts +141 -0
- package/src/correction/correction-planner.ts +117 -11
- package/src/correction/correction-surfaces.test.ts +22 -1
- package/src/local-llm-qos.test.ts +36 -0
- package/src/local-llm.ts +20 -3
- package/src/maintenance/atomic-file.ts +2 -0
- package/src/maintenance/projection-rebuild-abort.ts +40 -0
- package/src/maintenance/projection-timeline.ts +209 -0
- package/src/maintenance/rebuild-memory-projection-runner.ts +94 -0
- package/src/maintenance/rebuild-memory-projection.memory.test.ts +159 -0
- package/src/maintenance/rebuild-memory-projection.retain-raw.test.ts +202 -0
- package/src/maintenance/rebuild-memory-projection.ts +63 -91
- package/src/orchestration/full-corpus-heap-guard.ts +38 -0
- package/src/orchestration/maintenance.test.ts +2 -2
- package/src/orchestration/maintenance.ts +2 -0
- package/src/orchestration/projection-rebuild-schedule.test.ts +498 -0
- package/src/orchestration/projection-rebuild-schedule.ts +280 -9
- package/src/orchestration/session-context.ts +0 -15
- package/src/projection-rebuild-config.ts +82 -0
- package/src/recall-handles-wiring.test.ts +24 -0
- package/src/storage/memory-lifecycle-ledger-access.ts +61 -33
- package/src/storage/memory-read-store.ts +10 -4
- package/src/storage.ts +45 -33
- package/src/types.ts +8 -41
- package/dist/chunk-22DYJLFN.js.map +0 -1
- package/dist/chunk-6GU3TNJJ.js.map +0 -1
- package/dist/chunk-6JIHC5AS.js.map +0 -1
- package/dist/chunk-BLHPADUX.js.map +0 -1
- package/dist/chunk-CHI37EHP.js.map +0 -1
- package/dist/chunk-GBA4N2SG.js.map +0 -1
- package/dist/chunk-NGOZH7R5.js.map +0 -1
- package/dist/chunk-QLK3SL7Q.js.map +0 -1
- package/dist/chunk-RKDSELA3.js.map +0 -1
- package/dist/chunk-X6X4UASX.js.map +0 -1
- package/dist/chunk-ZS7RK6H6.js.map +0 -1
- /package/dist/{resolution-RSG4HZTL.js.map → access-mcp-correction-tools.js.map} +0 -0
- /package/dist/{auto-sync-PAWBFQWL.js.map → auto-sync-FN7E3OTO.js.map} +0 -0
- /package/dist/{chunk-YQSWNFZE.js.map → chunk-2CP577K6.js.map} +0 -0
- /package/dist/{chunk-345MEMRU.js.map → chunk-3OUGSOJP.js.map} +0 -0
- /package/dist/{chunk-G2STTRYB.js.map → chunk-4D2YH47Z.js.map} +0 -0
- /package/dist/{chunk-IXYIW3MZ.js.map → chunk-4K2H4KTR.js.map} +0 -0
- /package/dist/{chunk-UVVSOSHL.js.map → chunk-52CQKST6.js.map} +0 -0
- /package/dist/{chunk-H7BZBSP6.js.map → chunk-52II7PB6.js.map} +0 -0
- /package/dist/{chunk-2QZFZNXO.js.map → chunk-5CQO6LVM.js.map} +0 -0
- /package/dist/{chunk-NLDMTXWV.js.map → chunk-5LNPW7NE.js.map} +0 -0
- /package/dist/{chunk-WHTMVTU4.js.map → chunk-5X4ZJESN.js.map} +0 -0
- /package/dist/{chunk-WI37MWRZ.js.map → chunk-63UNVGZW.js.map} +0 -0
- /package/dist/{chunk-G3T6YMBO.js.map → chunk-64S6X4IU.js.map} +0 -0
- /package/dist/{chunk-CFCEJNOE.js.map → chunk-6KHF6PAB.js.map} +0 -0
- /package/dist/{chunk-35A7GCHG.js.map → chunk-6T42L5FI.js.map} +0 -0
- /package/dist/{chunk-JDOBIFBK.js.map → chunk-7CXL25AA.js.map} +0 -0
- /package/dist/{chunk-YLBE6PLR.js.map → chunk-7IGMKQWK.js.map} +0 -0
- /package/dist/{chunk-CSLK7BN6.js.map → chunk-7LYRFI5A.js.map} +0 -0
- /package/dist/{chunk-IB63OVUB.js.map → chunk-AJ6ORARY.js.map} +0 -0
- /package/dist/{chunk-CGOKNQDK.js.map → chunk-ANZXWOYD.js.map} +0 -0
- /package/dist/{chunk-5QXMESS7.js.map → chunk-AXC7UTLM.js.map} +0 -0
- /package/dist/{chunk-RFIJRZ4K.js.map → chunk-B657ZGDH.js.map} +0 -0
- /package/dist/{chunk-MY7B3HYC.js.map → chunk-CLCMDKTB.js.map} +0 -0
- /package/dist/{chunk-QPWUG2S3.js.map → chunk-CYEK6Z3P.js.map} +0 -0
- /package/dist/{chunk-IHCYCE6D.js.map → chunk-DJMVSUPK.js.map} +0 -0
- /package/dist/{chunk-HP4CU2ZA.js.map → chunk-DST7HRSG.js.map} +0 -0
- /package/dist/{chunk-IIFFC3RL.js.map → chunk-EDR6CVWZ.js.map} +0 -0
- /package/dist/{chunk-AUWMKDKL.js.map → chunk-EMVJU7WC.js.map} +0 -0
- /package/dist/{chunk-O6AYMAPJ.js.map → chunk-ENNC3RZ6.js.map} +0 -0
- /package/dist/{chunk-2JRB3Z5N.js.map → chunk-EP5WXE2G.js.map} +0 -0
- /package/dist/{chunk-I2KEH2LS.js.map → chunk-FC6RCOIU.js.map} +0 -0
- /package/dist/{chunk-OZVHLBH6.js.map → chunk-FLV7M7CT.js.map} +0 -0
- /package/dist/{chunk-Q6GI7HEC.js.map → chunk-FRH2UC7Q.js.map} +0 -0
- /package/dist/{chunk-3SL52JKD.js.map → chunk-FZVROZKC.js.map} +0 -0
- /package/dist/{chunk-2EZB2DL5.js.map → chunk-GE6HETIF.js.map} +0 -0
- /package/dist/{chunk-2DHJTJIY.js.map → chunk-GEGUBU3D.js.map} +0 -0
- /package/dist/{chunk-6AA7XFMO.js.map → chunk-GF4H3B3R.js.map} +0 -0
- /package/dist/{chunk-ME2LMFHF.js.map → chunk-HPAOMYKM.js.map} +0 -0
- /package/dist/{chunk-4NRZ7BRS.js.map → chunk-I25RINZK.js.map} +0 -0
- /package/dist/{chunk-XG4XXI66.js.map → chunk-I25RQA65.js.map} +0 -0
- /package/dist/{chunk-EJJMDLVB.js.map → chunk-IJ4FEGZR.js.map} +0 -0
- /package/dist/{chunk-EUL3S3LE.js.map → chunk-J5WI4QRP.js.map} +0 -0
- /package/dist/{chunk-LMMC55WM.js.map → chunk-JA54KIYD.js.map} +0 -0
- /package/dist/{chunk-5FLFPTDK.js.map → chunk-JA72X46J.js.map} +0 -0
- /package/dist/{chunk-NLYOOGZ7.js.map → chunk-KE5PWLI6.js.map} +0 -0
- /package/dist/{chunk-4DDIWRT7.js.map → chunk-KQI2PKYP.js.map} +0 -0
- /package/dist/{chunk-Y2ADLCB3.js.map → chunk-KSUOM3YU.js.map} +0 -0
- /package/dist/{chunk-BTOHGPHC.js.map → chunk-KZEMFD6E.js.map} +0 -0
- /package/dist/{chunk-NXVD46HT.js.map → chunk-L2VS27PZ.js.map} +0 -0
- /package/dist/{chunk-MYYHACOW.js.map → chunk-L34W4W4I.js.map} +0 -0
- /package/dist/{chunk-KRTIHXWC.js.map → chunk-L3PWXD73.js.map} +0 -0
- /package/dist/{chunk-NQHSXHJP.js.map → chunk-L6GNS5GB.js.map} +0 -0
- /package/dist/{chunk-44PBRUXB.js.map → chunk-M47Q6566.js.map} +0 -0
- /package/dist/{chunk-E7FN5N5E.js.map → chunk-MQNOIH2C.js.map} +0 -0
- /package/dist/{chunk-IDSZNHIP.js.map → chunk-MULNBSPP.js.map} +0 -0
- /package/dist/{chunk-RKSGUMVL.js.map → chunk-NBQIFCJE.js.map} +0 -0
- /package/dist/{chunk-I6WFBNA4.js.map → chunk-NHSVW7UT.js.map} +0 -0
- /package/dist/{chunk-32HO62I4.js.map → chunk-OFEHITAZ.js.map} +0 -0
- /package/dist/{chunk-PCO3P7WJ.js.map → chunk-OGVJXIHX.js.map} +0 -0
- /package/dist/{chunk-RYN4AIRM.js.map → chunk-OZABSIOV.js.map} +0 -0
- /package/dist/{chunk-HO7IQP7G.js.map → chunk-QMFKW4OU.js.map} +0 -0
- /package/dist/{chunk-34G4U6HS.js.map → chunk-QRZMJ2WN.js.map} +0 -0
- /package/dist/{chunk-GUD6FYQG.js.map → chunk-RSMIRLKM.js.map} +0 -0
- /package/dist/{chunk-TNVZCLJU.js.map → chunk-S5TGRZWY.js.map} +0 -0
- /package/dist/{chunk-O24EWFPQ.js.map → chunk-SNXBXYUE.js.map} +0 -0
- /package/dist/{chunk-KW77LGDX.js.map → chunk-SUAX5JWY.js.map} +0 -0
- /package/dist/{chunk-PNFWIB4X.js.map → chunk-SWRN6U7Q.js.map} +0 -0
- /package/dist/{chunk-R4NGLTUS.js.map → chunk-TDMNADPI.js.map} +0 -0
- /package/dist/{chunk-QCP75JGO.js.map → chunk-TFA6HPOA.js.map} +0 -0
- /package/dist/{chunk-LI76ESJL.js.map → chunk-TZQOCQXB.js.map} +0 -0
- /package/dist/{chunk-OV7EYM6M.js.map → chunk-U6OXJQEH.js.map} +0 -0
- /package/dist/{chunk-OWHPA4JS.js.map → chunk-V32NHP2R.js.map} +0 -0
- /package/dist/{chunk-JSUA4YFE.js.map → chunk-WG4TMZJ2.js.map} +0 -0
- /package/dist/{chunk-DQTCGVFK.js.map → chunk-WHCD4Z3D.js.map} +0 -0
- /package/dist/{chunk-KATEWTQJ.js.map → chunk-X7J56GPG.js.map} +0 -0
- /package/dist/{chunk-7KICGR5W.js.map → chunk-XPRAOTJY.js.map} +0 -0
- /package/dist/{chunk-2NV7MMMM.js.map → chunk-XQSJXNWC.js.map} +0 -0
- /package/dist/{chunk-RXT6UB25.js.map → chunk-YJAOYEWI.js.map} +0 -0
- /package/dist/{chunk-L6DJJEFW.js.map → chunk-YJEUHGZZ.js.map} +0 -0
- /package/dist/{chunk-AXFWMRKI.js.map → chunk-YQJCWR4R.js.map} +0 -0
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { fork } from "node:child_process";
|
|
3
|
+
import { once } from "node:events";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import test from "node:test";
|
|
10
|
+
import { commitPreparedFileAtomically } from "../maintenance/atomic-file.js";
|
|
11
|
+
import { watchProjectionRebuildParent } from "../maintenance/projection-rebuild-abort.js";
|
|
12
|
+
import { loadProjectionTimeline } from "../maintenance/projection-timeline.js";
|
|
13
|
+
import { rebuildMemoryProjection } from "../maintenance/rebuild-memory-projection.js";
|
|
14
|
+
import { initLogger, resetLogger, type LoggerBackend } from "../logger.js";
|
|
15
|
+
import { probeProjectionHealth } from "../memory-projection-store.js";
|
|
16
|
+
import { StorageManager } from "../storage.js";
|
|
17
|
+
import type { MemoryLifecycleEvent, PluginConfig } from "../types.js";
|
|
18
|
+
import {
|
|
19
|
+
createProjectionRebuildScheduleState,
|
|
20
|
+
forkProjectionRebuild,
|
|
21
|
+
maybeRebuildMemoryProjectionScheduled,
|
|
22
|
+
projectionRebuildChildEnv,
|
|
23
|
+
projectionRebuildForkTimeoutMs,
|
|
24
|
+
terminateScheduledProjectionRebuilds,
|
|
25
|
+
type ProjectionRebuildForkRequest,
|
|
26
|
+
type ProjectionRebuildForkResult,
|
|
27
|
+
} from "./projection-rebuild-schedule.js";
|
|
28
|
+
|
|
29
|
+
const PARENT_DISCONNECT_FLAG = "--projection-parent-disconnect-child";
|
|
30
|
+
|
|
31
|
+
if (process.argv.includes(PARENT_DISCONNECT_FLAG)) {
|
|
32
|
+
const memoryDir = process.argv[process.argv.indexOf(PARENT_DISCONNECT_FLAG) + 1];
|
|
33
|
+
if (!memoryDir) process.exit(1);
|
|
34
|
+
try {
|
|
35
|
+
const signal = watchProjectionRebuildParent();
|
|
36
|
+
process.send?.({ ready: true });
|
|
37
|
+
await new Promise<void>((resolve) => {
|
|
38
|
+
if (signal.aborted) {
|
|
39
|
+
resolve();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
signal.addEventListener("abort", () => resolve(), { once: true });
|
|
43
|
+
});
|
|
44
|
+
await rebuildMemoryProjection({
|
|
45
|
+
memoryDir,
|
|
46
|
+
dryRun: false,
|
|
47
|
+
now: new Date("2026-06-01T00:00:00.000Z"),
|
|
48
|
+
signal,
|
|
49
|
+
});
|
|
50
|
+
} catch {
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function config(memoryDir: string, overrides: Record<string, unknown> = {}): PluginConfig {
|
|
57
|
+
return {
|
|
58
|
+
memoryDir,
|
|
59
|
+
defaultNamespace: "ns-schedule",
|
|
60
|
+
projectionRebuildEnabled: true,
|
|
61
|
+
projectionRebuildIntervalMs: 6 * 60 * 60 * 1000,
|
|
62
|
+
projectionRebuildHeapUsageLimit: 0.6,
|
|
63
|
+
...overrides,
|
|
64
|
+
} as unknown as PluginConfig;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function quietHeap() {
|
|
68
|
+
return { used_heap_size: 1, heap_size_limit: 100 };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Windows reports TerminateProcess as an exit code, not SIGKILL. */
|
|
72
|
+
function assertChildKilled(child: { signalCode: NodeJS.Signals | null; exitCode: number | null }): void {
|
|
73
|
+
if (process.platform === "win32") {
|
|
74
|
+
assert.notEqual(child.exitCode, null);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
assert.equal(child.signalCode, "SIGKILL");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** A storage stand-in whose corpus reads fail the test if the daemon calls them. */
|
|
81
|
+
function corpusGuard(memoryDir: string): StorageManager {
|
|
82
|
+
const fail = async (): Promise<never> => {
|
|
83
|
+
throw new Error("daemon read the corpus");
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
dir: memoryDir,
|
|
87
|
+
isSecureStoreUnlocked: () => false,
|
|
88
|
+
readAllMemories: fail,
|
|
89
|
+
readAllColdMemories: fail,
|
|
90
|
+
readArchivedMemories: fail,
|
|
91
|
+
iterateMemoryLifecycleEvents: async function* () {
|
|
92
|
+
throw new Error("daemon read the ledger");
|
|
93
|
+
},
|
|
94
|
+
} as unknown as StorageManager;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function seedFact(memoryDir: string): Promise<void> {
|
|
98
|
+
const dir = path.join(memoryDir, "facts", "2026-01-01");
|
|
99
|
+
await mkdir(dir, { recursive: true });
|
|
100
|
+
await writeFile(
|
|
101
|
+
path.join(dir, "fact-1.md"),
|
|
102
|
+
[
|
|
103
|
+
"---",
|
|
104
|
+
"id: fact-1",
|
|
105
|
+
"category: fact",
|
|
106
|
+
"confidence: 0.8",
|
|
107
|
+
"created: 2026-01-01T00:00:00.000Z",
|
|
108
|
+
"updated: 2026-01-01T00:00:00.000Z",
|
|
109
|
+
"status: active",
|
|
110
|
+
"source: test",
|
|
111
|
+
"---",
|
|
112
|
+
"",
|
|
113
|
+
"scheduled rebuild fixture",
|
|
114
|
+
"",
|
|
115
|
+
].join("\n"),
|
|
116
|
+
"utf8",
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
test("shutting down the parent kills the projection rebuild child", async () => {
|
|
121
|
+
const child = fork(process.execPath, ["-e", "setInterval(() => {}, 1e9);"], { stdio: "ignore" });
|
|
122
|
+
const pending = forkProjectionRebuild(
|
|
123
|
+
{ memoryDir: "/tmp/unused", defaultNamespace: "default", now: new Date("2026-06-01T00:00:00.000Z") },
|
|
124
|
+
{ timeoutMs: 60_000, spawnChild: () => child },
|
|
125
|
+
);
|
|
126
|
+
terminateScheduledProjectionRebuilds();
|
|
127
|
+
await assert.rejects(pending, /exited/);
|
|
128
|
+
assertChildKilled(child);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("disposing one scheduler does not kill another scheduler's rebuild", async () => {
|
|
132
|
+
const first = fork(process.execPath, ["-e", "setInterval(() => {}, 1e9);"], { stdio: "ignore" });
|
|
133
|
+
const second = fork(process.execPath, ["-e", "setInterval(() => {}, 1e9);"], { stdio: "ignore" });
|
|
134
|
+
const request = {
|
|
135
|
+
memoryDir: "/tmp/unused",
|
|
136
|
+
defaultNamespace: "default",
|
|
137
|
+
now: new Date("2026-06-01T00:00:00.000Z"),
|
|
138
|
+
};
|
|
139
|
+
const stateA = createProjectionRebuildScheduleState();
|
|
140
|
+
const stateB = createProjectionRebuildScheduleState();
|
|
141
|
+
const pendingA = forkProjectionRebuild(request, { timeoutMs: 60_000, spawnChild: () => first, owner: stateA });
|
|
142
|
+
const pendingB = forkProjectionRebuild(request, { timeoutMs: 60_000, spawnChild: () => second, owner: stateB });
|
|
143
|
+
terminateScheduledProjectionRebuilds(stateA);
|
|
144
|
+
await assert.rejects(pendingA, /exited/);
|
|
145
|
+
assertChildKilled(first);
|
|
146
|
+
assert.equal(second.exitCode, null);
|
|
147
|
+
assert.equal(second.signalCode, null);
|
|
148
|
+
terminateScheduledProjectionRebuilds(stateB);
|
|
149
|
+
await assert.rejects(pendingB, /exited/);
|
|
150
|
+
assertChildKilled(second);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("a disconnected parent does not let the rebuild child publish", async () => {
|
|
154
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-orphan-"));
|
|
155
|
+
const projection = path.join(memoryDir, "state", "memory-projection.sqlite");
|
|
156
|
+
try {
|
|
157
|
+
await seedFact(memoryDir);
|
|
158
|
+
const child = fork(fileURLToPath(import.meta.url), [
|
|
159
|
+
PARENT_DISCONNECT_FLAG,
|
|
160
|
+
memoryDir,
|
|
161
|
+
], {
|
|
162
|
+
execArgv: ["--import", "tsx"],
|
|
163
|
+
stdio: ["ignore", "inherit", "inherit", "ipc"],
|
|
164
|
+
});
|
|
165
|
+
const outcome = await Promise.race([
|
|
166
|
+
once(child, "message").then(() => "ready" as const),
|
|
167
|
+
once(child, "exit").then(() => "exit" as const),
|
|
168
|
+
]);
|
|
169
|
+
assert.equal(outcome, "ready");
|
|
170
|
+
child.disconnect();
|
|
171
|
+
const [code] = await once(child, "exit");
|
|
172
|
+
assert.notEqual(code, 0);
|
|
173
|
+
assert.equal(existsSync(projection), false);
|
|
174
|
+
assert.equal(existsSync(`${projection}.tmp`), false);
|
|
175
|
+
} finally {
|
|
176
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("a hung projection rebuild child is killed at the timeout", async () => {
|
|
181
|
+
const child = fork(process.execPath, ["-e", "setInterval(() => {}, 1e9);"], { stdio: "ignore" });
|
|
182
|
+
await assert.rejects(
|
|
183
|
+
() => forkProjectionRebuild(
|
|
184
|
+
{ memoryDir: "/tmp/unused", defaultNamespace: "default", now: new Date("2026-06-01T00:00:00.000Z") },
|
|
185
|
+
{ timeoutMs: 200, spawnChild: () => child },
|
|
186
|
+
),
|
|
187
|
+
/timed out after 200ms/,
|
|
188
|
+
);
|
|
189
|
+
await new Promise<void>((resolve) => {
|
|
190
|
+
if (child.exitCode !== null || child.signalCode !== null) resolve();
|
|
191
|
+
else child.once("exit", () => resolve());
|
|
192
|
+
});
|
|
193
|
+
assertChildKilled(child);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("an aborted signal stops the corpus scan before the projection is published", async () => {
|
|
197
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-abort-scan-"));
|
|
198
|
+
const projection = path.join(memoryDir, "state", "memory-projection.sqlite");
|
|
199
|
+
try {
|
|
200
|
+
await seedFact(memoryDir);
|
|
201
|
+
const signal = AbortSignal.abort(new Error("projection rebuild runner parent disconnected"));
|
|
202
|
+
await assert.rejects(
|
|
203
|
+
() => rebuildMemoryProjection({
|
|
204
|
+
memoryDir,
|
|
205
|
+
dryRun: false,
|
|
206
|
+
now: new Date("2026-06-01T00:00:00.000Z"),
|
|
207
|
+
signal,
|
|
208
|
+
}),
|
|
209
|
+
(err: unknown) => {
|
|
210
|
+
assert.ok(err instanceof Error);
|
|
211
|
+
assert.equal(err.name, "AbortError");
|
|
212
|
+
assert.match(err.message, /corpus read aborted/);
|
|
213
|
+
return true;
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
assert.equal(existsSync(projection), false);
|
|
217
|
+
assert.equal(existsSync(`${projection}.tmp`), false);
|
|
218
|
+
} finally {
|
|
219
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test("an aborted signal stops an archive scan and the lifecycle ledger mid-stream", async () => {
|
|
224
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-abort-rest-"));
|
|
225
|
+
try {
|
|
226
|
+
const storage = new StorageManager(memoryDir);
|
|
227
|
+
await assert.rejects(
|
|
228
|
+
() => storage.readArchivedMemories({ retainRaw: false, abortSignal: AbortSignal.abort() }),
|
|
229
|
+
(err: unknown) => {
|
|
230
|
+
assert.ok(err instanceof Error);
|
|
231
|
+
assert.equal(err.name, "AbortError");
|
|
232
|
+
return true;
|
|
233
|
+
},
|
|
234
|
+
);
|
|
235
|
+
const controller = new AbortController();
|
|
236
|
+
let pulled = 0;
|
|
237
|
+
await assert.rejects(
|
|
238
|
+
() => loadProjectionTimeline({
|
|
239
|
+
storage: {
|
|
240
|
+
iterateMemoryLifecycleEvents(): AsyncIterable<MemoryLifecycleEvent> {
|
|
241
|
+
return (async function* () {
|
|
242
|
+
for (let index = 0; index < 5; index += 1) {
|
|
243
|
+
pulled += 1;
|
|
244
|
+
if (index === 1) controller.abort();
|
|
245
|
+
yield {
|
|
246
|
+
eventId: `e${index}`,
|
|
247
|
+
memoryId: "m",
|
|
248
|
+
eventType: "created",
|
|
249
|
+
timestamp: "2026-01-01T00:00:00.000Z",
|
|
250
|
+
actor: "test",
|
|
251
|
+
ruleVersion: "1",
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
})();
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
memoryDir,
|
|
258
|
+
memories: [],
|
|
259
|
+
signal: controller.signal,
|
|
260
|
+
}),
|
|
261
|
+
/projection rebuild aborted/,
|
|
262
|
+
);
|
|
263
|
+
assert.ok(pulled < 5);
|
|
264
|
+
} finally {
|
|
265
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test("an abort after the projection backup does not rename over the live file", async () => {
|
|
270
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-rename-"));
|
|
271
|
+
const output = path.join(dir, "memory-projection.sqlite");
|
|
272
|
+
const temp = `${output}.tmp`;
|
|
273
|
+
const backup = path.join(dir, "backup.sqlite");
|
|
274
|
+
try {
|
|
275
|
+
await writeFile(output, "live");
|
|
276
|
+
await writeFile(temp, "orphan");
|
|
277
|
+
await assert.rejects(
|
|
278
|
+
() => commitPreparedFileAtomically(temp, output, backup, async () => {
|
|
279
|
+
throw new Error("projection rebuild runner parent disconnected");
|
|
280
|
+
}),
|
|
281
|
+
/parent disconnected/,
|
|
282
|
+
);
|
|
283
|
+
assert.equal(await readFile(output, "utf8"), "live");
|
|
284
|
+
assert.equal(existsSync(temp), false);
|
|
285
|
+
assert.equal(await readFile(backup, "utf8"), "live");
|
|
286
|
+
} finally {
|
|
287
|
+
await rm(dir, { recursive: true, force: true });
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test("the fork hang cap follows a long interval and stays at least 30 minutes", () => {
|
|
292
|
+
assert.equal(projectionRebuildForkTimeoutMs(60_000), 30 * 60 * 1000);
|
|
293
|
+
assert.equal(projectionRebuildForkTimeoutMs(6 * 60 * 60 * 1000), 6 * 60 * 60 * 1000);
|
|
294
|
+
assert.equal(projectionRebuildForkTimeoutMs(Number.NaN), 30 * 60 * 1000);
|
|
295
|
+
assert.equal(projectionRebuildForkTimeoutMs(30 * 24 * 60 * 60 * 1000), 2_147_483_647);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test("projection rebuild child env keeps locators and drops secrets", () => {
|
|
299
|
+
const env = projectionRebuildChildEnv({
|
|
300
|
+
PATH: "/usr/bin",
|
|
301
|
+
HOME: "/tmp/remnic-home",
|
|
302
|
+
OPENAI_API_KEY: "sk-test",
|
|
303
|
+
REMNIC_SECURE_STORE_KEY: "unlock-material",
|
|
304
|
+
NODE_OPTIONS: "--conditions=remnic-source",
|
|
305
|
+
});
|
|
306
|
+
assert.equal(env.PATH, "/usr/bin");
|
|
307
|
+
assert.equal(env.HOME, "/tmp/remnic-home");
|
|
308
|
+
assert.equal(env.NODE_OPTIONS, "--conditions=remnic-source");
|
|
309
|
+
assert.equal(env.OPENAI_API_KEY, undefined);
|
|
310
|
+
assert.equal(env.REMNIC_SECURE_STORE_KEY, undefined);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test("scheduled projection rebuild forks and does not read the corpus in the daemon", async () => {
|
|
314
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-fork-"));
|
|
315
|
+
const calls: ProjectionRebuildForkRequest[] = [];
|
|
316
|
+
const timeouts: number[] = [];
|
|
317
|
+
try {
|
|
318
|
+
const state = createProjectionRebuildScheduleState();
|
|
319
|
+
await maybeRebuildMemoryProjectionScheduled({
|
|
320
|
+
config: config(memoryDir),
|
|
321
|
+
getStorage: () => corpusGuard(memoryDir),
|
|
322
|
+
state,
|
|
323
|
+
heapStatistics: quietHeap,
|
|
324
|
+
forkRebuild: async (request, options) => {
|
|
325
|
+
calls.push(request);
|
|
326
|
+
if (options?.timeoutMs !== undefined) timeouts.push(options.timeoutMs);
|
|
327
|
+
return { currentRows: 4, timelineRows: 5, entityMentionRows: 6 };
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
assert.equal(calls.length, 1);
|
|
331
|
+
assert.deepEqual(timeouts, [6 * 60 * 60 * 1000]);
|
|
332
|
+
assert.equal(calls[0]?.memoryDir, memoryDir);
|
|
333
|
+
assert.equal(calls[0]?.defaultNamespace, "ns-schedule");
|
|
334
|
+
assert.equal(state.inFlight, false);
|
|
335
|
+
assert.ok(state.lastRebuildAtMs > 0);
|
|
336
|
+
|
|
337
|
+
const again = calls.length;
|
|
338
|
+
await maybeRebuildMemoryProjectionScheduled({
|
|
339
|
+
config: config(memoryDir),
|
|
340
|
+
getStorage: () => corpusGuard(memoryDir),
|
|
341
|
+
state,
|
|
342
|
+
heapStatistics: quietHeap,
|
|
343
|
+
forkRebuild: async () => {
|
|
344
|
+
calls.push({ memoryDir, defaultNamespace: "ns-schedule", now: new Date() });
|
|
345
|
+
return { currentRows: 0, timelineRows: 0, entityMentionRows: 0 };
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
assert.equal(calls.length, again, "success interval suppresses a second fork");
|
|
349
|
+
} finally {
|
|
350
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test("scheduled projection rebuild keeps in-flight and failure backoff", async () => {
|
|
355
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-backoff-"));
|
|
356
|
+
try {
|
|
357
|
+
const inFlight = createProjectionRebuildScheduleState();
|
|
358
|
+
inFlight.inFlight = true;
|
|
359
|
+
let forks = 0;
|
|
360
|
+
const forkRebuild = async (): Promise<ProjectionRebuildForkResult> => {
|
|
361
|
+
forks += 1;
|
|
362
|
+
return { currentRows: 0, timelineRows: 0, entityMentionRows: 0 };
|
|
363
|
+
};
|
|
364
|
+
await maybeRebuildMemoryProjectionScheduled({
|
|
365
|
+
config: config(memoryDir),
|
|
366
|
+
state: inFlight,
|
|
367
|
+
heapStatistics: quietHeap,
|
|
368
|
+
forkRebuild,
|
|
369
|
+
});
|
|
370
|
+
assert.equal(forks, 0, "in-flight rebuild is not started again");
|
|
371
|
+
|
|
372
|
+
const failing = createProjectionRebuildScheduleState();
|
|
373
|
+
await maybeRebuildMemoryProjectionScheduled({
|
|
374
|
+
config: config(memoryDir),
|
|
375
|
+
state: failing,
|
|
376
|
+
heapStatistics: quietHeap,
|
|
377
|
+
forkRebuild: async () => {
|
|
378
|
+
throw new Error("runner failed");
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
assert.equal(failing.inFlight, false);
|
|
382
|
+
assert.equal(failing.lastRebuildAtMs, 0);
|
|
383
|
+
assert.ok(failing.lastFailureAtMs > 0);
|
|
384
|
+
await maybeRebuildMemoryProjectionScheduled({
|
|
385
|
+
config: config(memoryDir),
|
|
386
|
+
state: failing,
|
|
387
|
+
heapStatistics: quietHeap,
|
|
388
|
+
forkRebuild,
|
|
389
|
+
});
|
|
390
|
+
assert.equal(forks, 0, "failure backoff suppresses the retry");
|
|
391
|
+
} finally {
|
|
392
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
test("heap guard postpones a scheduled projection rebuild", async () => {
|
|
397
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-heap-"));
|
|
398
|
+
const warnings: string[] = [];
|
|
399
|
+
const backend: LoggerBackend = {
|
|
400
|
+
info() {},
|
|
401
|
+
warn(msg) {
|
|
402
|
+
warnings.push(msg);
|
|
403
|
+
},
|
|
404
|
+
error() {},
|
|
405
|
+
debug() {},
|
|
406
|
+
};
|
|
407
|
+
initLogger(backend, false, { timestamps: false });
|
|
408
|
+
try {
|
|
409
|
+
const state = createProjectionRebuildScheduleState();
|
|
410
|
+
let forks = 0;
|
|
411
|
+
await maybeRebuildMemoryProjectionScheduled({
|
|
412
|
+
config: config(memoryDir),
|
|
413
|
+
getStorage: () => corpusGuard(memoryDir),
|
|
414
|
+
state,
|
|
415
|
+
heapStatistics: () => ({ used_heap_size: 70, heap_size_limit: 100 }),
|
|
416
|
+
forkRebuild: async () => {
|
|
417
|
+
forks += 1;
|
|
418
|
+
return { currentRows: 0, timelineRows: 0, entityMentionRows: 0 };
|
|
419
|
+
},
|
|
420
|
+
});
|
|
421
|
+
assert.equal(forks, 0);
|
|
422
|
+
assert.equal(state.inFlight, false);
|
|
423
|
+
assert.equal(state.lastRebuildAtMs, 0);
|
|
424
|
+
assert.ok(state.lastFailureAtMs > 0);
|
|
425
|
+
assert.equal(warnings.length, 1);
|
|
426
|
+
assert.match(warnings[0] ?? "", /postponed/);
|
|
427
|
+
assert.match(warnings[0] ?? "", /heap used 70 of limit 100/);
|
|
428
|
+
assert.match(warnings[0] ?? "", /ratio 0\.700/);
|
|
429
|
+
assert.match(warnings[0] ?? "", /projectionRebuildHeapUsageLimit 0\.6/);
|
|
430
|
+
} finally {
|
|
431
|
+
resetLogger();
|
|
432
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test("heap guard does not postpone at the limit or with an unusable cap", async () => {
|
|
437
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-heap-ok-"));
|
|
438
|
+
try {
|
|
439
|
+
let forks = 0;
|
|
440
|
+
const forkRebuild = async (): Promise<ProjectionRebuildForkResult> => {
|
|
441
|
+
forks += 1;
|
|
442
|
+
return { currentRows: 1, timelineRows: 0, entityMentionRows: 0 };
|
|
443
|
+
};
|
|
444
|
+
const atLimit = createProjectionRebuildScheduleState();
|
|
445
|
+
await maybeRebuildMemoryProjectionScheduled({
|
|
446
|
+
config: config(memoryDir),
|
|
447
|
+
state: atLimit,
|
|
448
|
+
heapStatistics: () => ({ used_heap_size: 60, heap_size_limit: 100 }),
|
|
449
|
+
forkRebuild,
|
|
450
|
+
});
|
|
451
|
+
assert.equal(forks, 1, "ratio equal to the limit still runs");
|
|
452
|
+
|
|
453
|
+
const disabled = createProjectionRebuildScheduleState();
|
|
454
|
+
await maybeRebuildMemoryProjectionScheduled({
|
|
455
|
+
config: config(memoryDir, { projectionRebuildHeapUsageLimit: 1 }),
|
|
456
|
+
state: disabled,
|
|
457
|
+
heapStatistics: () => ({ used_heap_size: 100, heap_size_limit: 100 }),
|
|
458
|
+
forkRebuild,
|
|
459
|
+
});
|
|
460
|
+
assert.equal(forks, 2, "a limit of 1 never postpones");
|
|
461
|
+
|
|
462
|
+
const unusable = createProjectionRebuildScheduleState();
|
|
463
|
+
await maybeRebuildMemoryProjectionScheduled({
|
|
464
|
+
config: config(memoryDir),
|
|
465
|
+
state: unusable,
|
|
466
|
+
heapStatistics: () => ({ used_heap_size: 10, heap_size_limit: 0 }),
|
|
467
|
+
forkRebuild,
|
|
468
|
+
});
|
|
469
|
+
assert.equal(forks, 3, "a non-positive heap cap does not postpone");
|
|
470
|
+
} finally {
|
|
471
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
test("an unlocked secure store rebuilds in-process instead of forking", async () => {
|
|
476
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-unlocked-"));
|
|
477
|
+
try {
|
|
478
|
+
await seedFact(memoryDir);
|
|
479
|
+
const storage = new StorageManager(memoryDir);
|
|
480
|
+
storage.setSecureStoreKey(Buffer.alloc(32, 4), false);
|
|
481
|
+
assert.equal(storage.isSecureStoreUnlocked(), true);
|
|
482
|
+
let forks = 0;
|
|
483
|
+
await maybeRebuildMemoryProjectionScheduled({
|
|
484
|
+
config: config(memoryDir),
|
|
485
|
+
getStorage: () => storage,
|
|
486
|
+
state: createProjectionRebuildScheduleState(),
|
|
487
|
+
heapStatistics: quietHeap,
|
|
488
|
+
forkRebuild: async () => {
|
|
489
|
+
forks += 1;
|
|
490
|
+
throw new Error("forked an unlocked store");
|
|
491
|
+
},
|
|
492
|
+
});
|
|
493
|
+
assert.equal(forks, 0);
|
|
494
|
+
assert.equal(probeProjectionHealth(memoryDir).state, "openable");
|
|
495
|
+
} finally {
|
|
496
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
497
|
+
}
|
|
498
|
+
});
|