@remnic/core 9.3.771 → 9.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.d.ts +5 -5
- package/dist/access-admin-ops-surface.js +36 -35
- package/dist/access-boundary.d.ts +5 -5
- package/dist/access-boundary.js +37 -36
- package/dist/access-cli.js +109 -108
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +5 -5
- package/dist/access-http.js +48 -47
- package/dist/access-identity-continuity-surface.d.ts +4 -4
- package/dist/access-identity-continuity-surface.js +36 -35
- package/dist/access-lcm-surface.d.ts +5 -5
- package/dist/access-lcm-surface.js +36 -35
- package/dist/access-mcp.d.ts +5 -5
- package/dist/access-mcp.js +44 -43
- package/dist/access-observe-write-surface.d.ts +5 -5
- package/dist/access-observe-write-surface.js +36 -35
- package/dist/access-operations-batch.js +41 -40
- package/dist/access-operations.d.ts +5 -5
- package/dist/access-operations.js +43 -42
- package/dist/access-recall-surface.d.ts +5 -5
- package/dist/access-recall-surface.js +36 -35
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-CdW6B2qQ.d.ts → access-service-m-2VO_Ig.d.ts} +3 -3
- package/dist/access-service.d.ts +5 -5
- package/dist/access-service.js +36 -35
- package/dist/access-surface-catalog.d.ts +5 -5
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +2 -2
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/{auto-sync-2SOUW4JW.js → auto-sync-HMHQHUAG.js} +9 -9
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -4
- package/dist/bootstrap.js +2 -2
- package/dist/boxes.js +2 -2
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +12 -12
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/buffer.js +2 -2
- package/dist/calibration.d.ts +1 -1
- package/dist/calibration.js +4 -4
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-bflYNWsM.d.ts → catalog-BxWokdC2.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +4 -4
- package/dist/causal-chain.js +4 -4
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +17 -17
- package/dist/causal-retrieval.js +4 -4
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory-graph.js +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-PSNMICC2.js → chunk-27FLVMDC.js} +14 -14
- package/dist/{chunk-7FL4CNPV.js → chunk-2A3OXAP2.js} +2 -2
- package/dist/{chunk-U5HD7BB2.js → chunk-2FOD2YY3.js} +10 -10
- package/dist/{chunk-GG6AJN7A.js → chunk-2IZAGAJR.js} +2 -2
- package/dist/{chunk-6Y4JTNX7.js → chunk-2MR3MFQB.js} +2 -2
- package/dist/{chunk-AU7Q3LSC.js → chunk-2QSZNTDO.js} +4 -4
- package/dist/{chunk-IBAU2RZN.js → chunk-2U2A5HF4.js} +11 -5
- package/dist/chunk-2U2A5HF4.js.map +1 -0
- package/dist/chunk-37CTGERM.js +62 -0
- package/dist/chunk-37CTGERM.js.map +1 -0
- package/dist/{chunk-MYNRJGOY.js → chunk-3F4N4WDH.js} +76 -111
- package/dist/chunk-3F4N4WDH.js.map +1 -0
- package/dist/{chunk-7OSULYN2.js → chunk-4BFRBP45.js} +2 -2
- package/dist/{chunk-DQC3ZZYM.js → chunk-4KJLYTLS.js} +2 -2
- package/dist/{chunk-DMKMQTBH.js → chunk-4P4626RY.js} +5 -5
- package/dist/{chunk-GY3SKOS4.js → chunk-5EZXHU36.js} +2 -2
- package/dist/{chunk-OW4UXZNP.js → chunk-5QZDMSSN.js} +61 -61
- package/dist/chunk-64UDOIMI.js +121 -0
- package/dist/chunk-64UDOIMI.js.map +1 -0
- package/dist/{chunk-OTMAYEY5.js → chunk-66FLU5BT.js} +3 -3
- package/dist/{chunk-J2QYB2D5.js → chunk-6BISDEN6.js} +7 -7
- package/dist/{chunk-CXBFYSQY.js → chunk-6ZIETXZ2.js} +3 -3
- package/dist/{chunk-KYYL4U6X.js → chunk-7N2RUBAP.js} +3 -3
- package/dist/{chunk-U3TRHUSJ.js → chunk-7QWMTOIF.js} +45 -45
- package/dist/{chunk-L24JROPR.js → chunk-7WSLR2CU.js} +2 -2
- package/dist/{chunk-T4AWNIXJ.js → chunk-7Z2DZNWN.js} +18 -9
- package/dist/{chunk-T4AWNIXJ.js.map → chunk-7Z2DZNWN.js.map} +1 -1
- package/dist/{chunk-EXM3CQTZ.js → chunk-A3GOMRJG.js} +2 -2
- package/dist/{chunk-DCWIQFNA.js → chunk-AKUCU7CI.js} +7 -7
- package/dist/{chunk-XHYGJVXL.js → chunk-AXTXN4T6.js} +2 -2
- package/dist/{chunk-L42FA4BU.js → chunk-BGTAL46Y.js} +2 -2
- package/dist/{chunk-5QANTTY2.js → chunk-BRDJ2HFP.js} +2 -2
- package/dist/{chunk-7VFZTJ7K.js → chunk-BV2TIZ4F.js} +2 -2
- package/dist/{chunk-QMN3CIFS.js → chunk-CGS7UKWM.js} +2 -2
- package/dist/{chunk-LZ73Y56P.js → chunk-CLX5VDNY.js} +8 -8
- package/dist/{chunk-KYC3RLYJ.js → chunk-CXLNZXG5.js} +1 -1
- package/dist/{chunk-YOELDDBF.js → chunk-CZAA5N5S.js} +4 -4
- package/dist/{chunk-XG4NBBRW.js → chunk-CZAZX7JP.js} +5 -5
- package/dist/{chunk-QOGXUNWL.js → chunk-CZGIIADK.js} +7 -7
- package/dist/{chunk-QRDOSYOR.js → chunk-DBRYEIGY.js} +2 -2
- package/dist/{chunk-6QODJKOV.js → chunk-DGYCWCQ7.js} +3 -3
- package/dist/{chunk-RFZW7NID.js → chunk-DR6PEJU3.js} +4 -4
- package/dist/{chunk-UC4YOAC2.js → chunk-E5BK6CGV.js} +2 -2
- package/dist/{chunk-TKZ3AL5V.js → chunk-EHK6KZHK.js} +2 -2
- package/dist/{chunk-X5NUL5N4.js → chunk-EPGWWCZF.js} +3 -3
- package/dist/{chunk-JZ7P26GF.js → chunk-F53UF7CI.js} +2 -2
- package/dist/{chunk-SJHM6I4J.js → chunk-FC77VUX5.js} +2 -2
- package/dist/{chunk-DKTSR7EK.js → chunk-FDPZVY6D.js} +2 -2
- package/dist/{chunk-OUXPVWTZ.js → chunk-FLVL4L3L.js} +5 -5
- package/dist/{chunk-ZI3YYOOV.js → chunk-FZGGZAAU.js} +2 -2
- package/dist/{chunk-TQT3USCG.js → chunk-HG32URJJ.js} +2 -2
- package/dist/{chunk-ZQNCHPTZ.js → chunk-HLTAPHZZ.js} +2 -2
- package/dist/{chunk-LU7ATMRV.js → chunk-HRCACVHL.js} +3 -3
- package/dist/{chunk-LOPZ2DWR.js → chunk-I73G4UH7.js} +2 -2
- package/dist/{chunk-MJE4XV4A.js → chunk-IC6QX5TC.js} +2 -2
- package/dist/{chunk-27TJRC2Y.js → chunk-ILFJ7AVS.js} +7 -7
- package/dist/{chunk-VUA4S7P6.js → chunk-JIKJPDQJ.js} +4 -4
- package/dist/{chunk-BKTC7JCA.js → chunk-JLR3JSTL.js} +3 -3
- package/dist/{chunk-VQ34TERH.js → chunk-JZHHREBL.js} +2 -2
- package/dist/{chunk-IQVQJJL7.js → chunk-K2ZLHESQ.js} +2 -2
- package/dist/{chunk-PWFWCGOO.js → chunk-KAWTOYAW.js} +2 -2
- package/dist/{chunk-YRZMCPC5.js → chunk-KCJ5H6XQ.js} +4 -4
- package/dist/{chunk-DJECGBBM.js → chunk-KQDNAXOM.js} +2 -2
- package/dist/{chunk-WIWPSQYU.js → chunk-KQPJLK3X.js} +2 -2
- package/dist/{chunk-XNWLD3RR.js → chunk-LOR6ZM5R.js} +3 -3
- package/dist/{chunk-EGLUVV6B.js → chunk-M7GGMGMZ.js} +10 -10
- package/dist/{chunk-YTU7WKYN.js → chunk-MNUHL34L.js} +3 -3
- package/dist/{chunk-ZCWIH4LH.js → chunk-MRHFJV44.js} +2 -2
- package/dist/{chunk-W4H5A3TJ.js → chunk-MTR7BZQN.js} +3 -3
- package/dist/{chunk-PNLCEFE4.js → chunk-MTWKDOVO.js} +2 -2
- package/dist/{chunk-TECYUPFB.js → chunk-NG7YBCJO.js} +4 -4
- package/dist/{chunk-OSMBC3JU.js → chunk-O2EL7EGG.js} +2 -2
- package/dist/{chunk-HW5EF6LV.js → chunk-O7BBFJLP.js} +2 -2
- package/dist/{chunk-EHQ5HO5T.js → chunk-OBMR4VIX.js} +1 -1
- package/dist/{chunk-VFHDUFH5.js → chunk-OHDJ34CC.js} +2 -2
- package/dist/{chunk-6SHAUM5S.js → chunk-OUMTBFSQ.js} +4 -4
- package/dist/{chunk-27CQIO7T.js → chunk-P6SYWE4G.js} +57 -10
- package/dist/chunk-P6SYWE4G.js.map +1 -0
- package/dist/{chunk-EEKDRAWX.js → chunk-PRTA6444.js} +2 -2
- package/dist/{chunk-IQ7WCZRW.js → chunk-PUBTHW5O.js} +3 -3
- package/dist/{chunk-AGNBY3VG.js → chunk-PYHOAXTI.js} +2 -2
- package/dist/{chunk-UUH4YQOF.js → chunk-QLULYKWZ.js} +2 -2
- package/dist/{chunk-DBSMLRTO.js → chunk-QT2RZNRT.js} +2 -2
- package/dist/{chunk-HM6UJPPO.js → chunk-QWGNDWKB.js} +2 -2
- package/dist/{chunk-KCQA46NR.js → chunk-R5VAVVHP.js} +2 -2
- package/dist/{chunk-SXN3LCUT.js → chunk-RHOZ5LLO.js} +100 -4
- package/dist/chunk-RHOZ5LLO.js.map +1 -0
- package/dist/{chunk-6KYMPV2O.js → chunk-RL6NEVXT.js} +45 -2
- package/dist/chunk-RL6NEVXT.js.map +1 -0
- package/dist/{chunk-O7GOFAM3.js → chunk-RP7YXA67.js} +2 -2
- package/dist/{chunk-BVKCV2ZY.js → chunk-SMX5267P.js} +2 -2
- package/dist/{chunk-XBZQRZ6G.js → chunk-TN7THW5U.js} +2 -2
- package/dist/{chunk-JRZV3767.js → chunk-UI4FVU6T.js} +2 -2
- package/dist/{chunk-VGUOEDTU.js → chunk-V3UE5I5F.js} +2 -2
- package/dist/{chunk-7WV3F5DQ.js → chunk-V7IZKJI3.js} +2 -2
- package/dist/{chunk-VL7DP3OW.js → chunk-VFSP73LP.js} +2 -2
- package/dist/{chunk-C2DDH5UN.js → chunk-X4A62ET7.js} +14 -14
- package/dist/{chunk-WRBDUNSW.js → chunk-XN3TUUX2.js} +3 -3
- package/dist/{chunk-NNL4LJAD.js → chunk-XZ5I7OZR.js} +5 -5
- package/dist/{chunk-K2I3AWBR.js → chunk-YDSWRD33.js} +5 -5
- package/dist/{chunk-3NN73CM7.js → chunk-YFBTVOMB.js} +3 -3
- package/dist/{chunk-44YXWE35.js → chunk-YPEMNNNY.js} +2 -2
- package/dist/{chunk-ZZMRXJFY.js → chunk-ZIDSD6VC.js} +2 -2
- package/dist/{chunk-BMANIB5B.js → chunk-ZPOROUTX.js} +3 -3
- package/dist/{cli-Dfnc66gs.d.ts → cli-EiBBOt3r.d.ts} +3 -3
- package/dist/cli.d.ts +6 -6
- package/dist/cli.js +74 -73
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +13 -13
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compounding/preference-consolidator.js +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +13 -13
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/codex-materialize.js +2 -2
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +14 -14
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/contradiction/index.js +3 -3
- package/dist/{contradiction-scan-3FJYWS3G.js → contradiction-scan-SSKCAMLX.js} +3 -3
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/backend.js +5 -5
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/cleanup.js +2 -2
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.js +2 -2
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/indexer.js +2 -2
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/conversation-index/search.js +2 -2
- package/dist/day-summary.d.ts +1 -1
- package/dist/day-summary.js +2 -2
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +13 -13
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +4 -4
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-faithfulness.js +5 -5
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-telemetry.js +2 -2
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge-training.js +2 -2
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction-judge.js +5 -5
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +9 -9
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/fallback-llm.js +4 -4
- package/dist/{forget-OEE5OELK.js → forget-KHF7A44H.js} +3 -3
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/{graph-edge-decay-RXUCJIN4.js → graph-edge-decay-FO7AM4UR.js} +3 -3
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph-snapshot.js +2 -2
- package/dist/graph.d.ts +1 -1
- package/dist/graph.js +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +17 -12
- package/dist/index.js +124 -123
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/archive.js +2 -2
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +7 -7
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +9 -9
- package/dist/lcm/schema.js +3 -3
- package/dist/lcm/summarizer.js +3 -3
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/logger.d.ts +8 -2
- package/dist/logger.js +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +12 -12
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +12 -12
- package/dist/maintenance/rebuild-memory-projection.js +14 -14
- package/dist/mcp-memory-inspector-app.d.ts +5 -5
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +23 -3
- package/dist/memory-projection-store.js +9 -2
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/model-registry.js +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/models-json.js +2 -2
- package/dist/namespaces/migrate.d.ts +2 -2
- package/dist/namespaces/migrate.js +27 -26
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +15 -14
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +12 -12
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/native-knowledge.js +2 -2
- package/dist/negative.js +2 -2
- package/dist/operator-toolkit.d.ts +11 -2
- package/dist/operator-toolkit.js +36 -33
- package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
- package/dist/orchestration/compression-guideline-coordinator.js +2 -2
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +14 -14
- package/dist/{orchestrator-Y9wyG4jK.d.ts → orchestrator-B2Y28Z9t.d.ts} +3 -3
- package/dist/orchestrator.d.ts +4 -4
- package/dist/orchestrator.js +109 -108
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/profiling.js +2 -2
- package/dist/provenance.d.ts +1 -1
- package/dist/{purge-IHRX4Z7X.js → purge-NDWV6WYD.js} +4 -3
- package/dist/{purge-IHRX4Z7X.js.map → purge-NDWV6WYD.js.map} +1 -1
- package/dist/qmd-Db9mOkzB.d.ts +330 -0
- package/dist/qmd-preflight.d.ts +5 -0
- package/dist/qmd-preflight.js +31 -0
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +3 -305
- package/dist/qmd.js +11 -9
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-planner-llm.js +4 -4
- package/dist/recall-qos.js +2 -2
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-state.js +2 -2
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/relevance.js +2 -2
- package/dist/{resolution-33PIX3TT.js → resolution-VH4NGENZ.js} +3 -3
- package/dist/resolution-VH4NGENZ.js.map +1 -0
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resolve-provider-secret.js +2 -2
- package/dist/resume-bundles.js +4 -4
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-agents.js +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/routing/store.js +2 -2
- package/dist/runtime/better-sqlite.d.ts +17 -1
- package/dist/runtime/better-sqlite.js +5 -3
- package/dist/schemas.d.ts +22 -22
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/embed-helper.js +2 -2
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +14 -13
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +18 -17
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/lancedb-backend.js +3 -3
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +3 -3
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +3 -3
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/search/remote-backend.js +2 -2
- package/dist/{semantic-consolidation-bfXJNKVf.d.ts → semantic-consolidation-BDVIbLRw.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +14 -14
- package/dist/semantic-rule-promotion.js +12 -12
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +12 -12
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/session-observer-state.js +2 -2
- package/dist/session-transcript-migration.js +3 -3
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/shared-context/manager.js +2 -2
- package/dist/signal.d.ts +1 -1
- package/dist/storage-guards.js +2 -2
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +11 -11
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +7 -7
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-supersession.js +2 -2
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/threading.js +2 -2
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transcript.js +2 -2
- package/dist/transfer/autodetect.js +1 -1
- package/dist/transfer/backup.js +1 -1
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/export-sqlite.js +2 -2
- package/dist/transfer/import-sqlite.js +2 -2
- package/dist/transfer/types.d.ts +12 -12
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-D1iBqhJA.d.ts → types-ljkd82rn.d.ts} +13 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +13 -13
- package/package.json +2 -2
- package/src/logger.test.ts +120 -0
- package/src/logger.ts +37 -9
- package/src/memory-projection-open-failure.test.ts +322 -0
- package/src/memory-projection-store.ts +179 -2
- package/src/operator-toolkit.ts +64 -0
- package/src/qmd-preflight.test.ts +197 -0
- package/src/qmd-preflight.ts +167 -0
- package/src/qmd.ts +115 -129
- package/src/runtime/better-sqlite.test.ts +54 -0
- package/src/runtime/better-sqlite.ts +83 -3
- package/src/wearables/cleanup.test.ts +56 -0
- package/src/wearables/cleanup.ts +22 -1
- package/src/wearables/config.test.ts +25 -0
- package/src/wearables/config.ts +31 -4
- package/src/wearables/types.ts +12 -1
- package/dist/chunk-27CQIO7T.js.map +0 -1
- package/dist/chunk-6KYMPV2O.js.map +0 -1
- package/dist/chunk-IBAU2RZN.js.map +0 -1
- package/dist/chunk-MYNRJGOY.js.map +0 -1
- package/dist/chunk-NU3CSQ4H.js +0 -48
- package/dist/chunk-NU3CSQ4H.js.map +0 -1
- package/dist/chunk-SXN3LCUT.js.map +0 -1
- /package/dist/{auto-sync-2SOUW4JW.js.map → auto-sync-HMHQHUAG.js.map} +0 -0
- /package/dist/{chunk-PSNMICC2.js.map → chunk-27FLVMDC.js.map} +0 -0
- /package/dist/{chunk-7FL4CNPV.js.map → chunk-2A3OXAP2.js.map} +0 -0
- /package/dist/{chunk-U5HD7BB2.js.map → chunk-2FOD2YY3.js.map} +0 -0
- /package/dist/{chunk-GG6AJN7A.js.map → chunk-2IZAGAJR.js.map} +0 -0
- /package/dist/{chunk-6Y4JTNX7.js.map → chunk-2MR3MFQB.js.map} +0 -0
- /package/dist/{chunk-AU7Q3LSC.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-7OSULYN2.js.map → chunk-4BFRBP45.js.map} +0 -0
- /package/dist/{chunk-DQC3ZZYM.js.map → chunk-4KJLYTLS.js.map} +0 -0
- /package/dist/{chunk-DMKMQTBH.js.map → chunk-4P4626RY.js.map} +0 -0
- /package/dist/{chunk-GY3SKOS4.js.map → chunk-5EZXHU36.js.map} +0 -0
- /package/dist/{chunk-OW4UXZNP.js.map → chunk-5QZDMSSN.js.map} +0 -0
- /package/dist/{chunk-OTMAYEY5.js.map → chunk-66FLU5BT.js.map} +0 -0
- /package/dist/{chunk-J2QYB2D5.js.map → chunk-6BISDEN6.js.map} +0 -0
- /package/dist/{chunk-CXBFYSQY.js.map → chunk-6ZIETXZ2.js.map} +0 -0
- /package/dist/{chunk-KYYL4U6X.js.map → chunk-7N2RUBAP.js.map} +0 -0
- /package/dist/{chunk-U3TRHUSJ.js.map → chunk-7QWMTOIF.js.map} +0 -0
- /package/dist/{chunk-L24JROPR.js.map → chunk-7WSLR2CU.js.map} +0 -0
- /package/dist/{chunk-EXM3CQTZ.js.map → chunk-A3GOMRJG.js.map} +0 -0
- /package/dist/{chunk-DCWIQFNA.js.map → chunk-AKUCU7CI.js.map} +0 -0
- /package/dist/{chunk-XHYGJVXL.js.map → chunk-AXTXN4T6.js.map} +0 -0
- /package/dist/{chunk-L42FA4BU.js.map → chunk-BGTAL46Y.js.map} +0 -0
- /package/dist/{chunk-5QANTTY2.js.map → chunk-BRDJ2HFP.js.map} +0 -0
- /package/dist/{chunk-7VFZTJ7K.js.map → chunk-BV2TIZ4F.js.map} +0 -0
- /package/dist/{chunk-QMN3CIFS.js.map → chunk-CGS7UKWM.js.map} +0 -0
- /package/dist/{chunk-LZ73Y56P.js.map → chunk-CLX5VDNY.js.map} +0 -0
- /package/dist/{chunk-KYC3RLYJ.js.map → chunk-CXLNZXG5.js.map} +0 -0
- /package/dist/{chunk-YOELDDBF.js.map → chunk-CZAA5N5S.js.map} +0 -0
- /package/dist/{chunk-XG4NBBRW.js.map → chunk-CZAZX7JP.js.map} +0 -0
- /package/dist/{chunk-QOGXUNWL.js.map → chunk-CZGIIADK.js.map} +0 -0
- /package/dist/{chunk-QRDOSYOR.js.map → chunk-DBRYEIGY.js.map} +0 -0
- /package/dist/{chunk-6QODJKOV.js.map → chunk-DGYCWCQ7.js.map} +0 -0
- /package/dist/{chunk-RFZW7NID.js.map → chunk-DR6PEJU3.js.map} +0 -0
- /package/dist/{chunk-UC4YOAC2.js.map → chunk-E5BK6CGV.js.map} +0 -0
- /package/dist/{chunk-TKZ3AL5V.js.map → chunk-EHK6KZHK.js.map} +0 -0
- /package/dist/{chunk-X5NUL5N4.js.map → chunk-EPGWWCZF.js.map} +0 -0
- /package/dist/{chunk-JZ7P26GF.js.map → chunk-F53UF7CI.js.map} +0 -0
- /package/dist/{chunk-SJHM6I4J.js.map → chunk-FC77VUX5.js.map} +0 -0
- /package/dist/{chunk-DKTSR7EK.js.map → chunk-FDPZVY6D.js.map} +0 -0
- /package/dist/{chunk-OUXPVWTZ.js.map → chunk-FLVL4L3L.js.map} +0 -0
- /package/dist/{chunk-ZI3YYOOV.js.map → chunk-FZGGZAAU.js.map} +0 -0
- /package/dist/{chunk-TQT3USCG.js.map → chunk-HG32URJJ.js.map} +0 -0
- /package/dist/{chunk-ZQNCHPTZ.js.map → chunk-HLTAPHZZ.js.map} +0 -0
- /package/dist/{chunk-LU7ATMRV.js.map → chunk-HRCACVHL.js.map} +0 -0
- /package/dist/{chunk-LOPZ2DWR.js.map → chunk-I73G4UH7.js.map} +0 -0
- /package/dist/{chunk-MJE4XV4A.js.map → chunk-IC6QX5TC.js.map} +0 -0
- /package/dist/{chunk-27TJRC2Y.js.map → chunk-ILFJ7AVS.js.map} +0 -0
- /package/dist/{chunk-VUA4S7P6.js.map → chunk-JIKJPDQJ.js.map} +0 -0
- /package/dist/{chunk-BKTC7JCA.js.map → chunk-JLR3JSTL.js.map} +0 -0
- /package/dist/{chunk-VQ34TERH.js.map → chunk-JZHHREBL.js.map} +0 -0
- /package/dist/{chunk-IQVQJJL7.js.map → chunk-K2ZLHESQ.js.map} +0 -0
- /package/dist/{chunk-PWFWCGOO.js.map → chunk-KAWTOYAW.js.map} +0 -0
- /package/dist/{chunk-YRZMCPC5.js.map → chunk-KCJ5H6XQ.js.map} +0 -0
- /package/dist/{chunk-DJECGBBM.js.map → chunk-KQDNAXOM.js.map} +0 -0
- /package/dist/{chunk-WIWPSQYU.js.map → chunk-KQPJLK3X.js.map} +0 -0
- /package/dist/{chunk-XNWLD3RR.js.map → chunk-LOR6ZM5R.js.map} +0 -0
- /package/dist/{chunk-EGLUVV6B.js.map → chunk-M7GGMGMZ.js.map} +0 -0
- /package/dist/{chunk-YTU7WKYN.js.map → chunk-MNUHL34L.js.map} +0 -0
- /package/dist/{chunk-ZCWIH4LH.js.map → chunk-MRHFJV44.js.map} +0 -0
- /package/dist/{chunk-W4H5A3TJ.js.map → chunk-MTR7BZQN.js.map} +0 -0
- /package/dist/{chunk-PNLCEFE4.js.map → chunk-MTWKDOVO.js.map} +0 -0
- /package/dist/{chunk-TECYUPFB.js.map → chunk-NG7YBCJO.js.map} +0 -0
- /package/dist/{chunk-OSMBC3JU.js.map → chunk-O2EL7EGG.js.map} +0 -0
- /package/dist/{chunk-HW5EF6LV.js.map → chunk-O7BBFJLP.js.map} +0 -0
- /package/dist/{chunk-EHQ5HO5T.js.map → chunk-OBMR4VIX.js.map} +0 -0
- /package/dist/{chunk-VFHDUFH5.js.map → chunk-OHDJ34CC.js.map} +0 -0
- /package/dist/{chunk-6SHAUM5S.js.map → chunk-OUMTBFSQ.js.map} +0 -0
- /package/dist/{chunk-EEKDRAWX.js.map → chunk-PRTA6444.js.map} +0 -0
- /package/dist/{chunk-IQ7WCZRW.js.map → chunk-PUBTHW5O.js.map} +0 -0
- /package/dist/{chunk-AGNBY3VG.js.map → chunk-PYHOAXTI.js.map} +0 -0
- /package/dist/{chunk-UUH4YQOF.js.map → chunk-QLULYKWZ.js.map} +0 -0
- /package/dist/{chunk-DBSMLRTO.js.map → chunk-QT2RZNRT.js.map} +0 -0
- /package/dist/{chunk-HM6UJPPO.js.map → chunk-QWGNDWKB.js.map} +0 -0
- /package/dist/{chunk-KCQA46NR.js.map → chunk-R5VAVVHP.js.map} +0 -0
- /package/dist/{chunk-O7GOFAM3.js.map → chunk-RP7YXA67.js.map} +0 -0
- /package/dist/{chunk-BVKCV2ZY.js.map → chunk-SMX5267P.js.map} +0 -0
- /package/dist/{chunk-XBZQRZ6G.js.map → chunk-TN7THW5U.js.map} +0 -0
- /package/dist/{chunk-JRZV3767.js.map → chunk-UI4FVU6T.js.map} +0 -0
- /package/dist/{chunk-VGUOEDTU.js.map → chunk-V3UE5I5F.js.map} +0 -0
- /package/dist/{chunk-7WV3F5DQ.js.map → chunk-V7IZKJI3.js.map} +0 -0
- /package/dist/{chunk-VL7DP3OW.js.map → chunk-VFSP73LP.js.map} +0 -0
- /package/dist/{chunk-C2DDH5UN.js.map → chunk-X4A62ET7.js.map} +0 -0
- /package/dist/{chunk-WRBDUNSW.js.map → chunk-XN3TUUX2.js.map} +0 -0
- /package/dist/{chunk-NNL4LJAD.js.map → chunk-XZ5I7OZR.js.map} +0 -0
- /package/dist/{chunk-K2I3AWBR.js.map → chunk-YDSWRD33.js.map} +0 -0
- /package/dist/{chunk-3NN73CM7.js.map → chunk-YFBTVOMB.js.map} +0 -0
- /package/dist/{chunk-44YXWE35.js.map → chunk-YPEMNNNY.js.map} +0 -0
- /package/dist/{chunk-ZZMRXJFY.js.map → chunk-ZIDSD6VC.js.map} +0 -0
- /package/dist/{chunk-BMANIB5B.js.map → chunk-ZPOROUTX.js.map} +0 -0
- /package/dist/{contradiction-scan-3FJYWS3G.js.map → contradiction-scan-SSKCAMLX.js.map} +0 -0
- /package/dist/{forget-OEE5OELK.js.map → forget-KHF7A44H.js.map} +0 -0
- /package/dist/{graph-edge-decay-RXUCJIN4.js.map → graph-edge-decay-FO7AM4UR.js.map} +0 -0
- /package/dist/{resolution-33PIX3TT.js.map → qmd-preflight.js.map} +0 -0
package/dist/verified-recall.js
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
import {
|
|
2
2
|
compareVerifiedEpisodeResults,
|
|
3
3
|
searchVerifiedEpisodes
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-L2B3EE7B.js";
|
|
4
|
+
} from "./chunk-66FLU5BT.js";
|
|
5
|
+
import "./chunk-2A3OXAP2.js";
|
|
6
|
+
import "./chunk-M7GGMGMZ.js";
|
|
8
7
|
import "./chunk-M7XQSUBB.js";
|
|
8
|
+
import "./chunk-L2B3EE7B.js";
|
|
9
9
|
import "./chunk-5UZXUTVO.js";
|
|
10
10
|
import "./chunk-5GPPACXK.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-EHK6KZHK.js";
|
|
12
12
|
import "./chunk-6CIAGZ6X.js";
|
|
13
13
|
import "./chunk-SVOZFLIQ.js";
|
|
14
14
|
import "./chunk-LTJAMRGI.js";
|
|
15
15
|
import "./chunk-J6A3CX5N.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-4KJLYTLS.js";
|
|
17
17
|
import "./chunk-JS2HKKOK.js";
|
|
18
18
|
import "./chunk-AWJ2FHCF.js";
|
|
19
19
|
import "./chunk-42JKGUFJ.js";
|
|
20
20
|
import "./chunk-RULE4VG5.js";
|
|
21
21
|
import "./chunk-SCU65EZI.js";
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-RHOZ5LLO.js";
|
|
23
|
+
import "./chunk-RL6NEVXT.js";
|
|
24
24
|
import "./chunk-DM2T26WE.js";
|
|
25
25
|
import "./chunk-LDXUBPMO.js";
|
|
26
|
-
import "./chunk-
|
|
26
|
+
import "./chunk-MNUHL34L.js";
|
|
27
27
|
import "./chunk-AAD2ZS6P.js";
|
|
28
28
|
import "./chunk-G7D6GZ5J.js";
|
|
29
29
|
import "./chunk-VF4XKTX3.js";
|
|
30
30
|
import "./chunk-W5H6ZRPT.js";
|
|
31
|
-
import "./chunk-
|
|
32
|
-
import "./chunk-
|
|
31
|
+
import "./chunk-JIKJPDQJ.js";
|
|
32
|
+
import "./chunk-K2ZLHESQ.js";
|
|
33
33
|
import "./chunk-L2EXJQJP.js";
|
|
34
|
-
import "./chunk-
|
|
34
|
+
import "./chunk-VFSP73LP.js";
|
|
35
35
|
import "./chunk-RGMVMVMF.js";
|
|
36
36
|
import "./chunk-N7RWREIQ.js";
|
|
37
37
|
import "./chunk-OEHCMALU.js";
|
|
@@ -40,7 +40,7 @@ import "./chunk-5GKPFL3S.js";
|
|
|
40
40
|
import "./chunk-4DJQYKMN.js";
|
|
41
41
|
import "./chunk-EYIEWJNI.js";
|
|
42
42
|
import "./chunk-JUC24CTX.js";
|
|
43
|
-
import "./chunk-
|
|
43
|
+
import "./chunk-37CTGERM.js";
|
|
44
44
|
import "./chunk-J2HSAU72.js";
|
|
45
45
|
import "./chunk-A6XUJE5D.js";
|
|
46
46
|
import "./chunk-P7FMDTKL.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/core",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.4.1",
|
|
4
4
|
"description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -3000,7 +3000,7 @@
|
|
|
3000
3000
|
"core"
|
|
3001
3001
|
],
|
|
3002
3002
|
"peerDependencies": {
|
|
3003
|
-
"@remnic/coding-graph": "^9.
|
|
3003
|
+
"@remnic/coding-graph": "^9.4.1"
|
|
3004
3004
|
},
|
|
3005
3005
|
"peerDependenciesMeta": {
|
|
3006
3006
|
"@remnic/coding-graph": {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import { type LoggerBackend, initLogger, log } from "./logger.js";
|
|
5
|
+
|
|
6
|
+
const FIXED = "2026-07-11T20:00:00.000Z";
|
|
7
|
+
|
|
8
|
+
function capture(): { lines: string[]; backend: LoggerBackend } {
|
|
9
|
+
const lines: string[] = [];
|
|
10
|
+
const push =
|
|
11
|
+
(level: string) =>
|
|
12
|
+
(msg: string, ...args: unknown[]) => {
|
|
13
|
+
lines.push(args.length ? `${level}|${msg}|${JSON.stringify(args)}` : `${level}|${msg}`);
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
lines,
|
|
17
|
+
backend: {
|
|
18
|
+
info: push("info"),
|
|
19
|
+
warn: push("warn"),
|
|
20
|
+
error: push("error"),
|
|
21
|
+
debug: push("debug"),
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const savedEnv = process.env.REMNIC_LOG_TIMESTAMPS;
|
|
27
|
+
test.afterEach(() => {
|
|
28
|
+
if (savedEnv === undefined) Reflect.deleteProperty(process.env, "REMNIC_LOG_TIMESTAMPS");
|
|
29
|
+
else process.env.REMNIC_LOG_TIMESTAMPS = savedEnv;
|
|
30
|
+
// Reset to a silent backend (module default is NOOP) so this suite never
|
|
31
|
+
// leaks console output or timestamp state into sibling suites in-process.
|
|
32
|
+
initLogger({ info() {}, warn() {}, error() {}, debug() {} }, false, { timestamps: true });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("prefixes each level with an ISO 8601 timestamp by default", () => {
|
|
36
|
+
const { lines, backend } = capture();
|
|
37
|
+
Reflect.deleteProperty(process.env, "REMNIC_LOG_TIMESTAMPS");
|
|
38
|
+
initLogger(backend, true, { clock: () => FIXED });
|
|
39
|
+
|
|
40
|
+
log.info("hello");
|
|
41
|
+
log.warn("careful");
|
|
42
|
+
log.error("boom", new Error("bad"));
|
|
43
|
+
log.debug("trace");
|
|
44
|
+
|
|
45
|
+
assert.deepEqual(lines, [
|
|
46
|
+
`info|${FIXED} remnic: hello`,
|
|
47
|
+
`warn|${FIXED} remnic: careful`,
|
|
48
|
+
`error|${FIXED} remnic: boom — bad`,
|
|
49
|
+
`debug|${FIXED} remnic [debug]: trace`,
|
|
50
|
+
]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("timestamps: false restores the legacy 'remnic: ' format", () => {
|
|
54
|
+
const { lines, backend } = capture();
|
|
55
|
+
initLogger(backend, false, { timestamps: false, clock: () => FIXED });
|
|
56
|
+
|
|
57
|
+
log.info("hello");
|
|
58
|
+
assert.equal(lines[0], "info|remnic: hello");
|
|
59
|
+
assert.ok(!lines[0].includes(FIXED));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("REMNIC_LOG_TIMESTAMPS=false disables the prefix", () => {
|
|
63
|
+
const { lines, backend } = capture();
|
|
64
|
+
process.env.REMNIC_LOG_TIMESTAMPS = "false";
|
|
65
|
+
initLogger(backend, false, { clock: () => FIXED });
|
|
66
|
+
|
|
67
|
+
log.info("hello");
|
|
68
|
+
assert.equal(lines[0], "info|remnic: hello");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("explicit option overrides the env var", () => {
|
|
72
|
+
const { lines, backend } = capture();
|
|
73
|
+
process.env.REMNIC_LOG_TIMESTAMPS = "false";
|
|
74
|
+
initLogger(backend, false, { timestamps: true, clock: () => FIXED });
|
|
75
|
+
|
|
76
|
+
log.info("hello");
|
|
77
|
+
assert.equal(lines[0], `info|${FIXED} remnic: hello`);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("emits a real ISO 8601 timestamp when no clock is injected", () => {
|
|
81
|
+
const { lines, backend } = capture();
|
|
82
|
+
Reflect.deleteProperty(process.env, "REMNIC_LOG_TIMESTAMPS");
|
|
83
|
+
initLogger(backend, false);
|
|
84
|
+
|
|
85
|
+
log.info("hello");
|
|
86
|
+
const m = /^info\|(\S+) remnic: hello$/.exec(lines[0]);
|
|
87
|
+
assert.ok(m, `unexpected line: ${lines[0]}`);
|
|
88
|
+
assert.ok(!Number.isNaN(Date.parse(m[1])));
|
|
89
|
+
assert.equal(new Date(m[1]).toISOString(), m[1]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("preserves variadic args and gates debug on the debug flag", () => {
|
|
93
|
+
const { lines, backend } = capture();
|
|
94
|
+
initLogger(backend, false, { clock: () => FIXED });
|
|
95
|
+
log.debug("suppressed");
|
|
96
|
+
assert.equal(lines.length, 0, "debug must be gated when debug=false");
|
|
97
|
+
|
|
98
|
+
initLogger(backend, true, { clock: () => FIXED });
|
|
99
|
+
log.info("withargs", { a: 1 });
|
|
100
|
+
assert.equal(lines.at(-1), `info|${FIXED} remnic: withargs|[{"a":1}]`);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("unrecognized REMNIC_LOG_TIMESTAMPS falls through to the default (on)", () => {
|
|
104
|
+
const { lines, backend } = capture();
|
|
105
|
+
process.env.REMNIC_LOG_TIMESTAMPS = "maybe";
|
|
106
|
+
initLogger(backend, false, { clock: () => FIXED });
|
|
107
|
+
|
|
108
|
+
log.info("hello");
|
|
109
|
+
assert.equal(lines[0], `info|${FIXED} remnic: hello`);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("empty or whitespace-only REMNIC_LOG_TIMESTAMPS reads as unset (default on)", () => {
|
|
113
|
+
for (const raw of ["", " "]) {
|
|
114
|
+
const { lines, backend } = capture();
|
|
115
|
+
process.env.REMNIC_LOG_TIMESTAMPS = raw;
|
|
116
|
+
initLogger(backend, false, { clock: () => FIXED });
|
|
117
|
+
log.info("hello");
|
|
118
|
+
assert.equal(lines[0], `info|${FIXED} remnic: hello`, `raw=${JSON.stringify(raw)}`);
|
|
119
|
+
}
|
|
120
|
+
});
|
package/src/logger.ts
CHANGED
|
@@ -12,8 +12,29 @@ const NOOP_LOGGER: LoggerBackend = {
|
|
|
12
12
|
debug() {},
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
export interface LoggerOptions {
|
|
16
|
+
/** Prefix each emitted line with an ISO 8601 timestamp. Defaults to true. */
|
|
17
|
+
timestamps?: boolean;
|
|
18
|
+
/** Clock source for the timestamp prefix; injectable for tests. */
|
|
19
|
+
clock?: () => string;
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
let _backend: LoggerBackend = NOOP_LOGGER;
|
|
16
23
|
let _debug = false;
|
|
24
|
+
let _timestamps = true;
|
|
25
|
+
let _clock: () => string = () => new Date().toISOString();
|
|
26
|
+
|
|
27
|
+
// Coerce a boolean-like env string. Empty/whitespace-only and unrecognized
|
|
28
|
+
// values return undefined so callers fall through to the default (timestamps
|
|
29
|
+
// on) rather than silently disabling — an empty env var reads as "unset".
|
|
30
|
+
function coerceBool(value: string | undefined): boolean | undefined {
|
|
31
|
+
if (value === undefined) return undefined;
|
|
32
|
+
const s = value.trim().toLowerCase();
|
|
33
|
+
if (s === "") return undefined;
|
|
34
|
+
if (s === "0" || s === "false" || s === "no" || s === "off") return false;
|
|
35
|
+
if (s === "1" || s === "true" || s === "yes" || s === "on") return true;
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
17
38
|
|
|
18
39
|
// Late-bind console.* rather than capturing references at module import
|
|
19
40
|
// time. In production this is behaviour-identical to the pre-bound
|
|
@@ -31,28 +52,35 @@ const CONSOLE_LOGGER: LoggerBackend = {
|
|
|
31
52
|
debug: (msg, ...args) => console.debug(msg, ...args),
|
|
32
53
|
};
|
|
33
54
|
|
|
34
|
-
export function initLogger(backend?: LoggerBackend, debug?: boolean): void {
|
|
55
|
+
export function initLogger(backend?: LoggerBackend, debug?: boolean, options?: LoggerOptions): void {
|
|
35
56
|
_backend = backend ?? CONSOLE_LOGGER;
|
|
36
57
|
_debug = debug ?? false;
|
|
58
|
+
// Precedence: explicit option > REMNIC_LOG_TIMESTAMPS env > default (on).
|
|
59
|
+
_timestamps = options?.timestamps ?? coerceBool(process.env.REMNIC_LOG_TIMESTAMPS) ?? true;
|
|
60
|
+
_clock = options?.clock ?? (() => new Date().toISOString());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Format one log line: "<iso> remnic: <msg>" when timestamps are enabled,
|
|
64
|
+
// otherwise the legacy "remnic: <msg>". Timestamp is per-call.
|
|
65
|
+
function fmt(msg: string, label = "remnic"): string {
|
|
66
|
+
const ts = _timestamps ? `${_clock()} ` : "";
|
|
67
|
+
return `${ts}${label}: ${msg}`;
|
|
37
68
|
}
|
|
38
69
|
|
|
39
70
|
export const log = {
|
|
40
71
|
info(msg: string, ...args: unknown[]): void {
|
|
41
|
-
_backend.info(
|
|
72
|
+
_backend.info(fmt(msg), ...args);
|
|
42
73
|
},
|
|
43
74
|
warn(msg: string, ...args: unknown[]): void {
|
|
44
|
-
_backend.warn(
|
|
75
|
+
_backend.warn(fmt(msg), ...args);
|
|
45
76
|
},
|
|
46
77
|
error(msg: string, err?: unknown): void {
|
|
47
|
-
const detail =
|
|
48
|
-
|
|
49
|
-
_backend.error(
|
|
50
|
-
`remnic: ${msg}${detail ? ` — ${detail}` : ""}`,
|
|
51
|
-
);
|
|
78
|
+
const detail = err instanceof Error ? err.message : err ? String(err) : "";
|
|
79
|
+
_backend.error(fmt(`${msg}${detail ? ` — ${detail}` : ""}`));
|
|
52
80
|
},
|
|
53
81
|
debug(msg: string, ...args: unknown[]): void {
|
|
54
82
|
if (!_debug) return;
|
|
55
83
|
const fn = _backend.debug ?? _backend.info;
|
|
56
|
-
fn(
|
|
84
|
+
fn(fmt(msg, "remnic [debug]"), ...args);
|
|
57
85
|
},
|
|
58
86
|
};
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
|
|
7
|
+
import { initLogger } from "./logger.js";
|
|
8
|
+
import { rebuildMemoryProjection } from "./maintenance/rebuild-memory-projection.js";
|
|
9
|
+
import {
|
|
10
|
+
__resetProjectionOpenFailureSuppressionForTest,
|
|
11
|
+
__setProjectionReadonlyOpenerForTest,
|
|
12
|
+
getMemoryProjectionPath,
|
|
13
|
+
probeProjectionHealth,
|
|
14
|
+
readProjectedMemoryBrowse,
|
|
15
|
+
} from "./memory-projection-store.js";
|
|
16
|
+
import { summarizeProjectionHealth } from "./operator-toolkit.js";
|
|
17
|
+
import { openBetterSqlite3 } from "./runtime/better-sqlite.js";
|
|
18
|
+
import { StorageManager } from "./storage.js";
|
|
19
|
+
|
|
20
|
+
// Serialized: every test mutates the process-global logger backend and the
|
|
21
|
+
// module-level projection opener / rate-limit map. concurrency:false keeps
|
|
22
|
+
// them from racing each other.
|
|
23
|
+
const SERIAL = { concurrency: false } as const;
|
|
24
|
+
|
|
25
|
+
// The opener seam expects the real opener signature; derive it without
|
|
26
|
+
// importing the (unexported) alias.
|
|
27
|
+
type ProjectionOpener = NonNullable<Parameters<typeof __setProjectionReadonlyOpenerForTest>[0]>;
|
|
28
|
+
|
|
29
|
+
function abiStyleError(): Error {
|
|
30
|
+
// Mirrors the real native-binding mismatch better-sqlite3 throws when its
|
|
31
|
+
// addon was compiled for a different Node.js ABI (issue #1829 root cause).
|
|
32
|
+
// Classified as a native mismatch by isLikelyBetterSqlite3NativeBindingError.
|
|
33
|
+
return new Error(
|
|
34
|
+
"The module was compiled against a different Node.js version using NODE_MODULE_VERSION 127. " +
|
|
35
|
+
"This version of Node.js requires NODE_MODULE_VERSION 137."
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function captureLogs(): { warns: string[]; errors: string[]; restore: () => void } {
|
|
40
|
+
const warns: string[] = [];
|
|
41
|
+
const errors: string[] = [];
|
|
42
|
+
initLogger({
|
|
43
|
+
info() {},
|
|
44
|
+
warn(msg) {
|
|
45
|
+
warns.push(msg);
|
|
46
|
+
},
|
|
47
|
+
error(msg) {
|
|
48
|
+
errors.push(msg);
|
|
49
|
+
},
|
|
50
|
+
debug() {},
|
|
51
|
+
});
|
|
52
|
+
return { warns, errors, restore: () => initLogger() };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
test("absent projection index → quiet fallback, no error log, probe reports absent", SERIAL, async () => {
|
|
56
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-absent-"));
|
|
57
|
+
const { warns, restore } = captureLogs();
|
|
58
|
+
try {
|
|
59
|
+
// No projection file exists — the normal cold-install / never-built case.
|
|
60
|
+
assert.equal(probeProjectionHealth(dir).state, "absent");
|
|
61
|
+
assert.equal(readProjectedMemoryBrowse(dir, { limit: 5, offset: 0 }), null);
|
|
62
|
+
// The distinguishing guarantee from issue #1829: a MISSING file must stay
|
|
63
|
+
// quiet (no error spam). Only a PRESENT-but-unopenable file logs.
|
|
64
|
+
assert.equal(warns.length, 0);
|
|
65
|
+
} finally {
|
|
66
|
+
restore();
|
|
67
|
+
await rm(dir, { recursive: true, force: true });
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("present index + ABI-style open failure → distinct rate-limited warn + null + doctor signal", SERIAL, async () => {
|
|
72
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-abi-"));
|
|
73
|
+
const { warns, restore } = captureLogs();
|
|
74
|
+
__resetProjectionOpenFailureSuppressionForTest();
|
|
75
|
+
try {
|
|
76
|
+
// Build a real projection so the index file genuinely EXISTS on disk;
|
|
77
|
+
// then inject an opener that throws the wrong-ABI error on every open.
|
|
78
|
+
await rebuildMemoryProjection({ memoryDir: dir, dryRun: false });
|
|
79
|
+
assert.ok(getMemoryProjectionPath(dir));
|
|
80
|
+
const throwingOpener: ProjectionOpener = () => {
|
|
81
|
+
throw abiStyleError();
|
|
82
|
+
};
|
|
83
|
+
const restoreOpener = __setProjectionReadonlyOpenerForTest(throwingOpener);
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
// The read path returns null (full-scan fallback trigger preserved),
|
|
87
|
+
// but now emits the DISTINCT real-error warn that was missing before.
|
|
88
|
+
const first = readProjectedMemoryBrowse(dir, { limit: 5, offset: 0 });
|
|
89
|
+
assert.equal(first, null);
|
|
90
|
+
assert.equal(warns.length, 1);
|
|
91
|
+
const msg = warns[0];
|
|
92
|
+
assert.ok(msg, "expected a distinct projection open-failure warn");
|
|
93
|
+
assert.match(msg, /present but could not be opened/);
|
|
94
|
+
assert.match(msg, /wrong Node\.js ABI/);
|
|
95
|
+
|
|
96
|
+
// Doctor lens classifies the same failure.
|
|
97
|
+
const probe = probeProjectionHealth(dir);
|
|
98
|
+
assert.equal(probe.state, "unopenable");
|
|
99
|
+
assert.equal(probe.nativeBindingMismatch, true);
|
|
100
|
+
|
|
101
|
+
// Rate limit: a second open within the window is suppressed.
|
|
102
|
+
const second = readProjectedMemoryBrowse(dir, { limit: 5, offset: 0 });
|
|
103
|
+
assert.equal(second, null);
|
|
104
|
+
assert.equal(warns.length, 1, "rate limit must suppress the repeat warn");
|
|
105
|
+
|
|
106
|
+
// After resetting suppression, the warn fires again.
|
|
107
|
+
__resetProjectionOpenFailureSuppressionForTest();
|
|
108
|
+
readProjectedMemoryBrowse(dir, { limit: 5, offset: 0 });
|
|
109
|
+
assert.equal(warns.length, 2, "warn fires again after suppression reset");
|
|
110
|
+
} finally {
|
|
111
|
+
restoreOpener();
|
|
112
|
+
}
|
|
113
|
+
} finally {
|
|
114
|
+
restore();
|
|
115
|
+
await rm(dir, { recursive: true, force: true });
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("present index + WRAPPED ABI open failure (cause = native-binding error) → still reports the native-binding hint", SERIAL, async () => {
|
|
120
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-wrapped-abi-"));
|
|
121
|
+
const { warns, restore } = captureLogs();
|
|
122
|
+
__resetProjectionOpenFailureSuppressionForTest();
|
|
123
|
+
try {
|
|
124
|
+
await rebuildMemoryProjection({ memoryDir: dir, dryRun: false });
|
|
125
|
+
// Mirrors the production path: loadBetterSqlite3() catches the ABI error
|
|
126
|
+
// and re-throws a sanitized unavailableError WRAPPER whose message drops
|
|
127
|
+
// the ABI markers. The original error survives only on .cause. Before
|
|
128
|
+
// #1848 the classifier inspected only the wrapper's message and MISSED the
|
|
129
|
+
// mismatch, so the warn and doctor check wrongly suggested rebuilding the
|
|
130
|
+
// projection instead of better-sqlite3.
|
|
131
|
+
const throwingOpener: ProjectionOpener = () => {
|
|
132
|
+
throw new Error(
|
|
133
|
+
"better-sqlite3 is unavailable. Remnic attempted to load the native SQLite binding and could not.",
|
|
134
|
+
{ cause: abiStyleError() },
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
const restoreOpener = __setProjectionReadonlyOpenerForTest(throwingOpener);
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
// Browse warn carries the native-binding ABI hint (not the projection-rebuild hint).
|
|
141
|
+
const first = readProjectedMemoryBrowse(dir, { limit: 5, offset: 0 });
|
|
142
|
+
assert.equal(first, null);
|
|
143
|
+
assert.equal(warns.length, 1);
|
|
144
|
+
assert.match(warns[0], /wrong Node\.js ABI/);
|
|
145
|
+
assert.doesNotMatch(warns[0], /rebuild-memory-projection/);
|
|
146
|
+
|
|
147
|
+
// Doctor lens classifies the SAME wrapped failure as a native-binding mismatch.
|
|
148
|
+
const probe = probeProjectionHealth(dir);
|
|
149
|
+
assert.equal(probe.state, "unopenable");
|
|
150
|
+
assert.equal(probe.nativeBindingMismatch, true);
|
|
151
|
+
} finally {
|
|
152
|
+
restoreOpener();
|
|
153
|
+
}
|
|
154
|
+
} finally {
|
|
155
|
+
restore();
|
|
156
|
+
await rm(dir, { recursive: true, force: true });
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("present index + non-ABI open failure → distinct warn without the native-binding hint", SERIAL, async () => {
|
|
161
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-cantopen-"));
|
|
162
|
+
const { warns, restore } = captureLogs();
|
|
163
|
+
__resetProjectionOpenFailureSuppressionForTest();
|
|
164
|
+
try {
|
|
165
|
+
await rebuildMemoryProjection({ memoryDir: dir, dryRun: false });
|
|
166
|
+
// A corrupt-file / permission style failure: carries a stable SQLite
|
|
167
|
+
// code but is NOT a native-binding mismatch. Tests the failure CLASS,
|
|
168
|
+
// not just the reported ABI instance (hardening playbook).
|
|
169
|
+
const cantOpen = Object.assign(new Error("unable to open database file"), {
|
|
170
|
+
code: "SQLITE_CANTOPEN",
|
|
171
|
+
});
|
|
172
|
+
const restoreOpener = __setProjectionReadonlyOpenerForTest((() => {
|
|
173
|
+
throw cantOpen;
|
|
174
|
+
}) as ProjectionOpener);
|
|
175
|
+
try {
|
|
176
|
+
assert.equal(readProjectedMemoryBrowse(dir, { limit: 5, offset: 0 }), null);
|
|
177
|
+
assert.equal(warns.length, 1);
|
|
178
|
+
const msg = warns[0];
|
|
179
|
+
assert.ok(msg, "expected a distinct projection open-failure warn");
|
|
180
|
+
assert.match(msg, /present but could not be opened/);
|
|
181
|
+
assert.match(msg, /SQLITE_CANTOPEN/);
|
|
182
|
+
assert.doesNotMatch(msg, /native binding/);
|
|
183
|
+
const probe = probeProjectionHealth(dir);
|
|
184
|
+
assert.equal(probe.state, "unopenable");
|
|
185
|
+
assert.equal(probe.nativeBindingMismatch, false);
|
|
186
|
+
} finally {
|
|
187
|
+
restoreOpener();
|
|
188
|
+
}
|
|
189
|
+
} finally {
|
|
190
|
+
restore();
|
|
191
|
+
await rm(dir, { recursive: true, force: true });
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("full-scan fallback still returns results when the projection cannot serve", SERIAL, async () => {
|
|
196
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-fullscan-"));
|
|
197
|
+
const { restore } = captureLogs();
|
|
198
|
+
try {
|
|
199
|
+
const storage = new StorageManager(dir);
|
|
200
|
+
const a = await storage.writeMemory("fact", "alpha synthetic fact", { source: "test" });
|
|
201
|
+
const b = await storage.writeMemory("fact", "beta synthetic fact", { source: "test" });
|
|
202
|
+
|
|
203
|
+
// Absent projection: the browse returns null (the trigger the access
|
|
204
|
+
// layer keys on to run its full-corpus scan) ...
|
|
205
|
+
assert.equal(readProjectedMemoryBrowse(dir, { limit: 10, offset: 0 }), null);
|
|
206
|
+
|
|
207
|
+
// ... and the full-corpus data source the access layer scans still
|
|
208
|
+
// holds every memory (issue #1829: the fallback must keep serving).
|
|
209
|
+
const full = [...(await storage.readAllMemories()), ...(await storage.readArchivedMemories())];
|
|
210
|
+
const ids = new Set(full.map((m) => m.frontmatter.id));
|
|
211
|
+
assert.ok(ids.has(a.id));
|
|
212
|
+
assert.ok(ids.has(b.id));
|
|
213
|
+
assert.equal(full.length, 2);
|
|
214
|
+
|
|
215
|
+
// Regression guard for the exact #1829 failure: build the projection,
|
|
216
|
+
// then make it unopenable, and confirm the null trigger STILL fires so
|
|
217
|
+
// the full scan is reached (not a throw, not a stale cached page).
|
|
218
|
+
await rebuildMemoryProjection({ memoryDir: dir, dryRun: false });
|
|
219
|
+
const restoreOpener = __setProjectionReadonlyOpenerForTest((() => {
|
|
220
|
+
throw abiStyleError();
|
|
221
|
+
}) as ProjectionOpener);
|
|
222
|
+
try {
|
|
223
|
+
assert.equal(
|
|
224
|
+
readProjectedMemoryBrowse(dir, { limit: 10, offset: 0 }),
|
|
225
|
+
null,
|
|
226
|
+
"unopenable projection must return null so the full scan runs"
|
|
227
|
+
);
|
|
228
|
+
} finally {
|
|
229
|
+
restoreOpener();
|
|
230
|
+
}
|
|
231
|
+
} finally {
|
|
232
|
+
restore();
|
|
233
|
+
await rm(dir, { recursive: true, force: true });
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
test("present + valid projection → probe openable + doctor ok (schema validation passes)", SERIAL, async () => {
|
|
238
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-healthy-"));
|
|
239
|
+
try {
|
|
240
|
+
await rebuildMemoryProjection({ memoryDir: dir, dryRun: false });
|
|
241
|
+
const probe = probeProjectionHealth(dir);
|
|
242
|
+
assert.equal(probe.state, "openable");
|
|
243
|
+
assert.equal(probe.nativeBindingMismatch, false);
|
|
244
|
+
// Doctor lens reports OK for a schema-valid projection (issue #1848 round 2).
|
|
245
|
+
const check = summarizeProjectionHealth({ memoryDir: dir });
|
|
246
|
+
assert.equal(check.status, "ok");
|
|
247
|
+
assert.match(check.summary, /opens cleanly/i);
|
|
248
|
+
} finally {
|
|
249
|
+
await rm(dir, { recursive: true, force: true });
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
test("present projection with MISSING schema tables → probe present-but-invalid (doctor non-ok, rebuild hint)", SERIAL, async () => {
|
|
254
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-no-tables-"));
|
|
255
|
+
try {
|
|
256
|
+
// Create a sqlite file that OPENS cleanly but has NO projection tables
|
|
257
|
+
// (mirrors a half-built / stale / externally-created .sqlite that opens
|
|
258
|
+
// but cannot serve any browse query — issue #1848 round 2 root cause).
|
|
259
|
+
const dbPath = getMemoryProjectionPath(dir);
|
|
260
|
+
await mkdir(path.dirname(dbPath), { recursive: true });
|
|
261
|
+
const empty = openBetterSqlite3(dbPath); // creates a valid empty db
|
|
262
|
+
empty.close();
|
|
263
|
+
|
|
264
|
+
// Before #1848 round 2 this reported "openable" → doctor said ok while
|
|
265
|
+
// browse silently fell back to full-corpus scans on every memory list.
|
|
266
|
+
const probe = probeProjectionHealth(dir);
|
|
267
|
+
assert.equal(probe.state, "present-but-invalid");
|
|
268
|
+
assert.equal(probe.nativeBindingMismatch, false);
|
|
269
|
+
assert.ok(probe.detail, "expected a path-free detail for the schema failure");
|
|
270
|
+
|
|
271
|
+
// Doctor lens surfaces this as an ERROR with a rebuild hint — NOT ok.
|
|
272
|
+
const check = summarizeProjectionHealth({ memoryDir: dir });
|
|
273
|
+
assert.equal(check.status, "error");
|
|
274
|
+
assert.match(check.summary, /missing or unreadable/i);
|
|
275
|
+
assert.ok(check.remediation);
|
|
276
|
+
assert.match(check.remediation, /rebuild-memory-projection/);
|
|
277
|
+
|
|
278
|
+
// Browse still returns null (full-scan fallback trigger) — the projection
|
|
279
|
+
// is unusable, so the access layer must reach the full corpus.
|
|
280
|
+
assert.equal(readProjectedMemoryBrowse(dir, { limit: 5, offset: 0 }), null);
|
|
281
|
+
} finally {
|
|
282
|
+
await rm(dir, { recursive: true, force: true });
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test("present projection with memory_current MISSING required columns → probe present-but-invalid (doctor non-ok, rebuild hint)", SERIAL, async () => {
|
|
287
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-proj-no-cols-"));
|
|
288
|
+
try {
|
|
289
|
+
// A sqlite file that opens cleanly AND has a `memory_current` table, but
|
|
290
|
+
// the table is stale/half-built with none of the columns
|
|
291
|
+
// readProjectedMemoryBrowse SELECTs (issue #1848 round 3 root cause). The
|
|
292
|
+
// round-2 check only verified the table exists + answers `SELECT 1`, so a
|
|
293
|
+
// file like `CREATE TABLE memory_current (x INTEGER)` was reported
|
|
294
|
+
// "openable" → doctor said healthy while browse threw on the missing
|
|
295
|
+
// memory_id/path_rel/category/... columns and silently fell back.
|
|
296
|
+
const dbPath = getMemoryProjectionPath(dir);
|
|
297
|
+
await mkdir(path.dirname(dbPath), { recursive: true });
|
|
298
|
+
const stale = openBetterSqlite3(dbPath); // creates a valid db
|
|
299
|
+
stale.exec("CREATE TABLE memory_current (x INTEGER)");
|
|
300
|
+
stale.close();
|
|
301
|
+
|
|
302
|
+
// Before round 3 this reported "openable" → doctor said ok.
|
|
303
|
+
const probe = probeProjectionHealth(dir);
|
|
304
|
+
assert.equal(probe.state, "present-but-invalid");
|
|
305
|
+
assert.equal(probe.nativeBindingMismatch, false);
|
|
306
|
+
// displayErrorDetail surfaces only the path-free error class (ProjectionSchemaError).
|
|
307
|
+
assert.ok(probe.detail, "expected a path-free detail for the missing-column schema failure");
|
|
308
|
+
|
|
309
|
+
// Doctor lens surfaces this as an ERROR with a rebuild hint — NOT ok.
|
|
310
|
+
const check = summarizeProjectionHealth({ memoryDir: dir });
|
|
311
|
+
assert.equal(check.status, "error");
|
|
312
|
+
assert.match(check.summary, /missing or unreadable/i);
|
|
313
|
+
assert.ok(check.remediation);
|
|
314
|
+
assert.match(check.remediation, /rebuild-memory-projection/);
|
|
315
|
+
|
|
316
|
+
// Browse still returns null (full-scan fallback trigger) — the projection
|
|
317
|
+
// cannot serve queries missing the browse columns.
|
|
318
|
+
assert.equal(readProjectedMemoryBrowse(dir, { limit: 5, offset: 0 }), null);
|
|
319
|
+
} finally {
|
|
320
|
+
await rm(dir, { recursive: true, force: true });
|
|
321
|
+
}
|
|
322
|
+
});
|