@remnic/core 9.23.4 → 9.25.0
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 +12 -10
- package/dist/access-admin-ops-surface.js +40 -39
- package/dist/access-authorization-probe.d.ts +122 -0
- package/dist/access-authorization-probe.js +154 -0
- package/dist/access-boundary.d.ts +12 -10
- package/dist/access-boundary.js +40 -39
- package/dist/access-cli.js +119 -117
- package/dist/access-cli.js.map +1 -1
- package/dist/access-health-types.d.ts +54 -0
- package/dist/access-health-types.js +1 -0
- package/dist/access-http.d.ts +12 -10
- package/dist/access-http.js +51 -49
- package/dist/access-identity-continuity-surface.d.ts +9 -8
- package/dist/access-identity-continuity-surface.js +40 -39
- package/dist/access-lcm-surface.d.ts +12 -10
- package/dist/access-lcm-surface.js +40 -39
- package/dist/access-mcp.d.ts +12 -10
- package/dist/access-mcp.js +46 -45
- package/dist/access-memory-search-fanout.d.ts +3 -2
- package/dist/{access-namespace-preflight-CmErR03h.d.ts → access-namespace-preflight-wRSZEO5V.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +4 -3
- package/dist/access-namespace-preflight.js +40 -39
- package/dist/access-observe-write-surface.d.ts +13 -11
- package/dist/access-observe-write-surface.js +40 -39
- package/dist/access-operations-batch.js +42 -41
- package/dist/access-operations.d.ts +13 -11
- package/dist/access-operations.js +44 -43
- package/dist/access-recall-concurrency.d.ts +12 -10
- package/dist/access-recall-concurrency.js +40 -39
- package/dist/access-recall-response.d.ts +12 -10
- package/dist/access-recall-response.js +40 -39
- package/dist/access-recall-surface.d.ts +12 -10
- package/dist/access-recall-surface.js +40 -39
- package/dist/access-schema.d.ts +10 -10
- package/dist/access-schema.js +8 -8
- package/dist/{access-service-Pl-h7x4p.d.ts → access-service-BlNKWBC9.d.ts} +10 -40
- package/dist/access-service.d.ts +13 -11
- package/dist/access-service.js +40 -39
- package/dist/access-surface-catalog.d.ts +12 -10
- package/dist/access-token-capabilities.d.ts +15 -1
- package/dist/access-token-capabilities.js +3 -1
- package/dist/access-wearables-meetings-surface.d.ts +4 -3
- package/dist/action-confidence.d.ts +2 -1
- package/dist/active-memory-bridge.d.ts +2 -1
- package/dist/active-recall.d.ts +2 -1
- package/dist/active-recall.js +7 -6
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/auto-sync-5OE5QOZB.js +1 -1
- package/dist/behavior-learner.d.ts +2 -1
- package/dist/behavior-signals.d.ts +2 -1
- package/dist/bootstrap.d.ts +9 -8
- package/dist/briefing.d.ts +3 -2
- package/dist/briefing.js +9 -9
- package/dist/buffer-surprise-report.d.ts +2 -1
- package/dist/buffer.d.ts +6 -2
- package/dist/buffer.js +1 -1
- package/dist/bulk-import/index.d.ts +4 -3
- package/dist/calibration.d.ts +2 -1
- package/dist/capabilities.d.ts +2 -1
- package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-7FJQINUR.js} +2 -2
- package/dist/capsule-crypto-7FJQINUR.js.map +1 -0
- package/dist/{catalog-BFTVo2Ez.d.ts → catalog-BLLxZ5L5.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +2 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +2 -1
- package/dist/causal-consolidation.js +12 -12
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +2 -1
- package/dist/causal-trajectory-graph.js +2 -2
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
- package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
- package/dist/{chunk-34RC5RT7.js → chunk-2SA56WMI.js} +4 -4
- package/dist/{chunk-POHSSW2T.js → chunk-3CDMIR3C.js} +2 -2
- package/dist/{chunk-EXH5AK46.js → chunk-3I35RLJW.js} +27 -15
- package/dist/chunk-3I35RLJW.js.map +1 -0
- package/dist/{chunk-JRQBPN63.js → chunk-3UOSVTFR.js} +8 -8
- package/dist/chunk-443XCR34.js +213 -0
- package/dist/chunk-443XCR34.js.map +1 -0
- package/dist/{chunk-354T54RR.js → chunk-4TFIRMTE.js} +28 -1
- package/dist/chunk-4TFIRMTE.js.map +1 -0
- package/dist/{chunk-CNUZ2PN2.js → chunk-5ZGWA4AG.js} +14 -10
- package/dist/chunk-5ZGWA4AG.js.map +1 -0
- package/dist/{chunk-AT7XL2JJ.js → chunk-6LRTGCRV.js} +10 -10
- package/dist/{chunk-AJ7QCSIS.js → chunk-7CPOZH6Y.js} +2 -2
- package/dist/{chunk-EHOTE26K.js → chunk-AGR7MGUX.js} +2 -2
- package/dist/{chunk-D5ILARSD.js → chunk-AL4TZWI3.js} +2 -2
- package/dist/{chunk-RPOSRICW.js → chunk-AT6DNUCM.js} +2 -2
- package/dist/{chunk-KNB7IBBU.js → chunk-CKMO4RDY.js} +5 -5
- package/dist/{chunk-5CPI2QWG.js → chunk-CSXHRAJJ.js} +3 -3
- package/dist/{chunk-5XMJ2P62.js → chunk-DPYYSG6F.js} +7 -7
- package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
- package/dist/{chunk-K3C6CJOF.js → chunk-FIGDB2HR.js} +2 -2
- package/dist/{chunk-Z54EM5YZ.js → chunk-GF22HWS2.js} +4 -4
- package/dist/{chunk-ZYU7ZFLT.js → chunk-GJJBPI6I.js} +5 -1
- package/dist/chunk-GJJBPI6I.js.map +1 -0
- package/dist/{chunk-UZ7HGRHK.js → chunk-GNFZFJBJ.js} +2 -2
- package/dist/{chunk-W6ROK2KU.js → chunk-HNZKVLAN.js} +2 -2
- package/dist/{chunk-HVYOZAQ7.js → chunk-IE4HB6O5.js} +3 -3
- package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
- package/dist/chunk-JMDZDT24.js +38 -0
- package/dist/chunk-JMDZDT24.js.map +1 -0
- package/dist/{chunk-UZGJFIIG.js → chunk-JYIFGGEM.js} +2 -2
- package/dist/{chunk-VDX2J7OX.js → chunk-KQAFEZQX.js} +2 -2
- package/dist/{chunk-3SHB4YAW.js → chunk-L2DPF4DF.js} +4 -4
- package/dist/{chunk-SPWOLGXT.js → chunk-LARPWF3S.js} +3 -3
- package/dist/{chunk-NSRTLSBX.js → chunk-LFHMUWA2.js} +131 -131
- package/dist/{chunk-AYAROCWD.js → chunk-LLISELSY.js} +2 -2
- package/dist/{chunk-W3BKLKG6.js → chunk-LXKJNUND.js} +2 -2
- package/dist/{chunk-MMTG3SCJ.js → chunk-M5EPMNS4.js} +2 -2
- package/dist/{chunk-KYP5FSPG.js → chunk-MNLZGCM2.js} +10 -10
- package/dist/{chunk-TMX4MBSK.js → chunk-MPDX5QMH.js} +2 -2
- package/dist/{chunk-PO5LSKQO.js → chunk-MU7ZHSZE.js} +2 -2
- package/dist/{chunk-7AMFUATK.js → chunk-MZWSOLMT.js} +14 -1
- package/dist/chunk-MZWSOLMT.js.map +1 -0
- package/dist/{chunk-JVOA5VDZ.js → chunk-NMGO2HAZ.js} +3 -3
- package/dist/{chunk-CAGPP5NB.js → chunk-NRV4Y3PM.js} +1 -1
- package/dist/{chunk-H2M4YA6K.js → chunk-NVYCTASB.js} +2 -2
- package/dist/{chunk-M2PG7OTI.js → chunk-P25IPRXP.js} +7 -7
- package/dist/{chunk-6MFMTNY4.js → chunk-RROMWDDC.js} +50 -54
- package/dist/chunk-RROMWDDC.js.map +1 -0
- package/dist/{chunk-FPJWQZ35.js → chunk-SZN6XVFC.js} +2 -2
- package/dist/{chunk-ZLDMAGCB.js → chunk-TG2DJFH7.js} +80 -80
- package/dist/chunk-TG2DJFH7.js.map +1 -0
- package/dist/{chunk-4E3DWNTJ.js → chunk-THHPDPMS.js} +2 -2
- package/dist/{chunk-XPLTZEJU.js → chunk-U37RGPJT.js} +2 -2
- package/dist/{chunk-SCOT5DTA.js → chunk-V25OWXAC.js} +1 -1
- package/dist/chunk-V25OWXAC.js.map +1 -0
- package/dist/{chunk-3UD5ZAUA.js → chunk-VY6SDKWZ.js} +2 -2
- package/dist/{chunk-XJTYLU6J.js → chunk-W4ZDTHWZ.js} +3 -3
- package/dist/{chunk-3NAHZQU3.js → chunk-X3SQYAPP.js} +2 -2
- package/dist/{chunk-WMLHJ5UW.js → chunk-X6ROIHFE.js} +2 -2
- package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
- package/dist/{chunk-GCQIMJFH.js → chunk-XTAAG4SQ.js} +8 -8
- package/dist/{chunk-RSLXMGFP.js → chunk-ZN4UZWMT.js} +2 -2
- package/dist/{cli-DuMB83Mw.d.ts → cli-Zc6UclD1.d.ts} +5 -5
- package/dist/cli.d.ts +14 -12
- package/dist/cli.js +82 -80
- package/dist/compounding/engine.d.ts +3 -2
- package/dist/compounding/engine.js +9 -9
- package/dist/compounding/preference-consolidator.d.ts +2 -1
- package/dist/compression-optimizer.d.ts +2 -1
- package/dist/config.d.ts +2 -1
- package/dist/config.js +4 -3
- package/dist/connectors/codex-materialize-runner.d.ts +2 -1
- package/dist/connectors/codex-materialize-runner.js +9 -9
- package/dist/connectors/codex-materialize.d.ts +2 -1
- package/dist/connectors/index.d.ts +2 -1
- package/dist/connectors/index.js +12 -12
- package/dist/consolidation-provenance-check.d.ts +3 -2
- package/dist/consolidation-provenance-check.js +2 -2
- package/dist/consolidation-undo.d.ts +3 -2
- package/dist/contradiction/index.d.ts +3 -2
- package/dist/contradiction/index.js +1 -1
- package/dist/conversation-index/backend.d.ts +2 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +2 -1
- package/dist/conversation-index/faiss-adapter.d.ts +2 -1
- package/dist/conversation-index/indexer.d.ts +2 -1
- package/dist/conversation-index/search.d.ts +2 -1
- package/dist/corpus-watermark.d.ts +2 -1
- package/dist/corpus-watermark.js +18 -18
- package/dist/dashboard-runtime.js +2 -2
- package/dist/day-summary.d.ts +2 -1
- package/dist/delinearize.d.ts +2 -1
- package/dist/direct-answer-wiring.d.ts +2 -1
- package/dist/direct-answer.d.ts +2 -1
- package/dist/embedding-fallback.d.ts +2 -1
- package/dist/enrichment/index.d.ts +2 -1
- package/dist/entity-retrieval.d.ts +3 -2
- package/dist/entity-retrieval.js +9 -9
- package/dist/entity-schema.d.ts +2 -1
- package/dist/explicit-capture.d.ts +9 -8
- package/dist/explicit-capture.js +1 -1
- package/dist/extraction-error-classification.d.ts +2 -1
- package/dist/extraction-faithfulness.d.ts +2 -1
- package/dist/extraction-judge-telemetry.d.ts +2 -1
- package/dist/extraction-judge-training.d.ts +2 -1
- package/dist/extraction-judge.d.ts +2 -1
- package/dist/extraction-liveness.d.ts +5 -0
- package/dist/extraction-liveness.js +26 -0
- package/dist/extraction-liveness.js.map +1 -0
- package/dist/extraction.d.ts +2 -1
- package/dist/extraction.js +1 -1
- package/dist/fallback-llm.d.ts +2 -1
- package/dist/graph-dashboard-diff.d.ts +2 -1
- package/dist/graph-dashboard-key.d.ts +2 -1
- package/dist/graph-dashboard-parser.d.ts +2 -1
- package/dist/{graph-edge-decay-GF3ZSGSP.js → graph-edge-decay-Z6ENALU2.js} +4 -4
- package/dist/graph-edge-decay-Z6ENALU2.js.map +1 -0
- package/dist/graph-edge-reinforcement.d.ts +2 -1
- package/dist/graph-snapshot.d.ts +2 -1
- package/dist/graph-snapshot.js +3 -3
- package/dist/graph.d.ts +2 -1
- package/dist/graph.js +2 -2
- package/dist/importance.d.ts +2 -1
- package/dist/importers/index.d.ts +2 -1
- package/dist/in-flight-reads.d.ts +2 -1
- package/dist/index.d.ts +53 -51
- package/dist/index.js +229 -227
- package/dist/intent.d.ts +2 -1
- package/dist/lcm/engine.d.ts +2 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +2 -1
- package/dist/lcm/index.js +4 -4
- package/dist/lcm/tools.d.ts +2 -1
- package/dist/lifecycle.d.ts +2 -1
- package/dist/live-connectors-runner.d.ts +2 -1
- package/dist/local-llm.d.ts +2 -1
- package/dist/local-model-endpoint.d.ts +2 -1
- package/dist/maintenance/memory-governance.d.ts +2 -1
- package/dist/maintenance/memory-governance.js +9 -9
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +9 -9
- package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-projection.js +10 -10
- package/dist/{maintenance-DGvDB1xF.d.ts → maintenance-DD22oIx9.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +12 -10
- package/dist/memory-action-policy.d.ts +2 -1
- package/dist/memory-cache.d.ts +2 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
- package/dist/memory-projection-store.d.ts +2 -1
- package/dist/memory-provenance.d.ts +2 -1
- package/dist/memory-worth-outcomes.d.ts +3 -2
- package/dist/models-json.d.ts +2 -1
- package/dist/namespaces/migrate.d.ts +4 -3
- package/dist/namespaces/migrate.js +16 -16
- package/dist/namespaces/principal.d.ts +2 -1
- package/dist/namespaces/search.d.ts +2 -1
- package/dist/namespaces/search.js +6 -6
- package/dist/namespaces/storage.d.ts +4 -3
- package/dist/namespaces/storage.js +9 -9
- package/dist/native-knowledge.d.ts +2 -1
- package/dist/offline-sync-impression-drain.d.ts +2 -1
- package/dist/offline-sync-impression-drain.js +1 -1
- package/dist/operator-doctor-corpus.d.ts +2 -15
- package/dist/operator-doctor-corpus.js +19 -19
- package/dist/operator-doctor-types.d.ts +22 -0
- package/dist/operator-doctor-types.js +1 -0
- package/dist/operator-doctor-types.js.map +1 -0
- package/dist/operator-toolkit.d.ts +10 -13
- package/dist/operator-toolkit.js +32 -28
- package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
- package/dist/orchestration/maintenance.d.ts +5 -4
- package/dist/orchestration/maintenance.js +15 -15
- package/dist/{orchestrator-RXHefhAy.d.ts → orchestrator-BTGgoKli.d.ts} +7 -7
- package/dist/orchestrator.d.ts +9 -8
- package/dist/orchestrator.js +120 -118
- package/dist/patterns-cli.d.ts +2 -1
- package/dist/{pipeline-id_-sqYm.d.ts → pipeline-Bq5zU6Bp.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +2 -1
- package/dist/proactive-contention.d.ts +2 -1
- package/dist/provenance.d.ts +2 -1
- package/dist/{qmd-R6XaQOZK.d.ts → qmd-3ILJkC70.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +3 -2
- package/dist/qmd-recall-cache.d.ts +2 -1
- package/dist/qmd.d.ts +3 -2
- package/dist/recall-concurrency-config.d.ts +2 -1
- package/dist/recall-disclosure-escalation.d.ts +2 -1
- package/dist/recall-explain-renderer.d.ts +2 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +2 -1
- package/dist/recall-planner-llm.d.ts +2 -1
- package/dist/recall-state.d.ts +2 -1
- package/dist/recall-tag-filter.d.ts +2 -1
- package/dist/recall-timings.d.ts +2 -1
- package/dist/recall-xray-cli.d.ts +2 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +2 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +2 -1
- package/dist/recall-xray.js +2 -2
- package/dist/replay/normalizers/chatgpt.d.ts +2 -1
- package/dist/replay/normalizers/claude.d.ts +2 -1
- package/dist/replay/normalizers/openclaw.d.ts +2 -1
- package/dist/replay/normalizers/shared.d.ts +2 -1
- package/dist/replay/runner.d.ts +2 -1
- package/dist/replay/types.d.ts +2 -1
- package/dist/resolution-3K27T4VO.js +1 -1
- package/dist/resolve-auth-token.d.ts +2 -1
- package/dist/resume-bundles.js +6 -5
- package/dist/retrieval-agents.d.ts +3 -2
- package/dist/retrieval-tiers.d.ts +2 -1
- package/dist/routing/engine.d.ts +2 -1
- package/dist/routing/store.d.ts +2 -1
- package/dist/salvage-envelope.d.ts +2 -1
- package/dist/salvage-envelope.js +1 -1
- package/dist/{scope-profiles-EhyuAKkd.d.ts → scope-profiles-D0-ff4xT.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +2 -1
- package/dist/search/factory.d.ts +2 -1
- package/dist/search/factory.js +5 -5
- package/dist/search/index.d.ts +2 -1
- package/dist/search/index.js +9 -9
- package/dist/search/lancedb-backend.d.ts +2 -1
- package/dist/search/meilisearch-backend.d.ts +2 -1
- package/dist/search/noop-backend.d.ts +2 -1
- package/dist/search/orama-backend.d.ts +2 -1
- package/dist/search/port.d.ts +2 -1
- package/dist/search/remote-backend.d.ts +2 -1
- package/dist/{semantic-consolidation-B2xo26UQ.d.ts → semantic-consolidation-4Tfh7c1g.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +3 -2
- package/dist/semantic-consolidation.js +14 -14
- package/dist/semantic-rule-promotion.js +9 -9
- package/dist/semantic-rule-verifier.d.ts +2 -1
- package/dist/semantic-rule-verifier.js +9 -9
- package/dist/{service-BrWqlsZ4.d.ts → service-Z8uzoAST.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +2 -1
- package/dist/session-observer-state.d.ts +2 -1
- package/dist/shared-context/manager.d.ts +2 -1
- package/dist/signal.d.ts +2 -1
- package/dist/{storage-DgNVexXm.d.ts → storage-BZVMn8yJ.d.ts} +1 -1
- package/dist/storage.d.ts +3 -2
- package/dist/storage.js +8 -8
- package/dist/summarizer.d.ts +2 -1
- package/dist/summary-snapshot.d.ts +2 -1
- package/dist/temporal-supersession.d.ts +3 -2
- package/dist/temporal-timeline-recall.d.ts +2 -1
- package/dist/temporal-validity.d.ts +2 -1
- package/dist/threading.d.ts +2 -1
- package/dist/tier-migration.d.ts +3 -2
- package/dist/tier-routing.d.ts +2 -1
- package/dist/tokens.js +2 -2
- package/dist/topics.d.ts +2 -1
- package/dist/transcript.d.ts +2 -1
- package/dist/transfer/backup.js +4 -4
- package/dist/transfer/capsule-export.js +4 -4
- package/dist/transfer/capsule-import.js +3 -3
- package/dist/trust-score-stage.d.ts +2 -1
- package/dist/trust-score.d.ts +2 -1
- package/dist/{types-Bbs0qz6b.d.ts → types-DHBxIF0s.d.ts} +181 -5
- package/dist/types.d.ts +2 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +2 -1
- package/dist/verified-recall.js +9 -9
- package/dist/write-envelope.d.ts +2 -1
- package/dist/write-envelope.js +1 -1
- package/package.json +2 -2
- package/src/access-authorization-probe.ts +43 -0
- package/src/access-boundary.ts +2 -31
- package/src/access-health-types.ts +51 -0
- package/src/access-http.test.ts +94 -0
- package/src/access-http.ts +11 -0
- package/src/access-service-health.test.ts +212 -0
- package/src/access-service.ts +11 -39
- package/src/access-surface-catalog.test.ts +4 -3
- package/src/access-token-capabilities.ts +31 -0
- package/src/buffer.ts +30 -0
- package/src/cli.ts +2 -4
- package/src/config.ts +4 -4
- package/src/extraction-liveness.test.ts +461 -0
- package/src/extraction-liveness.ts +462 -0
- package/src/operator-doctor-types.ts +20 -0
- package/src/operator-toolkit.ts +9 -10
- package/src/types.ts +4 -4
- package/dist/chunk-354T54RR.js.map +0 -1
- package/dist/chunk-6MFMTNY4.js.map +0 -1
- package/dist/chunk-7AMFUATK.js.map +0 -1
- package/dist/chunk-CNUZ2PN2.js.map +0 -1
- package/dist/chunk-EXH5AK46.js.map +0 -1
- package/dist/chunk-SCOT5DTA.js.map +0 -1
- package/dist/chunk-ZLDMAGCB.js.map +0 -1
- package/dist/chunk-ZYU7ZFLT.js.map +0 -1
- /package/dist/{capsule-crypto-YO5QJ6L3.js.map → access-authorization-probe.js.map} +0 -0
- /package/dist/{graph-edge-decay-GF3ZSGSP.js.map → access-health-types.js.map} +0 -0
- /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
- /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
- /package/dist/{chunk-34RC5RT7.js.map → chunk-2SA56WMI.js.map} +0 -0
- /package/dist/{chunk-POHSSW2T.js.map → chunk-3CDMIR3C.js.map} +0 -0
- /package/dist/{chunk-JRQBPN63.js.map → chunk-3UOSVTFR.js.map} +0 -0
- /package/dist/{chunk-AT7XL2JJ.js.map → chunk-6LRTGCRV.js.map} +0 -0
- /package/dist/{chunk-AJ7QCSIS.js.map → chunk-7CPOZH6Y.js.map} +0 -0
- /package/dist/{chunk-EHOTE26K.js.map → chunk-AGR7MGUX.js.map} +0 -0
- /package/dist/{chunk-D5ILARSD.js.map → chunk-AL4TZWI3.js.map} +0 -0
- /package/dist/{chunk-RPOSRICW.js.map → chunk-AT6DNUCM.js.map} +0 -0
- /package/dist/{chunk-KNB7IBBU.js.map → chunk-CKMO4RDY.js.map} +0 -0
- /package/dist/{chunk-5CPI2QWG.js.map → chunk-CSXHRAJJ.js.map} +0 -0
- /package/dist/{chunk-5XMJ2P62.js.map → chunk-DPYYSG6F.js.map} +0 -0
- /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
- /package/dist/{chunk-K3C6CJOF.js.map → chunk-FIGDB2HR.js.map} +0 -0
- /package/dist/{chunk-Z54EM5YZ.js.map → chunk-GF22HWS2.js.map} +0 -0
- /package/dist/{chunk-UZ7HGRHK.js.map → chunk-GNFZFJBJ.js.map} +0 -0
- /package/dist/{chunk-W6ROK2KU.js.map → chunk-HNZKVLAN.js.map} +0 -0
- /package/dist/{chunk-HVYOZAQ7.js.map → chunk-IE4HB6O5.js.map} +0 -0
- /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
- /package/dist/{chunk-UZGJFIIG.js.map → chunk-JYIFGGEM.js.map} +0 -0
- /package/dist/{chunk-VDX2J7OX.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-3SHB4YAW.js.map → chunk-L2DPF4DF.js.map} +0 -0
- /package/dist/{chunk-SPWOLGXT.js.map → chunk-LARPWF3S.js.map} +0 -0
- /package/dist/{chunk-NSRTLSBX.js.map → chunk-LFHMUWA2.js.map} +0 -0
- /package/dist/{chunk-AYAROCWD.js.map → chunk-LLISELSY.js.map} +0 -0
- /package/dist/{chunk-W3BKLKG6.js.map → chunk-LXKJNUND.js.map} +0 -0
- /package/dist/{chunk-MMTG3SCJ.js.map → chunk-M5EPMNS4.js.map} +0 -0
- /package/dist/{chunk-KYP5FSPG.js.map → chunk-MNLZGCM2.js.map} +0 -0
- /package/dist/{chunk-TMX4MBSK.js.map → chunk-MPDX5QMH.js.map} +0 -0
- /package/dist/{chunk-PO5LSKQO.js.map → chunk-MU7ZHSZE.js.map} +0 -0
- /package/dist/{chunk-JVOA5VDZ.js.map → chunk-NMGO2HAZ.js.map} +0 -0
- /package/dist/{chunk-CAGPP5NB.js.map → chunk-NRV4Y3PM.js.map} +0 -0
- /package/dist/{chunk-H2M4YA6K.js.map → chunk-NVYCTASB.js.map} +0 -0
- /package/dist/{chunk-M2PG7OTI.js.map → chunk-P25IPRXP.js.map} +0 -0
- /package/dist/{chunk-FPJWQZ35.js.map → chunk-SZN6XVFC.js.map} +0 -0
- /package/dist/{chunk-4E3DWNTJ.js.map → chunk-THHPDPMS.js.map} +0 -0
- /package/dist/{chunk-XPLTZEJU.js.map → chunk-U37RGPJT.js.map} +0 -0
- /package/dist/{chunk-3UD5ZAUA.js.map → chunk-VY6SDKWZ.js.map} +0 -0
- /package/dist/{chunk-XJTYLU6J.js.map → chunk-W4ZDTHWZ.js.map} +0 -0
- /package/dist/{chunk-3NAHZQU3.js.map → chunk-X3SQYAPP.js.map} +0 -0
- /package/dist/{chunk-WMLHJ5UW.js.map → chunk-X6ROIHFE.js.map} +0 -0
- /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
- /package/dist/{chunk-GCQIMJFH.js.map → chunk-XTAAG4SQ.js.map} +0 -0
- /package/dist/{chunk-RSLXMGFP.js.map → chunk-ZN4UZWMT.js.map} +0 -0
package/src/access-http.test.ts
CHANGED
|
@@ -1642,6 +1642,15 @@ test("HTTP externalRequestHandler runs pre-auth, can end responses, and falls th
|
|
|
1642
1642
|
},
|
|
1643
1643
|
nativeKnowledgeEnabled: false,
|
|
1644
1644
|
projectionAvailable: false,
|
|
1645
|
+
extraction: {
|
|
1646
|
+
lastExtractionAt: null,
|
|
1647
|
+
bufferedSessionCount: 0,
|
|
1648
|
+
pendingTurnCount: 0,
|
|
1649
|
+
oldestBufferedTurnAgeMs: null,
|
|
1650
|
+
degraded: false,
|
|
1651
|
+
degradedReason: null,
|
|
1652
|
+
watermarkScope: "root-store",
|
|
1653
|
+
},
|
|
1645
1654
|
corpus: [],
|
|
1646
1655
|
}),
|
|
1647
1656
|
} satisfies Pick<EngramAccessService, "health">;
|
|
@@ -1758,6 +1767,15 @@ test("HTTP authTokenEntriesGetter is authoritative: scope policy binds connector
|
|
|
1758
1767
|
},
|
|
1759
1768
|
nativeKnowledgeEnabled: false,
|
|
1760
1769
|
projectionAvailable: false,
|
|
1770
|
+
extraction: {
|
|
1771
|
+
lastExtractionAt: null,
|
|
1772
|
+
bufferedSessionCount: 0,
|
|
1773
|
+
pendingTurnCount: 0,
|
|
1774
|
+
oldestBufferedTurnAgeMs: null,
|
|
1775
|
+
degraded: false,
|
|
1776
|
+
degradedReason: null,
|
|
1777
|
+
watermarkScope: "root-store",
|
|
1778
|
+
},
|
|
1761
1779
|
corpus: [],
|
|
1762
1780
|
}),
|
|
1763
1781
|
} satisfies Pick<EngramAccessService, "health">;
|
|
@@ -2960,3 +2978,79 @@ test("HTTP meetings get returns 400 (not 500) for a malformed percent-encoded id
|
|
|
2960
2978
|
await server.stop();
|
|
2961
2979
|
}
|
|
2962
2980
|
});
|
|
2981
|
+
|
|
2982
|
+
test("HTTP authorization probe verifies requested operation grants without invoking operations (issue #2129)", async () => {
|
|
2983
|
+
const service = {
|
|
2984
|
+
configRef: parseConfig({ memoryDir: "/tmp/remnic-http-authorization-probe", defaultNamespace: "default" }),
|
|
2985
|
+
} as unknown as EngramAccessService;
|
|
2986
|
+
const server = new EngramAccessHttpServer({
|
|
2987
|
+
service,
|
|
2988
|
+
port: 0,
|
|
2989
|
+
authTokenEntriesGetter: () => [
|
|
2990
|
+
{
|
|
2991
|
+
token: "delegate-token",
|
|
2992
|
+
capabilities: { version: 1, ops: ["recall", "observe", "lcm_compaction_flush"] },
|
|
2993
|
+
},
|
|
2994
|
+
{ token: "recall-only-token", capabilities: { version: 1, ops: ["recall"] } },
|
|
2995
|
+
{ token: "observe-only-token", capabilities: { version: 1, ops: ["observe"] } },
|
|
2996
|
+
{
|
|
2997
|
+
token: "fleet-scoped-token",
|
|
2998
|
+
capabilities: {
|
|
2999
|
+
version: 1,
|
|
3000
|
+
ops: ["continuity_audit_generate"],
|
|
3001
|
+
namespaces: ["default"],
|
|
3002
|
+
},
|
|
3003
|
+
},
|
|
3004
|
+
],
|
|
3005
|
+
adminConsoleEnabled: false,
|
|
3006
|
+
});
|
|
3007
|
+
const status = await server.start();
|
|
3008
|
+
const probe = (token: string, operations: string[]) => {
|
|
3009
|
+
const query = new URLSearchParams();
|
|
3010
|
+
for (const operation of operations) query.append("op", operation);
|
|
3011
|
+
return fetch(`http://127.0.0.1:${status.port}/engram/v1/authorization?${query}`, {
|
|
3012
|
+
headers: { authorization: `Bearer ${token}` },
|
|
3013
|
+
});
|
|
3014
|
+
};
|
|
3015
|
+
const delegateOperations = ["recall", "observe", "lcm_compaction_flush"];
|
|
3016
|
+
try {
|
|
3017
|
+
const authorized = await probe("delegate-token", [...delegateOperations, "recall"]);
|
|
3018
|
+
assert.equal(authorized.status, 200);
|
|
3019
|
+
assert.equal(authorized.headers.get("cache-control"), "no-store");
|
|
3020
|
+
assert.deepEqual(await authorized.json(), { authorized: true, operations: delegateOperations });
|
|
3021
|
+
|
|
3022
|
+
const alternateGrant = await probe("observe-only-token", ["namespace_writable"]);
|
|
3023
|
+
assert.equal(alternateGrant.status, 200);
|
|
3024
|
+
await alternateGrant.text();
|
|
3025
|
+
|
|
3026
|
+
const fleetWide = await probe("fleet-scoped-token", ["continuity_audit_generate"]);
|
|
3027
|
+
assert.equal(fleetWide.status, 403);
|
|
3028
|
+
assert.equal(fleetWide.headers.get("cache-control"), "no-store");
|
|
3029
|
+
await fleetWide.text();
|
|
3030
|
+
|
|
3031
|
+
const denied = await probe("recall-only-token", delegateOperations);
|
|
3032
|
+
assert.equal(
|
|
3033
|
+
denied.status,
|
|
3034
|
+
403,
|
|
3035
|
+
"a token missing any requested operation is rejected without running it",
|
|
3036
|
+
);
|
|
3037
|
+
assert.equal(denied.headers.get("cache-control"), "no-store");
|
|
3038
|
+
await denied.text();
|
|
3039
|
+
|
|
3040
|
+
const wrongToken = await probe("wrong-token", delegateOperations);
|
|
3041
|
+
assert.equal(wrongToken.status, 401);
|
|
3042
|
+
await wrongToken.text();
|
|
3043
|
+
|
|
3044
|
+
const empty = await probe("delegate-token", []);
|
|
3045
|
+
assert.equal(empty.status, 400);
|
|
3046
|
+
assert.equal(empty.headers.get("cache-control"), "no-store");
|
|
3047
|
+
await empty.text();
|
|
3048
|
+
|
|
3049
|
+
const unknown = await probe("delegate-token", ["not_an_operation"]);
|
|
3050
|
+
assert.equal(unknown.status, 400);
|
|
3051
|
+
assert.equal(unknown.headers.get("cache-control"), "no-store");
|
|
3052
|
+
await unknown.text();
|
|
3053
|
+
} finally {
|
|
3054
|
+
await server.stop();
|
|
3055
|
+
}
|
|
3056
|
+
});
|
package/src/access-http.ts
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
import { expandTildePath } from "./utils/path.js";
|
|
39
39
|
import { projectTagProjectId } from "./coding/coding-namespace.js";
|
|
40
40
|
import { getOperation, type OperationName } from "./access-boundary.js";
|
|
41
|
+
import { probeOperationAuthorization } from "./access-authorization-probe.js";
|
|
41
42
|
import { resolveQueryNamespaceWritablePreflight } from "./access-namespace-preflight.js";
|
|
42
43
|
import {
|
|
43
44
|
assertOperationAllowed,
|
|
@@ -889,6 +890,16 @@ export class EngramAccessHttpServer {
|
|
|
889
890
|
return;
|
|
890
891
|
}
|
|
891
892
|
|
|
893
|
+
if (req.method === "GET" && pathname === "/engram/v1/authorization") {
|
|
894
|
+
res.setHeader("cache-control", "no-store");
|
|
895
|
+
this.respondJson(
|
|
896
|
+
res,
|
|
897
|
+
200,
|
|
898
|
+
probeOperationAuthorization(tokenCapabilityStore.getStore(), parsed.searchParams.getAll("op")),
|
|
899
|
+
);
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
|
|
892
903
|
if (req.method === "GET" && pathname === "/engram/v1/adapters") {
|
|
893
904
|
// Issue #1850 round 5 (finding 1): adapter metadata is served after
|
|
894
905
|
// auth but was NOT op-gated, so a deny-all or narrow-ops token reached
|
|
@@ -449,3 +449,215 @@ test("health keeps namespace QMD failures scoped to the namespace", async () =>
|
|
|
449
449
|
await rm(rootDir, { recursive: true, force: true });
|
|
450
450
|
}
|
|
451
451
|
});
|
|
452
|
+
|
|
453
|
+
test("health surfaces extraction liveness as degraded when the buffer is non-empty and the watermark is stale", async () => {
|
|
454
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-liveness-"));
|
|
455
|
+
try {
|
|
456
|
+
const oldTs = new Date(Date.now() - 10_000).toISOString();
|
|
457
|
+
const config = parseConfig({ memoryDir, qmdEnabled: false, extractionLiveness: { staleWindowMs: 1000 } });
|
|
458
|
+
const service = new EngramAccessService({
|
|
459
|
+
config,
|
|
460
|
+
qmd: makeQmd({}),
|
|
461
|
+
buffer: {
|
|
462
|
+
getBufferSnapshot: async () => ({ bufferedSessionCount: 3, pendingTurnCount: 12, oldestTurnTimestamp: oldTs }),
|
|
463
|
+
},
|
|
464
|
+
// The extraction watermark is read from the daemon-global root store,
|
|
465
|
+
// not the per-namespace store (issue #2151).
|
|
466
|
+
storage: {
|
|
467
|
+
loadMeta: async () => ({
|
|
468
|
+
lastExtractionAt: oldTs,
|
|
469
|
+
extractionCount: 4,
|
|
470
|
+
lastConsolidationAt: null,
|
|
471
|
+
totalMemories: 0,
|
|
472
|
+
totalEntities: 0,
|
|
473
|
+
}),
|
|
474
|
+
},
|
|
475
|
+
async getStorage() {
|
|
476
|
+
return { dir: memoryDir };
|
|
477
|
+
},
|
|
478
|
+
} as unknown as Orchestrator);
|
|
479
|
+
|
|
480
|
+
const health = await service.health();
|
|
481
|
+
assert.equal(health.extraction.degraded, true);
|
|
482
|
+
assert.equal(health.extraction.bufferedSessionCount, 3);
|
|
483
|
+
assert.equal(health.extraction.pendingTurnCount, 12);
|
|
484
|
+
assert.equal(health.extraction.lastExtractionAt, oldTs);
|
|
485
|
+
const oldestAge = health.extraction.oldestBufferedTurnAgeMs ?? -1;
|
|
486
|
+
assert.ok(
|
|
487
|
+
oldestAge >= 10_000 && oldestAge < 60_000,
|
|
488
|
+
`oldest buffered turn age reflects the ~10s offset, not merely non-negative (got ${oldestAge}ms)`,
|
|
489
|
+
);
|
|
490
|
+
assert.ok(
|
|
491
|
+
health.extraction.degradedReason !== null && health.extraction.degradedReason.length > 0,
|
|
492
|
+
"degraded reason is populated",
|
|
493
|
+
);
|
|
494
|
+
} finally {
|
|
495
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
test("health reports extraction liveness ok when the buffer is empty (nothing to extract)", async () => {
|
|
500
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-liveness-ok-"));
|
|
501
|
+
try {
|
|
502
|
+
const oldTs = new Date(Date.now() - 10_000).toISOString();
|
|
503
|
+
const config = parseConfig({ memoryDir, qmdEnabled: false, extractionLiveness: { staleWindowMs: 1000 } });
|
|
504
|
+
const service = new EngramAccessService({
|
|
505
|
+
config,
|
|
506
|
+
qmd: makeQmd({}),
|
|
507
|
+
buffer: {
|
|
508
|
+
getBufferSnapshot: async () => ({ bufferedSessionCount: 0, pendingTurnCount: 0, oldestTurnTimestamp: null }),
|
|
509
|
+
},
|
|
510
|
+
storage: {
|
|
511
|
+
loadMeta: async () => ({
|
|
512
|
+
lastExtractionAt: oldTs,
|
|
513
|
+
extractionCount: 4,
|
|
514
|
+
lastConsolidationAt: null,
|
|
515
|
+
totalMemories: 0,
|
|
516
|
+
totalEntities: 0,
|
|
517
|
+
}),
|
|
518
|
+
},
|
|
519
|
+
async getStorage() {
|
|
520
|
+
return { dir: memoryDir };
|
|
521
|
+
},
|
|
522
|
+
} as unknown as Orchestrator);
|
|
523
|
+
|
|
524
|
+
const health = await service.health();
|
|
525
|
+
assert.equal(health.extraction.degraded, false);
|
|
526
|
+
assert.equal(health.extraction.bufferedSessionCount, 0);
|
|
527
|
+
assert.equal(health.extraction.lastExtractionAt, oldTs);
|
|
528
|
+
} finally {
|
|
529
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
test("health returns the same daemon-global extraction verdict for every namespace (issue #2151)", async () => {
|
|
534
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-liveness-ns-"));
|
|
535
|
+
try {
|
|
536
|
+
const rootTs = new Date().toISOString(); // fresh daemon-global watermark
|
|
537
|
+
const staleTs = new Date(Date.now() - 7_200_000).toISOString(); // 2h old
|
|
538
|
+
const config = parseConfig({
|
|
539
|
+
memoryDir,
|
|
540
|
+
qmdEnabled: false,
|
|
541
|
+
namespacesEnabled: true,
|
|
542
|
+
defaultNamespace: "default",
|
|
543
|
+
extractionLiveness: { staleWindowMs: 3_600_000 },
|
|
544
|
+
});
|
|
545
|
+
// Per-namespace stores return DIVERGING watermarks (fresh vs 2h stale vs
|
|
546
|
+
// never), but the global buffer is shared and the watermark must be sourced
|
|
547
|
+
// from the root store. Pre-fix, the extraction verdict tracked the
|
|
548
|
+
// namespace argument; post-fix it is identical for every namespace.
|
|
549
|
+
const perNamespaceMeta: Record<string, string | null> = { fresh: rootTs, stale: staleTs };
|
|
550
|
+
const service = new EngramAccessService({
|
|
551
|
+
config,
|
|
552
|
+
qmd: makeQmd({}),
|
|
553
|
+
buffer: {
|
|
554
|
+
getBufferSnapshot: async () => ({ bufferedSessionCount: 3, pendingTurnCount: 12, oldestTurnTimestamp: staleTs }),
|
|
555
|
+
},
|
|
556
|
+
storage: {
|
|
557
|
+
loadMeta: async () => ({
|
|
558
|
+
lastExtractionAt: rootTs,
|
|
559
|
+
extractionCount: 4,
|
|
560
|
+
lastConsolidationAt: null,
|
|
561
|
+
totalMemories: 0,
|
|
562
|
+
totalEntities: 0,
|
|
563
|
+
}),
|
|
564
|
+
},
|
|
565
|
+
async getStorage(namespace?: string) {
|
|
566
|
+
return {
|
|
567
|
+
dir: memoryDir,
|
|
568
|
+
loadMeta: async () => ({
|
|
569
|
+
lastExtractionAt: namespace ? perNamespaceMeta[namespace] ?? null : staleTs,
|
|
570
|
+
extractionCount: 4,
|
|
571
|
+
lastConsolidationAt: null,
|
|
572
|
+
totalMemories: 0,
|
|
573
|
+
totalEntities: 0,
|
|
574
|
+
}),
|
|
575
|
+
};
|
|
576
|
+
},
|
|
577
|
+
} as unknown as Orchestrator);
|
|
578
|
+
|
|
579
|
+
const fresh = (await service.health("fresh")).extraction;
|
|
580
|
+
const stale = (await service.health("stale")).extraction;
|
|
581
|
+
const def = (await service.health()).extraction;
|
|
582
|
+
// The namespace-governed fields must not vary with the namespace argument
|
|
583
|
+
// (oldestBufferedTurnAgeMs is time-derived and intentionally excluded).
|
|
584
|
+
assert.equal(stale.degraded, fresh.degraded, "degraded must not vary by namespace");
|
|
585
|
+
assert.equal(def.degraded, fresh.degraded, "default health matches namespaced health");
|
|
586
|
+
assert.equal(stale.lastExtractionAt, fresh.lastExtractionAt, "watermark must not vary by namespace");
|
|
587
|
+
assert.equal(def.lastExtractionAt, fresh.lastExtractionAt);
|
|
588
|
+
assert.equal(stale.degradedReason, fresh.degradedReason);
|
|
589
|
+
// Sourced from the fresh root watermark → healthy despite stale per-namespace stores.
|
|
590
|
+
assert.equal(fresh.degraded, false);
|
|
591
|
+
assert.equal(fresh.lastExtractionAt, rootTs);
|
|
592
|
+
} finally {
|
|
593
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
test("health reports extraction liveness degraded when the buffer read fails (§22)", async () => {
|
|
598
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-liveness-readfail-"));
|
|
599
|
+
try {
|
|
600
|
+
const freshTs = new Date().toISOString();
|
|
601
|
+
const config = parseConfig({ memoryDir, qmdEnabled: false, extractionLiveness: { staleWindowMs: 3_600_000 } });
|
|
602
|
+
const service = new EngramAccessService({
|
|
603
|
+
config,
|
|
604
|
+
qmd: makeQmd({}),
|
|
605
|
+
buffer: {
|
|
606
|
+
getBufferSnapshot: async () => {
|
|
607
|
+
throw new Error("buffer file corrupt");
|
|
608
|
+
},
|
|
609
|
+
},
|
|
610
|
+
// Fresh watermark → the ONLY fault is the unreadable buffer, proving the
|
|
611
|
+
// read failure (not staleness) drives the degradation.
|
|
612
|
+
storage: {
|
|
613
|
+
loadMeta: async () => ({
|
|
614
|
+
lastExtractionAt: freshTs,
|
|
615
|
+
extractionCount: 4,
|
|
616
|
+
lastConsolidationAt: null,
|
|
617
|
+
totalMemories: 0,
|
|
618
|
+
totalEntities: 0,
|
|
619
|
+
}),
|
|
620
|
+
},
|
|
621
|
+
async getStorage() {
|
|
622
|
+
return { dir: memoryDir };
|
|
623
|
+
},
|
|
624
|
+
} as unknown as Orchestrator);
|
|
625
|
+
|
|
626
|
+
const health = await service.health();
|
|
627
|
+
assert.equal(health.extraction.degraded, true, "an unreadable buffer must not report a healthy pipeline");
|
|
628
|
+
assert.match(health.extraction.degradedReason ?? "", /unreadable/);
|
|
629
|
+
assert.match(health.extraction.degradedReason ?? "", /buffer file corrupt/);
|
|
630
|
+
} finally {
|
|
631
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
test("health reports extraction liveness degraded when the watermark (meta) read fails (§22)", async () => {
|
|
636
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-liveness-metafail-"));
|
|
637
|
+
try {
|
|
638
|
+
const config = parseConfig({ memoryDir, qmdEnabled: false, extractionLiveness: { staleWindowMs: 3_600_000 } });
|
|
639
|
+
const service = new EngramAccessService({
|
|
640
|
+
config,
|
|
641
|
+
qmd: makeQmd({}),
|
|
642
|
+
// Empty buffer: proves the meta-read failure alone drives the degradation.
|
|
643
|
+
buffer: {
|
|
644
|
+
getBufferSnapshot: async () => ({ bufferedSessionCount: 0, pendingTurnCount: 0, oldestTurnTimestamp: null }),
|
|
645
|
+
},
|
|
646
|
+
storage: {
|
|
647
|
+
loadMeta: async () => {
|
|
648
|
+
throw new Error("meta.json unreadable");
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
async getStorage() {
|
|
652
|
+
return { dir: memoryDir };
|
|
653
|
+
},
|
|
654
|
+
} as unknown as Orchestrator);
|
|
655
|
+
|
|
656
|
+
const health = await service.health();
|
|
657
|
+
assert.equal(health.extraction.degraded, true, "an unreadable watermark must not report a healthy pipeline");
|
|
658
|
+
assert.match(health.extraction.degradedReason ?? "", /watermark unreadable/);
|
|
659
|
+
assert.match(health.extraction.degradedReason ?? "", /meta\.json unreadable/);
|
|
660
|
+
} finally {
|
|
661
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
662
|
+
}
|
|
663
|
+
});
|
package/src/access-service.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { readdirSync, unlinkSync } from "node:fs";
|
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
7
|
import { ZodError } from "zod";
|
|
8
8
|
import { AccessIdempotencyStore, hashAccessIdempotencyPayload } from "./access-idempotency.js";
|
|
9
|
+
import { computeExtractionLivenessStatus, ExtractionLivenessWarnThrottle } from "./extraction-liveness.js";
|
|
9
10
|
import { enforceNamespaceAllowList, tokenCapabilityStore } from "./access-token-capabilities.js";
|
|
10
11
|
import {
|
|
11
12
|
recordCitationUsage as recordCitationUsageForAccess,
|
|
@@ -18,7 +19,13 @@ import { resolveNamespaceCapabilities,
|
|
|
18
19
|
resolveMemoryLifecycleCapabilities,
|
|
19
20
|
resolveQmdCapabilities,
|
|
20
21
|
resolveSecurityCapabilities, resolveObjectiveStateCapabilities, resolveCompressionCapabilities, resolveRecallAuxiliaryCapabilities } from "./capabilities.js";
|
|
21
|
-
import { CorpusWatermarkCache, computeServiceCorpusWatermarks
|
|
22
|
+
import { CorpusWatermarkCache, computeServiceCorpusWatermarks } from "./corpus-watermark.js";
|
|
23
|
+
import type {
|
|
24
|
+
EngramAccessHealthResponse,
|
|
25
|
+
EngramAccessQmdCollectionState,
|
|
26
|
+
EngramAccessQmdHealthResponse,
|
|
27
|
+
} from "./access-health-types.js";
|
|
28
|
+
export type { EngramAccessHealthResponse, EngramAccessQmdCollectionState, EngramAccessQmdHealthResponse };
|
|
22
29
|
import { AccessAuditAdapter, type AccessAuditConfig, type AccessAuditResult } from "./access-audit.js";
|
|
23
30
|
import type { AnomalyDetectorResult } from "./recall-audit-anomaly.js";
|
|
24
31
|
import { resolveGitContext } from "./coding/git-context.js";
|
|
@@ -342,44 +349,6 @@ function normalizeTrustZoneInputError(error: unknown): EngramAccessInputError |
|
|
|
342
349
|
|
|
343
350
|
export const ENGRAM_ACCESS_WRITE_SCHEMA_VERSION = 1;
|
|
344
351
|
|
|
345
|
-
export interface EngramAccessHealthResponse {
|
|
346
|
-
ok: true;
|
|
347
|
-
memoryDir: string;
|
|
348
|
-
namespacesEnabled: boolean;
|
|
349
|
-
defaultNamespace: string;
|
|
350
|
-
searchBackend: string;
|
|
351
|
-
qmdEnabled: boolean;
|
|
352
|
-
qmd: EngramAccessQmdHealthResponse;
|
|
353
|
-
nativeKnowledgeEnabled: boolean;
|
|
354
|
-
projectionAvailable: boolean;
|
|
355
|
-
corpus: CorpusWatermark[];
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
export type EngramAccessQmdCollectionState =
|
|
359
|
-
| "present"
|
|
360
|
-
| "missing"
|
|
361
|
-
| "unknown"
|
|
362
|
-
| "skipped";
|
|
363
|
-
|
|
364
|
-
export interface EngramAccessQmdHealthResponse {
|
|
365
|
-
enabled: boolean;
|
|
366
|
-
active: boolean;
|
|
367
|
-
degraded: boolean;
|
|
368
|
-
mode: "cli" | "daemon" | "fallback" | "disabled" | "not-selected";
|
|
369
|
-
collection: string;
|
|
370
|
-
collectionState: EngramAccessQmdCollectionState;
|
|
371
|
-
installedVersion: string | null;
|
|
372
|
-
supportedVersion: string | null;
|
|
373
|
-
supported: boolean | null;
|
|
374
|
-
upgradeAvailable: boolean | null;
|
|
375
|
-
doctorAvailable: boolean | null;
|
|
376
|
-
debugStatus: string;
|
|
377
|
-
pendingEmbeddings: number | null;
|
|
378
|
-
oldestPendingAgeMs: number | null;
|
|
379
|
-
embeddingBacklogThreshold: number;
|
|
380
|
-
degradedReason?: string;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
352
|
export interface EngramAccessRecallRequest {
|
|
384
353
|
query: string;
|
|
385
354
|
sessionKey?: string;
|
|
@@ -1365,6 +1334,7 @@ export class EngramAccessService {
|
|
|
1365
1334
|
}
|
|
1366
1335
|
return this._accessIdentityContinuitySurface;
|
|
1367
1336
|
}
|
|
1337
|
+
private readonly extractionLivenessWarn = new ExtractionLivenessWarnThrottle();
|
|
1368
1338
|
|
|
1369
1339
|
constructor(private readonly orchestrator: Orchestrator) {
|
|
1370
1340
|
this.idempotency = new AccessIdempotencyStore(orchestrator.config.memoryDir);
|
|
@@ -2458,6 +2428,7 @@ export class EngramAccessService {
|
|
|
2458
2428
|
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2459
2429
|
const searchBackend = this.orchestrator.config.searchBackend ?? "qmd";
|
|
2460
2430
|
const qmdEnabled = resolveQmdCapabilities(this.orchestrator.config).qmd === true;
|
|
2431
|
+
const extraction = await computeExtractionLivenessStatus(this.orchestrator, this.extractionLivenessWarn);
|
|
2461
2432
|
let projectionAvailable = false;
|
|
2462
2433
|
try {
|
|
2463
2434
|
await stat(getMemoryProjectionPath(storage.dir));
|
|
@@ -2481,6 +2452,7 @@ export class EngramAccessService {
|
|
|
2481
2452
|
),
|
|
2482
2453
|
nativeKnowledgeEnabled: this.orchestrator.config.nativeKnowledge?.enabled === true,
|
|
2483
2454
|
projectionAvailable,
|
|
2455
|
+
extraction,
|
|
2484
2456
|
corpus: await computeServiceCorpusWatermarks(this.orchestrator, {
|
|
2485
2457
|
cache: this.corpusWatermarkCache, caps: tokenCapabilityStore.getStore() }),
|
|
2486
2458
|
};
|
|
@@ -493,9 +493,9 @@ test("MCP tools/list matches the catalog exactly (no untracked handlers)", async
|
|
|
493
493
|
* patterns from the source and compares against HTTP_ROUTES so a new
|
|
494
494
|
* service-invoking route cannot land without a catalog entry.
|
|
495
495
|
*
|
|
496
|
-
* Infrastructure routes (health, admin console, UI
|
|
497
|
-
* excluded — they
|
|
498
|
-
* migrated into the catalog in issue #1850 round 5.)
|
|
496
|
+
* Infrastructure routes (health, auth capability probes, admin console, UI
|
|
497
|
+
* assets, MCP delegate) are excluded — they do not invoke an access-service
|
|
498
|
+
* method. (Adapters was migrated into the catalog in issue #1850 round 5.)
|
|
499
499
|
*/
|
|
500
500
|
test("HTTP handler source routes match the catalog (static completeness)", () => {
|
|
501
501
|
const httpSource = readFileSync(
|
|
@@ -534,6 +534,7 @@ test("HTTP handler source routes match the catalog (static completeness)", () =>
|
|
|
534
534
|
|
|
535
535
|
const INFRA = [
|
|
536
536
|
/^\/engram\/v1\/health$/,
|
|
537
|
+
/^\/engram\/v1\/authorization$/,
|
|
537
538
|
/^\/engram\/v1\/admin\//,
|
|
538
539
|
/^\/engram\/ui/,
|
|
539
540
|
/^\/mcp$/,
|
|
@@ -249,6 +249,37 @@ export function capabilityAllowsOp(caps: TokenCapabilities | undefined | null, o
|
|
|
249
249
|
return caps.ops.includes(op);
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
/**
|
|
253
|
+
* The operation policy that all access surfaces use to decide whether a token
|
|
254
|
+
* can invoke an operation.
|
|
255
|
+
*/
|
|
256
|
+
export interface OperationAuthorizationPolicy {
|
|
257
|
+
readonly name: string;
|
|
258
|
+
readonly allowedByOps?: readonly string[];
|
|
259
|
+
readonly fleetWide?: boolean;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Apply an operation's alternate grant and fleet-wide restrictions without
|
|
264
|
+
* invoking its handler.
|
|
265
|
+
*/
|
|
266
|
+
export function assertOperationAuthorizationAllowed(
|
|
267
|
+
caps: TokenCapabilities | undefined | null,
|
|
268
|
+
operation: OperationAuthorizationPolicy,
|
|
269
|
+
): void {
|
|
270
|
+
if (operation.allowedByOps && operation.allowedByOps.length > 0) {
|
|
271
|
+
if (!operation.allowedByOps.some((allowedOperation) => capabilityAllowsOp(caps, allowedOperation))) {
|
|
272
|
+
throw new EngramAccessForbiddenError(`token is not permitted to call operation: ${operation.name}`);
|
|
273
|
+
}
|
|
274
|
+
} else {
|
|
275
|
+
assertOperationAllowed(caps, operation.name);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (operation.fleetWide) {
|
|
279
|
+
assertFleetWideOperationAllowed(caps);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
252
283
|
/**
|
|
253
284
|
* True when `caps` permits `namespace`.
|
|
254
285
|
* - record ABSENT / namespaces axis ABSENT ⇒ unrestricted (true).
|
package/src/buffer.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
SignalLevel,
|
|
11
11
|
} from "./types.js";
|
|
12
12
|
import { resolvePresentationCapabilities } from "./capabilities.js";
|
|
13
|
+
import type { ExtractionBufferSnapshot } from "./extraction-liveness.js";
|
|
13
14
|
|
|
14
15
|
export type TriggerDecision = "extract_now" | "extract_batch" | "keep_buffering";
|
|
15
16
|
|
|
@@ -306,6 +307,35 @@ export class SmartBuffer {
|
|
|
306
307
|
await this.enqueueMutation(async () => this.loadUnlocked());
|
|
307
308
|
}
|
|
308
309
|
|
|
310
|
+
/** Snapshot of buffered, not-yet-extracted work across sessions (#2151): session count,
|
|
311
|
+
* pending-turn total, oldest buffered turn. Counts retained (#562) + active turns per entry. */
|
|
312
|
+
async getBufferSnapshot(): Promise<ExtractionBufferSnapshot> {
|
|
313
|
+
await this.load();
|
|
314
|
+
let bufferedSessionCount = 0;
|
|
315
|
+
let pendingTurnCount = 0;
|
|
316
|
+
let oldestMs = Number.POSITIVE_INFINITY;
|
|
317
|
+
let oldestTurnTimestamp: string | null = null;
|
|
318
|
+
const consider = (turns: BufferTurn[] | undefined): void => {
|
|
319
|
+
if (!Array.isArray(turns) || turns.length === 0) return;
|
|
320
|
+
bufferedSessionCount += 1;
|
|
321
|
+
pendingTurnCount += turns.length;
|
|
322
|
+
const first = turns[0]?.timestamp;
|
|
323
|
+
const parsed = typeof first === "string" ? Date.parse(first) : Number.NaN;
|
|
324
|
+
if (Number.isFinite(parsed) && parsed < oldestMs) {
|
|
325
|
+
oldestMs = parsed;
|
|
326
|
+
oldestTurnTimestamp = first ?? null;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const entries = this.state.entries;
|
|
330
|
+
if (entries) {
|
|
331
|
+
// Retained turns (deferred #562) are pending too - count with active (oldest-first), like getTurns().
|
|
332
|
+
for (const entry of Object.values(entries)) consider([...(entry?.retainedTurns ?? []), ...(entry?.turns ?? [])]);
|
|
333
|
+
} else {
|
|
334
|
+
consider(this.state.turns);
|
|
335
|
+
}
|
|
336
|
+
return { bufferedSessionCount, pendingTurnCount, oldestTurnTimestamp };
|
|
337
|
+
}
|
|
338
|
+
|
|
309
339
|
/**
|
|
310
340
|
* Reset the buffer to an empty, usable state.
|
|
311
341
|
* Called when the persisted buffer file is corrupt and load() fails,
|
package/src/cli.ts
CHANGED
|
@@ -30,6 +30,7 @@ import { isRecallDisclosure, RECALL_DISCLOSURE_LEVELS } from "./types.js";
|
|
|
30
30
|
import { chunkContent } from "./chunking.js";
|
|
31
31
|
import { rescoreMemoryImportance } from "./importance.js";
|
|
32
32
|
import { renderQmdBacklogStatus } from "./qmd-status.js";
|
|
33
|
+
import { renderExtractionLivenessStats } from "./extraction-liveness.js";
|
|
33
34
|
import { exportJsonBundle } from "./transfer/export-json.js";
|
|
34
35
|
import { exportMarkdownBundle } from "./transfer/export-md.js";
|
|
35
36
|
import { backupMemoryDir } from "./transfer/backup.js";
|
|
@@ -3653,7 +3654,6 @@ export function registerCli(
|
|
|
3653
3654
|
// Ensure QMD is probed before checking availability
|
|
3654
3655
|
await orchestrator.qmd.probe();
|
|
3655
3656
|
|
|
3656
|
-
const meta = await orchestrator.storage.loadMeta();
|
|
3657
3657
|
const memories = await orchestrator.storage.readAllMemories();
|
|
3658
3658
|
const entities = await orchestrator.storage.readEntities();
|
|
3659
3659
|
const profile = await orchestrator.storage.readProfile();
|
|
@@ -3662,9 +3662,7 @@ export function registerCli(
|
|
|
3662
3662
|
console.log(`Total memories: ${memories.length}`);
|
|
3663
3663
|
console.log(`Total entities: ${entities.length}`);
|
|
3664
3664
|
console.log(`Profile size: ${profile.length} chars`);
|
|
3665
|
-
console.log(
|
|
3666
|
-
console.log(`Last extraction: ${meta.lastExtractionAt ?? "never"}`);
|
|
3667
|
-
console.log(`Last consolidation: ${meta.lastConsolidationAt ?? "never"}`);
|
|
3665
|
+
for (const line of await renderExtractionLivenessStats(orchestrator)) console.log(line);
|
|
3668
3666
|
console.log(`QMD: ${orchestrator.qmd.isAvailable() ? "available" : "not available"}`);
|
|
3669
3667
|
for (const line of await renderQmdBacklogStatus(orchestrator.qmd, orchestrator.config.qmdEmbeddingBacklogThreshold)) console.log(line);
|
|
3670
3668
|
|
package/src/config.ts
CHANGED
|
@@ -37,6 +37,7 @@ import { expandTildePath } from "./utils/path.js";
|
|
|
37
37
|
// config.ts → connectors/index.ts nor the reverse circular import arises.
|
|
38
38
|
import { coerceBool, coerceBooleanLike, coerceInstallExtension, coerceNumber } from "./connectors/coerce.js";
|
|
39
39
|
import { parseRecallConcurrencyConfig } from "./recall-concurrency-config.js";
|
|
40
|
+
import { parseExtractionLivenessConfig } from "./extraction-liveness.js";
|
|
40
41
|
import { hasLegacyConnectorEntries } from "./connectors/paths.js";
|
|
41
42
|
import {
|
|
42
43
|
parseQmdChunkStrategy,
|
|
@@ -2326,15 +2327,14 @@ export function parseConfig(
|
|
|
2326
2327
|
typeof cfg.activeRecallEntityGraphDepth === "number"
|
|
2327
2328
|
? Math.min(3, Math.max(0, Math.floor(cfg.activeRecallEntityGraphDepth)))
|
|
2328
2329
|
: 1,
|
|
2329
|
-
activeRecallIncludeCausalTrajectories:
|
|
2330
|
-
cfg.activeRecallIncludeCausalTrajectories === true,
|
|
2330
|
+
activeRecallIncludeCausalTrajectories: cfg.activeRecallIncludeCausalTrajectories === true,
|
|
2331
2331
|
activeRecallIncludeDaySummary: cfg.activeRecallIncludeDaySummary === true,
|
|
2332
2332
|
activeRecallAttachRecallExplain: cfg.activeRecallAttachRecallExplain === true,
|
|
2333
|
-
activeRecallAllowChainedActiveMemory:
|
|
2334
|
-
cfg.activeRecallAllowChainedActiveMemory === true,
|
|
2333
|
+
activeRecallAllowChainedActiveMemory: cfg.activeRecallAllowChainedActiveMemory === true,
|
|
2335
2334
|
dreaming,
|
|
2336
2335
|
dreamsPhases,
|
|
2337
2336
|
procedural,
|
|
2337
|
+
extractionLiveness: parseExtractionLivenessConfig(cfg),
|
|
2338
2338
|
wearables,
|
|
2339
2339
|
meetings,
|
|
2340
2340
|
activity,
|