@remnic/core 10.0.90 → 10.0.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.js +88 -88
- package/dist/access-authorization-probe.js +89 -89
- package/dist/access-boundary.js +88 -88
- package/dist/access-cli.js +191 -190
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +88 -88
- package/dist/access-http-admission.d.ts +14 -0
- package/dist/access-http-admission.d.ts.map +1 -0
- package/dist/access-http-admission.js +9 -0
- package/dist/access-http-briefing.js +89 -89
- package/dist/access-http-query.js +90 -90
- package/dist/access-http-types.d.ts +145 -0
- package/dist/access-http-types.d.ts.map +1 -0
- package/dist/access-http-types.js +1 -0
- package/dist/access-http.d.ts +3 -142
- package/dist/access-http.d.ts.map +1 -1
- package/dist/access-http.js +117 -116
- package/dist/access-identity-continuity-surface.js +88 -88
- package/dist/access-lcm-surface.js +88 -88
- package/dist/access-mcp.d.ts.map +1 -1
- package/dist/access-mcp.js +104 -104
- package/dist/access-namespace-preflight.js +88 -88
- package/dist/access-observe-write-category.js +12 -12
- package/dist/access-observe-write-surface.js +88 -88
- package/dist/access-offline-manifest.js +17 -17
- package/dist/access-operations-batch.js +92 -92
- package/dist/access-operations.js +99 -99
- package/dist/access-recall-concurrency.js +88 -88
- package/dist/access-recall-diagnostics.js +6 -6
- package/dist/access-recall-response.js +88 -88
- package/dist/access-recall-surface.js +88 -88
- package/dist/access-schema.js +8 -8
- package/dist/access-service.js +88 -88
- package/dist/access-surface-catalog.js +90 -90
- package/dist/active-memory-bridge.js +6 -6
- package/dist/active-recall.js +42 -42
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/auto-sync-3AZW7MXI.js +3 -3
- package/dist/briefing.js +30 -30
- package/dist/buffer-admission.d.ts +9 -0
- package/dist/buffer-admission.d.ts.map +1 -1
- package/dist/buffer-admission.js +3 -1
- package/dist/buffer.js +14 -14
- package/dist/calibration.js +5 -5
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.js +35 -35
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.js +2 -2
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-4XYAWK5H.js → chunk-25BUV3TU.js} +2 -2
- package/dist/{chunk-C2HORX76.js → chunk-27XYV2XL.js} +2 -2
- package/dist/{chunk-3NF4QUNZ.js → chunk-2JSDPUKD.js} +5 -5
- package/dist/{chunk-AJHNXIQU.js → chunk-2LCRG2YV.js} +2 -2
- package/dist/{chunk-ARRTLPRC.js → chunk-3UMDRGFS.js} +2 -2
- package/dist/{chunk-G54BOKZ6.js → chunk-3XIWW4TB.js} +9 -9
- package/dist/{chunk-GCBIXUPT.js → chunk-47F6WWLQ.js} +2 -2
- package/dist/{chunk-TSS3D7ZY.js → chunk-4CJTQHEG.js} +3 -3
- package/dist/{chunk-4X7HQKAG.js → chunk-4XINO77L.js} +2 -2
- package/dist/{chunk-ELHJK7LM.js → chunk-5IYOKDM4.js} +12 -12
- package/dist/{chunk-F74G4KIH.js → chunk-5UCMYPVF.js} +2 -2
- package/dist/{chunk-3PJEDHLD.js → chunk-63O7LVMN.js} +3 -3
- package/dist/{chunk-52II7PB6.js → chunk-645WOU5I.js} +4 -4
- package/dist/{chunk-QEZ3DW5O.js → chunk-65AUYLU3.js} +5 -5
- package/dist/{chunk-G6HWNPZA.js → chunk-66L5ZRJC.js} +2 -2
- package/dist/{chunk-TNW6BOMM.js → chunk-6HM6HARE.js} +2 -2
- package/dist/{chunk-GOZXQNIM.js → chunk-6P7U3HWG.js} +3 -3
- package/dist/{chunk-CYCEROPR.js → chunk-6QMWECO5.js} +7 -7
- package/dist/{chunk-SBRUTD5O.js → chunk-6SRYCJ5I.js} +10 -10
- package/dist/{chunk-BLSHFIR6.js → chunk-7HTUYFR3.js} +5 -5
- package/dist/{chunk-2N4OUSIA.js → chunk-7L3TODI7.js} +2 -2
- package/dist/{chunk-P452SEKO.js → chunk-AH637HZ5.js} +2 -2
- package/dist/{chunk-J6GZ2254.js → chunk-AL3TCNSJ.js} +4 -4
- package/dist/{chunk-NIVKG3DS.js → chunk-AOFEMUHG.js} +6 -6
- package/dist/{chunk-BIVKPQ6Q.js → chunk-AP6NCP3V.js} +8 -8
- package/dist/{chunk-25Q52SOT.js → chunk-ATPWMT2E.js} +3 -3
- package/dist/{chunk-HXFIILGF.js → chunk-BFPF5N3H.js} +4 -4
- package/dist/{chunk-ROKDHO74.js → chunk-BMWMTAQF.js} +4 -4
- package/dist/{chunk-4Q26RNSR.js → chunk-CD4BCCNP.js} +2 -2
- package/dist/{chunk-5SOSQTVE.js → chunk-CIEEYVUB.js} +2 -2
- package/dist/{chunk-TFEHSPGQ.js → chunk-E5PPE4VA.js} +4 -4
- package/dist/{chunk-3UZ2VMKD.js → chunk-E6M225BJ.js} +6 -6
- package/dist/{chunk-TIGYOZBU.js → chunk-E6Z4FBX6.js} +4 -4
- package/dist/{chunk-QKERFEJS.js → chunk-EFYN5I7Z.js} +2 -2
- package/dist/{chunk-M3BEJJNV.js → chunk-ENQCH3SW.js} +8 -1
- package/dist/chunk-ENQCH3SW.js.map +1 -0
- package/dist/{chunk-QD5R6U5J.js → chunk-EV76IZ37.js} +2 -2
- package/dist/{chunk-S45INSV3.js → chunk-FF6N7BXC.js} +4 -4
- package/dist/{chunk-2U4LMSEX.js → chunk-FRSHF6FU.js} +3 -3
- package/dist/{chunk-ZOJUWVAU.js → chunk-GKL6QYZO.js} +1 -1
- package/dist/{chunk-ZBFLV657.js → chunk-GNXGJBCA.js} +2 -2
- package/dist/{chunk-5UBXIV3N.js → chunk-GRTKLWYX.js} +14 -14
- package/dist/{chunk-Q5XJYCFE.js → chunk-HVKUCT3W.js} +2 -2
- package/dist/chunk-I3V3JJS7.js +24 -0
- package/dist/chunk-I3V3JJS7.js.map +1 -0
- package/dist/{chunk-YLTU2DC4.js → chunk-IHCXMYSE.js} +2 -2
- package/dist/{chunk-2G4TV2ML.js → chunk-IPT2OY4B.js} +4 -4
- package/dist/{chunk-ZANNIXXE.js → chunk-IQMDQJCD.js} +3 -3
- package/dist/{chunk-S7GJNA3K.js → chunk-IQWUACVG.js} +2 -2
- package/dist/{chunk-QNSZYTSG.js → chunk-ITHZFHST.js} +2 -2
- package/dist/{chunk-OXQ7F45O.js → chunk-J4MMPQ7Q.js} +6 -6
- package/dist/{chunk-IBDWYRDR.js → chunk-JBCCWVU2.js} +2 -2
- package/dist/{chunk-H3WAT6BR.js → chunk-JC36FPQ5.js} +2 -2
- package/dist/{chunk-QUMKDRCF.js → chunk-JDY34KBL.js} +4 -4
- package/dist/{chunk-77PDJ4OE.js → chunk-KEPXC4KN.js} +2 -2
- package/dist/{chunk-7LCGFUMB.js → chunk-KQAFEZQX.js} +4 -4
- package/dist/{chunk-M5O2ANZD.js → chunk-KUIRDD74.js} +24 -22
- package/dist/chunk-KUIRDD74.js.map +1 -0
- package/dist/{chunk-JM2YZKCQ.js → chunk-LJQFJF4J.js} +6 -6
- package/dist/{chunk-DC55RIEZ.js → chunk-M4IEZGCK.js} +4 -4
- package/dist/{chunk-UWRHHRDK.js → chunk-MKRYQROF.js} +5 -5
- package/dist/{chunk-LHGPU6DQ.js → chunk-MVMRUGBH.js} +6 -6
- package/dist/{chunk-2XOFVTTT.js → chunk-N74SGESS.js} +2 -2
- package/dist/{chunk-TRMZHGIX.js → chunk-NJJMVS5Y.js} +15 -15
- package/dist/{chunk-3DAWHP5K.js → chunk-NZSRRVJQ.js} +5 -5
- package/dist/{chunk-ROGO7FRA.js → chunk-O55EKIEC.js} +2 -2
- package/dist/{chunk-SO4DZIVF.js → chunk-ODL4ZTNI.js} +37 -35
- package/dist/chunk-ODL4ZTNI.js.map +1 -0
- package/dist/{chunk-IPD5GC7C.js → chunk-OFVCFKDH.js} +2 -2
- package/dist/{chunk-J5WI4QRP.js → chunk-OIGJZHDU.js} +4 -4
- package/dist/{chunk-K3FH3LAQ.js → chunk-OJXK5C6Z.js} +4 -4
- package/dist/{chunk-OL553AWT.js → chunk-P5VZSSYL.js} +12 -12
- package/dist/{chunk-3ICAWZUU.js → chunk-PLCYKAWH.js} +4 -4
- package/dist/{chunk-PDOOUXCS.js → chunk-PPCLZ4JU.js} +2 -2
- package/dist/{chunk-HLN2HOXX.js → chunk-PUEO37QG.js} +6 -6
- package/dist/{chunk-32YX7EJ3.js → chunk-QL7RHYK6.js} +13 -13
- package/dist/{chunk-TX6EHB2Q.js → chunk-QVMOCJRV.js} +2 -2
- package/dist/{chunk-YMJRLT7S.js → chunk-R2DOFBG4.js} +3 -3
- package/dist/{chunk-NQP4ZYGG.js → chunk-RGUUBAT5.js} +3 -3
- package/dist/{chunk-P4JED3ZL.js → chunk-RMXS4I66.js} +2 -2
- package/dist/{chunk-VKILERSL.js → chunk-RO7RUBLD.js} +2 -2
- package/dist/{chunk-MTTYIXSU.js → chunk-RRTVGD3J.js} +9 -9
- package/dist/{chunk-3TKX2RYK.js → chunk-RSK2WIEM.js} +2 -2
- package/dist/{chunk-DT7SNJH6.js → chunk-RYWROSL5.js} +4 -4
- package/dist/{chunk-SYKJBS7S.js → chunk-SHUBTAY2.js} +24 -24
- package/dist/{chunk-OZNBZJ3S.js → chunk-SLDRXK37.js} +8 -8
- package/dist/{chunk-ATWFYXEN.js → chunk-STSLB4HT.js} +139 -139
- package/dist/{chunk-G67EUQAB.js → chunk-TG3R2SID.js} +4 -4
- package/dist/{chunk-N7EKND7S.js → chunk-TRBGGJKZ.js} +169 -168
- package/dist/{chunk-N7EKND7S.js.map → chunk-TRBGGJKZ.js.map} +1 -1
- package/dist/{chunk-YAVIBVCU.js → chunk-UA2NDTIU.js} +4 -4
- package/dist/{chunk-KVSOEVAF.js → chunk-UE6RRXMF.js} +2 -2
- package/dist/{chunk-TAUHAP5J.js → chunk-UXPXOVJI.js} +9 -9
- package/dist/{chunk-QKES7GU6.js → chunk-VMVVSZTD.js} +2 -2
- package/dist/{chunk-YRZPBN46.js → chunk-VNUOAXWP.js} +2 -2
- package/dist/{chunk-EA2LA5RI.js → chunk-VPQFK63H.js} +2 -2
- package/dist/{chunk-UH3FPX3L.js → chunk-W7K5BP3M.js} +2 -2
- package/dist/{chunk-PKZ274PI.js → chunk-WLBEZZK5.js} +3 -3
- package/dist/{chunk-TQ4SCPGQ.js → chunk-WRT7GJ2D.js} +3 -3
- package/dist/{chunk-5MF6LMUY.js → chunk-WUUES6CU.js} +2 -2
- package/dist/{chunk-CC4V7HNP.js → chunk-WWK6J6SE.js} +53 -53
- package/dist/{chunk-LEEAO2TX.js → chunk-XICOH5HT.js} +3 -3
- package/dist/{chunk-CN7Q3T2J.js → chunk-XNI3URDR.js} +2 -2
- package/dist/{chunk-64S6X4IU.js → chunk-XTN54NML.js} +4 -4
- package/dist/{chunk-PWPIERBM.js → chunk-YCNIGRRF.js} +4 -4
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-DZ7DPDVW.js → chunk-YODUDA6R.js} +15 -15
- package/dist/{chunk-4GMI5HFH.js → chunk-YS2GHSWN.js} +20 -20
- package/dist/{chunk-2K3AUDH7.js → chunk-YYOMGOHB.js} +4 -4
- package/dist/{chunk-B56LORLY.js → chunk-Z4Q6USKJ.js} +2 -2
- package/dist/{chunk-IHJZSRDM.js → chunk-ZCLEYJPB.js} +83 -83
- package/dist/{chunk-D5EV6Y2L.js → chunk-ZT6WPSII.js} +2 -2
- package/dist/{chunk-3Y5X6YFH.js → chunk-ZZ67UTQX.js} +2 -2
- package/dist/cli.js +147 -146
- package/dist/coding/export-okf-codegraph.js +30 -30
- package/dist/coding/pre-action-gate.js +2 -2
- package/dist/compounding/engine.js +31 -31
- package/dist/config.js +42 -42
- package/dist/connectors/codex-materialize-runner.js +32 -32
- package/dist/connectors/codex-materialize.js +2 -2
- package/dist/connectors/index.js +36 -36
- package/dist/consolidation-provenance-check.js +2 -2
- package/dist/contradiction/index.js +6 -6
- package/dist/{contradiction-scan-P7KXB5R4.js → contradiction-scan-P2MHYFVG.js} +5 -5
- package/dist/convergence-refresh.js +32 -32
- package/dist/corpus-watermark.js +33 -33
- package/dist/dashboard-runtime.js +2 -2
- package/dist/deep-recall-http-glue.js +9 -9
- package/dist/deep-recall.js +2 -2
- package/dist/embedding-fallback.js +3 -3
- package/dist/entity-retrieval.js +31 -31
- package/dist/event-order-recall.js +3 -3
- package/dist/explicit-capture.js +10 -10
- package/dist/external-wiki-access.js +89 -89
- package/dist/extraction-evidence-class.js +2 -2
- package/dist/extraction-normalization.js +1 -1
- package/dist/extraction-source-grounding.js +3 -3
- package/dist/extraction.js +46 -46
- package/dist/{first-start-migration-A6PHIBUQ.js → first-start-migration-QFI7B5SH.js} +7 -7
- package/dist/{graph-edge-decay-EKWXRBWF.js → graph-edge-decay-OEX5OGMI.js} +6 -6
- package/dist/graph-edge-decay-OEX5OGMI.js.map +1 -0
- package/dist/graph-jsonl.js +3 -3
- package/dist/graph-snapshot.js +3 -3
- package/dist/graph.js +2 -2
- package/dist/harmonic-retrieval.js +29 -29
- package/dist/index.js +300 -299
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.js +8 -8
- package/dist/local-llm-config.js +1 -1
- package/dist/local-llm.js +2 -2
- package/dist/location/index.js +32 -32
- package/dist/maintenance/memory-governance.js +30 -30
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +29 -29
- package/dist/maintenance/rebuild-memory-projection-runner.js +32 -32
- package/dist/maintenance/rebuild-memory-projection.js +31 -31
- package/dist/memory-browse-operations.js +89 -89
- package/dist/memory-browse.js +10 -10
- package/dist/memory-subject.js +1 -1
- package/dist/namespaces/migrate.js +31 -31
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.js +30 -30
- package/dist/offline-sync-changeset-generations.js +4 -4
- package/dist/offline-sync-embedding-generation.js +3 -3
- package/dist/offline-sync-impression-drain.js +3 -3
- package/dist/offline-sync-snapshot-stream.js +6 -6
- package/dist/offline-sync.js +7 -7
- package/dist/operator-doctor-corpus.js +34 -34
- package/dist/operator-toolkit.js +58 -58
- package/dist/orchestration/backlog-scheduler.js +192 -191
- package/dist/orchestration/backlog-scheduler.js.map +1 -1
- package/dist/orchestration/buffer-drain-runner.js +192 -191
- package/dist/orchestration/maintenance.js +48 -48
- package/dist/orchestration/turn-ingestion.d.ts +2 -2
- package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
- package/dist/orchestrator.js +192 -191
- package/dist/provenance.js +2 -2
- package/dist/qmd.js +6 -6
- package/dist/recall-navigation-operations.js +89 -89
- package/dist/recall-navigation.js +88 -88
- package/dist/recall-state-view-admission.js +7 -7
- package/dist/recall-why-service.js +14 -14
- package/dist/recall-why.js +5 -5
- package/dist/reconcile/cursor.js +2 -2
- package/dist/reconcile/manifest.js +6 -6
- package/dist/reconcile/plan.js +2 -2
- package/dist/{resolution-23ZBDM6A.js → resolution-N7H3F2E4.js} +7 -7
- package/dist/resolution-N7H3F2E4.js.map +1 -0
- package/dist/resume-bundles.js +44 -44
- package/dist/salvage-envelope.js +1 -1
- package/dist/search/factory.js +6 -6
- package/dist/search/index.js +10 -10
- package/dist/semantic-consolidation.js +38 -38
- package/dist/semantic-rule-promotion.js +29 -29
- package/dist/semantic-rule-verifier.js +29 -29
- package/dist/source-agent-qualifier.js +42 -42
- package/dist/standup/build.js +29 -29
- package/dist/storage.js +28 -28
- package/dist/subject-config.js +1 -1
- package/dist/summarizer.js +5 -5
- package/dist/support-passport/index.js +105 -105
- package/dist/tier-routing.js +3 -3
- package/dist/{tier-stats-C3IAMS4X.js → tier-stats-FQGQSFET.js} +7 -7
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/export-okf.js +29 -29
- package/dist/verified-recall.js +29 -29
- package/dist/who-knows-cli.js +30 -30
- package/dist/who-knows.js +29 -29
- package/dist/write-envelope.js +1 -1
- package/package.json +2 -2
- package/src/access-http-admission.ts +33 -0
- package/src/access-http-types.ts +153 -0
- package/src/access-http.test.ts +63 -1
- package/src/access-http.ts +26 -148
- package/src/access-mcp.test.ts +24 -0
- package/src/access-mcp.ts +3 -0
- package/src/access-observe-replay-durability.test.ts +4 -1
- package/src/access-service-observe-idempotency.test.ts +44 -0
- package/src/buffer-admission.ts +13 -0
- package/src/orchestration/turn-ingestion.ts +3 -3
- package/dist/chunk-M3BEJJNV.js.map +0 -1
- package/dist/chunk-M5O2ANZD.js.map +0 -1
- package/dist/chunk-SO4DZIVF.js.map +0 -1
- /package/dist/{contradiction-scan-P7KXB5R4.js.map → access-http-admission.js.map} +0 -0
- /package/dist/{graph-edge-decay-EKWXRBWF.js.map → access-http-types.js.map} +0 -0
- /package/dist/{chunk-4XYAWK5H.js.map → chunk-25BUV3TU.js.map} +0 -0
- /package/dist/{chunk-C2HORX76.js.map → chunk-27XYV2XL.js.map} +0 -0
- /package/dist/{chunk-3NF4QUNZ.js.map → chunk-2JSDPUKD.js.map} +0 -0
- /package/dist/{chunk-AJHNXIQU.js.map → chunk-2LCRG2YV.js.map} +0 -0
- /package/dist/{chunk-ARRTLPRC.js.map → chunk-3UMDRGFS.js.map} +0 -0
- /package/dist/{chunk-G54BOKZ6.js.map → chunk-3XIWW4TB.js.map} +0 -0
- /package/dist/{chunk-GCBIXUPT.js.map → chunk-47F6WWLQ.js.map} +0 -0
- /package/dist/{chunk-TSS3D7ZY.js.map → chunk-4CJTQHEG.js.map} +0 -0
- /package/dist/{chunk-4X7HQKAG.js.map → chunk-4XINO77L.js.map} +0 -0
- /package/dist/{chunk-ELHJK7LM.js.map → chunk-5IYOKDM4.js.map} +0 -0
- /package/dist/{chunk-F74G4KIH.js.map → chunk-5UCMYPVF.js.map} +0 -0
- /package/dist/{chunk-3PJEDHLD.js.map → chunk-63O7LVMN.js.map} +0 -0
- /package/dist/{chunk-52II7PB6.js.map → chunk-645WOU5I.js.map} +0 -0
- /package/dist/{chunk-QEZ3DW5O.js.map → chunk-65AUYLU3.js.map} +0 -0
- /package/dist/{chunk-G6HWNPZA.js.map → chunk-66L5ZRJC.js.map} +0 -0
- /package/dist/{chunk-TNW6BOMM.js.map → chunk-6HM6HARE.js.map} +0 -0
- /package/dist/{chunk-GOZXQNIM.js.map → chunk-6P7U3HWG.js.map} +0 -0
- /package/dist/{chunk-CYCEROPR.js.map → chunk-6QMWECO5.js.map} +0 -0
- /package/dist/{chunk-SBRUTD5O.js.map → chunk-6SRYCJ5I.js.map} +0 -0
- /package/dist/{chunk-BLSHFIR6.js.map → chunk-7HTUYFR3.js.map} +0 -0
- /package/dist/{chunk-2N4OUSIA.js.map → chunk-7L3TODI7.js.map} +0 -0
- /package/dist/{chunk-P452SEKO.js.map → chunk-AH637HZ5.js.map} +0 -0
- /package/dist/{chunk-J6GZ2254.js.map → chunk-AL3TCNSJ.js.map} +0 -0
- /package/dist/{chunk-NIVKG3DS.js.map → chunk-AOFEMUHG.js.map} +0 -0
- /package/dist/{chunk-BIVKPQ6Q.js.map → chunk-AP6NCP3V.js.map} +0 -0
- /package/dist/{chunk-25Q52SOT.js.map → chunk-ATPWMT2E.js.map} +0 -0
- /package/dist/{chunk-HXFIILGF.js.map → chunk-BFPF5N3H.js.map} +0 -0
- /package/dist/{chunk-ROKDHO74.js.map → chunk-BMWMTAQF.js.map} +0 -0
- /package/dist/{chunk-4Q26RNSR.js.map → chunk-CD4BCCNP.js.map} +0 -0
- /package/dist/{chunk-5SOSQTVE.js.map → chunk-CIEEYVUB.js.map} +0 -0
- /package/dist/{chunk-TFEHSPGQ.js.map → chunk-E5PPE4VA.js.map} +0 -0
- /package/dist/{chunk-3UZ2VMKD.js.map → chunk-E6M225BJ.js.map} +0 -0
- /package/dist/{chunk-TIGYOZBU.js.map → chunk-E6Z4FBX6.js.map} +0 -0
- /package/dist/{chunk-QKERFEJS.js.map → chunk-EFYN5I7Z.js.map} +0 -0
- /package/dist/{chunk-QD5R6U5J.js.map → chunk-EV76IZ37.js.map} +0 -0
- /package/dist/{chunk-S45INSV3.js.map → chunk-FF6N7BXC.js.map} +0 -0
- /package/dist/{chunk-2U4LMSEX.js.map → chunk-FRSHF6FU.js.map} +0 -0
- /package/dist/{chunk-ZOJUWVAU.js.map → chunk-GKL6QYZO.js.map} +0 -0
- /package/dist/{chunk-ZBFLV657.js.map → chunk-GNXGJBCA.js.map} +0 -0
- /package/dist/{chunk-5UBXIV3N.js.map → chunk-GRTKLWYX.js.map} +0 -0
- /package/dist/{chunk-Q5XJYCFE.js.map → chunk-HVKUCT3W.js.map} +0 -0
- /package/dist/{chunk-YLTU2DC4.js.map → chunk-IHCXMYSE.js.map} +0 -0
- /package/dist/{chunk-2G4TV2ML.js.map → chunk-IPT2OY4B.js.map} +0 -0
- /package/dist/{chunk-ZANNIXXE.js.map → chunk-IQMDQJCD.js.map} +0 -0
- /package/dist/{chunk-S7GJNA3K.js.map → chunk-IQWUACVG.js.map} +0 -0
- /package/dist/{chunk-QNSZYTSG.js.map → chunk-ITHZFHST.js.map} +0 -0
- /package/dist/{chunk-OXQ7F45O.js.map → chunk-J4MMPQ7Q.js.map} +0 -0
- /package/dist/{chunk-IBDWYRDR.js.map → chunk-JBCCWVU2.js.map} +0 -0
- /package/dist/{chunk-H3WAT6BR.js.map → chunk-JC36FPQ5.js.map} +0 -0
- /package/dist/{chunk-QUMKDRCF.js.map → chunk-JDY34KBL.js.map} +0 -0
- /package/dist/{chunk-77PDJ4OE.js.map → chunk-KEPXC4KN.js.map} +0 -0
- /package/dist/{chunk-7LCGFUMB.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-JM2YZKCQ.js.map → chunk-LJQFJF4J.js.map} +0 -0
- /package/dist/{chunk-DC55RIEZ.js.map → chunk-M4IEZGCK.js.map} +0 -0
- /package/dist/{chunk-UWRHHRDK.js.map → chunk-MKRYQROF.js.map} +0 -0
- /package/dist/{chunk-LHGPU6DQ.js.map → chunk-MVMRUGBH.js.map} +0 -0
- /package/dist/{chunk-2XOFVTTT.js.map → chunk-N74SGESS.js.map} +0 -0
- /package/dist/{chunk-TRMZHGIX.js.map → chunk-NJJMVS5Y.js.map} +0 -0
- /package/dist/{chunk-3DAWHP5K.js.map → chunk-NZSRRVJQ.js.map} +0 -0
- /package/dist/{chunk-ROGO7FRA.js.map → chunk-O55EKIEC.js.map} +0 -0
- /package/dist/{chunk-IPD5GC7C.js.map → chunk-OFVCFKDH.js.map} +0 -0
- /package/dist/{chunk-J5WI4QRP.js.map → chunk-OIGJZHDU.js.map} +0 -0
- /package/dist/{chunk-K3FH3LAQ.js.map → chunk-OJXK5C6Z.js.map} +0 -0
- /package/dist/{chunk-OL553AWT.js.map → chunk-P5VZSSYL.js.map} +0 -0
- /package/dist/{chunk-3ICAWZUU.js.map → chunk-PLCYKAWH.js.map} +0 -0
- /package/dist/{chunk-PDOOUXCS.js.map → chunk-PPCLZ4JU.js.map} +0 -0
- /package/dist/{chunk-HLN2HOXX.js.map → chunk-PUEO37QG.js.map} +0 -0
- /package/dist/{chunk-32YX7EJ3.js.map → chunk-QL7RHYK6.js.map} +0 -0
- /package/dist/{chunk-TX6EHB2Q.js.map → chunk-QVMOCJRV.js.map} +0 -0
- /package/dist/{chunk-YMJRLT7S.js.map → chunk-R2DOFBG4.js.map} +0 -0
- /package/dist/{chunk-NQP4ZYGG.js.map → chunk-RGUUBAT5.js.map} +0 -0
- /package/dist/{chunk-P4JED3ZL.js.map → chunk-RMXS4I66.js.map} +0 -0
- /package/dist/{chunk-VKILERSL.js.map → chunk-RO7RUBLD.js.map} +0 -0
- /package/dist/{chunk-MTTYIXSU.js.map → chunk-RRTVGD3J.js.map} +0 -0
- /package/dist/{chunk-3TKX2RYK.js.map → chunk-RSK2WIEM.js.map} +0 -0
- /package/dist/{chunk-DT7SNJH6.js.map → chunk-RYWROSL5.js.map} +0 -0
- /package/dist/{chunk-SYKJBS7S.js.map → chunk-SHUBTAY2.js.map} +0 -0
- /package/dist/{chunk-OZNBZJ3S.js.map → chunk-SLDRXK37.js.map} +0 -0
- /package/dist/{chunk-ATWFYXEN.js.map → chunk-STSLB4HT.js.map} +0 -0
- /package/dist/{chunk-G67EUQAB.js.map → chunk-TG3R2SID.js.map} +0 -0
- /package/dist/{chunk-YAVIBVCU.js.map → chunk-UA2NDTIU.js.map} +0 -0
- /package/dist/{chunk-KVSOEVAF.js.map → chunk-UE6RRXMF.js.map} +0 -0
- /package/dist/{chunk-TAUHAP5J.js.map → chunk-UXPXOVJI.js.map} +0 -0
- /package/dist/{chunk-QKES7GU6.js.map → chunk-VMVVSZTD.js.map} +0 -0
- /package/dist/{chunk-YRZPBN46.js.map → chunk-VNUOAXWP.js.map} +0 -0
- /package/dist/{chunk-EA2LA5RI.js.map → chunk-VPQFK63H.js.map} +0 -0
- /package/dist/{chunk-UH3FPX3L.js.map → chunk-W7K5BP3M.js.map} +0 -0
- /package/dist/{chunk-PKZ274PI.js.map → chunk-WLBEZZK5.js.map} +0 -0
- /package/dist/{chunk-TQ4SCPGQ.js.map → chunk-WRT7GJ2D.js.map} +0 -0
- /package/dist/{chunk-5MF6LMUY.js.map → chunk-WUUES6CU.js.map} +0 -0
- /package/dist/{chunk-CC4V7HNP.js.map → chunk-WWK6J6SE.js.map} +0 -0
- /package/dist/{chunk-LEEAO2TX.js.map → chunk-XICOH5HT.js.map} +0 -0
- /package/dist/{chunk-CN7Q3T2J.js.map → chunk-XNI3URDR.js.map} +0 -0
- /package/dist/{chunk-64S6X4IU.js.map → chunk-XTN54NML.js.map} +0 -0
- /package/dist/{chunk-PWPIERBM.js.map → chunk-YCNIGRRF.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-DZ7DPDVW.js.map → chunk-YODUDA6R.js.map} +0 -0
- /package/dist/{chunk-4GMI5HFH.js.map → chunk-YS2GHSWN.js.map} +0 -0
- /package/dist/{chunk-2K3AUDH7.js.map → chunk-YYOMGOHB.js.map} +0 -0
- /package/dist/{chunk-B56LORLY.js.map → chunk-Z4Q6USKJ.js.map} +0 -0
- /package/dist/{chunk-IHJZSRDM.js.map → chunk-ZCLEYJPB.js.map} +0 -0
- /package/dist/{chunk-D5EV6Y2L.js.map → chunk-ZT6WPSII.js.map} +0 -0
- /package/dist/{chunk-3Y5X6YFH.js.map → chunk-ZZ67UTQX.js.map} +0 -0
- /package/dist/{resolution-23ZBDM6A.js.map → contradiction-scan-P2MHYFVG.js.map} +0 -0
- /package/dist/{first-start-migration-A6PHIBUQ.js.map → first-start-migration-QFI7B5SH.js.map} +0 -0
- /package/dist/{tier-stats-C3IAMS4X.js.map → tier-stats-FQGQSFET.js.map} +0 -0
package/src/access-http.test.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
type TokenCapabilities,
|
|
23
23
|
} from "./access-token-capabilities.js";
|
|
24
24
|
import { BriefingTimeoutError } from "./briefing-deadline.js";
|
|
25
|
+
import { initLogger, resetLogger, type LoggerBackend } from "./logger.js";
|
|
25
26
|
import { parseConfig } from "./config.js";
|
|
26
27
|
import { readPair, writePair } from "./contradiction/contradiction-review.js";
|
|
27
28
|
import { createChatSession } from "./chat/chat-session.js";
|
|
@@ -815,7 +816,16 @@ test("HTTP coding-context endpoint accepts projectTag shorthand", async () => {
|
|
|
815
816
|
}
|
|
816
817
|
});
|
|
817
818
|
|
|
818
|
-
test("HTTP observe answers 503 buffer_admission_refused when durable capture hits the entry cap", async () => {
|
|
819
|
+
test("HTTP observe answers 503 buffer_admission_refused when durable capture hits the entry cap", async (t) => {
|
|
820
|
+
const warns: string[] = [];
|
|
821
|
+
const backend: LoggerBackend = {
|
|
822
|
+
info() {},
|
|
823
|
+
warn(msg) { warns.push(msg); },
|
|
824
|
+
error() {},
|
|
825
|
+
debug() {},
|
|
826
|
+
};
|
|
827
|
+
initLogger(backend, false, { timestamps: false });
|
|
828
|
+
t.after(() => resetLogger());
|
|
819
829
|
const refusal = new Error("buffer at session-entry cap");
|
|
820
830
|
refusal.name = "ReplayAdmissionRefusedError";
|
|
821
831
|
// SAFETY: this fixture drives only the observe route; the remaining service members are unreachable.
|
|
@@ -852,6 +862,58 @@ test("HTTP observe answers 503 buffer_admission_refused when durable capture hit
|
|
|
852
862
|
error: "buffer at session-entry cap",
|
|
853
863
|
code: "buffer_admission_refused",
|
|
854
864
|
});
|
|
865
|
+
assert.equal(response.headers.get("retry-after"), "5", "503 must carry the advisory backpressure hint");
|
|
866
|
+
const requestId = response.headers.get("x-request-id");
|
|
867
|
+
assert.ok(requestId, "the response must expose the correlation id");
|
|
868
|
+
assert.ok(
|
|
869
|
+
warns.some((line) => line.includes(requestId) && line.includes("buffer admission refused")),
|
|
870
|
+
`capacity refusal must log a correlated warn, got ${JSON.stringify(warns)}`,
|
|
871
|
+
);
|
|
872
|
+
} finally {
|
|
873
|
+
await server.stop();
|
|
874
|
+
}
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
test("HTTP observe missing-storage-target refusal is a non-retryable request fault, not 503 backpressure", async () => {
|
|
878
|
+
const refusal = new Error(
|
|
879
|
+
"accepted capture requires an explicit storage target (writeNamespaceOverride or scopeProfileWritePlan.writeNamespace)",
|
|
880
|
+
);
|
|
881
|
+
refusal.name = "StorageTargetRequiredError";
|
|
882
|
+
// SAFETY: this fixture drives only the observe route; the remaining service members are unreachable.
|
|
883
|
+
const service = Object.assign({} as EngramAccessService, {
|
|
884
|
+
observe: async () => {
|
|
885
|
+
throw refusal;
|
|
886
|
+
},
|
|
887
|
+
});
|
|
888
|
+
const server = new EngramAccessHttpServer({
|
|
889
|
+
service,
|
|
890
|
+
port: 0,
|
|
891
|
+
authToken: "test-token",
|
|
892
|
+
adminConsoleEnabled: false,
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
const status = await server.start();
|
|
896
|
+
try {
|
|
897
|
+
const response = await fetch(
|
|
898
|
+
`http://127.0.0.1:${status.port}/engram/v1/observe`,
|
|
899
|
+
{
|
|
900
|
+
method: "POST",
|
|
901
|
+
headers: {
|
|
902
|
+
authorization: "Bearer test-token",
|
|
903
|
+
"content-type": "application/json",
|
|
904
|
+
},
|
|
905
|
+
body: JSON.stringify({
|
|
906
|
+
sessionKey: "missing-target-test-session",
|
|
907
|
+
messages: [{ role: "user", content: "no target" }],
|
|
908
|
+
}),
|
|
909
|
+
},
|
|
910
|
+
);
|
|
911
|
+
assert.equal(response.status, 400, "a request with no storage target cannot succeed on retry");
|
|
912
|
+
assert.deepEqual(await response.json(), {
|
|
913
|
+
error: refusal.message,
|
|
914
|
+
code: "storage_target_required",
|
|
915
|
+
});
|
|
916
|
+
assert.equal(response.headers.get("retry-after"), null, "no backpressure hint on a permanent fault");
|
|
855
917
|
} finally {
|
|
856
918
|
await server.stop();
|
|
857
919
|
}
|
package/src/access-http.ts
CHANGED
|
@@ -7,6 +7,7 @@ import path from "node:path";
|
|
|
7
7
|
import { fileURLToPath, URL } from "node:url";
|
|
8
8
|
import { gunzipSync } from "node:zlib";
|
|
9
9
|
import { log } from "./logger.js";
|
|
10
|
+
import { respondBufferAdmissionError } from "./access-http-admission.js";
|
|
10
11
|
import { resolveNamespaceCapabilities } from "./capabilities.js";
|
|
11
12
|
import { WriteRateLimiter, type WriteRateLimitReservation } from "./write-rate-limiter.js";
|
|
12
13
|
import { abortError, isAbortError } from "./abort-error.js";
|
|
@@ -81,149 +82,30 @@ import { ReviewDeckAccessHttpBase } from "./review/review-deck-http-base.js";
|
|
|
81
82
|
import { serializeInlineScriptValue } from "./inline-script.js";
|
|
82
83
|
import { toDottedRemnicName } from "./access-mcp-tool-names.js";
|
|
83
84
|
import type { SupportPassportExternalRequestHandler } from "./support-passport/public-http.js";
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
* entry that validated, so identity can never lag validation.
|
|
109
|
-
*/
|
|
110
|
-
authTokenEntriesGetter?: () => ReadonlyArray<{ token: string; connector?: string; capabilities?: TokenCapabilities }>;
|
|
111
|
-
/**
|
|
112
|
-
* Optional per-request scope policy for tokens sourced from
|
|
113
|
-
* `authTokenEntriesGetter`. Return false to deny the (validated) token
|
|
114
|
-
* for this pathname. Static `authToken`/`authTokens` (operator-supplied)
|
|
115
|
-
* bypass the policy. Entries whose connector is missing FAIL CLOSED when
|
|
116
|
-
* a policy is configured.
|
|
117
|
-
*/
|
|
118
|
-
tokenPathPolicy?: (connector: string, pathname: string | undefined) => boolean;
|
|
119
|
-
principal?: string;
|
|
120
|
-
maxBodyBytes?: number;
|
|
121
|
-
/**
|
|
122
|
-
* Max non-replayed write requests per rolling window before 429
|
|
123
|
-
* `write_rate_limited` (issue #1937). Positive integer; defaults to 30.
|
|
124
|
-
*/
|
|
125
|
-
writeRateLimitMaxRequests?: number;
|
|
126
|
-
/** Rolling window for the write rate limit, in ms. Positive integer; defaults to 60000. */
|
|
127
|
-
writeRateLimitWindowMs?: number;
|
|
128
|
-
adminConsoleEnabled?: boolean;
|
|
129
|
-
adminConsolePublicDir?: string;
|
|
130
|
-
/** Inject the primary auth token into the admin console shell for trusted launch surfaces. */
|
|
131
|
-
adminConsolePrefillToken?: boolean;
|
|
132
|
-
trustPrincipalHeader?: boolean;
|
|
133
|
-
/** Enable adapter-based identity resolution from request headers */
|
|
134
|
-
enableAdapters?: boolean;
|
|
135
|
-
/** Custom adapter registry (defaults to built-in adapters) */
|
|
136
|
-
adapterRegistry?: AdapterRegistry;
|
|
137
|
-
/** Enable oai-mem-citation blocks in recall responses (issue #379). */
|
|
138
|
-
citationsEnabled?: boolean;
|
|
139
|
-
/** Auto-enable citations for Codex adapter connections (issue #379). */
|
|
140
|
-
citationsAutoDetect?: boolean;
|
|
141
|
-
/** Advertise legacy engram.* tool aliases on tools/list (issue #1427). Default true. */
|
|
142
|
-
emitLegacyTools?: boolean;
|
|
143
|
-
/** Optional authenticated admin dashboard/config controls supplied by the host server. */
|
|
144
|
-
adminControls?: RemnicAdminControls;
|
|
145
|
-
/**
|
|
146
|
-
* Standalone readiness state. Defaults to ready so embedded hosts keep their
|
|
147
|
-
* existing health behavior.
|
|
148
|
-
*/
|
|
149
|
-
readiness?: () => AccessHttpReadinessState;
|
|
150
|
-
/**
|
|
151
|
-
* When set, every 401 response includes
|
|
152
|
-
* `WWW-Authenticate: Bearer resource_metadata="<value>"` so MCP clients
|
|
153
|
-
* can discover the OAuth 2.0 protected-resource metadata document
|
|
154
|
-
* (RFC 9728). Must be an absolute http(s) URL; constructor throws on
|
|
155
|
-
* anything else. Unset → bare `Bearer`.
|
|
156
|
-
*/
|
|
157
|
-
resourceMetadataUrl?: string;
|
|
158
|
-
/**
|
|
159
|
-
* Optional pre-auth request handler (e.g. OAuth facade mounted by
|
|
160
|
-
* `@remnic/server`). Runs after the admin-console handler and BEFORE
|
|
161
|
-
* bearer authorization. Return true if the request was fully handled
|
|
162
|
-
* (response ended). `ctx.authorized` reports whether the request
|
|
163
|
-
* carries a valid operator bearer token, so the handler can gate
|
|
164
|
-
* operator-only endpoints without owning token validation.
|
|
165
|
-
* Errors thrown by the handler flow into the existing error handling.
|
|
166
|
-
*/
|
|
167
|
-
externalRequestHandler?: SupportPassportExternalRequestHandler;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export interface EngramAccessHttpServerStatus {
|
|
171
|
-
running: boolean;
|
|
172
|
-
host: string;
|
|
173
|
-
port: number;
|
|
174
|
-
maxBodyBytes: number;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export interface RemnicAdminHarnessStatus {
|
|
178
|
-
id: string;
|
|
179
|
-
label: string;
|
|
180
|
-
detected: boolean;
|
|
181
|
-
enabled: boolean;
|
|
182
|
-
source?: string;
|
|
183
|
-
detail?: string;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export interface RemnicAdminModelOption {
|
|
187
|
-
id: string;
|
|
188
|
-
label: string;
|
|
189
|
-
provider: string;
|
|
190
|
-
detected: boolean;
|
|
191
|
-
enabled: boolean;
|
|
192
|
-
default?: boolean;
|
|
193
|
-
source?: string;
|
|
194
|
-
endpoint?: string;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export interface RemnicAdminFeatureStatus {
|
|
198
|
-
key: string;
|
|
199
|
-
label: string;
|
|
200
|
-
enabled: boolean;
|
|
201
|
-
writable: boolean;
|
|
202
|
-
restartRequired?: boolean;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
export interface RemnicAdminConfigStatus {
|
|
206
|
-
path: string;
|
|
207
|
-
exists: boolean;
|
|
208
|
-
writable: boolean;
|
|
209
|
-
restartRequired: boolean;
|
|
210
|
-
values: Record<string, string | number | boolean | null>;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export interface RemnicAdminDashboardStatus {
|
|
214
|
-
config: RemnicAdminConfigStatus;
|
|
215
|
-
harnesses: RemnicAdminHarnessStatus[];
|
|
216
|
-
providers?: RemnicAdminHarnessStatus[];
|
|
217
|
-
models: RemnicAdminModelOption[];
|
|
218
|
-
features: RemnicAdminFeatureStatus[];
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export type RemnicAdminConfigPatch = Record<string, unknown>;
|
|
222
|
-
|
|
223
|
-
export interface RemnicAdminControls {
|
|
224
|
-
status: () => Promise<RemnicAdminDashboardStatus>;
|
|
225
|
-
update?: (patch: RemnicAdminConfigPatch) => Promise<RemnicAdminDashboardStatus>;
|
|
226
|
-
}
|
|
85
|
+
import type {
|
|
86
|
+
AccessHttpReadinessState,
|
|
87
|
+
EngramAccessHttpServerOptions,
|
|
88
|
+
EngramAccessHttpServerStatus,
|
|
89
|
+
RemnicAdminHarnessStatus,
|
|
90
|
+
RemnicAdminModelOption,
|
|
91
|
+
RemnicAdminFeatureStatus,
|
|
92
|
+
RemnicAdminConfigStatus,
|
|
93
|
+
RemnicAdminDashboardStatus,
|
|
94
|
+
RemnicAdminConfigPatch,
|
|
95
|
+
RemnicAdminControls,
|
|
96
|
+
} from "./access-http-types.js";
|
|
97
|
+
export type {
|
|
98
|
+
AccessHttpReadinessState,
|
|
99
|
+
EngramAccessHttpServerOptions,
|
|
100
|
+
EngramAccessHttpServerStatus,
|
|
101
|
+
RemnicAdminHarnessStatus,
|
|
102
|
+
RemnicAdminModelOption,
|
|
103
|
+
RemnicAdminFeatureStatus,
|
|
104
|
+
RemnicAdminConfigStatus,
|
|
105
|
+
RemnicAdminDashboardStatus,
|
|
106
|
+
RemnicAdminConfigPatch,
|
|
107
|
+
RemnicAdminControls,
|
|
108
|
+
} from "./access-http-types.js";
|
|
227
109
|
|
|
228
110
|
export function resolveDefaultAdminConsolePublicDir(sourceUrl = import.meta.url): string {
|
|
229
111
|
const thisDir = path.dirname(fileURLToPath(sourceUrl));
|
|
@@ -549,11 +431,7 @@ export class EngramAccessHttpServer extends ReviewDeckAccessHttpBase {
|
|
|
549
431
|
});
|
|
550
432
|
return;
|
|
551
433
|
}
|
|
552
|
-
if (err.
|
|
553
|
-
// Durable-capture backpressure (#3251/#1908): the request was
|
|
554
|
-
// never accepted — the buffer is at entry capacity. Retryable,
|
|
555
|
-
// not a server fault (503, not 500).
|
|
556
|
-
this.respondJson(res, 503, { error: err.message, code: "buffer_admission_refused" });
|
|
434
|
+
if (respondBufferAdmissionError(err, res, correlationId, (status, body) => this.respondJson(res, status, body))) {
|
|
557
435
|
return;
|
|
558
436
|
}
|
|
559
437
|
if (res.headersSent) {
|
package/src/access-mcp.test.ts
CHANGED
|
@@ -150,6 +150,30 @@ test("MCP reports buffer admission refusal as retryable and does not return succ
|
|
|
150
150
|
});
|
|
151
151
|
|
|
152
152
|
|
|
153
|
+
test("MCP reports a missing storage target as a non-retryable storage_target_required error", async () => {
|
|
154
|
+
const failure = new Error("accepted capture requires an explicit storage target");
|
|
155
|
+
failure.name = "StorageTargetRequiredError";
|
|
156
|
+
// SAFETY: the mock overrides only observe; every other MCP dispatch path is unreachable in this test.
|
|
157
|
+
const service = Object.assign({} as EngramAccessService, {
|
|
158
|
+
observe: async () => {
|
|
159
|
+
throw failure;
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
const server = new EngramMcpServer(service);
|
|
163
|
+
const response = await server.handleRequest(
|
|
164
|
+
makeToolRequest("engram.observe", {
|
|
165
|
+
sessionKey: "no-target-session",
|
|
166
|
+
messages: [{ role: "user", content: "cannot succeed on retry" }],
|
|
167
|
+
}),
|
|
168
|
+
);
|
|
169
|
+
// SAFETY: a tools/call request always resolves to a JSON-RPC result envelope; only isError and structuredContent are asserted.
|
|
170
|
+
const result = response as {
|
|
171
|
+
result?: { isError?: boolean; structuredContent?: { code?: string; retryable?: boolean } };
|
|
172
|
+
};
|
|
173
|
+
assert.equal(result.result?.isError, true);
|
|
174
|
+
assert.deepEqual(result.result?.structuredContent, { code: "storage_target_required", retryable: false }, JSON.stringify(response));
|
|
175
|
+
});
|
|
176
|
+
|
|
153
177
|
// ──────────────────────────────────────────────────────────────────────────
|
|
154
178
|
// Finding 2 (#396 new): invalid MCP briefing format values must be rejected
|
|
155
179
|
// ──────────────────────────────────────────────────────────────────────────
|
package/src/access-mcp.ts
CHANGED
|
@@ -2434,6 +2434,9 @@ export class EngramMcpServer {
|
|
|
2434
2434
|
};
|
|
2435
2435
|
if (admissionBackpressure) {
|
|
2436
2436
|
result.structuredContent = { code: "buffer_admission_refused", retryable: true };
|
|
2437
|
+
} else if (err instanceof Error && err.name === "StorageTargetRequiredError") {
|
|
2438
|
+
// A permanent property of the request: tell clients not to retry it.
|
|
2439
|
+
result.structuredContent = { code: "storage_target_required", retryable: false };
|
|
2437
2440
|
}
|
|
2438
2441
|
return { jsonrpc: "2.0", id, result };
|
|
2439
2442
|
}
|
|
@@ -1600,7 +1600,10 @@ test("#3251 namespaced buffered admission without writeNamespaceOverride or plan
|
|
|
1600
1600
|
[makeReplayTurn("no-target-sess", "capture without target")],
|
|
1601
1601
|
bufferedObserveOptions({ sessionOwnerPrincipal: "alice" }),
|
|
1602
1602
|
),
|
|
1603
|
-
|
|
1603
|
+
(err: Error) =>
|
|
1604
|
+
err.name === "StorageTargetRequiredError" &&
|
|
1605
|
+
/requires an explicit storage target/.test(err.message),
|
|
1606
|
+
"the missing-target refusal must be its own non-retryable class, never ReplayAdmissionRefusedError",
|
|
1604
1607
|
);
|
|
1605
1608
|
assert.equal(lcmCalls.length, 0, "zero LCM archival on rejected admission");
|
|
1606
1609
|
assert.equal(queued.length, 0, "zero extraction queued on rejected admission");
|
|
@@ -22,6 +22,7 @@ import { EngramAccessService } from "./access-service.js";
|
|
|
22
22
|
import { EngramAccessInputError } from "./access-service.js";
|
|
23
23
|
import { initLogger } from "./logger.js";
|
|
24
24
|
import { Orchestrator } from "./orchestrator.js";
|
|
25
|
+
import { ReplayAdmissionRefusedError } from "./orchestration/turn-ingestion.js";
|
|
25
26
|
import type { EngramAccessObserveRequest } from "./access-service.js";
|
|
26
27
|
import type { CodingContext, PluginConfig } from "./types.js";
|
|
27
28
|
|
|
@@ -328,6 +329,49 @@ test("#2206 project-scope-off ignores ambient coding context in observe idempote
|
|
|
328
329
|
}
|
|
329
330
|
});
|
|
330
331
|
|
|
332
|
+
test("#1649 a capacity-refused observe does not consume its idempotencyKey", async () => {
|
|
333
|
+
const memoryDir = mkdtempSync(join(tmpdir(), "remnic-observe-cap-idem-"));
|
|
334
|
+
try {
|
|
335
|
+
const probe = makeObserveProbe(memoryDir);
|
|
336
|
+
const service = new EngramAccessService(probe.orch);
|
|
337
|
+
const orch: Orchestrator = probe.orch;
|
|
338
|
+
const realIngest = orch.ingestReplayBatch.bind(orch);
|
|
339
|
+
type IngestFn = Orchestrator["ingestReplayBatch"];
|
|
340
|
+
let armed = true;
|
|
341
|
+
orch.ingestReplayBatch = async (...args: Parameters<IngestFn>): Promise<void> => {
|
|
342
|
+
if (armed) {
|
|
343
|
+
armed = false;
|
|
344
|
+
throw new ReplayAdmissionRefusedError(
|
|
345
|
+
"durable observe capture refused: extraction buffer at entry capacity for batch containing pi-geek:abc123",
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
return realIngest(...args);
|
|
349
|
+
};
|
|
350
|
+
const key = "observe-capacity-pi-geek-abc123-#1";
|
|
351
|
+
|
|
352
|
+
// First attempt refuses at entry capacity — the key must stay unused.
|
|
353
|
+
await assert.rejects(
|
|
354
|
+
service.observe(observeRequest({ idempotencyKey: key })),
|
|
355
|
+
(err: Error) => err instanceof ReplayAdmissionRefusedError,
|
|
356
|
+
"the seeded first attempt must refuse with the capacity backpressure error",
|
|
357
|
+
);
|
|
358
|
+
assert.equal(probe.extractionCalls.length, 0, "refused attempt must not ingest");
|
|
359
|
+
|
|
360
|
+
// Identical retry, same key: a REAL miss once capacity exists, not a replay
|
|
361
|
+
// of a response that never happened.
|
|
362
|
+
const retry = await service.observe(observeRequest({ idempotencyKey: key }));
|
|
363
|
+
assert.equal(retry.idempotencyReplay, undefined, "refusal must not have cached a response");
|
|
364
|
+
assert.equal(probe.extractionCalls.length, 1, "retry is admitted exactly once");
|
|
365
|
+
|
|
366
|
+
// Third identical request replays — the success bound the key, not the refusal.
|
|
367
|
+
const replay = await service.observe(observeRequest({ idempotencyKey: key }));
|
|
368
|
+
assert.equal(replay.idempotencyReplay, true, "post-success identical request replays");
|
|
369
|
+
assert.equal(probe.extractionCalls.length, 1, "replay must not ingest again");
|
|
370
|
+
} finally {
|
|
371
|
+
rmSync(memoryDir, { recursive: true, force: true });
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
331
375
|
test("#1649 review fix: projectTag observe replays correctly despite scope resolution side effects", async () => {
|
|
332
376
|
// The fingerprint folds in the RESOLVED writeNamespace (not the raw ambient
|
|
333
377
|
// context). resolveMemoryScopePlan seeds the session context from projectTag
|
package/src/buffer-admission.ts
CHANGED
|
@@ -26,6 +26,19 @@ export class ReplayAdmissionRefusedError extends Error {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Durable observe capture rejected because the request resolves to no storage
|
|
31
|
+
* target (namespaces ON with neither writeNamespaceOverride nor a plan's
|
|
32
|
+
* writeNamespace). A property of the request — retrying cannot fix it — so it
|
|
33
|
+
* must never be classified as retryable backpressure.
|
|
34
|
+
*/
|
|
35
|
+
export class StorageTargetRequiredError extends Error {
|
|
36
|
+
constructor(message: string) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.name = "StorageTargetRequiredError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
29
42
|
/**
|
|
30
43
|
* Live-admission bound (#1908 policy, backlog-safe): a NEW session enters
|
|
31
44
|
* only while under the cap or when an EMPTY entry can be reclaimed. Buffered
|
|
@@ -59,8 +59,8 @@ import {
|
|
|
59
59
|
|
|
60
60
|
// The class lives in ../buffer-admission.js next to BufferAdmissionRefusedError;
|
|
61
61
|
// re-exported here so existing importers keep their import path.
|
|
62
|
-
import { ReplayAdmissionRefusedError } from "../buffer-admission.js";
|
|
63
|
-
export { ReplayAdmissionRefusedError };
|
|
62
|
+
import { ReplayAdmissionRefusedError, StorageTargetRequiredError } from "../buffer-admission.js";
|
|
63
|
+
export { ReplayAdmissionRefusedError, StorageTargetRequiredError };
|
|
64
64
|
|
|
65
65
|
export interface TurnIngestionDeps {
|
|
66
66
|
readonly buffer: SmartBuffer;
|
|
@@ -428,7 +428,7 @@ export class TurnIngestionCoordinator {
|
|
|
428
428
|
? options.scopeProfileWritePlan?.writeNamespace
|
|
429
429
|
: this.deps.config.defaultNamespace);
|
|
430
430
|
if (!resolvedWriteTarget) {
|
|
431
|
-
throw new
|
|
431
|
+
throw new StorageTargetRequiredError(
|
|
432
432
|
"accepted capture requires an explicit storage target (writeNamespaceOverride or scopeProfileWritePlan.writeNamespace)",
|
|
433
433
|
);
|
|
434
434
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/buffer-admission.ts"],"sourcesContent":["/** Buffer session-entry admission: refusal errors and the live-admission probe. */\n\nimport { selectEvictedBufferKeys, type BufferEvictionHooks } from \"./buffer-eviction.js\";\nimport type { BufferEntryState } from \"./types.js\";\n\n/**\n * Raised when a NEW live-capture session cannot be admitted because the\n * session-entry cap is full of non-evictable backlog. The turn was never\n * accepted; the request is retryable once extraction drains an entry.\n */\nexport class BufferAdmissionRefusedError extends Error {\n constructor(bufferKey: string, maxSessionEntries: number) {\n super(\n `buffer[${bufferKey}]: live capture refused at the session-entry cap (${maxSessionEntries}); ` +\n \"buffered backlog is no longer evicted to admit new sessions. Retry after extraction frees an entry\",\n );\n this.name = \"BufferAdmissionRefusedError\";\n }\n}\n\n/** Durable observe capture refused at the entry cap; the request is retryable. */\nexport class ReplayAdmissionRefusedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ReplayAdmissionRefusedError\";\n }\n}\n\n/**\n * Live-admission bound (#1908 policy, backlog-safe): a NEW session enters\n * only while under the cap or when an EMPTY entry can be reclaimed. Buffered\n * backlog is never dropped for a live capture; the caller refuses instead.\n */\nexport function canAdmitNewEntryUnlocked(\n entries: Readonly<Record<string, BufferEntryState>>,\n bufferKey: string,\n maxSessionEntries: number,\n hooks: BufferEvictionHooks,\n): boolean {\n const count = Object.keys(entries).length;\n if (count < maxSessionEntries) return true;\n // Probe post-admission (as if this key had landed): admission is safe\n // exactly when an EMPTY entry could then be reclaimed.\n return selectEvictedBufferKeys(entries, [bufferKey], Math.max(0, count - 1), hooks).length > 0;\n}\n"],"mappings":";;;;;AAUO,IAAM,8BAAN,cAA0C,MAAM;AAAA,EACrD,YAAY,WAAmB,mBAA2B;AACxD;AAAA,MACE,UAAU,SAAS,qDAAqD,iBAAiB;AAAA,IAE3F;AACA,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,8BAAN,cAA0C,MAAM;AAAA,EACrD,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAOO,SAAS,yBACd,SACA,WACA,mBACA,OACS;AACT,QAAM,QAAQ,OAAO,KAAK,OAAO,EAAE;AACnC,MAAI,QAAQ,kBAAmB,QAAO;AAGtC,SAAO,wBAAwB,SAAS,CAAC,SAAS,GAAG,KAAK,IAAI,GAAG,QAAQ,CAAC,GAAG,KAAK,EAAE,SAAS;AAC/F;","names":[]}
|