@remnic/core 9.69.86 → 9.69.88
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 +74 -67
- package/dist/access-authorization-probe.js +75 -68
- package/dist/access-boundary.js +74 -67
- package/dist/access-citation-namespace.js +2 -2
- package/dist/access-cli.js +158 -151
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.d.ts.map +1 -1
- package/dist/access-extraction-force-flush.js +74 -67
- package/dist/access-http-briefing.js +75 -68
- package/dist/access-http-offline-stream.d.ts.map +1 -1
- package/dist/access-http-offline-stream.js +1 -1
- package/dist/access-http-query.js +76 -69
- package/dist/access-http.js +100 -93
- package/dist/access-identity-continuity-surface.js +74 -67
- package/dist/access-lcm-surface.js +74 -67
- package/dist/access-mcp-output-schemas.d.ts.map +1 -1
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts.map +1 -1
- package/dist/access-mcp.js +89 -82
- package/dist/access-namespace-preflight.js +74 -67
- package/dist/access-observe-write-category.js +19 -13
- package/dist/access-observe-write-surface.js +74 -67
- package/dist/access-offline-manifest.js +15 -10
- package/dist/access-operations-batch.js +78 -71
- package/dist/access-operations.js +85 -78
- package/dist/access-recall-concurrency.js +74 -67
- package/dist/access-recall-diagnostics.js +4 -4
- package/dist/access-recall-response.js +74 -67
- package/dist/access-recall-surface.js +74 -67
- package/dist/access-schema.js +15 -7
- package/dist/access-service-helpers.d.ts +1 -0
- package/dist/access-service-helpers.d.ts.map +1 -1
- package/dist/access-service-helpers.js +1 -1
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +74 -67
- package/dist/access-surface-catalog.js +76 -69
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +34 -28
- 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-WEUDMXUW.js → auto-sync-U5N3CB5Y.js} +10 -10
- package/dist/background-generation.js +2 -2
- package/dist/briefing.js +18 -18
- package/dist/buffer.js +9 -8
- package/dist/calibration.js +2 -2
- package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-YO5QJ6L3.js} +2 -2
- package/dist/{capsule-merge-3MNURAQ3.js → capsule-merge-ZCXUPLNJ.js} +2 -2
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.js +21 -21
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.js +3 -3
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-JE334SIA.js → chunk-22DYJLFN.js} +2 -2
- package/dist/{chunk-DGAWEJVI.js → chunk-2DLWLNO4.js} +3 -3
- package/dist/{chunk-J3IWHCMF.js → chunk-2DT7PIDZ.js} +3 -3
- package/dist/{chunk-NKFLHW7J.js → chunk-2NAD4YCI.js} +2 -2
- package/dist/{chunk-SV72F4DS.js → chunk-2WLMWP2T.js} +2 -2
- package/dist/{chunk-IVH7INFM.js → chunk-3O5BB45T.js} +7 -7
- package/dist/{chunk-RDEUG2M2.js → chunk-3SGTV7RD.js} +6 -6
- package/dist/{chunk-QOPB6KE3.js → chunk-3TB2XQ3C.js} +2 -2
- package/dist/{chunk-C7JAUNFC.js → chunk-4KN2JLQV.js} +2 -2
- package/dist/{chunk-TIQZNDZ5.js → chunk-4MP7XR5J.js} +2 -2
- package/dist/chunk-4NSLQ7EU.js +137 -0
- package/dist/chunk-4NSLQ7EU.js.map +1 -0
- package/dist/{chunk-7DE2NOON.js → chunk-4O4XCBOS.js} +3 -3
- package/dist/{chunk-SLEAJ67D.js → chunk-4OQET73E.js} +4 -4
- package/dist/{chunk-Q3THVX75.js → chunk-4RL3JOB3.js} +2 -2
- package/dist/{chunk-GDYU6VF4.js → chunk-5AYUHSAU.js} +2 -2
- package/dist/{chunk-B47OHVFT.js → chunk-5E6RYRYW.js} +7 -7
- package/dist/{chunk-2U3R3DDH.js → chunk-5FAGCOZD.js} +9 -9
- package/dist/{chunk-CRKWSSS4.js → chunk-5MNUBT7T.js} +2 -2
- package/dist/{chunk-CK5KOVHW.js → chunk-5R627MYY.js} +3 -2
- package/dist/{chunk-CK5KOVHW.js.map → chunk-5R627MYY.js.map} +1 -1
- package/dist/chunk-5X4MXNEU.js +64 -0
- package/dist/chunk-5X4MXNEU.js.map +1 -0
- package/dist/{chunk-52II7PB6.js → chunk-645WOU5I.js} +4 -4
- package/dist/{chunk-7G6WUOLB.js → chunk-66DKTOBY.js} +2 -2
- package/dist/{chunk-AZ2X5LNA.js → chunk-6LYAEM54.js} +2 -2
- package/dist/{chunk-DUJYRVUD.js → chunk-6O2VUWV6.js} +3 -3
- package/dist/{chunk-IMAP236M.js → chunk-6UQFJULG.js} +2 -2
- package/dist/chunk-75PT4N7Q.js +75 -0
- package/dist/chunk-75PT4N7Q.js.map +1 -0
- package/dist/{chunk-2I6VHX6Q.js → chunk-76M5OK7V.js} +2 -2
- package/dist/{chunk-OEBLZZKK.js → chunk-7XG7KMIW.js} +2 -2
- package/dist/{chunk-FYAU4S6E.js → chunk-A4VSOUCB.js} +3 -3
- package/dist/{chunk-GEX5NI36.js → chunk-AE5U5NMS.js} +2 -2
- package/dist/{chunk-UNJOB4DY.js → chunk-AEHVZY3X.js} +2 -2
- package/dist/{chunk-ML2MVAEZ.js → chunk-AEU4EQGV.js} +1 -1
- package/dist/{chunk-3SG4FGDV.js → chunk-AWD36R4D.js} +5 -2
- package/dist/chunk-AWD36R4D.js.map +1 -0
- package/dist/{chunk-JVY556FW.js → chunk-AWG3TIAY.js} +2 -2
- package/dist/{chunk-JX6USXZR.js → chunk-AXC4WSF3.js} +4 -4
- package/dist/{chunk-BOUFVFV2.js → chunk-AZSGSRIM.js} +2 -2
- package/dist/{chunk-VZBW6CDG.js → chunk-B3O3IRZN.js} +1 -1
- package/dist/{chunk-4V44AA7O.js → chunk-BGI4NUAO.js} +2 -2
- package/dist/{chunk-BNPLDVM6.js → chunk-BJVO4H5C.js} +2 -2
- package/dist/{chunk-S42HZILI.js → chunk-BLVR4WYU.js} +3 -3
- package/dist/{chunk-JXMECXMF.js → chunk-BOZJD5PK.js} +2 -2
- package/dist/{chunk-6DTJBTHL.js → chunk-BUQKSQXL.js} +15 -3
- package/dist/chunk-BUQKSQXL.js.map +1 -0
- package/dist/{chunk-OWHERGF2.js → chunk-BXLOS5AJ.js} +2 -2
- package/dist/{chunk-EVBI7S4J.js → chunk-C6U57KG4.js} +4 -4
- package/dist/{chunk-RB776UH3.js → chunk-C7V3KPKJ.js} +235 -93
- package/dist/chunk-C7V3KPKJ.js.map +1 -0
- package/dist/{chunk-T4BE5KJM.js → chunk-C7ZDKWPS.js} +4 -4
- package/dist/{chunk-HKFJ3PF3.js → chunk-CRXRZA3G.js} +2 -2
- package/dist/{chunk-NMBX4D7P.js → chunk-CZJA2EQE.js} +2 -2
- package/dist/{chunk-BJX3VQWZ.js → chunk-D5BSQR63.js} +2 -2
- package/dist/{chunk-MFZACYZ6.js → chunk-DGS34QSY.js} +2 -2
- package/dist/{chunk-UVYI6VIX.js → chunk-DQEMWVMT.js} +1 -1
- package/dist/{chunk-DQISIT63.js → chunk-DZ42MDZE.js} +3 -3
- package/dist/{chunk-5ELENZTA.js → chunk-EDIH6X2P.js} +2 -2
- package/dist/{chunk-3BTFBQLO.js → chunk-EFHNFTWB.js} +49 -3
- package/dist/chunk-EFHNFTWB.js.map +1 -0
- package/dist/{chunk-C3QXITIP.js → chunk-EQUD7FP4.js} +2 -2
- package/dist/chunk-ETUZFFPU.js +218 -0
- package/dist/chunk-ETUZFFPU.js.map +1 -0
- package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
- package/dist/{chunk-IA3X2Y4K.js → chunk-FJLQXMTU.js} +3 -3
- package/dist/{chunk-TY446V34.js → chunk-FKD656D2.js} +2 -2
- package/dist/{chunk-CLXTDOKV.js → chunk-FUNBJQYR.js} +2 -2
- package/dist/{chunk-CLSYE5OZ.js → chunk-G2STTRYB.js} +2 -2
- package/dist/{chunk-SQDKX4RW.js → chunk-GWM6T5EQ.js} +2 -2
- package/dist/{chunk-AXDOF4VI.js → chunk-GZDTVYK2.js} +2 -2
- package/dist/{chunk-55FCXCXJ.js → chunk-H56VY4BY.js} +7 -7
- package/dist/{chunk-OM5BIPBR.js → chunk-H5BJWPUI.js} +4 -4
- package/dist/{chunk-7QK5TUTW.js → chunk-HLB7GKGG.js} +2 -2
- package/dist/{chunk-CHDGJJV6.js → chunk-HWLIMQE2.js} +2 -2
- package/dist/{chunk-QB75LKQQ.js → chunk-IOSZHHJC.js} +34 -15
- package/dist/chunk-IOSZHHJC.js.map +1 -0
- package/dist/{chunk-NAFPHFDM.js → chunk-JNLEJE4A.js} +2 -2
- package/dist/{chunk-7UUKRS3J.js → chunk-JVPWRNHA.js} +3 -3
- package/dist/{chunk-6ET2VII7.js → chunk-JYG2334B.js} +2 -2
- package/dist/chunk-K6T33R4Q.js +535 -0
- package/dist/chunk-K6T33R4Q.js.map +1 -0
- package/dist/{chunk-2QG4SLZI.js → chunk-KF7PQ7G2.js} +2 -2
- package/dist/{chunk-WIKO4SCR.js → chunk-LHRQBMJN.js} +2 -2
- package/dist/{chunk-IFCKHPY4.js → chunk-LO4UKPKX.js} +2 -2
- package/dist/{chunk-TEV2JGU5.js → chunk-LU7E2MXE.js} +19 -19
- package/dist/{chunk-RJLV4BKR.js → chunk-LV5H6FTN.js} +2 -2
- package/dist/{chunk-IBGEHKQ6.js → chunk-LW3HKRL7.js} +3 -3
- package/dist/{chunk-3XQYM4RE.js → chunk-M6C7SOR6.js} +2 -2
- package/dist/{chunk-JN72EPOE.js → chunk-MAAL6OZV.js} +7 -7
- package/dist/chunk-MAAL6OZV.js.map +1 -0
- package/dist/{chunk-MY2PLXSM.js → chunk-MCTM4YPL.js} +2 -1
- package/dist/{chunk-MY2PLXSM.js.map → chunk-MCTM4YPL.js.map} +1 -1
- package/dist/{chunk-T4QGUXCV.js → chunk-MXCAJKMA.js} +9 -9
- package/dist/{chunk-BMYZTZ5D.js → chunk-MY7B3HYC.js} +2 -2
- package/dist/{chunk-NB3LRY4T.js → chunk-N4PYB235.js} +2 -2
- package/dist/{chunk-S3YM4SZQ.js → chunk-N7QV3CMX.js} +2 -2
- package/dist/{chunk-3GN2PEOT.js → chunk-NYKIUQL6.js} +2 -2
- package/dist/{chunk-WQZZDN5M.js → chunk-OCFXVDBZ.js} +322 -376
- package/dist/chunk-OCFXVDBZ.js.map +1 -0
- package/dist/{chunk-L2LBMKSI.js → chunk-OK52IY3W.js} +10 -10
- package/dist/{chunk-WB2I2EQK.js → chunk-P2ODTYOF.js} +2 -2
- package/dist/{chunk-RIEX7NOZ.js → chunk-PEBHPCX2.js} +2 -2
- package/dist/{chunk-VYCOJKSX.js → chunk-PO7NXNGC.js} +2 -2
- package/dist/{chunk-G6SVZWPB.js → chunk-PZX3AQLF.js} +44 -1
- package/dist/chunk-PZX3AQLF.js.map +1 -0
- package/dist/{chunk-XAITGGX5.js → chunk-Q4AUIFUA.js} +4 -4
- package/dist/{chunk-EU3N5MK3.js → chunk-QAW55ZHJ.js} +4 -4
- package/dist/{chunk-SVZWVZ7E.js → chunk-QB57WIS6.js} +101 -93
- package/dist/chunk-QB57WIS6.js.map +1 -0
- package/dist/{chunk-I4G4UWQA.js → chunk-QI2E6ISQ.js} +1 -1
- package/dist/{chunk-CK5U7JGH.js → chunk-QI7K7BZ5.js} +2 -2
- package/dist/{chunk-VTPASHTO.js → chunk-R3X2T2LP.js} +3 -3
- package/dist/{chunk-I53NAHZ4.js → chunk-RBITPCMK.js} +10 -9
- package/dist/chunk-RBITPCMK.js.map +1 -0
- package/dist/{chunk-EJPF6XDQ.js → chunk-RDJ6C7NZ.js} +3 -3
- package/dist/{chunk-C2WWQ4OR.js → chunk-RMMA44HE.js} +1 -1
- package/dist/chunk-RMMA44HE.js.map +1 -0
- package/dist/{chunk-QC56VZXC.js → chunk-S2GE2K36.js} +85 -82
- package/dist/{chunk-QC56VZXC.js.map → chunk-S2GE2K36.js.map} +1 -1
- package/dist/{chunk-2UPTRDGM.js → chunk-SCXURCVT.js} +3 -3
- package/dist/{chunk-S55WTPFJ.js → chunk-STEOT4DI.js} +20 -20
- package/dist/chunk-STEOT4DI.js.map +1 -0
- package/dist/{chunk-N3MNDVJO.js → chunk-SWBC3UER.js} +2 -2
- package/dist/{chunk-ZTHGFTMW.js → chunk-TKC5LZ43.js} +2 -2
- package/dist/chunk-TYT4TEQV.js +45 -0
- package/dist/chunk-TYT4TEQV.js.map +1 -0
- package/dist/{chunk-YRLHEEQT.js → chunk-U6VC6RP3.js} +2 -2
- package/dist/chunk-UCPGOUDZ.js +726 -0
- package/dist/chunk-UCPGOUDZ.js.map +1 -0
- package/dist/{chunk-MOQPEFLN.js → chunk-UP75KL3L.js} +2 -2
- package/dist/{chunk-D5F7TKMH.js → chunk-V4JZCTMK.js} +2 -2
- package/dist/{chunk-NAYBHNGN.js → chunk-VALKBYBN.js} +2 -2
- package/dist/{chunk-BUKK5SWA.js → chunk-VDX2J7OX.js} +2 -2
- package/dist/{chunk-H36X4NRH.js → chunk-VVX5PZFS.js} +2 -2
- package/dist/{chunk-RCQKAOOB.js → chunk-W3XXFPRI.js} +52 -52
- package/dist/{chunk-W75BBBSY.js → chunk-WKY7N3L7.js} +11 -11
- package/dist/{chunk-GZAGLCQH.js → chunk-X5SHE2O3.js} +3 -3
- package/dist/{chunk-OAOBL6OY.js → chunk-XOV7NRY5.js} +5 -5
- package/dist/{chunk-FZVROZKC.js → chunk-XVZA6VXC.js} +4 -4
- package/dist/{chunk-RGMVMVMF.js → chunk-YBA52OKG.js} +2 -1
- package/dist/chunk-YBA52OKG.js.map +1 -0
- package/dist/{chunk-IP5VLSLO.js → chunk-YJ7MW627.js} +2 -2
- package/dist/{chunk-HS75MCQF.js → chunk-YRULQW5J.js} +2 -2
- package/dist/{chunk-DINRT75P.js → chunk-YSBL7VPO.js} +2 -2
- package/dist/{chunk-QWUJWBZ5.js → chunk-Z3O53WZR.js} +2 -2
- package/dist/{chunk-KERNN6BC.js → chunk-Z5LP6ILP.js} +2 -2
- package/dist/{chunk-5FNZ3G6X.js → chunk-Z6EZCN6Z.js} +5 -5
- package/dist/chunk-ZJP66Q4I.js +48 -0
- package/dist/chunk-ZJP66Q4I.js.map +1 -0
- package/dist/{chunk-JS3S2HVG.js → chunk-ZZZ4I455.js} +2 -2
- package/dist/cli.js +122 -115
- package/dist/coding/export-okf-codegraph.js +19 -19
- package/dist/coding/pre-action-gate.js +2 -2
- package/dist/compounding/engine.js +19 -19
- package/dist/config.js +34 -28
- package/dist/connectors/codex-materialize-runner.js +18 -18
- package/dist/connectors/index.js +18 -18
- package/dist/console/state.d.ts +30 -0
- package/dist/console/state.d.ts.map +1 -1
- package/dist/contradiction/index.js +7 -7
- package/dist/{contradiction-scan-5EJYRKD3.js → contradiction-scan-TAGMOUQ2.js} +3 -3
- package/dist/convergence-refresh.js +20 -20
- package/dist/corpus-watermark.js +20 -20
- package/dist/correction/correction-access-wiring.d.ts.map +1 -1
- package/dist/dashboard-runtime.js +2 -2
- package/dist/deep-recall-http-glue.js +15 -8
- package/dist/deep-recall-policy-llm.js +3 -3
- package/dist/deep-recall.js +2 -2
- package/dist/embedding-fallback.d.ts +41 -31
- package/dist/embedding-fallback.d.ts.map +1 -1
- package/dist/embedding-fallback.js +9 -1
- package/dist/embedding-generation-lock.d.ts +49 -0
- package/dist/embedding-generation-lock.d.ts.map +1 -0
- package/dist/embedding-generation-lock.js +19 -0
- package/dist/embedding-index-storage.d.ts +276 -0
- package/dist/embedding-index-storage.d.ts.map +1 -0
- package/dist/embedding-index-storage.js +28 -0
- package/dist/entity-retrieval.js +19 -19
- package/dist/event-order-recall.js +3 -3
- package/dist/explicit-capture.js +6 -6
- package/dist/external-wiki-access.js +75 -68
- package/dist/extraction-faithfulness.js +3 -3
- package/dist/extraction-judge.js +3 -3
- package/dist/extraction-liveness.d.ts +9 -0
- package/dist/extraction-liveness.d.ts.map +1 -1
- package/dist/extraction-liveness.js +2 -1
- package/dist/extraction-llm-health.d.ts +32 -0
- package/dist/extraction-llm-health.d.ts.map +1 -0
- package/dist/extraction-llm-health.js +17 -0
- package/dist/extraction-span-config.js +3 -2
- package/dist/extraction-span-materialize.js +2 -2
- package/dist/extraction.js +29 -28
- package/dist/fallback-llm.js +2 -2
- package/dist/{first-start-migration-GAT7G733.js → first-start-migration-7OATHJKB.js} +4 -4
- package/dist/{graph-edge-decay-PVKDKLQK.js → graph-edge-decay-MKIRZ762.js} +6 -6
- package/dist/graph-jsonl.js +4 -4
- package/dist/graph-snapshot.js +4 -4
- package/dist/graph.js +5 -5
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +237 -206
- package/dist/json-extract.d.ts.map +1 -1
- package/dist/json-extract.js +1 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.js +5 -5
- package/dist/local-llm.d.ts.map +1 -1
- package/dist/local-llm.js +2 -2
- package/dist/location/index.js +21 -21
- package/dist/maintenance/memory-governance.js +18 -18
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +18 -18
- package/dist/maintenance/rebuild-memory-projection.js +19 -19
- package/dist/memory-browse-operations.js +75 -68
- package/dist/memory-browse.js +3 -3
- package/dist/memory-subject.js +3 -3
- package/dist/namespaces/migrate.js +19 -19
- package/dist/namespaces/search.js +4 -4
- package/dist/namespaces/storage.js +18 -18
- package/dist/offline-sync-embedding-generation.d.ts +207 -0
- package/dist/offline-sync-embedding-generation.d.ts.map +1 -0
- package/dist/offline-sync-embedding-generation.js +42 -0
- package/dist/offline-sync-embedding-generation.js.map +1 -0
- package/dist/offline-sync-exclude-globs.d.ts +15 -0
- package/dist/offline-sync-exclude-globs.d.ts.map +1 -1
- package/dist/offline-sync-exclude-globs.js +11 -3
- package/dist/offline-sync-file-io.d.ts +7 -0
- package/dist/offline-sync-file-io.d.ts.map +1 -1
- package/dist/offline-sync-file-io.js +14 -2
- package/dist/offline-sync-impression-drain.js +3 -3
- package/dist/offline-sync-runtime-state.d.ts +5 -0
- package/dist/offline-sync-runtime-state.d.ts.map +1 -0
- package/dist/offline-sync-runtime-state.js +14 -0
- package/dist/offline-sync-runtime-state.js.map +1 -0
- package/dist/offline-sync-snapshot-stream.d.ts +26 -0
- package/dist/offline-sync-snapshot-stream.d.ts.map +1 -0
- package/dist/offline-sync-snapshot-stream.js +28 -0
- package/dist/offline-sync-snapshot-stream.js.map +1 -0
- package/dist/offline-sync-upload-staging.d.ts +34 -0
- package/dist/offline-sync-upload-staging.d.ts.map +1 -0
- package/dist/offline-sync-upload-staging.js +26 -0
- package/dist/offline-sync-upload-staging.js.map +1 -0
- package/dist/offline-sync.d.ts +46 -27
- package/dist/offline-sync.d.ts.map +1 -1
- package/dist/offline-sync.js +21 -8
- package/dist/operator-doctor-corpus.js +21 -21
- package/dist/operator-toolkit.js +46 -40
- package/dist/orchestration/extraction-run.d.ts.map +1 -1
- package/dist/orchestration/maintenance.js +30 -30
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +159 -152
- package/dist/recall-navigation-operations.js +75 -68
- package/dist/recall-navigation.js +74 -67
- package/dist/recall-planner-llm.js +2 -2
- package/dist/recall-state-view-admission.js +3 -3
- package/dist/recall-why-service.js +6 -6
- package/dist/recall-why.js +3 -3
- package/dist/reconcile/manifest.js +4 -4
- package/dist/{resolution-UYJU5JUA.js → resolution-K4A3VPKZ.js} +8 -8
- package/dist/resolution-K4A3VPKZ.js.map +1 -0
- package/dist/resume-bundles.js +35 -29
- package/dist/salvage-envelope.js +5 -5
- package/dist/search/factory.js +3 -3
- package/dist/search/index.js +7 -7
- package/dist/secure-store/index.js +2 -2
- package/dist/secure-store/secure-fs.d.ts +14 -1
- package/dist/secure-store/secure-fs.d.ts.map +1 -1
- package/dist/semantic-consolidation.js +19 -19
- package/dist/semantic-rule-promotion.js +18 -18
- package/dist/semantic-rule-verifier.js +18 -18
- package/dist/source-agent-qualifier.js +23 -22
- package/dist/standup/build.js +18 -18
- package/dist/{state-ITXJKXRE.js → state-JB47KHYV.js} +2 -2
- package/dist/state-JB47KHYV.js.map +1 -0
- package/dist/storage.d.ts +9 -3
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +17 -17
- package/dist/subject-config.js +4 -4
- package/dist/summarizer.js +6 -6
- package/dist/support-passport/index.js +77 -70
- package/dist/{trace-ZFVRH4GO.js → trace-LXXCMZJA.js} +3 -3
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +3 -3
- package/dist/transfer/export-okf.js +19 -19
- package/dist/{tui-55UJMJX7.js → tui-2Z5WOV7L.js} +3 -3
- package/dist/tui-2Z5WOV7L.js.map +1 -0
- package/dist/verified-recall.js +18 -18
- package/dist/who-knows-cli.js +19 -19
- package/dist/who-knows.js +18 -18
- package/dist/write-envelope.js +4 -4
- package/package.json +2 -2
- package/src/access-extraction-force-flush.ts +15 -7
- package/src/access-http-offline-stream.ts +3 -0
- package/src/access-mcp-output-schemas.ts +1 -0
- package/src/access-mcp.ts +90 -28
- package/src/access-service-health.test.ts +41 -5
- package/src/access-service-helpers.ts +1 -0
- package/src/access-service-observe-lcm-parity.test.ts +56 -24
- package/src/access-service.ts +7 -18
- package/src/console/state.test.ts +56 -0
- package/src/console/state.ts +83 -0
- package/src/correction/correction-access-wiring.ts +36 -8
- package/src/correction/correction-classify-parse.test.ts +178 -0
- package/src/embedding-fallback.ts +325 -141
- package/src/embedding-generation-lock.ts +141 -0
- package/src/embedding-index-storage.test.ts +245 -0
- package/src/embedding-index-storage.ts +1068 -0
- package/src/extraction-liveness.ts +13 -1
- package/src/extraction-llm-health.test.ts +103 -0
- package/src/extraction-llm-health.ts +71 -0
- package/src/index.ts +3 -3
- package/src/json-extract.ts +6 -0
- package/src/local-llm-thinking.test.ts +12 -0
- package/src/local-llm.ts +1 -0
- package/src/offline-sync-embedding-generation.test.ts +2173 -0
- package/src/offline-sync-embedding-generation.ts +885 -0
- package/src/offline-sync-exclude-globs.ts +112 -0
- package/src/offline-sync-file-io.ts +48 -0
- package/src/offline-sync-runtime-state.ts +48 -0
- package/src/offline-sync-snapshot-stream.ts +99 -0
- package/src/offline-sync-upload-staging.ts +291 -0
- package/src/offline-sync.test.ts +164 -1
- package/src/offline-sync.ts +458 -453
- package/src/orchestration/extraction-run.test.ts +55 -1
- package/src/orchestration/extraction-run.ts +13 -0
- package/src/orchestrator.ts +2 -1
- package/src/secure-store/secure-fs.ts +26 -6
- package/src/storage.ts +11 -6
- package/dist/chunk-3BTFBQLO.js.map +0 -1
- package/dist/chunk-3SG4FGDV.js.map +0 -1
- package/dist/chunk-6DTJBTHL.js.map +0 -1
- package/dist/chunk-AREGMX2J.js +0 -50
- package/dist/chunk-AREGMX2J.js.map +0 -1
- package/dist/chunk-C2WWQ4OR.js.map +0 -1
- package/dist/chunk-G6SVZWPB.js.map +0 -1
- package/dist/chunk-I53NAHZ4.js.map +0 -1
- package/dist/chunk-JN72EPOE.js.map +0 -1
- package/dist/chunk-QB75LKQQ.js.map +0 -1
- package/dist/chunk-RB776UH3.js.map +0 -1
- package/dist/chunk-RGMVMVMF.js.map +0 -1
- package/dist/chunk-S55WTPFJ.js.map +0 -1
- package/dist/chunk-SVZWVZ7E.js.map +0 -1
- package/dist/chunk-WQZZDN5M.js.map +0 -1
- /package/dist/{auto-sync-WEUDMXUW.js.map → auto-sync-U5N3CB5Y.js.map} +0 -0
- /package/dist/{capsule-crypto-GWVG7LGC.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
- /package/dist/{capsule-merge-3MNURAQ3.js.map → capsule-merge-ZCXUPLNJ.js.map} +0 -0
- /package/dist/{chunk-JE334SIA.js.map → chunk-22DYJLFN.js.map} +0 -0
- /package/dist/{chunk-DGAWEJVI.js.map → chunk-2DLWLNO4.js.map} +0 -0
- /package/dist/{chunk-J3IWHCMF.js.map → chunk-2DT7PIDZ.js.map} +0 -0
- /package/dist/{chunk-NKFLHW7J.js.map → chunk-2NAD4YCI.js.map} +0 -0
- /package/dist/{chunk-SV72F4DS.js.map → chunk-2WLMWP2T.js.map} +0 -0
- /package/dist/{chunk-IVH7INFM.js.map → chunk-3O5BB45T.js.map} +0 -0
- /package/dist/{chunk-RDEUG2M2.js.map → chunk-3SGTV7RD.js.map} +0 -0
- /package/dist/{chunk-QOPB6KE3.js.map → chunk-3TB2XQ3C.js.map} +0 -0
- /package/dist/{chunk-C7JAUNFC.js.map → chunk-4KN2JLQV.js.map} +0 -0
- /package/dist/{chunk-TIQZNDZ5.js.map → chunk-4MP7XR5J.js.map} +0 -0
- /package/dist/{chunk-7DE2NOON.js.map → chunk-4O4XCBOS.js.map} +0 -0
- /package/dist/{chunk-SLEAJ67D.js.map → chunk-4OQET73E.js.map} +0 -0
- /package/dist/{chunk-Q3THVX75.js.map → chunk-4RL3JOB3.js.map} +0 -0
- /package/dist/{chunk-GDYU6VF4.js.map → chunk-5AYUHSAU.js.map} +0 -0
- /package/dist/{chunk-B47OHVFT.js.map → chunk-5E6RYRYW.js.map} +0 -0
- /package/dist/{chunk-2U3R3DDH.js.map → chunk-5FAGCOZD.js.map} +0 -0
- /package/dist/{chunk-CRKWSSS4.js.map → chunk-5MNUBT7T.js.map} +0 -0
- /package/dist/{chunk-52II7PB6.js.map → chunk-645WOU5I.js.map} +0 -0
- /package/dist/{chunk-7G6WUOLB.js.map → chunk-66DKTOBY.js.map} +0 -0
- /package/dist/{chunk-AZ2X5LNA.js.map → chunk-6LYAEM54.js.map} +0 -0
- /package/dist/{chunk-DUJYRVUD.js.map → chunk-6O2VUWV6.js.map} +0 -0
- /package/dist/{chunk-IMAP236M.js.map → chunk-6UQFJULG.js.map} +0 -0
- /package/dist/{chunk-2I6VHX6Q.js.map → chunk-76M5OK7V.js.map} +0 -0
- /package/dist/{chunk-OEBLZZKK.js.map → chunk-7XG7KMIW.js.map} +0 -0
- /package/dist/{chunk-FYAU4S6E.js.map → chunk-A4VSOUCB.js.map} +0 -0
- /package/dist/{chunk-GEX5NI36.js.map → chunk-AE5U5NMS.js.map} +0 -0
- /package/dist/{chunk-UNJOB4DY.js.map → chunk-AEHVZY3X.js.map} +0 -0
- /package/dist/{chunk-ML2MVAEZ.js.map → chunk-AEU4EQGV.js.map} +0 -0
- /package/dist/{chunk-JVY556FW.js.map → chunk-AWG3TIAY.js.map} +0 -0
- /package/dist/{chunk-JX6USXZR.js.map → chunk-AXC4WSF3.js.map} +0 -0
- /package/dist/{chunk-BOUFVFV2.js.map → chunk-AZSGSRIM.js.map} +0 -0
- /package/dist/{chunk-VZBW6CDG.js.map → chunk-B3O3IRZN.js.map} +0 -0
- /package/dist/{chunk-4V44AA7O.js.map → chunk-BGI4NUAO.js.map} +0 -0
- /package/dist/{chunk-BNPLDVM6.js.map → chunk-BJVO4H5C.js.map} +0 -0
- /package/dist/{chunk-S42HZILI.js.map → chunk-BLVR4WYU.js.map} +0 -0
- /package/dist/{chunk-JXMECXMF.js.map → chunk-BOZJD5PK.js.map} +0 -0
- /package/dist/{chunk-OWHERGF2.js.map → chunk-BXLOS5AJ.js.map} +0 -0
- /package/dist/{chunk-EVBI7S4J.js.map → chunk-C6U57KG4.js.map} +0 -0
- /package/dist/{chunk-T4BE5KJM.js.map → chunk-C7ZDKWPS.js.map} +0 -0
- /package/dist/{chunk-HKFJ3PF3.js.map → chunk-CRXRZA3G.js.map} +0 -0
- /package/dist/{chunk-NMBX4D7P.js.map → chunk-CZJA2EQE.js.map} +0 -0
- /package/dist/{chunk-BJX3VQWZ.js.map → chunk-D5BSQR63.js.map} +0 -0
- /package/dist/{chunk-MFZACYZ6.js.map → chunk-DGS34QSY.js.map} +0 -0
- /package/dist/{chunk-UVYI6VIX.js.map → chunk-DQEMWVMT.js.map} +0 -0
- /package/dist/{chunk-DQISIT63.js.map → chunk-DZ42MDZE.js.map} +0 -0
- /package/dist/{chunk-5ELENZTA.js.map → chunk-EDIH6X2P.js.map} +0 -0
- /package/dist/{chunk-C3QXITIP.js.map → chunk-EQUD7FP4.js.map} +0 -0
- /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
- /package/dist/{chunk-IA3X2Y4K.js.map → chunk-FJLQXMTU.js.map} +0 -0
- /package/dist/{chunk-TY446V34.js.map → chunk-FKD656D2.js.map} +0 -0
- /package/dist/{chunk-CLXTDOKV.js.map → chunk-FUNBJQYR.js.map} +0 -0
- /package/dist/{chunk-CLSYE5OZ.js.map → chunk-G2STTRYB.js.map} +0 -0
- /package/dist/{chunk-SQDKX4RW.js.map → chunk-GWM6T5EQ.js.map} +0 -0
- /package/dist/{chunk-AXDOF4VI.js.map → chunk-GZDTVYK2.js.map} +0 -0
- /package/dist/{chunk-55FCXCXJ.js.map → chunk-H56VY4BY.js.map} +0 -0
- /package/dist/{chunk-OM5BIPBR.js.map → chunk-H5BJWPUI.js.map} +0 -0
- /package/dist/{chunk-7QK5TUTW.js.map → chunk-HLB7GKGG.js.map} +0 -0
- /package/dist/{chunk-CHDGJJV6.js.map → chunk-HWLIMQE2.js.map} +0 -0
- /package/dist/{chunk-NAFPHFDM.js.map → chunk-JNLEJE4A.js.map} +0 -0
- /package/dist/{chunk-7UUKRS3J.js.map → chunk-JVPWRNHA.js.map} +0 -0
- /package/dist/{chunk-6ET2VII7.js.map → chunk-JYG2334B.js.map} +0 -0
- /package/dist/{chunk-2QG4SLZI.js.map → chunk-KF7PQ7G2.js.map} +0 -0
- /package/dist/{chunk-WIKO4SCR.js.map → chunk-LHRQBMJN.js.map} +0 -0
- /package/dist/{chunk-IFCKHPY4.js.map → chunk-LO4UKPKX.js.map} +0 -0
- /package/dist/{chunk-TEV2JGU5.js.map → chunk-LU7E2MXE.js.map} +0 -0
- /package/dist/{chunk-RJLV4BKR.js.map → chunk-LV5H6FTN.js.map} +0 -0
- /package/dist/{chunk-IBGEHKQ6.js.map → chunk-LW3HKRL7.js.map} +0 -0
- /package/dist/{chunk-3XQYM4RE.js.map → chunk-M6C7SOR6.js.map} +0 -0
- /package/dist/{chunk-T4QGUXCV.js.map → chunk-MXCAJKMA.js.map} +0 -0
- /package/dist/{chunk-BMYZTZ5D.js.map → chunk-MY7B3HYC.js.map} +0 -0
- /package/dist/{chunk-NB3LRY4T.js.map → chunk-N4PYB235.js.map} +0 -0
- /package/dist/{chunk-S3YM4SZQ.js.map → chunk-N7QV3CMX.js.map} +0 -0
- /package/dist/{chunk-3GN2PEOT.js.map → chunk-NYKIUQL6.js.map} +0 -0
- /package/dist/{chunk-L2LBMKSI.js.map → chunk-OK52IY3W.js.map} +0 -0
- /package/dist/{chunk-WB2I2EQK.js.map → chunk-P2ODTYOF.js.map} +0 -0
- /package/dist/{chunk-RIEX7NOZ.js.map → chunk-PEBHPCX2.js.map} +0 -0
- /package/dist/{chunk-VYCOJKSX.js.map → chunk-PO7NXNGC.js.map} +0 -0
- /package/dist/{chunk-XAITGGX5.js.map → chunk-Q4AUIFUA.js.map} +0 -0
- /package/dist/{chunk-EU3N5MK3.js.map → chunk-QAW55ZHJ.js.map} +0 -0
- /package/dist/{chunk-I4G4UWQA.js.map → chunk-QI2E6ISQ.js.map} +0 -0
- /package/dist/{chunk-CK5U7JGH.js.map → chunk-QI7K7BZ5.js.map} +0 -0
- /package/dist/{chunk-VTPASHTO.js.map → chunk-R3X2T2LP.js.map} +0 -0
- /package/dist/{chunk-EJPF6XDQ.js.map → chunk-RDJ6C7NZ.js.map} +0 -0
- /package/dist/{chunk-2UPTRDGM.js.map → chunk-SCXURCVT.js.map} +0 -0
- /package/dist/{chunk-N3MNDVJO.js.map → chunk-SWBC3UER.js.map} +0 -0
- /package/dist/{chunk-ZTHGFTMW.js.map → chunk-TKC5LZ43.js.map} +0 -0
- /package/dist/{chunk-YRLHEEQT.js.map → chunk-U6VC6RP3.js.map} +0 -0
- /package/dist/{chunk-MOQPEFLN.js.map → chunk-UP75KL3L.js.map} +0 -0
- /package/dist/{chunk-D5F7TKMH.js.map → chunk-V4JZCTMK.js.map} +0 -0
- /package/dist/{chunk-NAYBHNGN.js.map → chunk-VALKBYBN.js.map} +0 -0
- /package/dist/{chunk-BUKK5SWA.js.map → chunk-VDX2J7OX.js.map} +0 -0
- /package/dist/{chunk-H36X4NRH.js.map → chunk-VVX5PZFS.js.map} +0 -0
- /package/dist/{chunk-RCQKAOOB.js.map → chunk-W3XXFPRI.js.map} +0 -0
- /package/dist/{chunk-W75BBBSY.js.map → chunk-WKY7N3L7.js.map} +0 -0
- /package/dist/{chunk-GZAGLCQH.js.map → chunk-X5SHE2O3.js.map} +0 -0
- /package/dist/{chunk-OAOBL6OY.js.map → chunk-XOV7NRY5.js.map} +0 -0
- /package/dist/{chunk-FZVROZKC.js.map → chunk-XVZA6VXC.js.map} +0 -0
- /package/dist/{chunk-IP5VLSLO.js.map → chunk-YJ7MW627.js.map} +0 -0
- /package/dist/{chunk-HS75MCQF.js.map → chunk-YRULQW5J.js.map} +0 -0
- /package/dist/{chunk-DINRT75P.js.map → chunk-YSBL7VPO.js.map} +0 -0
- /package/dist/{chunk-QWUJWBZ5.js.map → chunk-Z3O53WZR.js.map} +0 -0
- /package/dist/{chunk-KERNN6BC.js.map → chunk-Z5LP6ILP.js.map} +0 -0
- /package/dist/{chunk-5FNZ3G6X.js.map → chunk-Z6EZCN6Z.js.map} +0 -0
- /package/dist/{chunk-JS3S2HVG.js.map → chunk-ZZZ4I455.js.map} +0 -0
- /package/dist/{contradiction-scan-5EJYRKD3.js.map → contradiction-scan-TAGMOUQ2.js.map} +0 -0
- /package/dist/{graph-edge-decay-PVKDKLQK.js.map → embedding-generation-lock.js.map} +0 -0
- /package/dist/{resolution-UYJU5JUA.js.map → embedding-index-storage.js.map} +0 -0
- /package/dist/{state-ITXJKXRE.js.map → extraction-llm-health.js.map} +0 -0
- /package/dist/{first-start-migration-GAT7G733.js.map → first-start-migration-7OATHJKB.js.map} +0 -0
- /package/dist/{tui-55UJMJX7.js.map → graph-edge-decay-MKIRZ762.js.map} +0 -0
- /package/dist/{trace-ZFVRH4GO.js.map → trace-LXXCMZJA.js.map} +0 -0
|
@@ -433,14 +433,13 @@ test("#2128: successful LCM flush does not bind per-call project context", async
|
|
|
433
433
|
test("#2128: extraction force-flush uses observe's scoped target even when LCM is disabled", async () => {
|
|
434
434
|
const probe = makeParityProbe(withSelfPolicyPrefix("pi-geek"));
|
|
435
435
|
const service = new EngramAccessService(probe.orch);
|
|
436
|
-
const deadlineMs = Date.now() + 10_000;
|
|
437
436
|
const abortController = new AbortController();
|
|
438
437
|
probe.lcmEngine.enabled = false;
|
|
439
438
|
|
|
440
439
|
const response = await service.extractionForceFlush({
|
|
441
440
|
sessionKey: "pi-geek:force-flush",
|
|
442
441
|
projectTag: "Acme/Webshop",
|
|
443
|
-
deadlineMs,
|
|
442
|
+
deadlineMs: 10_000,
|
|
444
443
|
abortSignal: abortController.signal,
|
|
445
444
|
authenticatedPrincipal: "pi-geek",
|
|
446
445
|
});
|
|
@@ -460,7 +459,11 @@ test("#2128: extraction force-flush uses observe's scoped target even when LCM i
|
|
|
460
459
|
false,
|
|
461
460
|
"force-flush must let the orchestrator discover all session buffer keys",
|
|
462
461
|
);
|
|
463
|
-
|
|
462
|
+
// #3140: the duration budget arrives at the orchestrator as an absolute deadline.
|
|
463
|
+
assert.ok(
|
|
464
|
+
(call.options.extractionDeadlineMs ?? 0) >= Date.now() + 9_000,
|
|
465
|
+
"the orchestrator deadline is the duration converted at force-flush entry",
|
|
466
|
+
);
|
|
464
467
|
assert.equal(call.options.failOnExtractionFailure, true);
|
|
465
468
|
assert.equal(call.options.abortSignal, abortController.signal);
|
|
466
469
|
assert.equal(call.options.writeNamespaceOverride, expectedNamespace);
|
|
@@ -573,7 +576,7 @@ test("#2128: pending extraction barriers stay isolated by authenticated principa
|
|
|
573
576
|
sessionKey,
|
|
574
577
|
namespace: "team",
|
|
575
578
|
authenticatedPrincipal: "alice",
|
|
576
|
-
deadlineMs:
|
|
579
|
+
deadlineMs: 500,
|
|
577
580
|
});
|
|
578
581
|
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
579
582
|
pending.get("alice")?.();
|
|
@@ -583,7 +586,7 @@ test("#2128: pending extraction barriers stay isolated by authenticated principa
|
|
|
583
586
|
sessionKey,
|
|
584
587
|
namespace: "team",
|
|
585
588
|
authenticatedPrincipal: "bob",
|
|
586
|
-
deadlineMs:
|
|
589
|
+
deadlineMs: 500,
|
|
587
590
|
});
|
|
588
591
|
pending.get("bob")?.();
|
|
589
592
|
assert.equal((await bobFlush).flushed, true);
|
|
@@ -600,7 +603,7 @@ test("#2128: chained observes remain behind one force-flush barrier", async () =
|
|
|
600
603
|
const sessionKey = "chained-observes";
|
|
601
604
|
|
|
602
605
|
await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
|
|
603
|
-
const flushPromise = service.extractionForceFlush({ sessionKey, deadlineMs:
|
|
606
|
+
const flushPromise = service.extractionForceFlush({ sessionKey, deadlineMs: 500 });
|
|
604
607
|
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
605
608
|
await service.observe(observeRequest({ sessionKey, skipExtraction: false }));
|
|
606
609
|
assert.equal(resolvers.length, 2);
|
|
@@ -669,7 +672,7 @@ test("#2128: force-flush deadline cancels the pending observe extraction", async
|
|
|
669
672
|
await assert.rejects(
|
|
670
673
|
service.extractionForceFlush({
|
|
671
674
|
sessionKey,
|
|
672
|
-
deadlineMs:
|
|
675
|
+
deadlineMs: 25,
|
|
673
676
|
}),
|
|
674
677
|
(error: unknown) =>
|
|
675
678
|
error instanceof EngramAccessInputError &&
|
|
@@ -893,7 +896,7 @@ test("#2128: post-flush retained cleanup is best effort and receives lifecycle g
|
|
|
893
896
|
},
|
|
894
897
|
};
|
|
895
898
|
const service = new EngramAccessService(probe.orch);
|
|
896
|
-
const deadlineMs =
|
|
899
|
+
const deadlineMs = 10_000;
|
|
897
900
|
|
|
898
901
|
const response = await service.extractionForceFlush({
|
|
899
902
|
sessionKey: "pi-geek:cleanup-best-effort",
|
|
@@ -903,11 +906,15 @@ test("#2128: post-flush retained cleanup is best effort and receives lifecycle g
|
|
|
903
906
|
});
|
|
904
907
|
|
|
905
908
|
assert.equal(response.flushed, true);
|
|
906
|
-
assert.
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
909
|
+
assert.equal(cleanupCalls.length, 1);
|
|
910
|
+
// #3140: cleanup receives the duration converted to an absolute deadline.
|
|
911
|
+
assert.equal(cleanupCalls[0]?.sessionKey, "pi-geek:cleanup-best-effort");
|
|
912
|
+
assert.equal(cleanupCalls[0]?.ownerPrincipal, "pi-geek");
|
|
913
|
+
assert.equal(cleanupCalls[0]?.options?.abortSignal, abortController.signal);
|
|
914
|
+
assert.ok(
|
|
915
|
+
(cleanupCalls[0]?.options?.deadlineMs ?? 0) >= Date.now() + 9_000,
|
|
916
|
+
"cleanup deadline is the duration converted at force-flush entry",
|
|
917
|
+
);
|
|
911
918
|
});
|
|
912
919
|
|
|
913
920
|
test("#2128: post-flush retained cleanup stops on abort or deadline", async (t) => {
|
|
@@ -982,7 +989,11 @@ test("#2128: post-flush retained cleanup stops on abort or deadline", async (t)
|
|
|
982
989
|
/replay extraction deadline exceeded \(retained_turn_cleanup\)/,
|
|
983
990
|
);
|
|
984
991
|
});
|
|
985
|
-
test("#
|
|
992
|
+
test("#3140: a duration deadline reaches scope resolution and aborts it when it elapses", async () => {
|
|
993
|
+
// Regression for issue #3140: `deadlineMs` is a BUDGET from now. The old
|
|
994
|
+
// absolute-epoch reading compared a relative value (e.g. 30000) against
|
|
995
|
+
// Date.now(), so a live-session force flush was rejected INSTANTLY with
|
|
996
|
+
// `replay extraction deadline exceeded (scope_resolution)` before any work.
|
|
986
997
|
const probe = makeParityProbe({ namespacesEnabled: false } as Partial<PluginConfig>);
|
|
987
998
|
const service = new EngramAccessService(probe.orch);
|
|
988
999
|
let scopeResolutionStarted = false;
|
|
@@ -991,17 +1002,23 @@ test("#2206: an expired force-flush deadline stops before scope resolution", asy
|
|
|
991
1002
|
};
|
|
992
1003
|
internals.resolveMemoryScopePlan = async () => {
|
|
993
1004
|
scopeResolutionStarted = true;
|
|
994
|
-
|
|
1005
|
+
return new Promise<never>(() => {});
|
|
995
1006
|
};
|
|
996
1007
|
|
|
1008
|
+
const started = Date.now();
|
|
997
1009
|
await assert.rejects(
|
|
998
1010
|
service.extractionForceFlush({
|
|
999
|
-
sessionKey: "
|
|
1000
|
-
deadlineMs:
|
|
1011
|
+
sessionKey: "duration-deadline-scope-resolution",
|
|
1012
|
+
deadlineMs: 30,
|
|
1001
1013
|
}),
|
|
1002
1014
|
/scope_resolution/,
|
|
1003
1015
|
);
|
|
1004
|
-
assert.equal(scopeResolutionStarted,
|
|
1016
|
+
assert.equal(scopeResolutionStarted, true, "the budget lets scope resolution start");
|
|
1017
|
+
assert.ok(
|
|
1018
|
+
Date.now() - started >= 25,
|
|
1019
|
+
"the flush waits out the budget instead of failing instantly",
|
|
1020
|
+
);
|
|
1021
|
+
assert.equal(probe.extractionForceFlushCalls.length, 0);
|
|
1005
1022
|
});
|
|
1006
1023
|
|
|
1007
1024
|
test("#2206: abort during scope resolution cancels pre-resolution observe preparations", async () => {
|
|
@@ -1089,8 +1106,10 @@ test("#2206: scope-resolution deadline cancels preparations by raw projectTag an
|
|
|
1089
1106
|
await observeScopeGate;
|
|
1090
1107
|
return resolveMemoryScopePlan(request);
|
|
1091
1108
|
}
|
|
1109
|
+
// Blocked scope work, as a live session's pending observe preparations
|
|
1110
|
+
// would hold it (#3140): the duration budget elapses while it hangs.
|
|
1092
1111
|
flushScopeStarted = true;
|
|
1093
|
-
|
|
1112
|
+
return new Promise<never>(() => {});
|
|
1094
1113
|
};
|
|
1095
1114
|
|
|
1096
1115
|
const observe = service.observe(observeRequest({
|
|
@@ -1104,12 +1123,12 @@ test("#2206: scope-resolution deadline cancels preparations by raw projectTag an
|
|
|
1104
1123
|
service.extractionForceFlush({
|
|
1105
1124
|
sessionKey: "pi-geek:raw-hint-deadline",
|
|
1106
1125
|
authenticatedPrincipal: "pi-geek",
|
|
1107
|
-
deadlineMs:
|
|
1126
|
+
deadlineMs: 1,
|
|
1108
1127
|
...rawHintCase,
|
|
1109
1128
|
}),
|
|
1110
1129
|
/scope_resolution/,
|
|
1111
1130
|
);
|
|
1112
|
-
assert.equal(flushScopeStarted,
|
|
1131
|
+
assert.equal(flushScopeStarted, true);
|
|
1113
1132
|
releaseObserveScope();
|
|
1114
1133
|
const response = await observe;
|
|
1115
1134
|
assert.equal(response.extractionQueued, false);
|
|
@@ -1132,12 +1151,19 @@ test("#2128: aborted or expired extraction force-flush never touches a buffer",
|
|
|
1132
1151
|
}),
|
|
1133
1152
|
/extraction force-flush aborted/,
|
|
1134
1153
|
);
|
|
1154
|
+
// #3140: the expired-at-entry scenario is gone (durations always start in
|
|
1155
|
+
// the future); a TINY budget elapsing while scope work is blocked still
|
|
1156
|
+
// rejects with the same error and never reaches the buffer.
|
|
1157
|
+
const internals = service as unknown as {
|
|
1158
|
+
resolveMemoryScopePlan: (request: unknown) => Promise<never>;
|
|
1159
|
+
};
|
|
1160
|
+
internals.resolveMemoryScopePlan = async () => new Promise<never>(() => {});
|
|
1135
1161
|
await assert.rejects(
|
|
1136
1162
|
() =>
|
|
1137
1163
|
service.extractionForceFlush({
|
|
1138
1164
|
sessionKey: "pi-geek:expired-flush",
|
|
1139
1165
|
authenticatedPrincipal: "pi-geek",
|
|
1140
|
-
deadlineMs:
|
|
1166
|
+
deadlineMs: 1,
|
|
1141
1167
|
}),
|
|
1142
1168
|
(error: unknown) =>
|
|
1143
1169
|
error instanceof EngramAccessInputError &&
|
|
@@ -1167,13 +1193,19 @@ test("#2128: self-deps wires force-flush cancellation into the observe tracker",
|
|
|
1167
1193
|
cancellations.push({ sessionKey, principal, namespace });
|
|
1168
1194
|
};
|
|
1169
1195
|
|
|
1196
|
+
// #3140: a tiny budget elapsing while scope work is blocked still cancels
|
|
1197
|
+
// the pending observe preparations via the same deadline hook.
|
|
1198
|
+
const internals = service as unknown as {
|
|
1199
|
+
resolveMemoryScopePlan: (request: unknown) => Promise<never>;
|
|
1200
|
+
};
|
|
1201
|
+
internals.resolveMemoryScopePlan = async () => new Promise<never>(() => {});
|
|
1170
1202
|
await assert.rejects(
|
|
1171
1203
|
() =>
|
|
1172
1204
|
service.extractionForceFlush({
|
|
1173
1205
|
sessionKey: "pi-geek:cancel-hook",
|
|
1174
1206
|
namespace: "pi-geek",
|
|
1175
1207
|
authenticatedPrincipal: "pi-geek",
|
|
1176
|
-
deadlineMs:
|
|
1208
|
+
deadlineMs: 1,
|
|
1177
1209
|
}),
|
|
1178
1210
|
(error: unknown) =>
|
|
1179
1211
|
error instanceof EngramAccessInputError &&
|
|
@@ -1198,7 +1230,7 @@ test("#2128: late extraction deadline is surfaced as an access input error", asy
|
|
|
1198
1230
|
service.extractionForceFlush({
|
|
1199
1231
|
sessionKey: "pi-geek:late-deadline",
|
|
1200
1232
|
authenticatedPrincipal: "pi-geek",
|
|
1201
|
-
deadlineMs:
|
|
1233
|
+
deadlineMs: 10_000,
|
|
1202
1234
|
}),
|
|
1203
1235
|
(error: unknown) =>
|
|
1204
1236
|
error instanceof EngramAccessInputError &&
|
package/src/access-service.ts
CHANGED
|
@@ -313,9 +313,9 @@ import {
|
|
|
313
313
|
buildOfflineSyncSnapshotFromBase,
|
|
314
314
|
compileOfflineSyncExcludeGlobs,
|
|
315
315
|
filterOfflineSyncDeletionRevisions,
|
|
316
|
-
iterateOfflineSyncSnapshotFileRecords,
|
|
317
316
|
readOfflineSyncFileContentChunk,
|
|
318
317
|
} from "./offline-sync.js";
|
|
318
|
+
import { buildEmbeddingAwareSnapshotStream } from "./offline-sync-snapshot-stream.js";
|
|
319
319
|
import { selfDeps } from "./orchestration/self-deps.js";
|
|
320
320
|
import { ReviewDeckSurface } from "./review/review-deck-surface.js";
|
|
321
321
|
import { formatProfileTraceAscii } from "./profiling.js";
|
|
@@ -5523,31 +5523,20 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
|
|
|
5523
5523
|
): Promise<EngramAccessOfflineSyncSnapshotStreamResponse> {
|
|
5524
5524
|
const resolvedNamespace = this.resolveReadableNamespace(options.namespace, options.principal);
|
|
5525
5525
|
const storage = await offlineSyncStorageForSnapshot(this.orchestrator, resolvedNamespace);
|
|
5526
|
-
const storageHash = createHash("sha256").update(storage.dir).digest("hex").slice(0, 16);
|
|
5527
|
-
const deletions = await filterOfflineSyncDeletionRevisions({
|
|
5528
|
-
root: storage.dir,
|
|
5529
|
-
deletions: [...(await storage.readDeletionRevisions())].map(([path, mtimeMs]) => ({ path, mtimeMs })),
|
|
5530
|
-
includeTranscripts: options.includeTranscripts !== false,
|
|
5531
|
-
userExcludeRegexps: this.offlineSyncUserExcludes,
|
|
5532
|
-
});
|
|
5533
5526
|
return {
|
|
5534
|
-
|
|
5535
|
-
format: OFFLINE_SYNC_SNAPSHOT_FORMAT,
|
|
5536
|
-
schemaVersion: 1,
|
|
5537
|
-
createdAt: new Date().toISOString(),
|
|
5538
|
-
sourceId: `remnic:${resolvedNamespace}:${storageHash}`,
|
|
5539
|
-
includeTranscripts: options.includeTranscripts !== false,
|
|
5540
|
-
deletions,
|
|
5541
|
-
files: iterateOfflineSyncSnapshotFileRecords({
|
|
5527
|
+
...await buildEmbeddingAwareSnapshotStream({
|
|
5542
5528
|
root: storage.dir,
|
|
5529
|
+
namespace: resolvedNamespace,
|
|
5543
5530
|
includeContent: options.includeContent === true,
|
|
5544
5531
|
includeTranscripts: options.includeTranscripts !== false,
|
|
5532
|
+
userExcludeRegexps: this.offlineSyncUserExcludes,
|
|
5533
|
+
excludeFile: createSupportPassportPrivateFileExclusion(storage),
|
|
5545
5534
|
readFile: async ({ filePath }) => storage.readOfflineSyncFile(filePath),
|
|
5546
5535
|
readFileDigest: async ({ filePath }) => storage.digestOfflineSyncFile(filePath),
|
|
5536
|
+
deletions: [...(await storage.readDeletionRevisions())].map(([path, mtimeMs]) => ({ path, mtimeMs })),
|
|
5547
5537
|
signal: options.signal,
|
|
5548
|
-
userExcludeRegexps: this.offlineSyncUserExcludes,
|
|
5549
|
-
excludeFile: createSupportPassportPrivateFileExclusion(storage),
|
|
5550
5538
|
}),
|
|
5539
|
+
namespace: resolvedNamespace,
|
|
5551
5540
|
};
|
|
5552
5541
|
}
|
|
5553
5542
|
async offlineSyncManifestStream(
|
|
@@ -222,3 +222,59 @@ test("maintenance ledger merges judge-verdicts + rebuilt-observations and picks
|
|
|
222
222
|
rmSync(baseDir, { recursive: true, force: true });
|
|
223
223
|
}
|
|
224
224
|
});
|
|
225
|
+
|
|
226
|
+
test("console state surfaces embedding index layout and durable failure status (#3146)", async () => {
|
|
227
|
+
const baseDir = mkdtempSync(path.join(tmpdir(), "remnic-console-embindex-"));
|
|
228
|
+
try {
|
|
229
|
+
const stateDir = path.join(baseDir, "state", "embeddings");
|
|
230
|
+
mkdirSync(stateDir, { recursive: true });
|
|
231
|
+
writeFileSync(
|
|
232
|
+
path.join(stateDir, "shard-0000.json"),
|
|
233
|
+
JSON.stringify({
|
|
234
|
+
version: 1,
|
|
235
|
+
provider: "openai",
|
|
236
|
+
model: "text-embedding-3-small",
|
|
237
|
+
entries: { "mem-1": { vector: [0.1], path: "facts/a.md" } },
|
|
238
|
+
}),
|
|
239
|
+
);
|
|
240
|
+
writeFileSync(
|
|
241
|
+
path.join(baseDir, "state", "embedding-fallback-status.json"),
|
|
242
|
+
JSON.stringify({
|
|
243
|
+
version: 1,
|
|
244
|
+
failureCount: 3,
|
|
245
|
+
lastWriteFailure: {
|
|
246
|
+
ts: "2026-09-26T00:00:00.000Z",
|
|
247
|
+
kind: "capacity",
|
|
248
|
+
message: "shard needs 600000000 chars",
|
|
249
|
+
memoryId: "mem-1",
|
|
250
|
+
},
|
|
251
|
+
}),
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const snapshot = await gatherConsoleState(
|
|
255
|
+
makeOrchestrator({ config: { memoryDir: baseDir } }),
|
|
256
|
+
);
|
|
257
|
+
assert.ok(snapshot.embeddingIndex, "snapshot must carry the embedding index block");
|
|
258
|
+
assert.equal(snapshot.embeddingIndex.legacyFileBytes, null);
|
|
259
|
+
assert.equal(snapshot.embeddingIndex.shardCount, 1);
|
|
260
|
+
assert.ok(snapshot.embeddingIndex.shardBytes > 0);
|
|
261
|
+
assert.equal(snapshot.embeddingIndex.status?.failureCount, 3);
|
|
262
|
+
assert.equal(snapshot.embeddingIndex.status?.lastWriteFailure?.kind, "capacity");
|
|
263
|
+
assert.deepEqual(snapshot.errors, []);
|
|
264
|
+
} finally {
|
|
265
|
+
rmSync(baseDir, { recursive: true, force: true });
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test("console state omits the embedding index block when no index state exists", async () => {
|
|
270
|
+
const baseDir = mkdtempSync(path.join(tmpdir(), "remnic-console-embindex-empty-"));
|
|
271
|
+
try {
|
|
272
|
+
const snapshot = await gatherConsoleState(
|
|
273
|
+
makeOrchestrator({ config: { memoryDir: baseDir } }),
|
|
274
|
+
);
|
|
275
|
+
assert.equal(snapshot.embeddingIndex, undefined);
|
|
276
|
+
assert.deepEqual(snapshot.errors, []);
|
|
277
|
+
} finally {
|
|
278
|
+
rmSync(baseDir, { recursive: true, force: true });
|
|
279
|
+
}
|
|
280
|
+
});
|
package/src/console/state.ts
CHANGED
|
@@ -149,6 +149,11 @@ export interface ConsoleStateSnapshot {
|
|
|
149
149
|
daemon: ConsoleDaemonInfo;
|
|
150
150
|
/** Faithfulness gate distribution (issue #1576). Absent when the gate is off. */
|
|
151
151
|
faithfulness?: ConsoleFaithfulnessDistribution;
|
|
152
|
+
/**
|
|
153
|
+
* Embedding-fallback index layout + durable diagnostics (issue #3146).
|
|
154
|
+
* Absent when the memory dir carries no embedding index state at all.
|
|
155
|
+
*/
|
|
156
|
+
embeddingIndex?: ConsoleEmbeddingIndexState;
|
|
152
157
|
/**
|
|
153
158
|
* Subsystem read errors. One entry per failed reader keyed by
|
|
154
159
|
* subsystem name (e.g. `"bufferState: ..."`). An empty array means
|
|
@@ -157,6 +162,25 @@ export interface ConsoleStateSnapshot {
|
|
|
157
162
|
errors: string[];
|
|
158
163
|
}
|
|
159
164
|
|
|
165
|
+
/** Loose view of `state/embedding-fallback-status.json` (written by EmbeddingFallback). */
|
|
166
|
+
export interface ConsoleEmbeddingIndexStatus {
|
|
167
|
+
failureCount?: number;
|
|
168
|
+
lastWriteFailure?: { ts: string; kind: string; message: string; memoryId?: string };
|
|
169
|
+
lastReadRecovery?: { ts: string; message: string };
|
|
170
|
+
lastSuccessAt?: string;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Embedding-fallback index layout + durable failure diagnostics (issue #3146). */
|
|
174
|
+
export interface ConsoleEmbeddingIndexState {
|
|
175
|
+
/** Size in bytes of the legacy single-file index, when present. */
|
|
176
|
+
legacyFileBytes: number | null;
|
|
177
|
+
/** Shard files under `state/embeddings/` (indexes past the single-file budget). */
|
|
178
|
+
shardCount: number;
|
|
179
|
+
shardBytes: number;
|
|
180
|
+
/** Durable diagnostics written by EmbeddingFallback, when present. */
|
|
181
|
+
status: ConsoleEmbeddingIndexStatus | null;
|
|
182
|
+
}
|
|
183
|
+
|
|
160
184
|
const MAX_LEDGER_TAIL = 50;
|
|
161
185
|
const MAX_VERDICT_TAIL = 25;
|
|
162
186
|
const MAX_DEDUP_TAIL = 10;
|
|
@@ -182,6 +206,7 @@ export async function gatherConsoleState(
|
|
|
182
206
|
);
|
|
183
207
|
const qmdProbe = readQmdProbe(orchestrator, errors);
|
|
184
208
|
const daemon = readDaemonInfo(orchestrator, errors);
|
|
209
|
+
const embeddingIndex = await readEmbeddingIndexState(orchestrator, errors);
|
|
185
210
|
|
|
186
211
|
// Faithfulness gate distribution (issue #1576). Optional — absent when
|
|
187
212
|
// the gate is off or the orchestrator does not expose the accessor.
|
|
@@ -203,10 +228,68 @@ export async function gatherConsoleState(
|
|
|
203
228
|
qmdProbe,
|
|
204
229
|
daemon,
|
|
205
230
|
...(faithfulness ? { faithfulness } : {}),
|
|
231
|
+
...(embeddingIndex ? { embeddingIndex } : {}),
|
|
206
232
|
errors,
|
|
207
233
|
};
|
|
208
234
|
}
|
|
209
235
|
|
|
236
|
+
const EMBEDDING_SHARD_PATTERN = /^shard-\d{4}\.json$/;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Read the embedding-fallback index layout and its durable failure
|
|
240
|
+
* diagnostics straight off disk (issue #3146): legacy file size, shard
|
|
241
|
+
* count/bytes under `state/embeddings/`, and the status file
|
|
242
|
+
* EmbeddingFallback writes on write failures and corrupt-file recovery.
|
|
243
|
+
* Returns undefined when the memory dir carries no index state at all.
|
|
244
|
+
*/
|
|
245
|
+
async function readEmbeddingIndexState(
|
|
246
|
+
orchestrator: ConsoleStateOrchestratorLike,
|
|
247
|
+
errors: string[],
|
|
248
|
+
): Promise<ConsoleEmbeddingIndexState | undefined> {
|
|
249
|
+
try {
|
|
250
|
+
const memoryDir = orchestrator.config?.memoryDir;
|
|
251
|
+
if (!memoryDir) return undefined;
|
|
252
|
+
const stateDir = path.join(memoryDir, "state");
|
|
253
|
+
|
|
254
|
+
let legacyFileBytes: number | null = null;
|
|
255
|
+
try {
|
|
256
|
+
legacyFileBytes = (await fs.stat(path.join(stateDir, "embeddings.json"))).size;
|
|
257
|
+
} catch (err) {
|
|
258
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") throw err;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let shardCount = 0;
|
|
262
|
+
let shardBytes = 0;
|
|
263
|
+
let shardNames: string[] = [];
|
|
264
|
+
try {
|
|
265
|
+
shardNames = await fs.readdir(path.join(stateDir, "embeddings"));
|
|
266
|
+
} catch (err) {
|
|
267
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") throw err;
|
|
268
|
+
}
|
|
269
|
+
for (const name of shardNames) {
|
|
270
|
+
if (!EMBEDDING_SHARD_PATTERN.test(name)) continue;
|
|
271
|
+
shardCount += 1;
|
|
272
|
+
shardBytes += (await fs.stat(path.join(stateDir, "embeddings", name))).size;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
let status: ConsoleEmbeddingIndexStatus | null = null;
|
|
276
|
+
try {
|
|
277
|
+
const parsed: unknown = JSON.parse(
|
|
278
|
+
await fs.readFile(path.join(stateDir, "embedding-fallback-status.json"), "utf-8"),
|
|
279
|
+
);
|
|
280
|
+
if (parsed && typeof parsed === "object") status = parsed as ConsoleEmbeddingIndexStatus;
|
|
281
|
+
} catch (err) {
|
|
282
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") throw err;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (legacyFileBytes === null && shardCount === 0 && status === null) return undefined;
|
|
286
|
+
return { legacyFileBytes, shardCount, shardBytes, status };
|
|
287
|
+
} catch (err) {
|
|
288
|
+
errors.push(`embeddingIndex: ${describeError(err)}`);
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
210
293
|
function readBufferState(
|
|
211
294
|
orchestrator: ConsoleStateOrchestratorLike,
|
|
212
295
|
errors: string[],
|
|
@@ -30,6 +30,7 @@ import { writeFileAtomically } from "../maintenance/atomic-file.js";
|
|
|
30
30
|
import type { Orchestrator } from "../orchestrator.js";
|
|
31
31
|
import type { MemoryFile, MemoryStatus, PluginConfig } from "../types.js";
|
|
32
32
|
import { stripAttributesSuffix } from "../structured-attributes.js";
|
|
33
|
+
import { extractJsonCandidates } from "../json-extract.js";
|
|
33
34
|
import { supersessionKeysForFact } from "../temporal-supersession.js";
|
|
34
35
|
import { computeContentHash } from "../content-hash.js";
|
|
35
36
|
import { sanitizeMemoryContent } from "../sanitize.js";
|
|
@@ -1010,16 +1011,43 @@ function parseClassifyResponse(
|
|
|
1010
1011
|
raw: string,
|
|
1011
1012
|
candidates: PlannerCandidate[],
|
|
1012
1013
|
): LlmClassificationResult {
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1014
|
+
// Correction plans can mutate memory: accept one schema-valid, verbatim
|
|
1015
|
+
// response, never an arbitrary example or a fence-rewritten patch payload.
|
|
1016
|
+
// The response envelope gates candidacy; actions need only ≥1 valid entry
|
|
1017
|
+
// (an empty list is fine, an all-malformed list is unusable). Malformed
|
|
1018
|
+
// siblings are dropped after selection, so one bad action cannot discard
|
|
1019
|
+
// the whole plan; distinct eligible responses stay ambiguous (fail closed).
|
|
1020
|
+
const responses = new Map<string, Record<string, unknown>>();
|
|
1021
|
+
let sawJson = false;
|
|
1022
|
+
for (const candidate of new Set([raw.trim(), ...extractJsonCandidates(raw)])) {
|
|
1023
|
+
if (!raw.includes(candidate)) continue;
|
|
1024
|
+
try {
|
|
1025
|
+
const parsed: unknown = JSON.parse(candidate);
|
|
1026
|
+
sawJson = true;
|
|
1027
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue;
|
|
1028
|
+
const value = parsed as Record<string, unknown>;
|
|
1029
|
+
if (!isClassification(value.classification) ||
|
|
1030
|
+
typeof value.confidence !== "number" || !Number.isFinite(value.confidence) ||
|
|
1031
|
+
value.confidence < 0 || value.confidence > 1 || !Array.isArray(value.actions)) continue;
|
|
1032
|
+
const hasUsable = value.actions.some((action) => {
|
|
1033
|
+
try {
|
|
1034
|
+
validateCorrectionAction(action);
|
|
1035
|
+
return true;
|
|
1036
|
+
} catch {
|
|
1037
|
+
return false;
|
|
1038
|
+
}
|
|
1039
|
+
});
|
|
1040
|
+
if (hasUsable || value.actions.length === 0) responses.set(JSON.stringify(value), value);
|
|
1041
|
+
} catch {
|
|
1042
|
+
// Keep scanning after malformed JSON, not after mere syntax success.
|
|
1043
|
+
}
|
|
1018
1044
|
}
|
|
1019
|
-
if (
|
|
1020
|
-
return fallbackClassification(candidates,
|
|
1045
|
+
if (responses.size !== 1) {
|
|
1046
|
+
return fallbackClassification(candidates, responses.size > 1
|
|
1047
|
+
? "LLM returned ambiguous correction responses"
|
|
1048
|
+
: sawJson ? "LLM returned invalid correction response" : "LLM returned non-JSON response");
|
|
1021
1049
|
}
|
|
1022
|
-
const obj =
|
|
1050
|
+
const obj = responses.values().next().value as Record<string, unknown>;
|
|
1023
1051
|
const classification = isClassification(obj.classification) ? obj.classification : "outdated";
|
|
1024
1052
|
const confidence = typeof obj.confidence === "number" ? Math.min(1, Math.max(0, obj.confidence)) : 0.5;
|
|
1025
1053
|
const rawActions = Array.isArray(obj.actions) ? obj.actions : [];
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parseClassifyResponse regression tests (issue #3134).
|
|
3
|
+
*
|
|
4
|
+
* Proves the correction planner's single LLM-response parse chokepoint:
|
|
5
|
+
* - fenced JSON responses (```json … ```) parse into real actions instead of
|
|
6
|
+
* degrading to the deterministic fallback (#3134, same class as #1514);
|
|
7
|
+
* - genuinely non-JSON responses still return the byte-identical
|
|
8
|
+
* deterministic fallback (rule 13);
|
|
9
|
+
* - bare JSON keeps parsing through the same candidate chain.
|
|
10
|
+
*/
|
|
11
|
+
import assert from "node:assert/strict";
|
|
12
|
+
import { test } from "node:test";
|
|
13
|
+
|
|
14
|
+
import { parseClassifyResponse } from "./correction-access-wiring.js";
|
|
15
|
+
import type { PlannerCandidate } from "./correction-planner.js";
|
|
16
|
+
|
|
17
|
+
const CANDIDATES: PlannerCandidate[] = [
|
|
18
|
+
{ memoryId: "m1", path: "facts/m1.md", content: "m1 content", excerpt: "m1 excerpt", score: 1 },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const CLASSIFY_JSON = JSON.stringify({
|
|
22
|
+
classification: "wrong",
|
|
23
|
+
confidence: 0.9,
|
|
24
|
+
actions: [{ kind: "edit", memoryId: "m1", patch: "m1 corrected content" }],
|
|
25
|
+
relevance: [{ memoryId: "m1", why: "names the corrected fact" }],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("#3134 fenced json classify response parses into actions instead of fallback", () => {
|
|
29
|
+
const result = parseClassifyResponse(["```json", CLASSIFY_JSON, "```"].join("\n"), CANDIDATES);
|
|
30
|
+
assert.equal(result.fallback, undefined, "a fenced response must not degrade to the fallback");
|
|
31
|
+
assert.equal(result.classification, "wrong");
|
|
32
|
+
assert.equal(result.confidence, 0.9);
|
|
33
|
+
assert.deepEqual(result.actions, [{ kind: "edit", memoryId: "m1", patch: "m1 corrected content" }]);
|
|
34
|
+
assert.deepEqual(result.relevance, [{ memoryId: "m1", why: "names the corrected fact" }]);
|
|
35
|
+
assert.deepEqual(result.warnings, []);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("#3134 fenced response without a language tag parses", () => {
|
|
39
|
+
const result = parseClassifyResponse(["```", CLASSIFY_JSON, "```"].join("\n"), CANDIDATES);
|
|
40
|
+
assert.equal(result.fallback, undefined);
|
|
41
|
+
assert.equal(result.actions.length, 1);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("#3134 prose-wrapped fenced response with trailing prose parses", () => {
|
|
45
|
+
const result = parseClassifyResponse(
|
|
46
|
+
["Here is the classification:", "```json", CLASSIFY_JSON, "```", "Done."].join("\n"),
|
|
47
|
+
CANDIDATES
|
|
48
|
+
);
|
|
49
|
+
assert.equal(result.fallback, undefined);
|
|
50
|
+
assert.equal(result.actions.length, 1);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("#3134 bare JSON with an inner markdown code block keeps its patch content verbatim", () => {
|
|
54
|
+
const patch = "```\nconst fixed = true;\n```";
|
|
55
|
+
const result = parseClassifyResponse(
|
|
56
|
+
JSON.stringify({
|
|
57
|
+
classification: "wrong",
|
|
58
|
+
confidence: 0.8,
|
|
59
|
+
actions: [{ kind: "edit", memoryId: "m1", patch }],
|
|
60
|
+
}),
|
|
61
|
+
CANDIDATES
|
|
62
|
+
);
|
|
63
|
+
assert.equal(result.fallback, undefined, "valid bare JSON must not degrade to the fallback");
|
|
64
|
+
assert.deepEqual(result.actions, [{ kind: "edit", memoryId: "m1", patch }], "inner code-block delimiters must survive verbatim");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("#3134 outer-fenced JSON with an inner code block parses with the patch verbatim", () => {
|
|
68
|
+
const patch = "```py\nprint(\"fixed\")\n```";
|
|
69
|
+
const inner = JSON.stringify({
|
|
70
|
+
classification: "wrong",
|
|
71
|
+
confidence: 0.8,
|
|
72
|
+
actions: [{ kind: "edit", memoryId: "m1", patch }],
|
|
73
|
+
});
|
|
74
|
+
const result = parseClassifyResponse(["```json", inner, "```"].join("\n"), CANDIDATES);
|
|
75
|
+
assert.equal(result.fallback, undefined, "an outer fence plus an inner code block must not degrade to the fallback");
|
|
76
|
+
assert.deepEqual(result.actions, [{ kind: "edit", memoryId: "m1", patch }], "inner code-block delimiters must survive verbatim");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("#3134 genuinely non-JSON response still returns the deterministic fallback", () => {
|
|
80
|
+
const result = parseClassifyResponse("I'm sorry, I cannot classify that request.", CANDIDATES);
|
|
81
|
+
assert.deepEqual(result, {
|
|
82
|
+
classification: "outdated",
|
|
83
|
+
confidence: 0,
|
|
84
|
+
actions: [],
|
|
85
|
+
relevance: [{ memoryId: "m1", why: "located for review" }],
|
|
86
|
+
warnings: ["LLM returned non-JSON response"],
|
|
87
|
+
fallback: true,
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("#3134 empty response still returns the deterministic fallback", () => {
|
|
92
|
+
const result = parseClassifyResponse("", CANDIDATES);
|
|
93
|
+
assert.equal(result.fallback, true);
|
|
94
|
+
assert.deepEqual(result.warnings, ["LLM returned non-JSON response"]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("#3134 bare JSON keeps parsing through the same candidate chain", () => {
|
|
98
|
+
const result = parseClassifyResponse(CLASSIFY_JSON, CANDIDATES);
|
|
99
|
+
assert.equal(result.fallback, undefined);
|
|
100
|
+
assert.equal(result.classification, "wrong");
|
|
101
|
+
assert.equal(result.confidence, 0.9);
|
|
102
|
+
assert.equal(result.actions.length, 1);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("#3134 bare JSON object with no actions still parses without fallback", () => {
|
|
106
|
+
const result = parseClassifyResponse(
|
|
107
|
+
JSON.stringify({ classification: "incomplete", confidence: 0.4, actions: [] }),
|
|
108
|
+
CANDIDATES
|
|
109
|
+
);
|
|
110
|
+
assert.equal(result.fallback, undefined);
|
|
111
|
+
assert.equal(result.classification, "incomplete");
|
|
112
|
+
assert.equal(result.actions.length, 0);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("#3145 skips unrelated JSON objects before the correction response", () => {
|
|
116
|
+
const result = parseClassifyResponse("Example: {}\nAnswer: " + CLASSIFY_JSON, CANDIDATES);
|
|
117
|
+
assert.equal(result.fallback, undefined);
|
|
118
|
+
assert.equal(result.classification, "wrong");
|
|
119
|
+
assert.equal(result.actions.length, 1);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("#3145 rejects ambiguous valid correction drafts instead of choosing an example", () => {
|
|
123
|
+
const other = JSON.stringify({ classification: "outdated", confidence: 0.99,
|
|
124
|
+
actions: [{ kind: "edit", memoryId: "m1", patch: "wrong example" }] });
|
|
125
|
+
const result = parseClassifyResponse(other + "\nActual answer: " + CLASSIFY_JSON, CANDIDATES);
|
|
126
|
+
assert.equal(result.fallback, true);
|
|
127
|
+
assert.equal(result.confidence, 0);
|
|
128
|
+
assert.deepEqual(result.actions, []);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("#3145 skips malformed correction actions before a valid response", () => {
|
|
132
|
+
const malformed = JSON.stringify({ classification: "wrong", confidence: 0.9,
|
|
133
|
+
actions: [{ kind: "invented-action" }] });
|
|
134
|
+
const result = parseClassifyResponse(malformed + "\n" + CLASSIFY_JSON, CANDIDATES);
|
|
135
|
+
assert.equal(result.fallback, undefined);
|
|
136
|
+
assert.deepEqual(result.actions, [{ kind: "edit", memoryId: "m1", patch: "m1 corrected content" }]);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("#3145 keeps the usable action when a sibling action is malformed", () => {
|
|
140
|
+
const mixed = JSON.stringify({
|
|
141
|
+
classification: "outdated",
|
|
142
|
+
confidence: 0.8,
|
|
143
|
+
actions: [
|
|
144
|
+
{ kind: "edit", memoryId: "m1", patch: "m1 corrected content" },
|
|
145
|
+
{ kind: "invented-action" },
|
|
146
|
+
],
|
|
147
|
+
});
|
|
148
|
+
const result = parseClassifyResponse(mixed, CANDIDATES);
|
|
149
|
+
assert.equal(result.fallback, undefined, "one malformed sibling must not discard the whole plan");
|
|
150
|
+
assert.deepEqual(result.actions, [{ kind: "edit", memoryId: "m1", patch: "m1 corrected content" }]);
|
|
151
|
+
assert.equal(
|
|
152
|
+
result.warnings.filter((w) => w.startsWith("dropped malformed action")).length,
|
|
153
|
+
1,
|
|
154
|
+
"exactly the malformed sibling is dropped with a warning",
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("#3145 a partially valid draft is ambiguous against a distinct valid draft", () => {
|
|
159
|
+
const partialDraft = JSON.stringify({
|
|
160
|
+
classification: "outdated",
|
|
161
|
+
confidence: 0.8,
|
|
162
|
+
actions: [
|
|
163
|
+
{ kind: "edit", memoryId: "m1", patch: "partial example" },
|
|
164
|
+
{ kind: "invented-action" },
|
|
165
|
+
],
|
|
166
|
+
});
|
|
167
|
+
const result = parseClassifyResponse(partialDraft + "\n" + CLASSIFY_JSON, CANDIDATES);
|
|
168
|
+
assert.equal(result.fallback, true);
|
|
169
|
+
assert.equal(result.confidence, 0);
|
|
170
|
+
assert.deepEqual(result.actions, []);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("#3145 an unrelated standalone object never becomes a plausible correction", () => {
|
|
174
|
+
const result = parseClassifyResponse("{}", CANDIDATES);
|
|
175
|
+
assert.equal(result.fallback, true);
|
|
176
|
+
assert.equal(result.confidence, 0);
|
|
177
|
+
assert.deepEqual(result.actions, []);
|
|
178
|
+
});
|