@remnic/core 10.0.51 → 10.0.53
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 +24 -24
- package/dist/access-authorization-probe.js +25 -25
- package/dist/access-boundary.js +24 -24
- package/dist/access-cli.js +65 -65
- package/dist/access-extraction-force-flush.js +24 -24
- package/dist/access-http-briefing.js +25 -25
- package/dist/access-http-query.js +26 -26
- package/dist/access-http.js +40 -40
- package/dist/access-identity-continuity-surface.js +24 -24
- package/dist/access-lcm-surface.js +24 -24
- package/dist/access-mcp.js +33 -33
- package/dist/access-namespace-preflight.js +24 -24
- package/dist/access-observe-write-surface.js +24 -24
- package/dist/access-operations-batch.js +25 -25
- package/dist/access-operations.js +32 -32
- package/dist/access-recall-concurrency.js +24 -24
- package/dist/access-recall-response.js +24 -24
- package/dist/access-recall-surface.js +24 -24
- package/dist/access-service.js +24 -24
- package/dist/access-surface-catalog.js +26 -26
- package/dist/active-recall.js +9 -9
- package/dist/briefing.js +10 -10
- package/dist/buffer.js +5 -5
- package/dist/causal-consolidation.js +11 -11
- package/dist/{chunk-3NL4ALUP.js → chunk-24SIB3EW.js} +3 -3
- package/dist/{chunk-Y3T5KQCR.js → chunk-2EYCW2ET.js} +2 -2
- package/dist/{chunk-AHGOOZUC.js → chunk-34UVJNSG.js} +2 -2
- package/dist/{chunk-2EXF6IIB.js → chunk-3632XJMR.js} +2 -2
- package/dist/{chunk-KETS5A62.js → chunk-3H3PNQEF.js} +2 -2
- package/dist/{chunk-SFRBUBUZ.js → chunk-3LNAQLW4.js} +3 -3
- package/dist/{chunk-75BK4XGV.js → chunk-4BUJICMI.js} +10 -10
- package/dist/{chunk-KIWO4327.js → chunk-4W5B5Z6P.js} +2 -2
- package/dist/{chunk-B35EQQ7L.js → chunk-53OFDW3P.js} +3 -3
- package/dist/{chunk-2ONKXEC7.js → chunk-5LBBXI2A.js} +2 -2
- package/dist/{chunk-UCLJTGP3.js → chunk-65B5RFKQ.js} +2 -2
- package/dist/{chunk-KAJYSO3U.js → chunk-6CDNOREO.js} +2 -2
- package/dist/{chunk-POJRFSJM.js → chunk-7XGNGLAN.js} +2 -2
- package/dist/{chunk-A6JDT6QF.js → chunk-AO5ZOD32.js} +2 -2
- package/dist/{chunk-RA7YRL6H.js → chunk-AOSCGNIC.js} +3 -3
- package/dist/{chunk-LWMLBVGB.js → chunk-B43P3DTC.js} +2 -2
- package/dist/{chunk-SJD334AG.js → chunk-CA6X37OB.js} +217 -173
- package/dist/chunk-CA6X37OB.js.map +1 -0
- package/dist/{chunk-VUMWVYMR.js → chunk-CIMD2MUR.js} +3 -3
- package/dist/{chunk-XRFLR3XF.js → chunk-DLZGSZVC.js} +22 -9
- package/dist/chunk-DLZGSZVC.js.map +1 -0
- package/dist/{chunk-5CWH2LKL.js → chunk-DOJBV6WR.js} +29 -14
- package/dist/chunk-DOJBV6WR.js.map +1 -0
- package/dist/{chunk-44EUCSG4.js → chunk-FFQNNFHX.js} +2 -2
- package/dist/{chunk-HEF4BRMT.js → chunk-FZLZUDJJ.js} +2 -2
- package/dist/{chunk-L3EFYRYK.js → chunk-GGFQAGOT.js} +7 -7
- package/dist/{chunk-ZLCBLDJO.js → chunk-GIRWNTMV.js} +2 -2
- package/dist/{chunk-EC2KVA27.js → chunk-H4DWSOBQ.js} +169 -105
- package/dist/chunk-H4DWSOBQ.js.map +1 -0
- package/dist/{chunk-SHNM7RIT.js → chunk-HJ4X4BGS.js} +2 -2
- package/dist/{chunk-MUNYUSBU.js → chunk-HJQ4NKKO.js} +2 -2
- package/dist/{chunk-V6Z4NAJZ.js → chunk-HM3ZTDAX.js} +2 -2
- package/dist/{chunk-EZS6QJNC.js → chunk-IFOCK3OJ.js} +2 -2
- package/dist/{chunk-LXXIV7Y2.js → chunk-JEX2JL3U.js} +7 -2
- package/dist/{chunk-LXXIV7Y2.js.map → chunk-JEX2JL3U.js.map} +1 -1
- package/dist/{chunk-DF6ZF2BN.js → chunk-LIVNX7WK.js} +2 -2
- package/dist/{chunk-WY66J4PI.js → chunk-LRVFS4KA.js} +2 -2
- package/dist/{chunk-LMB47UM6.js → chunk-LTDK6HBV.js} +2 -2
- package/dist/{chunk-HCIRR3BA.js → chunk-M4U25HLR.js} +2 -2
- package/dist/{chunk-YK7ZJPQM.js → chunk-MGN2RQRG.js} +2 -2
- package/dist/{chunk-G26YNEOC.js → chunk-NWA6IXR3.js} +1 -1
- package/dist/{chunk-G26YNEOC.js.map → chunk-NWA6IXR3.js.map} +1 -1
- package/dist/{chunk-JIJAWTRK.js → chunk-OCXDZJL4.js} +264 -194
- package/dist/chunk-OCXDZJL4.js.map +1 -0
- package/dist/{chunk-IUQXRRJB.js → chunk-OMWQO7H6.js} +2 -2
- package/dist/{chunk-7VO6E5UD.js → chunk-OVZIYLBZ.js} +6 -2
- package/dist/chunk-OVZIYLBZ.js.map +1 -0
- package/dist/{chunk-SPTPBKZX.js → chunk-OWNAWY6D.js} +2 -2
- package/dist/{chunk-XKDQTDXN.js → chunk-PFUXPTBT.js} +36 -15
- package/dist/chunk-PFUXPTBT.js.map +1 -0
- package/dist/{chunk-DQOGZZJA.js → chunk-QAHP5SBG.js} +3 -3
- package/dist/{chunk-GBGU5OZP.js → chunk-QF5EJ5VP.js} +13 -13
- package/dist/{chunk-FT75AQ74.js → chunk-QS5DUSBM.js} +2 -2
- package/dist/{chunk-72CBJ5VP.js → chunk-R3WZ74B2.js} +3 -3
- package/dist/{chunk-PDTNQLPC.js → chunk-RG3I2663.js} +2 -2
- package/dist/{chunk-CK6GCGMX.js → chunk-RTJJPW3C.js} +2 -2
- package/dist/{chunk-RJDYDF5K.js → chunk-TRAOZ2WP.js} +2 -2
- package/dist/{chunk-6ZAU7LAR.js → chunk-TTTPTQ6S.js} +2 -2
- package/dist/{chunk-JS44PBCM.js → chunk-U2A56LLF.js} +6 -6
- package/dist/{chunk-MC7PXJDP.js → chunk-UBOWDOL5.js} +5 -5
- package/dist/{chunk-4FM35YIA.js → chunk-UQYBPPVC.js} +2 -2
- package/dist/{chunk-OCRLJJOV.js → chunk-V4VCBFAL.js} +3 -3
- package/dist/{chunk-FNNGWN3O.js → chunk-VGE4PUY6.js} +2 -2
- package/dist/{chunk-5DVOBBTV.js → chunk-VV73XT3A.js} +2 -2
- package/dist/{chunk-GE3ZX6YK.js → chunk-W7NKMRAF.js} +2 -2
- package/dist/{chunk-AJJPXUE6.js → chunk-WBN66HPI.js} +2 -2
- package/dist/{chunk-XWJUFER3.js → chunk-WGFEGBFB.js} +2 -2
- package/dist/{chunk-43TUWQNR.js → chunk-XDKEHZUC.js} +2 -2
- package/dist/{chunk-ROAKLYOL.js → chunk-XHEKS4UN.js} +2 -2
- package/dist/{chunk-ZKK3VMWU.js → chunk-XVTB6BZS.js} +2 -2
- package/dist/{chunk-AZLD4CKG.js → chunk-Y56D5FSD.js} +17 -17
- package/dist/{chunk-MPWOAIIH.js → chunk-YDT3OEYF.js} +2 -2
- package/dist/{chunk-IN6U2BS5.js → chunk-YJHOVA42.js} +2 -2
- package/dist/{chunk-TC55M5PO.js → chunk-YLN4ZQV4.js} +2 -2
- package/dist/cli.js +50 -50
- package/dist/coding/export-okf-codegraph.js +9 -9
- package/dist/compounding/engine.js +11 -11
- package/dist/config.js +9 -9
- package/dist/connectors/codex-materialize-runner.js +10 -10
- package/dist/connectors/index.js +10 -10
- package/dist/convergence-refresh.js +12 -12
- package/dist/corpus-watermark.js +12 -12
- package/dist/entity-retrieval.js +10 -10
- package/dist/external-wiki-access.js +25 -25
- package/dist/extraction.js +14 -14
- package/dist/harmonic-retrieval.js +10 -10
- package/dist/index.js +65 -65
- package/dist/location/index.js +12 -12
- package/dist/maintenance/memory-governance.js +10 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
- package/dist/maintenance/rebuild-memory-projection-runner.js +12 -12
- package/dist/maintenance/rebuild-memory-projection.js +11 -11
- package/dist/memory-browse-operations.js +25 -25
- package/dist/memory-browse.js +5 -5
- package/dist/namespaces/migrate.js +11 -11
- package/dist/namespaces/search.d.ts.map +1 -1
- package/dist/namespaces/search.js +8 -8
- package/dist/namespaces/storage.js +10 -10
- package/dist/operator-doctor-corpus.js +13 -13
- package/dist/operator-toolkit.js +18 -18
- package/dist/orchestration/extraction-persist-deps.d.ts +2 -0
- package/dist/orchestration/extraction-persist-deps.d.ts.map +1 -1
- package/dist/orchestration/extraction-persist-promotion.d.ts +40 -10
- package/dist/orchestration/extraction-persist-promotion.d.ts.map +1 -1
- package/dist/orchestration/extraction-persist.d.ts.map +1 -1
- package/dist/orchestration/lifecycle-pending-fallback-drain.d.ts +18 -0
- package/dist/orchestration/lifecycle-pending-fallback-drain.d.ts.map +1 -0
- package/dist/orchestration/maintenance.d.ts +11 -13
- package/dist/orchestration/maintenance.d.ts.map +1 -1
- package/dist/orchestration/maintenance.js +20 -20
- package/dist/orchestration/qmd-maintenance-completion.d.ts +20 -0
- package/dist/orchestration/qmd-maintenance-completion.d.ts.map +1 -0
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +65 -65
- package/dist/qmd.js +2 -2
- package/dist/recall-composition-decision.js +2 -2
- package/dist/recall-navigation-operations.js +25 -25
- package/dist/recall-navigation.js +24 -24
- package/dist/recall-state-view-admission.js +5 -5
- package/dist/recall-why-service.js +5 -5
- package/dist/resume-bundles.js +9 -9
- package/dist/search/factory.js +7 -7
- package/dist/search/index.js +7 -7
- package/dist/search/lancedb-backend.d.ts +3 -0
- package/dist/search/lancedb-backend.d.ts.map +1 -1
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.d.ts +3 -0
- package/dist/search/meilisearch-backend.d.ts.map +1 -1
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/orama-backend.d.ts +3 -0
- package/dist/search/orama-backend.d.ts.map +1 -1
- package/dist/search/orama-backend.js +2 -2
- package/dist/search/port.d.ts +7 -0
- package/dist/search/port.d.ts.map +1 -1
- package/dist/search/port.js +1 -1
- package/dist/search/remote-backend.d.ts +2 -0
- package/dist/search/remote-backend.d.ts.map +1 -1
- package/dist/search/remote-backend.js +2 -2
- package/dist/semantic-consolidation.js +11 -11
- package/dist/semantic-rule-promotion.js +10 -10
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/source-agent-qualifier.js +13 -13
- package/dist/standup/build.js +10 -10
- package/dist/storage/entity-canonical-id-migration-adapter.d.ts +7 -1
- package/dist/storage/entity-canonical-id-migration-adapter.d.ts.map +1 -1
- package/dist/storage/entity-migration-maintenance-pending.d.ts +31 -0
- package/dist/storage/entity-migration-maintenance-pending.d.ts.map +1 -0
- package/dist/storage.d.ts +2 -2
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +9 -9
- package/dist/support-passport/index.js +27 -27
- package/dist/transfer/export-okf.js +10 -10
- package/dist/verified-recall.js +10 -10
- package/dist/who-knows-cli.js +11 -11
- package/dist/who-knows.js +10 -10
- package/package.json +2 -2
- package/src/namespaces/search.test.ts +121 -0
- package/src/namespaces/search.ts +8 -0
- package/src/orchestration/extraction-persist-deps.ts +3 -0
- package/src/orchestration/extraction-persist-promotion.ts +104 -16
- package/src/orchestration/extraction-persist.ts +66 -77
- package/src/orchestration/lifecycle-pending-fallback-drain.ts +97 -0
- package/src/orchestration/maintenance.test.ts +443 -1
- package/src/orchestration/maintenance.ts +73 -95
- package/src/orchestration/qmd-maintenance-completion.ts +32 -0
- package/src/orchestrator-entity-write-failure.test.ts +370 -0
- package/src/orchestrator.ts +9 -1
- package/src/search/lancedb-backend.ts +29 -12
- package/src/search/meilisearch-backend.test.ts +148 -0
- package/src/search/meilisearch-backend.ts +41 -14
- package/src/search/orama-backend.test.ts +75 -1
- package/src/search/orama-backend.ts +22 -7
- package/src/search/port.ts +7 -0
- package/src/search/remote-backend.ts +4 -0
- package/src/storage/entity-canonical-id-migration-adapter.ts +44 -9
- package/src/storage/entity-migration-maintenance-pending-helpers.test.ts +87 -0
- package/src/storage/entity-migration-maintenance-pending.test.ts +242 -0
- package/src/storage/entity-migration-maintenance-pending.ts +89 -0
- package/src/storage.ts +2 -2
- package/dist/chunk-5CWH2LKL.js.map +0 -1
- package/dist/chunk-7VO6E5UD.js.map +0 -1
- package/dist/chunk-EC2KVA27.js.map +0 -1
- package/dist/chunk-JIJAWTRK.js.map +0 -1
- package/dist/chunk-SJD334AG.js.map +0 -1
- package/dist/chunk-XKDQTDXN.js.map +0 -1
- package/dist/chunk-XRFLR3XF.js.map +0 -1
- /package/dist/{chunk-3NL4ALUP.js.map → chunk-24SIB3EW.js.map} +0 -0
- /package/dist/{chunk-Y3T5KQCR.js.map → chunk-2EYCW2ET.js.map} +0 -0
- /package/dist/{chunk-AHGOOZUC.js.map → chunk-34UVJNSG.js.map} +0 -0
- /package/dist/{chunk-2EXF6IIB.js.map → chunk-3632XJMR.js.map} +0 -0
- /package/dist/{chunk-KETS5A62.js.map → chunk-3H3PNQEF.js.map} +0 -0
- /package/dist/{chunk-SFRBUBUZ.js.map → chunk-3LNAQLW4.js.map} +0 -0
- /package/dist/{chunk-75BK4XGV.js.map → chunk-4BUJICMI.js.map} +0 -0
- /package/dist/{chunk-KIWO4327.js.map → chunk-4W5B5Z6P.js.map} +0 -0
- /package/dist/{chunk-B35EQQ7L.js.map → chunk-53OFDW3P.js.map} +0 -0
- /package/dist/{chunk-2ONKXEC7.js.map → chunk-5LBBXI2A.js.map} +0 -0
- /package/dist/{chunk-UCLJTGP3.js.map → chunk-65B5RFKQ.js.map} +0 -0
- /package/dist/{chunk-KAJYSO3U.js.map → chunk-6CDNOREO.js.map} +0 -0
- /package/dist/{chunk-POJRFSJM.js.map → chunk-7XGNGLAN.js.map} +0 -0
- /package/dist/{chunk-A6JDT6QF.js.map → chunk-AO5ZOD32.js.map} +0 -0
- /package/dist/{chunk-RA7YRL6H.js.map → chunk-AOSCGNIC.js.map} +0 -0
- /package/dist/{chunk-LWMLBVGB.js.map → chunk-B43P3DTC.js.map} +0 -0
- /package/dist/{chunk-VUMWVYMR.js.map → chunk-CIMD2MUR.js.map} +0 -0
- /package/dist/{chunk-44EUCSG4.js.map → chunk-FFQNNFHX.js.map} +0 -0
- /package/dist/{chunk-HEF4BRMT.js.map → chunk-FZLZUDJJ.js.map} +0 -0
- /package/dist/{chunk-L3EFYRYK.js.map → chunk-GGFQAGOT.js.map} +0 -0
- /package/dist/{chunk-ZLCBLDJO.js.map → chunk-GIRWNTMV.js.map} +0 -0
- /package/dist/{chunk-SHNM7RIT.js.map → chunk-HJ4X4BGS.js.map} +0 -0
- /package/dist/{chunk-MUNYUSBU.js.map → chunk-HJQ4NKKO.js.map} +0 -0
- /package/dist/{chunk-V6Z4NAJZ.js.map → chunk-HM3ZTDAX.js.map} +0 -0
- /package/dist/{chunk-EZS6QJNC.js.map → chunk-IFOCK3OJ.js.map} +0 -0
- /package/dist/{chunk-DF6ZF2BN.js.map → chunk-LIVNX7WK.js.map} +0 -0
- /package/dist/{chunk-WY66J4PI.js.map → chunk-LRVFS4KA.js.map} +0 -0
- /package/dist/{chunk-LMB47UM6.js.map → chunk-LTDK6HBV.js.map} +0 -0
- /package/dist/{chunk-HCIRR3BA.js.map → chunk-M4U25HLR.js.map} +0 -0
- /package/dist/{chunk-YK7ZJPQM.js.map → chunk-MGN2RQRG.js.map} +0 -0
- /package/dist/{chunk-IUQXRRJB.js.map → chunk-OMWQO7H6.js.map} +0 -0
- /package/dist/{chunk-SPTPBKZX.js.map → chunk-OWNAWY6D.js.map} +0 -0
- /package/dist/{chunk-DQOGZZJA.js.map → chunk-QAHP5SBG.js.map} +0 -0
- /package/dist/{chunk-GBGU5OZP.js.map → chunk-QF5EJ5VP.js.map} +0 -0
- /package/dist/{chunk-FT75AQ74.js.map → chunk-QS5DUSBM.js.map} +0 -0
- /package/dist/{chunk-72CBJ5VP.js.map → chunk-R3WZ74B2.js.map} +0 -0
- /package/dist/{chunk-PDTNQLPC.js.map → chunk-RG3I2663.js.map} +0 -0
- /package/dist/{chunk-CK6GCGMX.js.map → chunk-RTJJPW3C.js.map} +0 -0
- /package/dist/{chunk-RJDYDF5K.js.map → chunk-TRAOZ2WP.js.map} +0 -0
- /package/dist/{chunk-6ZAU7LAR.js.map → chunk-TTTPTQ6S.js.map} +0 -0
- /package/dist/{chunk-JS44PBCM.js.map → chunk-U2A56LLF.js.map} +0 -0
- /package/dist/{chunk-MC7PXJDP.js.map → chunk-UBOWDOL5.js.map} +0 -0
- /package/dist/{chunk-4FM35YIA.js.map → chunk-UQYBPPVC.js.map} +0 -0
- /package/dist/{chunk-OCRLJJOV.js.map → chunk-V4VCBFAL.js.map} +0 -0
- /package/dist/{chunk-FNNGWN3O.js.map → chunk-VGE4PUY6.js.map} +0 -0
- /package/dist/{chunk-5DVOBBTV.js.map → chunk-VV73XT3A.js.map} +0 -0
- /package/dist/{chunk-GE3ZX6YK.js.map → chunk-W7NKMRAF.js.map} +0 -0
- /package/dist/{chunk-AJJPXUE6.js.map → chunk-WBN66HPI.js.map} +0 -0
- /package/dist/{chunk-XWJUFER3.js.map → chunk-WGFEGBFB.js.map} +0 -0
- /package/dist/{chunk-43TUWQNR.js.map → chunk-XDKEHZUC.js.map} +0 -0
- /package/dist/{chunk-ROAKLYOL.js.map → chunk-XHEKS4UN.js.map} +0 -0
- /package/dist/{chunk-ZKK3VMWU.js.map → chunk-XVTB6BZS.js.map} +0 -0
- /package/dist/{chunk-AZLD4CKG.js.map → chunk-Y56D5FSD.js.map} +0 -0
- /package/dist/{chunk-MPWOAIIH.js.map → chunk-YDT3OEYF.js.map} +0 -0
- /package/dist/{chunk-IN6U2BS5.js.map → chunk-YJHOVA42.js.map} +0 -0
- /package/dist/{chunk-TC55M5PO.js.map → chunk-YLN4ZQV4.js.map} +0 -0
|
@@ -21,9 +21,11 @@ import path from "node:path";
|
|
|
21
21
|
import { readProjectionRebuiltAt } from "../maintenance/projection-support.js";
|
|
22
22
|
import { lstat, mkdir, mkdtemp, readdir, readFile, rm, stat, symlink, writeFile } from "node:fs/promises";
|
|
23
23
|
import { execFileSync } from "node:child_process";
|
|
24
|
-
import { setTimeout as delay } from "node:timers/promises";
|
|
24
|
+
import { setImmediate, setTimeout as delay } from "node:timers/promises";
|
|
25
25
|
|
|
26
26
|
import { MaintenanceScheduler } from "./maintenance.js";
|
|
27
|
+
import { EmbedHelper } from "../search/embed-helper.js";
|
|
28
|
+
import { OramaBackend } from "../search/orama-backend.js";
|
|
27
29
|
import {
|
|
28
30
|
createProjectionRebuildScheduleState,
|
|
29
31
|
maybeRebuildMemoryProjectionScheduled,
|
|
@@ -2982,3 +2984,443 @@ test("maintenance tool request invokes the scheduled projection rebuild wiring (
|
|
|
2982
2984
|
await rm(memoryDir, { recursive: true, force: true });
|
|
2983
2985
|
}
|
|
2984
2986
|
});
|
|
2987
|
+
|
|
2988
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
2989
|
+
// requestQmdMaintenanceCompletion — #3287 review: a caller that must know the
|
|
2990
|
+
// re-index actually ran (the entity-migration pending marker) cannot rely on
|
|
2991
|
+
// requestQmdMaintenanceForTool, which only arms a debounced timer.
|
|
2992
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
2993
|
+
|
|
2994
|
+
/**
|
|
2995
|
+
* Non-namespace scheduler over a scriptable QMD backend. Like QmdClient, plain
|
|
2996
|
+
* `update()` is fail-open: it resolves even when the min-interval gate or the
|
|
2997
|
+
* failure backoff suppressed it or it errored, so only `updateStrict()` says
|
|
2998
|
+
* whether an update actually ran.
|
|
2999
|
+
*/
|
|
3000
|
+
function completionScheduler(
|
|
3001
|
+
backend: {
|
|
3002
|
+
available?: boolean;
|
|
3003
|
+
/** What a plain, fail-open update() does (default: resolve). */
|
|
3004
|
+
update?: () => Promise<void>;
|
|
3005
|
+
/** What a strict update does; `false` omits the method (a backend that cannot confirm an update). */
|
|
3006
|
+
updateStrict?: (() => Promise<void>) | false;
|
|
3007
|
+
},
|
|
3008
|
+
overrides: Record<string, boolean> = {},
|
|
3009
|
+
): MaintenanceScheduler {
|
|
3010
|
+
const runStrict = backend.updateStrict || (async () => undefined);
|
|
3011
|
+
const strict = backend.updateStrict === false ? {} : {
|
|
3012
|
+
async updateStrict() {
|
|
3013
|
+
if (!(backend.available ?? true)) throw new Error("QMD unavailable");
|
|
3014
|
+
await runStrict();
|
|
3015
|
+
},
|
|
3016
|
+
};
|
|
3017
|
+
// Object.create yields an untyped value, so no assertion is needed: the scheduler reads only these members.
|
|
3018
|
+
const qmd: SearchBackend = Object.assign(Object.create(null), {
|
|
3019
|
+
isAvailable: () => backend.available ?? true,
|
|
3020
|
+
update: backend.update ?? (async () => undefined),
|
|
3021
|
+
async embed() {},
|
|
3022
|
+
...strict,
|
|
3023
|
+
});
|
|
3024
|
+
const router: NamespaceSearchRouter = Object.create(null);
|
|
3025
|
+
const catalog: NamespaceCatalog = Object.assign(Object.create(null), { enabled: false });
|
|
3026
|
+
return new MaintenanceScheduler({
|
|
3027
|
+
config: fixtureConfig({ namespacesEnabled: false, qmdAutoEmbedEnabled: false, ...overrides }),
|
|
3028
|
+
getQmd: () => qmd,
|
|
3029
|
+
namespaceSearchRouter: router,
|
|
3030
|
+
namespaceCatalog: catalog,
|
|
3031
|
+
});
|
|
3032
|
+
}
|
|
3033
|
+
|
|
3034
|
+
test("requestQmdMaintenanceCompletion resolves true once the pass that covers it has run", async () => {
|
|
3035
|
+
const scheduler = completionScheduler({});
|
|
3036
|
+
try {
|
|
3037
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3038
|
+
assert.equal(scheduler.isQmdMaintenancePending(), true, "the request arms the debounced pass");
|
|
3039
|
+
await scheduler.runQmdMaintenance();
|
|
3040
|
+
assert.equal(await served, true);
|
|
3041
|
+
} finally {
|
|
3042
|
+
await scheduler.dispose();
|
|
3043
|
+
}
|
|
3044
|
+
});
|
|
3045
|
+
|
|
3046
|
+
test("requestQmdMaintenanceCompletion serves every request that was waiting when the pass started", async () => {
|
|
3047
|
+
const scheduler = completionScheduler({});
|
|
3048
|
+
try {
|
|
3049
|
+
const waiting = [scheduler.requestQmdMaintenanceCompletion(), scheduler.requestQmdMaintenanceCompletion()];
|
|
3050
|
+
await scheduler.runQmdMaintenance();
|
|
3051
|
+
assert.deepEqual(await Promise.all(waiting), [true, true]);
|
|
3052
|
+
} finally {
|
|
3053
|
+
await scheduler.dispose();
|
|
3054
|
+
}
|
|
3055
|
+
});
|
|
3056
|
+
|
|
3057
|
+
test("requestQmdMaintenanceCompletion resolves false when the covering pass fails", async () => {
|
|
3058
|
+
const scheduler = completionScheduler({
|
|
3059
|
+
updateStrict: async () => {
|
|
3060
|
+
throw new Error("qmd update failed");
|
|
3061
|
+
},
|
|
3062
|
+
});
|
|
3063
|
+
try {
|
|
3064
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3065
|
+
await scheduler.runQmdMaintenance();
|
|
3066
|
+
assert.equal(await served, false, "a failed update left the index stale: the request stays owed");
|
|
3067
|
+
} finally {
|
|
3068
|
+
await scheduler.dispose();
|
|
3069
|
+
}
|
|
3070
|
+
});
|
|
3071
|
+
|
|
3072
|
+
test("requestQmdMaintenanceCompletion resolves false when dispose() clears the armed timer", async () => {
|
|
3073
|
+
const scheduler = completionScheduler({});
|
|
3074
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3075
|
+
assert.equal(scheduler.isQmdMaintenancePending(), true);
|
|
3076
|
+
await scheduler.dispose();
|
|
3077
|
+
assert.equal(await served, false, "a destroy inside the debounce window must leave the re-index owed");
|
|
3078
|
+
});
|
|
3079
|
+
|
|
3080
|
+
test("requestQmdMaintenanceCompletion resolves false without arming anything when QMD is unavailable or disposed", async () => {
|
|
3081
|
+
const unavailable = completionScheduler({ available: false });
|
|
3082
|
+
try {
|
|
3083
|
+
assert.equal(await unavailable.requestQmdMaintenanceCompletion(), false);
|
|
3084
|
+
assert.equal(unavailable.isQmdMaintenancePending(), false, "no timer may be armed for a refused request");
|
|
3085
|
+
} finally {
|
|
3086
|
+
await unavailable.dispose();
|
|
3087
|
+
}
|
|
3088
|
+
const off = completionScheduler({}, { qmdMaintenanceEnabled: false });
|
|
3089
|
+
try {
|
|
3090
|
+
assert.equal(await off.requestQmdMaintenanceCompletion(), false, "maintenance switched off: nothing will ever serve it");
|
|
3091
|
+
assert.equal(off.isQmdMaintenancePending(), false);
|
|
3092
|
+
} finally {
|
|
3093
|
+
await off.dispose();
|
|
3094
|
+
}
|
|
3095
|
+
const disposed = completionScheduler({});
|
|
3096
|
+
await disposed.dispose();
|
|
3097
|
+
assert.equal(await disposed.requestQmdMaintenanceCompletion(), false);
|
|
3098
|
+
assert.equal(disposed.isQmdMaintenancePending(), false);
|
|
3099
|
+
});
|
|
3100
|
+
|
|
3101
|
+
test("requestQmdMaintenanceCompletion resolves false when the update was suppressed or errored but plain update() still returned normally", async () => {
|
|
3102
|
+
// QmdClient.update() is fail-open: a min-interval gate or failure backoff
|
|
3103
|
+
// suppression resolves it silently, and so does an error. Reading that as
|
|
3104
|
+
// served cleared the marker with no re-index (default non-namespace config).
|
|
3105
|
+
for (const reason of ["QMD update skipped by min-interval gate", "QMD update skipped by recent failure backoff", "spawn qmd ENOENT"]) {
|
|
3106
|
+
const scheduler = completionScheduler({
|
|
3107
|
+
update: async () => undefined,
|
|
3108
|
+
updateStrict: async () => {
|
|
3109
|
+
throw new Error(reason);
|
|
3110
|
+
},
|
|
3111
|
+
});
|
|
3112
|
+
try {
|
|
3113
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3114
|
+
await scheduler.runQmdMaintenance();
|
|
3115
|
+
assert.equal(await served, false, reason);
|
|
3116
|
+
} finally {
|
|
3117
|
+
await scheduler.dispose();
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
});
|
|
3121
|
+
|
|
3122
|
+
test("requestQmdMaintenanceCompletion resolves false for a backend that cannot confirm an update", async () => {
|
|
3123
|
+
const scheduler = completionScheduler({ updateStrict: false });
|
|
3124
|
+
try {
|
|
3125
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3126
|
+
await scheduler.runQmdMaintenance();
|
|
3127
|
+
assert.equal(await served, false, "plain update() says nothing about whether it indexed");
|
|
3128
|
+
} finally {
|
|
3129
|
+
await scheduler.dispose();
|
|
3130
|
+
}
|
|
3131
|
+
});
|
|
3132
|
+
|
|
3133
|
+
test("requestQmdMaintenanceCompletion keeps embedding after a suppressed update, as before", async () => {
|
|
3134
|
+
let embeds = 0;
|
|
3135
|
+
const qmd: SearchBackend = Object.assign(Object.create(null), {
|
|
3136
|
+
isAvailable: () => true,
|
|
3137
|
+
async update() {},
|
|
3138
|
+
async updateStrict() {
|
|
3139
|
+
throw new Error("QMD update skipped by min-interval gate");
|
|
3140
|
+
},
|
|
3141
|
+
async embed() {
|
|
3142
|
+
embeds += 1;
|
|
3143
|
+
},
|
|
3144
|
+
});
|
|
3145
|
+
const router: NamespaceSearchRouter = Object.create(null);
|
|
3146
|
+
const catalog: NamespaceCatalog = Object.assign(Object.create(null), { enabled: false });
|
|
3147
|
+
const scheduler = new MaintenanceScheduler({
|
|
3148
|
+
config: fixtureConfig({ namespacesEnabled: false, qmdAutoEmbedEnabled: true, qmdEmbedMinIntervalMs: 0 }),
|
|
3149
|
+
getQmd: () => qmd,
|
|
3150
|
+
namespaceSearchRouter: router,
|
|
3151
|
+
namespaceCatalog: catalog,
|
|
3152
|
+
});
|
|
3153
|
+
try {
|
|
3154
|
+
scheduler.requestQmdMaintenanceForTool("test");
|
|
3155
|
+
await scheduler.runQmdMaintenance();
|
|
3156
|
+
assert.equal(embeds, 1, "a suppressed update must not skip a due embed");
|
|
3157
|
+
} finally {
|
|
3158
|
+
await scheduler.dispose();
|
|
3159
|
+
}
|
|
3160
|
+
});
|
|
3161
|
+
|
|
3162
|
+
test("requestQmdMaintenanceCompletion follows updateCompleted for backends with no strict update (Orama, LanceDB, Meilisearch, remote)", async () => {
|
|
3163
|
+
for (const completed of [true, false]) {
|
|
3164
|
+
let updates = 0;
|
|
3165
|
+
const backend: SearchBackend = Object.assign(Object.create(null), {
|
|
3166
|
+
isAvailable: () => true,
|
|
3167
|
+
// Fail-open like every non-QMD backend: resolves even when it returned early or failed.
|
|
3168
|
+
async update() {
|
|
3169
|
+
updates += 1;
|
|
3170
|
+
},
|
|
3171
|
+
async updateCompleted() {
|
|
3172
|
+
return completed;
|
|
3173
|
+
},
|
|
3174
|
+
async embed() {},
|
|
3175
|
+
});
|
|
3176
|
+
const scheduler = new MaintenanceScheduler({
|
|
3177
|
+
config: fixtureConfig({ namespacesEnabled: false, qmdAutoEmbedEnabled: false }),
|
|
3178
|
+
getQmd: () => backend,
|
|
3179
|
+
namespaceSearchRouter: Object.create(null),
|
|
3180
|
+
namespaceCatalog: Object.assign(Object.create(null), { enabled: false }),
|
|
3181
|
+
});
|
|
3182
|
+
try {
|
|
3183
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3184
|
+
await scheduler.runQmdMaintenance();
|
|
3185
|
+
assert.equal(await served, completed);
|
|
3186
|
+
assert.equal(updates, 0, "updateCompleted is the update, not an extra call after update()");
|
|
3187
|
+
} finally {
|
|
3188
|
+
await scheduler.dispose();
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
});
|
|
3192
|
+
|
|
3193
|
+
test("requestQmdMaintenanceCompletion is served by a real non-QMD backend (Orama) once its re-index completes", async () => {
|
|
3194
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-completion-orama-"));
|
|
3195
|
+
try {
|
|
3196
|
+
await mkdir(path.join(root, "facts"), { recursive: true });
|
|
3197
|
+
await writeFile(path.join(root, "facts", "fact.md"), "---\nid: mem-completion\n---\nA fact the re-index must cover.");
|
|
3198
|
+
const orama = new OramaBackend({
|
|
3199
|
+
dbPath: path.join(root, "orama-db"),
|
|
3200
|
+
collection: "openclaw-engram",
|
|
3201
|
+
embedHelper: new EmbedHelper(fixtureConfig({})),
|
|
3202
|
+
memoryDir: root,
|
|
3203
|
+
embeddingDimension: 4,
|
|
3204
|
+
});
|
|
3205
|
+
assert.equal(await orama.probe(), true);
|
|
3206
|
+
const scheduler = new MaintenanceScheduler({
|
|
3207
|
+
config: fixtureConfig({ namespacesEnabled: false, qmdAutoEmbedEnabled: false }),
|
|
3208
|
+
getQmd: () => orama,
|
|
3209
|
+
namespaceSearchRouter: Object.create(null),
|
|
3210
|
+
namespaceCatalog: Object.assign(Object.create(null), { enabled: false }),
|
|
3211
|
+
});
|
|
3212
|
+
try {
|
|
3213
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3214
|
+
await scheduler.runQmdMaintenance();
|
|
3215
|
+
assert.equal(await served, true);
|
|
3216
|
+
assert.equal((await orama.bm25Search("re-index")).some((r) => r.docid === "mem-completion"), true, "the pass indexed the corpus");
|
|
3217
|
+
} finally {
|
|
3218
|
+
await scheduler.dispose();
|
|
3219
|
+
}
|
|
3220
|
+
} finally {
|
|
3221
|
+
await rm(root, { recursive: true, force: true });
|
|
3222
|
+
}
|
|
3223
|
+
});
|
|
3224
|
+
|
|
3225
|
+
test("requestQmdMaintenanceCompletion resolves false when the backend became unavailable before the armed pass ran", async () => {
|
|
3226
|
+
const backend = { available: true };
|
|
3227
|
+
const scheduler = completionScheduler(backend);
|
|
3228
|
+
try {
|
|
3229
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3230
|
+
// The orchestrator swaps to a no-op backend when the collection goes missing;
|
|
3231
|
+
// that pass resolves without indexing anything, so it must not count as served.
|
|
3232
|
+
backend.available = false;
|
|
3233
|
+
await scheduler.runQmdMaintenance();
|
|
3234
|
+
assert.equal(await served, false);
|
|
3235
|
+
} finally {
|
|
3236
|
+
await scheduler.dispose();
|
|
3237
|
+
}
|
|
3238
|
+
});
|
|
3239
|
+
|
|
3240
|
+
test("requestQmdMaintenanceCompletion is served by the next pass when requested during an in-flight one", async () => {
|
|
3241
|
+
const release = Promise.withResolvers<void>();
|
|
3242
|
+
let updates = 0;
|
|
3243
|
+
const scheduler = completionScheduler({
|
|
3244
|
+
updateStrict: async () => {
|
|
3245
|
+
updates += 1;
|
|
3246
|
+
if (updates === 1) await release.promise;
|
|
3247
|
+
},
|
|
3248
|
+
});
|
|
3249
|
+
try {
|
|
3250
|
+
scheduler.requestQmdMaintenanceForTool("first");
|
|
3251
|
+
const firstPass = scheduler.runQmdMaintenance();
|
|
3252
|
+
// Requested while pass 1 is mid-flight: pass 1 started before this request's
|
|
3253
|
+
// rewrite landed, so only the NEXT pass may serve it.
|
|
3254
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3255
|
+
release.resolve();
|
|
3256
|
+
await firstPass;
|
|
3257
|
+
assert.equal(updates, 1);
|
|
3258
|
+
await scheduler.runQmdMaintenance();
|
|
3259
|
+
assert.equal(updates, 2, "the follow-up pass ran");
|
|
3260
|
+
assert.equal(await served, true);
|
|
3261
|
+
} finally {
|
|
3262
|
+
await scheduler.dispose();
|
|
3263
|
+
}
|
|
3264
|
+
});
|
|
3265
|
+
|
|
3266
|
+
test("requestQmdMaintenanceCompletion over namespaces: true only when a namespace ran and none failed", async () => {
|
|
3267
|
+
for (const outcome of [{ eligible: true, expected: true }, { eligible: false, expected: false }]) {
|
|
3268
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-qmd-completion-ns-"));
|
|
3269
|
+
const config = fixtureConfig({
|
|
3270
|
+
memoryDir,
|
|
3271
|
+
namespacesEnabled: true,
|
|
3272
|
+
defaultNamespace: "default",
|
|
3273
|
+
sharedNamespace: "shared",
|
|
3274
|
+
namespacePolicies: [],
|
|
3275
|
+
maintenanceNamespaceLockStaleMs: 100,
|
|
3276
|
+
qmdAutoEmbedEnabled: false,
|
|
3277
|
+
});
|
|
3278
|
+
const catalog: NamespaceCatalog = Object.assign(Object.create(null), {
|
|
3279
|
+
enabled: true,
|
|
3280
|
+
async listNamespaces() {
|
|
3281
|
+
return [{ namespace: "default" }];
|
|
3282
|
+
},
|
|
3283
|
+
async markMaintenance() {},
|
|
3284
|
+
});
|
|
3285
|
+
const router: NamespaceSearchRouter = Object.assign(Object.create(null), {
|
|
3286
|
+
async updateNamespacesDetailed(ns: string[]): Promise<NamespaceUpdateResult> {
|
|
3287
|
+
return outcome.eligible ? { backendCount: ns.length, eligibleNamespaces: ns } : { backendCount: 0, eligibleNamespaces: [] };
|
|
3288
|
+
},
|
|
3289
|
+
async embedNamespaces(): Promise<void> {},
|
|
3290
|
+
});
|
|
3291
|
+
const scheduler = buildScheduler({ config, catalog, router });
|
|
3292
|
+
try {
|
|
3293
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3294
|
+
await scheduler.runQmdMaintenance();
|
|
3295
|
+
assert.equal(await served, outcome.expected);
|
|
3296
|
+
} finally {
|
|
3297
|
+
await scheduler.dispose();
|
|
3298
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
});
|
|
3302
|
+
|
|
3303
|
+
test("requestQmdMaintenanceCompletion over namespaces: a permanent skip (branch_disabled) does not block serving", async () => {
|
|
3304
|
+
// A cataloged branch namespace is never maintained by default; that is a standing configuration,
|
|
3305
|
+
// not an unfinished pass, so the ran namespace must still serve the request.
|
|
3306
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-qmd-completion-permanent-"));
|
|
3307
|
+
const config = fixtureConfig({
|
|
3308
|
+
memoryDir,
|
|
3309
|
+
namespacesEnabled: true,
|
|
3310
|
+
defaultNamespace: "default",
|
|
3311
|
+
sharedNamespace: "shared",
|
|
3312
|
+
namespacePolicies: [],
|
|
3313
|
+
maintenanceNamespaceLockStaleMs: 100,
|
|
3314
|
+
qmdAutoEmbedEnabled: false,
|
|
3315
|
+
});
|
|
3316
|
+
const catalog: NamespaceCatalog = Object.assign(Object.create(null), {
|
|
3317
|
+
enabled: true,
|
|
3318
|
+
async listNamespaces() {
|
|
3319
|
+
return [{ namespace: "feature-x", kind: "branch" }];
|
|
3320
|
+
},
|
|
3321
|
+
async markMaintenance() {},
|
|
3322
|
+
});
|
|
3323
|
+
const router: NamespaceSearchRouter = Object.assign(Object.create(null), {
|
|
3324
|
+
async updateNamespacesDetailed(ns: string[]): Promise<NamespaceUpdateResult> {
|
|
3325
|
+
return { backendCount: ns.length, eligibleNamespaces: ns };
|
|
3326
|
+
},
|
|
3327
|
+
async embedNamespaces(): Promise<void> {},
|
|
3328
|
+
});
|
|
3329
|
+
const scheduler = buildScheduler({ config, catalog, router });
|
|
3330
|
+
try {
|
|
3331
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3332
|
+
await scheduler.runQmdMaintenance();
|
|
3333
|
+
assert.equal(await served, true);
|
|
3334
|
+
} finally {
|
|
3335
|
+
await scheduler.dispose();
|
|
3336
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
3337
|
+
}
|
|
3338
|
+
});
|
|
3339
|
+
|
|
3340
|
+
test("requestQmdMaintenanceCompletion over namespaces: more namespaces than the cycle budget: a later pass serves once all have run", async () => {
|
|
3341
|
+
// Four configured namespaces, a three-namespace cycle budget: three run, one is skipped
|
|
3342
|
+
// as budget_exhausted. That pass did not cover the whole selection, so it must not serve.
|
|
3343
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-qmd-completion-budget-"));
|
|
3344
|
+
const config = fixtureConfig({
|
|
3345
|
+
memoryDir,
|
|
3346
|
+
namespacesEnabled: true,
|
|
3347
|
+
defaultNamespace: "default",
|
|
3348
|
+
sharedNamespace: "shared",
|
|
3349
|
+
namespacePolicies: [{ name: "project-a" }, { name: "project-b" }],
|
|
3350
|
+
maintenanceNamespaceLockStaleMs: 100,
|
|
3351
|
+
qmdAutoEmbedEnabled: false,
|
|
3352
|
+
maintenanceMaxNamespacesPerCycle: 3,
|
|
3353
|
+
});
|
|
3354
|
+
const catalog: NamespaceCatalog = Object.assign(Object.create(null), {
|
|
3355
|
+
enabled: true,
|
|
3356
|
+
async listNamespaces() {
|
|
3357
|
+
return [{ namespace: "default" }];
|
|
3358
|
+
},
|
|
3359
|
+
async markMaintenance() {},
|
|
3360
|
+
});
|
|
3361
|
+
const router: NamespaceSearchRouter = Object.assign(Object.create(null), {
|
|
3362
|
+
async updateNamespacesDetailed(ns: string[]): Promise<NamespaceUpdateResult> {
|
|
3363
|
+
return { backendCount: ns.length, eligibleNamespaces: ns };
|
|
3364
|
+
},
|
|
3365
|
+
async embedNamespaces(): Promise<void> {},
|
|
3366
|
+
});
|
|
3367
|
+
const scheduler = buildScheduler({ config, catalog, router });
|
|
3368
|
+
try {
|
|
3369
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3370
|
+
let settled = false;
|
|
3371
|
+
void served.then(() => {
|
|
3372
|
+
settled = true;
|
|
3373
|
+
});
|
|
3374
|
+
await scheduler.runQmdMaintenance();
|
|
3375
|
+
await setImmediate();
|
|
3376
|
+
assert.equal(settled, false, "three ran, project-b was skipped as budget_exhausted: still owed");
|
|
3377
|
+
// The deferred request re-arms a pass; the planner rotates to the namespace that was skipped.
|
|
3378
|
+
await scheduler.runQmdMaintenance();
|
|
3379
|
+
assert.equal(await served, true, "every namespace has now run since the request");
|
|
3380
|
+
} finally {
|
|
3381
|
+
await scheduler.dispose();
|
|
3382
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
3383
|
+
}
|
|
3384
|
+
});
|
|
3385
|
+
|
|
3386
|
+
test("requestQmdMaintenanceCompletion over namespaces: a pass that adds no coverage ends the request unserved instead of re-arming forever", async () => {
|
|
3387
|
+
// Budget 1 with default and shared: default always ranks first, so shared never gets a turn.
|
|
3388
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-qmd-completion-budget-"));
|
|
3389
|
+
const config = fixtureConfig({
|
|
3390
|
+
memoryDir,
|
|
3391
|
+
namespacesEnabled: true,
|
|
3392
|
+
defaultNamespace: "default",
|
|
3393
|
+
sharedNamespace: "shared",
|
|
3394
|
+
namespacePolicies: [],
|
|
3395
|
+
maintenanceNamespaceLockStaleMs: 100,
|
|
3396
|
+
qmdAutoEmbedEnabled: false,
|
|
3397
|
+
maintenanceMaxNamespacesPerCycle: 1,
|
|
3398
|
+
});
|
|
3399
|
+
const catalog: NamespaceCatalog = Object.assign(Object.create(null), {
|
|
3400
|
+
enabled: true,
|
|
3401
|
+
async listNamespaces() {
|
|
3402
|
+
return [{ namespace: "default" }];
|
|
3403
|
+
},
|
|
3404
|
+
async markMaintenance() {},
|
|
3405
|
+
});
|
|
3406
|
+
const router: NamespaceSearchRouter = Object.assign(Object.create(null), {
|
|
3407
|
+
async updateNamespacesDetailed(ns: string[]): Promise<NamespaceUpdateResult> {
|
|
3408
|
+
return { backendCount: ns.length, eligibleNamespaces: ns };
|
|
3409
|
+
},
|
|
3410
|
+
async embedNamespaces(): Promise<void> {},
|
|
3411
|
+
});
|
|
3412
|
+
const scheduler = buildScheduler({ config, catalog, router });
|
|
3413
|
+
try {
|
|
3414
|
+
const served = scheduler.requestQmdMaintenanceCompletion();
|
|
3415
|
+
await scheduler.runQmdMaintenance();
|
|
3416
|
+
// Pass 1 covered default: progress, so the request stays waiting for another pass.
|
|
3417
|
+
assert.equal(scheduler.isQmdMaintenancePending(), true);
|
|
3418
|
+
await scheduler.runQmdMaintenance();
|
|
3419
|
+
// Pass 2 ran default again and added nothing: the request ends unserved and no pass is re-armed.
|
|
3420
|
+
assert.equal(await served, false);
|
|
3421
|
+
assert.equal(scheduler.isQmdMaintenancePending(), false);
|
|
3422
|
+
} finally {
|
|
3423
|
+
await scheduler.dispose();
|
|
3424
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
3425
|
+
}
|
|
3426
|
+
});
|