@modusensus/dsh-mneme 0.14.0-beta.1 → 0.14.0-beta.2
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/LICENSE +21 -21
- package/README.md +830 -830
- package/assets/icon.svg +3 -3
- package/bin/cli.mjs +964 -964
- package/bin/dsh-mneme-choro.mjs +262 -262
- package/bin/dsh-mneme-mcp.mjs +510 -510
- package/bin/dsh-mneme-serve.mjs +151 -151
- package/cordis.patch.yml +21 -21
- package/docs/CONFIGURATION.md +407 -404
- package/docs/CONTINUITY.md +139 -139
- package/docs/DAEMON.md +57 -57
- package/docs/DIRECTORIES.md +114 -114
- package/docs/DISTILL.md +397 -371
- package/docs/DSH-GO.md +97 -97
- package/docs/ENTITIES.md +247 -247
- package/docs/FORGET.md +77 -77
- package/docs/KB.md +110 -110
- package/docs/LOCAL_MODEL.md +222 -222
- package/docs/SEMANTIC.md +256 -256
- package/docs/SHARE.md +552 -552
- package/docs/SLEEP.md +202 -202
- package/docs/STORAGE.md +122 -122
- package/docs/WORKFLOWS.md +366 -366
- package/lib/api-standalone.js +1007 -1007
- package/lib/api.js +3600 -3600
- package/lib/attachment-text.js +122 -122
- package/lib/bootstrap-http.js +105 -105
- package/lib/bootstrap.js +215 -215
- package/lib/candidates.js +454 -454
- package/lib/capabilities.js +819 -819
- package/lib/choro-command.js +111 -111
- package/lib/client.js +14420 -14322
- package/lib/commands.js +95 -95
- package/lib/config-keys.js +144 -144
- package/lib/config.js +1361 -1344
- package/lib/content-hash.js +54 -54
- package/lib/continuity.js +258 -258
- package/lib/date-hint.js +32 -0
- package/lib/diary/auto.js +190 -190
- package/lib/diary/compose.js +440 -440
- package/lib/diary/dir.js +59 -59
- package/lib/diary/export.js +97 -97
- package/lib/diary/index.js +26 -26
- package/lib/diary/library.js +189 -189
- package/lib/diary/qq-inbox.js +142 -142
- package/lib/diary/rollover.js +61 -61
- package/lib/diary/session-provider.js +122 -122
- package/lib/document-index.js +94 -94
- package/lib/document.js +322 -322
- package/lib/dream/clustering.js +123 -123
- package/lib/dream/decisions.js +945 -945
- package/lib/dream/narratives.js +44 -44
- package/lib/dream/sleep.js +2027 -2027
- package/lib/dream/triage.js +139 -139
- package/lib/dream.js +1879 -1879
- package/lib/dsh-go/host.js +162 -162
- package/lib/dsh-go/panel.js +2091 -2091
- package/lib/dsh-go/text.js +342 -342
- package/lib/dsh-go/views/common.js +68 -68
- package/lib/dsh-go/views/entity.js +48 -48
- package/lib/dsh-go/views/memory.js +198 -198
- package/lib/dsh-go/views/root.js +30 -30
- package/lib/dsh-go/views/settings.js +398 -398
- package/lib/dsh-go/views/status.js +51 -51
- package/lib/embedding.js +342 -342
- package/lib/entities/extractor.js +285 -285
- package/lib/fence.js +24 -24
- package/lib/graph/anchoring.js +184 -184
- package/lib/guide.js +74 -74
- package/lib/heat.js +144 -144
- package/lib/hot-memory.js +119 -119
- package/lib/image-describe.js +158 -0
- package/lib/index.js +852 -852
- package/lib/inject.js +656 -651
- package/lib/kb/index.js +309 -309
- package/lib/kb/routes.js +219 -219
- package/lib/kb/tools.js +148 -148
- package/lib/lang.js +607 -595
- package/lib/local-embedder.js +358 -358
- package/lib/maintenance.js +162 -162
- package/lib/memory-source.js +9 -9
- package/lib/mirror.js +330 -330
- package/lib/organize.js +456 -456
- package/lib/peak-hours.js +172 -172
- package/lib/pipeline-activities.js +178 -178
- package/lib/pipeline-attribution.js +165 -165
- package/lib/pipeline-command.js +279 -279
- package/lib/pipeline-confirm.js +142 -142
- package/lib/pipeline-exec.js +174 -174
- package/lib/pipeline-nudge-auto.js +129 -129
- package/lib/pipeline-nudge.js +1623 -1623
- package/lib/pipeline-observations.js +181 -181
- package/lib/pipeline-observe.js +133 -133
- package/lib/pipeline-runner.js +361 -361
- package/lib/pipeline-runs.js +442 -442
- package/lib/pipeline.js +716 -716
- package/lib/placement.js +13 -13
- package/lib/pre-inject-gate.js +354 -354
- package/lib/profile-extract.js +164 -164
- package/lib/profile-facts.js +356 -356
- package/lib/provenance-http.js +251 -251
- package/lib/quality-filter.js +162 -162
- package/lib/recall-stats.js +190 -190
- package/lib/reclaim-http.js +150 -150
- package/lib/reranker.js +269 -269
- package/lib/runtime/adopt.js +176 -176
- package/lib/runtime/closure.js +172 -172
- package/lib/runtime/download.js +247 -247
- package/lib/runtime/layout.js +265 -265
- package/lib/runtime/loader.js +252 -252
- package/lib/runtime/model-fetch.js +361 -361
- package/lib/runtime/provision.js +237 -237
- package/lib/runtime/tarball.js +130 -130
- package/lib/runtime/verify.js +223 -223
- package/lib/safe-slice.js +18 -18
- package/lib/scope-state.js +277 -277
- package/lib/scope.js +187 -187
- package/lib/search/adaptive.js +60 -60
- package/lib/search/bm25.js +96 -96
- package/lib/semantic.js +572 -572
- package/lib/sensitive-scan.js +209 -209
- package/lib/serve.js +228 -228
- package/lib/service.js +3268 -3268
- package/lib/session-gate.js +91 -91
- package/lib/session-usage.js +350 -350
- package/lib/settings.js +827 -817
- package/lib/share-http.js +281 -281
- package/lib/share-import.js +234 -234
- package/lib/share.js +335 -335
- package/lib/store.js +5895 -5895
- package/lib/summarize.js +1388 -1343
- package/lib/tools.js +1370 -1356
- package/lib/user-settings.js +230 -230
- package/lib/vector-index.js +180 -180
- package/lib/version-check.js +122 -122
- package/lib/wiki/claims.js +267 -267
- package/lib/wiki/cli-hint.js +90 -90
- package/lib/wiki/inject.js +164 -164
- package/lib/wiki/partition.js +200 -200
- package/lib/wiki/plan.js +214 -214
- package/lib/wiki/queries.js +640 -640
- package/lib/wiki/render.js +261 -261
- package/lib/wiki/scan.js +371 -371
- package/lib/wiki/t0.js +500 -500
- package/lib/wiki/t1-jobs.js +232 -232
- package/lib/wiki/t1.js +609 -609
- package/lib/write-admission.js +404 -404
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +1 -1
- package/runtime-manifest.json +526 -526
- package/scripts/benchmark-embed.js +201 -201
- package/scripts/benchmark-recall.js +249 -249
- package/scripts/benchmark-rerank.js +166 -166
- package/scripts/build-runtime-manifest.mjs +224 -224
- package/scripts/changelog-prep.mjs +91 -91
- package/scripts/check-sync.js +44 -44
- package/scripts/e2e-dsh.js +220 -220
- package/scripts/mneme-runtime.mjs +277 -277
- package/scripts/publish-gate.mjs +197 -197
- package/scripts/release-docs.mjs +210 -210
- package/scripts/release-notes.mjs +164 -164
- package/scripts/stress-dsh.js +255 -255
- package/scripts/sync-lib.js +47 -47
- package/scripts/sync-test-badge.mjs +69 -69
- package/scripts/test-count-sync.mjs +48 -48
- package/src/api-standalone.js +1007 -1007
- package/src/api.js +3600 -3600
- package/src/attachment-text.js +122 -122
- package/src/bootstrap-http.js +105 -105
- package/src/bootstrap.js +215 -215
- package/src/candidates.js +454 -454
- package/src/capabilities.js +819 -819
- package/src/choro-command.js +111 -111
- package/src/commands.js +95 -95
- package/src/config-keys.js +144 -144
- package/src/config.js +1361 -1344
- package/src/content-hash.js +54 -54
- package/src/continuity.js +258 -258
- package/src/date-hint.js +32 -0
- package/src/diary/auto.js +190 -190
- package/src/diary/compose.js +440 -440
- package/src/diary/dir.js +59 -59
- package/src/diary/export.js +97 -97
- package/src/diary/index.js +26 -26
- package/src/diary/library.js +189 -189
- package/src/diary/qq-inbox.js +142 -142
- package/src/diary/rollover.js +61 -61
- package/src/diary/session-provider.js +122 -122
- package/src/document-index.js +94 -94
- package/src/document.js +322 -322
- package/src/dream/clustering.js +123 -123
- package/src/dream/decisions.js +945 -945
- package/src/dream/narratives.js +44 -44
- package/src/dream/sleep.js +2027 -2027
- package/src/dream/triage.js +139 -139
- package/src/dream.js +1879 -1879
- package/src/dsh-go/host.js +162 -162
- package/src/dsh-go/panel.js +2091 -2091
- package/src/dsh-go/text.js +342 -342
- package/src/dsh-go/views/common.js +68 -68
- package/src/dsh-go/views/entity.js +48 -48
- package/src/dsh-go/views/memory.js +198 -198
- package/src/dsh-go/views/root.js +30 -30
- package/src/dsh-go/views/settings.js +398 -398
- package/src/dsh-go/views/status.js +51 -51
- package/src/embedding.js +342 -342
- package/src/entities/extractor.js +285 -285
- package/src/fence.js +24 -24
- package/src/graph/anchoring.js +184 -184
- package/src/guide.js +74 -74
- package/src/heat.js +144 -144
- package/src/hot-memory.js +119 -119
- package/src/image-describe.js +158 -0
- package/src/index.js +852 -852
- package/src/inject.js +656 -651
- package/src/kb/index.js +309 -309
- package/src/kb/routes.js +219 -219
- package/src/kb/tools.js +148 -148
- package/src/lang.js +607 -595
- package/src/local-embedder.js +358 -358
- package/src/maintenance.js +162 -162
- package/src/memory-source.js +9 -9
- package/src/mirror.js +330 -330
- package/src/organize.js +456 -456
- package/src/peak-hours.js +172 -172
- package/src/pipeline-activities.js +178 -178
- package/src/pipeline-attribution.js +165 -165
- package/src/pipeline-command.js +279 -279
- package/src/pipeline-confirm.js +142 -142
- package/src/pipeline-exec.js +174 -174
- package/src/pipeline-nudge-auto.js +129 -129
- package/src/pipeline-nudge.js +1623 -1623
- package/src/pipeline-observations.js +181 -181
- package/src/pipeline-observe.js +133 -133
- package/src/pipeline-runner.js +361 -361
- package/src/pipeline-runs.js +442 -442
- package/src/pipeline.js +716 -716
- package/src/placement.js +13 -13
- package/src/pre-inject-gate.js +354 -354
- package/src/profile-extract.js +164 -164
- package/src/profile-facts.js +356 -356
- package/src/provenance-http.js +251 -251
- package/src/quality-filter.js +162 -162
- package/src/recall-stats.js +190 -190
- package/src/reclaim-http.js +150 -150
- package/src/reranker.js +269 -269
- package/src/runtime/adopt.js +176 -176
- package/src/runtime/closure.js +172 -172
- package/src/runtime/download.js +247 -247
- package/src/runtime/layout.js +265 -265
- package/src/runtime/loader.js +252 -252
- package/src/runtime/model-fetch.js +361 -361
- package/src/runtime/provision.js +237 -237
- package/src/runtime/tarball.js +130 -130
- package/src/runtime/verify.js +223 -223
- package/src/safe-slice.js +18 -18
- package/src/scope-state.js +277 -277
- package/src/scope.js +187 -187
- package/src/search/adaptive.js +60 -60
- package/src/search/bm25.js +96 -96
- package/src/semantic.js +572 -572
- package/src/sensitive-scan.js +209 -209
- package/src/serve.js +228 -228
- package/src/service.js +3268 -3268
- package/src/session-gate.js +91 -91
- package/src/session-usage.js +350 -350
- package/src/settings.js +827 -817
- package/src/share-http.js +281 -281
- package/src/share-import.js +234 -234
- package/src/share.js +335 -335
- package/src/store.js +5895 -5895
- package/src/summarize.js +1388 -1343
- package/src/tools.js +1370 -1356
- package/src/user-settings.js +230 -230
- package/src/vector-index.js +180 -180
- package/src/version-check.js +122 -122
- package/src/wiki/claims.js +267 -267
- package/src/wiki/cli-hint.js +90 -90
- package/src/wiki/inject.js +164 -164
- package/src/wiki/partition.js +200 -200
- package/src/wiki/plan.js +214 -214
- package/src/wiki/queries.js +640 -640
- package/src/wiki/render.js +261 -261
- package/src/wiki/scan.js +371 -371
- package/src/wiki/t0.js +500 -500
- package/src/wiki/t1-jobs.js +232 -232
- package/src/wiki/t1.js +609 -609
- package/src/write-admission.js +404 -404
- package/test/adaptive-inject-budget.test.js +85 -85
- package/test/api-hardening.test.js +173 -173
- package/test/api-nudge-route.test.js +259 -259
- package/test/api-routes-gaps.test.js +1092 -1092
- package/test/api.test.js +3007 -2998
- package/test/attachment-text.test.js +139 -139
- package/test/audit.test.js +448 -448
- package/test/baseline-persist.test.js +248 -248
- package/test/benchmark.test.js +94 -94
- package/test/bm25-corpus-cache.test.js +145 -145
- package/test/bootstrap.test.js +228 -228
- package/test/candidates.test.js +345 -345
- package/test/capabilities.test.js +577 -577
- package/test/capacity-warning.test.js +262 -262
- package/test/changelog-prep.test.js +125 -125
- package/test/choro-command.test.js +218 -218
- package/test/cli-enums.test.js +37 -37
- package/test/cli-flag-value.test.js +86 -86
- package/test/cli-receive.test.js +390 -390
- package/test/cli-share.test.js +437 -437
- package/test/client-share.test.js +225 -225
- package/test/client.test.js +4595 -4425
- package/test/clustering.test.js +100 -100
- package/test/commands.test.js +106 -106
- package/test/config-keys-routes.test.js +233 -233
- package/test/config.test.js +153 -153
- package/test/conflict-freeze.test.js +344 -344
- package/test/conflict-ledger-enforce.test.js +452 -452
- package/test/conflict-ledger.test.js +242 -242
- package/test/conflict-reviewed.test.js +79 -79
- package/test/content-hash.test.js +204 -204
- package/test/continuity.test.js +452 -452
- package/test/contrast.test.js +432 -432
- package/test/date-hint.test.js +156 -0
- package/test/dedupe-candidate-window.test.js +180 -180
- package/test/dependency-overrides.test.js +78 -78
- package/test/diary-library.test.js +187 -187
- package/test/diary.test.js +576 -576
- package/test/differentiate-feedback.test.js +248 -248
- package/test/distill-tx-embed-gap.test.js +110 -110
- package/test/docs-config-keys.test.js +65 -65
- package/test/document-dir.test.js +233 -233
- package/test/document.test.js +703 -703
- package/test/dream-archive-guardrail.test.js +116 -116
- package/test/dream-baseline-clamp.test.js +174 -174
- package/test/dream-candidate-hybrid.test.js +281 -281
- package/test/dream-coverage-degrade.test.js +86 -86
- package/test/dream-decision-evidence.test.js +314 -314
- package/test/dream-failure-backoff.test.js +173 -173
- package/test/dream-fence.test.js +207 -207
- package/test/dream-maxtokens-fallback.test.js +132 -132
- package/test/dream-merge-guardrail.test.js +219 -219
- package/test/dream-peak-hours.test.js +194 -194
- package/test/dream.test.js +1528 -1528
- package/test/dsh-go-host.test.js +134 -134
- package/test/dsh-go-panel-actions.test.js +854 -854
- package/test/dsh-go-panel.test.js +251 -251
- package/test/embed-ready-poll.test.js +94 -94
- package/test/embed-text-reasons.test.js +112 -112
- package/test/embedding-cache-f32.test.js +276 -276
- package/test/embedding-ready.test.js +226 -226
- package/test/entities.test.js +711 -711
- package/test/entity-recall.test.js +179 -179
- package/test/epistemic.test.js +325 -325
- package/test/failure-query.test.js +147 -147
- package/test/failure-retention.test.js +105 -105
- package/test/fnew-0112.test.js +311 -311
- package/test/fnew-03.test.js +422 -422
- package/test/forget-corrections.test.js +70 -70
- package/test/graph-anchoring.test.js +184 -184
- package/test/graph-api.test.js +333 -333
- package/test/graph-boosted-relations.test.js +189 -189
- package/test/graph-inject-budget.test.js +103 -103
- package/test/graph-multipath.test.js +269 -269
- package/test/graph-passive-confirm.test.js +91 -91
- package/test/graph-weight-evolution.test.js +104 -104
- package/test/heat.test.js +175 -175
- package/test/helpers/dream-mock.js +86 -86
- package/test/helpers/peer-worker.mjs +25 -25
- package/test/helpers/runtime-source.js +60 -60
- package/test/helpers/tar-builder.js +80 -80
- package/test/helpers/write-admission-samples.js +312 -312
- package/test/hot-memory.test.js +259 -259
- package/test/image-description.test.js +271 -0
- package/test/image-memory.test.js +170 -170
- package/test/inject-content-cap.test.js +91 -91
- package/test/inject-first-round-bm25.test.js +89 -89
- package/test/inject-heat.test.js +77 -77
- package/test/inject-parent-gate.test.js +134 -109
- package/test/inject-pin-explicit.test.js +300 -300
- package/test/inject-pin-vector-crowd.test.js +225 -225
- package/test/inject-pools.test.js +195 -195
- package/test/inject-recall.test.js +172 -172
- package/test/inject-rotation.test.js +161 -161
- package/test/inject.test.js +553 -553
- package/test/issue-617-step1-query-and-fusion.test.js +361 -361
- package/test/kb-api-wiring.test.js +128 -128
- package/test/kb-collections.test.js +272 -272
- package/test/kb-routes.test.js +379 -379
- package/test/lang.test.js +98 -98
- package/test/lastrunat-persist.test.js +101 -101
- package/test/lib-smoke.test.js +116 -116
- package/test/llm-audit.test.js +815 -815
- package/test/llm-message-source.test.js +207 -207
- package/test/local-embedder.test.js +292 -292
- package/test/maintenance.test.js +501 -501
- package/test/mcp-stdio.test.js +385 -385
- package/test/mint-source.test.js +311 -311
- package/test/mirror-dirty.test.js +424 -424
- package/test/mirror-edit-digest.test.js +187 -187
- package/test/mirror-generation.test.js +499 -499
- package/test/mirror-types.test.js +208 -208
- package/test/mirror.test.js +249 -249
- package/test/narrative-bars.test.js +162 -162
- package/test/organize-tool.test.js +232 -232
- package/test/organize.test.js +418 -418
- package/test/panel-chart-scale.test.js +90 -90
- package/test/panel-tokens.test.js +245 -245
- package/test/peak-hours-observability.test.js +70 -70
- package/test/peer-blockers.test.js +193 -193
- package/test/persona-addressing.test.js +83 -83
- package/test/persona-api.test.js +172 -172
- package/test/persona-by-session.test.js +568 -568
- package/test/persona-flag.test.js +36 -36
- package/test/persona-inject.test.js +145 -145
- package/test/persona-settings.test.js +198 -198
- package/test/pipeline-activities.test.js +155 -155
- package/test/pipeline-attribution.test.js +175 -175
- package/test/pipeline-command.test.js +243 -243
- package/test/pipeline-confirm.test.js +148 -148
- package/test/pipeline-exec.test.js +172 -172
- package/test/pipeline-nudge-auto.test.js +248 -248
- package/test/pipeline-nudge.test.js +1278 -1278
- package/test/pipeline-observations.test.js +157 -157
- package/test/pipeline-observe.test.js +127 -127
- package/test/pipeline-r1r2.test.js +278 -278
- package/test/pipeline-runner.test.js +468 -468
- package/test/pipeline-runs.test.js +767 -767
- package/test/pipeline.test.js +636 -636
- package/test/placement.test.js +36 -36
- package/test/policy-epoch.test.js +259 -259
- package/test/pre-inject-gate.test.js +444 -444
- package/test/profile-extract.test.js +269 -269
- package/test/profile-facts.test.js +492 -492
- package/test/prompt-stance.test.js +128 -128
- package/test/provenance-http.test.js +367 -367
- package/test/publish-gate.test.js +272 -272
- package/test/quality-backfill.test.js +290 -290
- package/test/quality-filter.test.js +295 -295
- package/test/readme-claims.test.js +113 -113
- package/test/reasoning-effort.test.js +752 -752
- package/test/recall-anti-update.test.js +82 -82
- package/test/recall-evals.test.js +253 -253
- package/test/recall-layer.test.js +326 -326
- package/test/recall-retention.test.js +128 -128
- package/test/recall-stats.test.js +274 -274
- package/test/receipt-chain.test.js +451 -451
- package/test/reclaim-http.test.js +209 -209
- package/test/reflection-update-gate.test.js +129 -129
- package/test/reflection.test.js +226 -226
- package/test/reindex-backfill.test.js +475 -475
- package/test/reindex-scheduler.test.js +369 -369
- package/test/release-docs.test.js +156 -156
- package/test/release-notes.test.js +265 -265
- package/test/release-workflow.test.js +93 -93
- package/test/reranker-single-logit.test.js +73 -73
- package/test/reranker.test.js +197 -197
- package/test/resident-status.test.js +83 -83
- package/test/route-policy.test.js +113 -113
- package/test/runtime-adopt.test.js +206 -206
- package/test/runtime-cli.test.js +89 -89
- package/test/runtime-closure.test.js +193 -193
- package/test/runtime-download.test.js +302 -302
- package/test/runtime-layout.test.js +163 -163
- package/test/runtime-loader.test.js +255 -255
- package/test/runtime-manifest.test.js +159 -159
- package/test/runtime-model-fetch.test.js +348 -348
- package/test/runtime-provision.test.js +101 -101
- package/test/runtime-tarball.test.js +81 -81
- package/test/runtime-verify.test.js +319 -319
- package/test/scope-candidates.test.js +491 -491
- package/test/scope-distill-stamp.test.js +134 -134
- package/test/scope-explicit.test.js +452 -452
- package/test/scope-inject-soft.test.js +106 -106
- package/test/scope-optional-service.test.js +110 -110
- package/test/scope-retrieval.test.js +197 -197
- package/test/scope-state.test.js +610 -610
- package/test/scope-storage.test.js +255 -255
- package/test/scope-strict.test.js +367 -367
- package/test/search-fusion.test.js +90 -90
- package/test/security-doc.test.js +188 -188
- package/test/semantic.test.js +124 -124
- package/test/sensitive-scan.test.js +251 -251
- package/test/serve-bin.test.js +121 -121
- package/test/serve.test.js +258 -258
- package/test/service-search.test.js +174 -174
- package/test/service.test.js +410 -410
- package/test/session-gate.test.js +264 -264
- package/test/session-usage.test.js +317 -317
- package/test/settings.test.js +273 -273
- package/test/share-foreign-rows.test.js +144 -144
- package/test/share-http.test.js +144 -144
- package/test/share-import.test.js +577 -577
- package/test/share-imported-guard.test.js +311 -311
- package/test/share-imported-identity.test.js +111 -111
- package/test/share-pack.test.js +511 -511
- package/test/share-receive-http.test.js +756 -756
- package/test/share-routes.test.js +337 -337
- package/test/share-store.test.js +133 -133
- package/test/share-validate.test.js +101 -101
- package/test/skip-invalid-restore.test.js +262 -262
- package/test/sleep-action-set.test.js +441 -441
- package/test/sleep-catchup.test.js +315 -315
- package/test/sleep-failure-backoff.test.js +156 -156
- package/test/sleep-heat.test.js +174 -174
- package/test/sleep-scheduler-rearm.test.js +89 -89
- package/test/sleep.test.js +1455 -1455
- package/test/standalone-api.test.js +1344 -1344
- package/test/store-vector-cache.test.js +98 -98
- package/test/store-write-path-columns.test.js +191 -191
- package/test/store.test.js +744 -744
- package/test/stress.test.js +209 -209
- package/test/summarize-occurred-at.test.js +127 -127
- package/test/summarize-parse-diagnostics.test.js +75 -75
- package/test/summarize-reasoning-effort.test.js +189 -189
- package/test/summarize.test.js +2251 -2251
- package/test/supersede-state-tracking.test.js +394 -394
- package/test/test-count-sync.test.js +71 -71
- package/test/tool-state-ignore.test.js +65 -65
- package/test/tools-dto-schema-matrix.test.js +398 -398
- package/test/tools-memory-get-schema.test.js +65 -65
- package/test/tools.test.js +585 -585
- package/test/updated-at-semantics.test.js +113 -113
- package/test/user-settings-preview.test.js +127 -127
- package/test/user-settings-segments.test.js +527 -527
- package/test/vector-index.test.js +334 -334
- package/test/version-check.test.js +152 -152
- package/test/webServer-optional.test.js +82 -82
- package/test/wiki-api.test.js +734 -734
- package/test/wiki-claims.test.js +194 -194
- package/test/wiki-cli-hint.test.js +118 -118
- package/test/wiki-inject.test.js +265 -265
- package/test/wiki-partition.test.js +112 -112
- package/test/wiki-plan.test.js +80 -80
- package/test/wiki-provenance.test.js +202 -202
- package/test/wiki-queries.test.js +398 -398
- package/test/wiki-scan.test.js +208 -208
- package/test/wiki-store.test.js +190 -190
- package/test/wiki-t0.test.js +456 -456
- package/test/wiki-t1-jobs.test.js +125 -125
- package/test/wiki-t1.test.js +460 -460
- package/test/wiki-tools.test.js +176 -176
- package/test/workflow-guards.test.js +155 -155
- package/test/write-admission.test.js +668 -668
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { createStore } from "../src/store.js";
|
|
4
|
-
import { createService } from "../src/service.js";
|
|
5
|
-
import { createTools } from "../src/tools.js";
|
|
6
|
-
|
|
7
|
-
// v0.9.0:failure_memories.query 的起点是 2,367 行里只有 69 行非空(2.9%)。
|
|
8
|
-
// 但那个分母误导——按「expected 逐字落在某次 dream_runs.decisions 里」归属后
|
|
9
|
-
// (2026-10-14 实测,D:/DSH/.dsh/memory/memory.db):
|
|
10
|
-
// dream 侧 2,118 行,query 非空率 0.0%——机器巩固没有用户在场,本该为空;
|
|
11
|
-
// 入口侧 249 行,query 非空率 27.7%——模型自愿填 reason 的那部分。
|
|
12
|
-
// 所以要修的是入口侧,不是 dream 侧。
|
|
13
|
-
//
|
|
14
|
-
// 修法:工具层是唯一同时握着「改写动作」与「本轮会话」的入口(service 层只认
|
|
15
|
-
// ctx.query,见 src/service.js updateMemory 内的 saveFailure 调用)。调用方没给
|
|
16
|
-
// reason 时,工具自己去会话里取当轮用户原话——与注入侧共用同一份实现
|
|
17
|
-
// (src/inject.js 的 lastUserQuery),不复制第二份。
|
|
18
|
-
//
|
|
19
|
-
// 本文件锁三件事:① 没给 reason 时真的落到原话;② 给了 reason 不被覆盖;
|
|
20
|
-
// ③ 两边都取不到时写 NULL 而不是空串——空串会假装「有意图」,NULL 才说实话。
|
|
21
|
-
|
|
22
|
-
function setup(config = {}) {
|
|
23
|
-
const store = createStore(":memory:");
|
|
24
|
-
const service = createService({
|
|
25
|
-
store,
|
|
26
|
-
mirror: null,
|
|
27
|
-
config: { reflectionFailureTracking: true, ...config }
|
|
28
|
-
});
|
|
29
|
-
const registered = [];
|
|
30
|
-
const ctx = { tools: { register(def) { registered.push(def); return () => {}; } } };
|
|
31
|
-
createTools(ctx, service, config, null);
|
|
32
|
-
const tool = (name) => registered.find((def) => def.name === name);
|
|
33
|
-
return { store, service, tool };
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const seed = (store) => store.save({ type: "preference", title: "语言", content: "喜欢 Python", importance: 3 });
|
|
37
|
-
|
|
38
|
-
/** exec 形状与宿主一致:工具 execute 的第二个参数(src/tools.js 里的 arguments[1])。 */
|
|
39
|
-
const execWith = (events, extra = {}) => ({
|
|
40
|
-
agent: { session: { id: "s-failure-query", snapshotEvents: () => events, ...extra } }
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const userMessage = (text, seq) => ({
|
|
44
|
-
type: "user/message",
|
|
45
|
-
...(seq === undefined ? {} : { seq }),
|
|
46
|
-
data: { source: { kind: "user" }, content: [{ type: "text", text }] }
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const assistantMessage = (text, seq) => ({
|
|
50
|
-
type: "assistant/message",
|
|
51
|
-
...(seq === undefined ? {} : { seq }),
|
|
52
|
-
data: { message: { content: [{ type: "text", text }] } }
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const run = (def, args, exec) => def.execute.bind(def)(args, exec);
|
|
56
|
-
|
|
57
|
-
test("memory_update 没给 reason 时,query 落当轮用户原话", async () => {
|
|
58
|
-
const { store, tool } = setup();
|
|
59
|
-
const mem = seed(store);
|
|
60
|
-
await run(
|
|
61
|
-
tool("memory_update"),
|
|
62
|
-
{ id: mem.id, content: "喜欢 Rust" },
|
|
63
|
-
execWith([userMessage("不对,我喜欢的是 Rust,不是 Python")])
|
|
64
|
-
);
|
|
65
|
-
const [row] = store.listFailures();
|
|
66
|
-
assert.equal(row.query, "不对,我喜欢的是 Rust,不是 Python");
|
|
67
|
-
// expected/actual 语义未变:expected = 改成了什么,actual = 原本是什么。
|
|
68
|
-
assert.equal(row.expected, "喜欢 Rust");
|
|
69
|
-
assert.equal(row.actual, "喜欢 Python");
|
|
70
|
-
assert.equal(row.failure_type, "user_correction");
|
|
71
|
-
assert.equal(row.memory_id, mem.id);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test("memory_update 给了 reason 就用 reason,不被会话原话顶掉", async () => {
|
|
75
|
-
const { store, tool } = setup();
|
|
76
|
-
const mem = seed(store);
|
|
77
|
-
await run(
|
|
78
|
-
tool("memory_update"),
|
|
79
|
-
{ id: mem.id, content: "喜欢 Rust", reason: "用户说:换成 Rust" },
|
|
80
|
-
execWith([userMessage("这句是当轮原话,但调用方已经说清了理由")])
|
|
81
|
-
);
|
|
82
|
-
assert.equal(store.listFailures()[0].query, "用户说:换成 Rust");
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test("reason 是空白串时按「没给」处理,退回会话原话", async () => {
|
|
86
|
-
const { store, tool } = setup();
|
|
87
|
-
const mem = seed(store);
|
|
88
|
-
// 与 api-standalone 的 PUT /memories/:id 同口径(body.reason.trim() 为空即视作未提供)。
|
|
89
|
-
await run(
|
|
90
|
-
tool("memory_update"),
|
|
91
|
-
{ id: mem.id, content: "喜欢 Rust", reason: " " },
|
|
92
|
-
execWith([userMessage("换成 Rust 吧")])
|
|
93
|
-
);
|
|
94
|
-
assert.equal(store.listFailures()[0].query, "换成 Rust 吧");
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("两边都取不到时写 NULL,不写空串(空串会假装有意图)", async () => {
|
|
98
|
-
const { store, tool } = setup();
|
|
99
|
-
const mem = seed(store);
|
|
100
|
-
// 会话里只有助手消息 → 取不到「用户原话」。
|
|
101
|
-
await run(tool("memory_update"), { id: mem.id, content: "喜欢 Rust" }, execWith([assistantMessage("好的")]));
|
|
102
|
-
assert.equal(store.listFailures()[0].query, null);
|
|
103
|
-
|
|
104
|
-
// 完全没有 exec(老宿主 / 直调)→ 同样 NULL,不抛。
|
|
105
|
-
const mem2 = store.save({ type: "preference", title: "编辑器", content: "vim", importance: 3 });
|
|
106
|
-
await run(tool("memory_update"), { id: mem2.id, content: "emacs" });
|
|
107
|
-
assert.equal(store.listFailures()[1].query, null);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test("被撤回/压缩遮蔽的用户消息不算当轮原话(复用注入侧同一份实现)", async () => {
|
|
111
|
-
const { store, tool } = setup();
|
|
112
|
-
const mem = seed(store);
|
|
113
|
-
// seq 1 被 rewind 遮蔽(surface.nodes 只暴露 2)——同 inject.js visibleSeqsOf 口径。
|
|
114
|
-
// 这条同时锁住「没有抄第二份实现」:naive 的副本会漏掉可见面过滤。
|
|
115
|
-
const events = [userMessage("我想撤回的那句话", 1), assistantMessage("好", 2)];
|
|
116
|
-
await run(
|
|
117
|
-
tool("memory_update"),
|
|
118
|
-
{ id: mem.id, content: "喜欢 Rust" },
|
|
119
|
-
execWith(events, { surface: { nodes: [2] } })
|
|
120
|
-
);
|
|
121
|
-
assert.equal(store.listFailures()[0].query, null, "被遮蔽的消息不许当成原话");
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
test("会话内部读不出来时退化为 NULL,不让改写本身失败", async () => {
|
|
125
|
-
const { store, tool } = setup();
|
|
126
|
-
const mem = seed(store);
|
|
127
|
-
// 宿主 getter 抛错(cordis Proxy 裸读未 inject 属性)——lastUserQuery 的 catch 兜住。
|
|
128
|
-
const exec = {
|
|
129
|
-
agent: {
|
|
130
|
-
get session() {
|
|
131
|
-
throw new Error("not injected");
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
await run(tool("memory_update"), { id: mem.id, content: "喜欢 Rust" }, exec);
|
|
136
|
-
const [row] = store.listFailures();
|
|
137
|
-
assert.equal(row.query, null);
|
|
138
|
-
assert.equal(row.expected, "喜欢 Rust", "改写本身照常完成");
|
|
139
|
-
assert.equal(store.getById(mem.id).content, "喜欢 Rust");
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
test("过长的原话按注入侧同一上限截断(不是各截各的)", async () => {
|
|
143
|
-
const { store, tool } = setup();
|
|
144
|
-
const mem = seed(store);
|
|
145
|
-
await run(tool("memory_update"), { id: mem.id, content: "喜欢 Rust" }, execWith([userMessage("长".repeat(900))]));
|
|
146
|
-
assert.equal(store.listFailures()[0].query.length, 500, "safeSlice(…, 500) 与注入侧一致");
|
|
147
|
-
});
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { createStore } from "../src/store.js";
|
|
4
|
+
import { createService } from "../src/service.js";
|
|
5
|
+
import { createTools } from "../src/tools.js";
|
|
6
|
+
|
|
7
|
+
// v0.9.0:failure_memories.query 的起点是 2,367 行里只有 69 行非空(2.9%)。
|
|
8
|
+
// 但那个分母误导——按「expected 逐字落在某次 dream_runs.decisions 里」归属后
|
|
9
|
+
// (2026-10-14 实测,D:/DSH/.dsh/memory/memory.db):
|
|
10
|
+
// dream 侧 2,118 行,query 非空率 0.0%——机器巩固没有用户在场,本该为空;
|
|
11
|
+
// 入口侧 249 行,query 非空率 27.7%——模型自愿填 reason 的那部分。
|
|
12
|
+
// 所以要修的是入口侧,不是 dream 侧。
|
|
13
|
+
//
|
|
14
|
+
// 修法:工具层是唯一同时握着「改写动作」与「本轮会话」的入口(service 层只认
|
|
15
|
+
// ctx.query,见 src/service.js updateMemory 内的 saveFailure 调用)。调用方没给
|
|
16
|
+
// reason 时,工具自己去会话里取当轮用户原话——与注入侧共用同一份实现
|
|
17
|
+
// (src/inject.js 的 lastUserQuery),不复制第二份。
|
|
18
|
+
//
|
|
19
|
+
// 本文件锁三件事:① 没给 reason 时真的落到原话;② 给了 reason 不被覆盖;
|
|
20
|
+
// ③ 两边都取不到时写 NULL 而不是空串——空串会假装「有意图」,NULL 才说实话。
|
|
21
|
+
|
|
22
|
+
function setup(config = {}) {
|
|
23
|
+
const store = createStore(":memory:");
|
|
24
|
+
const service = createService({
|
|
25
|
+
store,
|
|
26
|
+
mirror: null,
|
|
27
|
+
config: { reflectionFailureTracking: true, ...config }
|
|
28
|
+
});
|
|
29
|
+
const registered = [];
|
|
30
|
+
const ctx = { tools: { register(def) { registered.push(def); return () => {}; } } };
|
|
31
|
+
createTools(ctx, service, config, null);
|
|
32
|
+
const tool = (name) => registered.find((def) => def.name === name);
|
|
33
|
+
return { store, service, tool };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const seed = (store) => store.save({ type: "preference", title: "语言", content: "喜欢 Python", importance: 3 });
|
|
37
|
+
|
|
38
|
+
/** exec 形状与宿主一致:工具 execute 的第二个参数(src/tools.js 里的 arguments[1])。 */
|
|
39
|
+
const execWith = (events, extra = {}) => ({
|
|
40
|
+
agent: { session: { id: "s-failure-query", snapshotEvents: () => events, ...extra } }
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const userMessage = (text, seq) => ({
|
|
44
|
+
type: "user/message",
|
|
45
|
+
...(seq === undefined ? {} : { seq }),
|
|
46
|
+
data: { source: { kind: "user" }, content: [{ type: "text", text }] }
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const assistantMessage = (text, seq) => ({
|
|
50
|
+
type: "assistant/message",
|
|
51
|
+
...(seq === undefined ? {} : { seq }),
|
|
52
|
+
data: { message: { content: [{ type: "text", text }] } }
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const run = (def, args, exec) => def.execute.bind(def)(args, exec);
|
|
56
|
+
|
|
57
|
+
test("memory_update 没给 reason 时,query 落当轮用户原话", async () => {
|
|
58
|
+
const { store, tool } = setup();
|
|
59
|
+
const mem = seed(store);
|
|
60
|
+
await run(
|
|
61
|
+
tool("memory_update"),
|
|
62
|
+
{ id: mem.id, content: "喜欢 Rust" },
|
|
63
|
+
execWith([userMessage("不对,我喜欢的是 Rust,不是 Python")])
|
|
64
|
+
);
|
|
65
|
+
const [row] = store.listFailures();
|
|
66
|
+
assert.equal(row.query, "不对,我喜欢的是 Rust,不是 Python");
|
|
67
|
+
// expected/actual 语义未变:expected = 改成了什么,actual = 原本是什么。
|
|
68
|
+
assert.equal(row.expected, "喜欢 Rust");
|
|
69
|
+
assert.equal(row.actual, "喜欢 Python");
|
|
70
|
+
assert.equal(row.failure_type, "user_correction");
|
|
71
|
+
assert.equal(row.memory_id, mem.id);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("memory_update 给了 reason 就用 reason,不被会话原话顶掉", async () => {
|
|
75
|
+
const { store, tool } = setup();
|
|
76
|
+
const mem = seed(store);
|
|
77
|
+
await run(
|
|
78
|
+
tool("memory_update"),
|
|
79
|
+
{ id: mem.id, content: "喜欢 Rust", reason: "用户说:换成 Rust" },
|
|
80
|
+
execWith([userMessage("这句是当轮原话,但调用方已经说清了理由")])
|
|
81
|
+
);
|
|
82
|
+
assert.equal(store.listFailures()[0].query, "用户说:换成 Rust");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("reason 是空白串时按「没给」处理,退回会话原话", async () => {
|
|
86
|
+
const { store, tool } = setup();
|
|
87
|
+
const mem = seed(store);
|
|
88
|
+
// 与 api-standalone 的 PUT /memories/:id 同口径(body.reason.trim() 为空即视作未提供)。
|
|
89
|
+
await run(
|
|
90
|
+
tool("memory_update"),
|
|
91
|
+
{ id: mem.id, content: "喜欢 Rust", reason: " " },
|
|
92
|
+
execWith([userMessage("换成 Rust 吧")])
|
|
93
|
+
);
|
|
94
|
+
assert.equal(store.listFailures()[0].query, "换成 Rust 吧");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("两边都取不到时写 NULL,不写空串(空串会假装有意图)", async () => {
|
|
98
|
+
const { store, tool } = setup();
|
|
99
|
+
const mem = seed(store);
|
|
100
|
+
// 会话里只有助手消息 → 取不到「用户原话」。
|
|
101
|
+
await run(tool("memory_update"), { id: mem.id, content: "喜欢 Rust" }, execWith([assistantMessage("好的")]));
|
|
102
|
+
assert.equal(store.listFailures()[0].query, null);
|
|
103
|
+
|
|
104
|
+
// 完全没有 exec(老宿主 / 直调)→ 同样 NULL,不抛。
|
|
105
|
+
const mem2 = store.save({ type: "preference", title: "编辑器", content: "vim", importance: 3 });
|
|
106
|
+
await run(tool("memory_update"), { id: mem2.id, content: "emacs" });
|
|
107
|
+
assert.equal(store.listFailures()[1].query, null);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("被撤回/压缩遮蔽的用户消息不算当轮原话(复用注入侧同一份实现)", async () => {
|
|
111
|
+
const { store, tool } = setup();
|
|
112
|
+
const mem = seed(store);
|
|
113
|
+
// seq 1 被 rewind 遮蔽(surface.nodes 只暴露 2)——同 inject.js visibleSeqsOf 口径。
|
|
114
|
+
// 这条同时锁住「没有抄第二份实现」:naive 的副本会漏掉可见面过滤。
|
|
115
|
+
const events = [userMessage("我想撤回的那句话", 1), assistantMessage("好", 2)];
|
|
116
|
+
await run(
|
|
117
|
+
tool("memory_update"),
|
|
118
|
+
{ id: mem.id, content: "喜欢 Rust" },
|
|
119
|
+
execWith(events, { surface: { nodes: [2] } })
|
|
120
|
+
);
|
|
121
|
+
assert.equal(store.listFailures()[0].query, null, "被遮蔽的消息不许当成原话");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("会话内部读不出来时退化为 NULL,不让改写本身失败", async () => {
|
|
125
|
+
const { store, tool } = setup();
|
|
126
|
+
const mem = seed(store);
|
|
127
|
+
// 宿主 getter 抛错(cordis Proxy 裸读未 inject 属性)——lastUserQuery 的 catch 兜住。
|
|
128
|
+
const exec = {
|
|
129
|
+
agent: {
|
|
130
|
+
get session() {
|
|
131
|
+
throw new Error("not injected");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
await run(tool("memory_update"), { id: mem.id, content: "喜欢 Rust" }, exec);
|
|
136
|
+
const [row] = store.listFailures();
|
|
137
|
+
assert.equal(row.query, null);
|
|
138
|
+
assert.equal(row.expected, "喜欢 Rust", "改写本身照常完成");
|
|
139
|
+
assert.equal(store.getById(mem.id).content, "喜欢 Rust");
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("过长的原话按注入侧同一上限截断(不是各截各的)", async () => {
|
|
143
|
+
const { store, tool } = setup();
|
|
144
|
+
const mem = seed(store);
|
|
145
|
+
await run(tool("memory_update"), { id: mem.id, content: "喜欢 Rust" }, execWith([userMessage("长".repeat(900))]));
|
|
146
|
+
assert.equal(store.listFailures()[0].query.length, 500, "safeSlice(…, 500) 与注入侧一致");
|
|
147
|
+
});
|
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { Config } from "../src/config.js";
|
|
7
|
-
import { createStore } from "../src/store.js";
|
|
8
|
-
|
|
9
|
-
// 与 test/recall-retention.test.js 同款,这组测试故意分两半,因为弄丢的正是「两半
|
|
10
|
-
// 都在」:
|
|
11
|
-
// 1. 行为锁——deleteOldFailures 真的删对行、比较方向正确、空表不炸。
|
|
12
|
-
// 2. 接线锁——src/index.js 的启动块真的调它,且读的是装配后的 cfg。第二半用源码
|
|
13
|
-
// 文本断言,理由与 test/client.test.js 的 bilingual 锁同款:启动期清理只在运维
|
|
14
|
-
// 时才会跑到,运行时冒烟测不到「这一行被挪回装配之前了」。
|
|
15
|
-
//
|
|
16
|
-
// 这一批补的是「写死」这条欠账:failure_memories 的清理此前排在 createStore 之后、
|
|
17
|
-
// cfg 装配之前,天数硬编码 90,是四张启动期清理表里唯一没有键可陈述的一张。
|
|
18
|
-
|
|
19
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
20
|
-
const srcText = (name) => readFileSync(join(here, "..", "src", name), "utf8");
|
|
21
|
-
const daysAgo = (n) => new Date(Date.now() - n * 86400000).toISOString();
|
|
22
|
-
|
|
23
|
-
// saveFailure 只认当前时刻,所以插进去之后把 created_at 改写成指定时刻。
|
|
24
|
-
function seedFailure(store, createdAt, id) {
|
|
25
|
-
store.saveFailure({ id, failure_type: "user_correction", expected: "新值", actual: "旧值" });
|
|
26
|
-
store.db.prepare("UPDATE failure_memories SET created_at = ? WHERE id = ?").run(createdAt, id);
|
|
27
|
-
return id;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
test("deleteOldFailures 删掉窗口外的行、留下窗口内的行", () => {
|
|
31
|
-
const store = createStore(":memory:");
|
|
32
|
-
seedFailure(store, daysAgo(200), "old-1");
|
|
33
|
-
seedFailure(store, daysAgo(120), "old-2");
|
|
34
|
-
seedFailure(store, daysAgo(10), "fresh-1");
|
|
35
|
-
seedFailure(store, daysAgo(1), "fresh-2");
|
|
36
|
-
|
|
37
|
-
assert.equal(store.listFailures().length, 4);
|
|
38
|
-
const removed = store.deleteOldFailures(daysAgo(90));
|
|
39
|
-
assert.equal(removed, 2);
|
|
40
|
-
// assert 的是留下了哪两行,不是物理顺序
|
|
41
|
-
assert.deepEqual(store.listFailures().map((r) => r.id).sort(), ["fresh-1", "fresh-2"]);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("边界两侧各留 1 小时裕量:锁的是比较方向不是毫秒级巧合", () => {
|
|
45
|
-
const store = createStore(":memory:");
|
|
46
|
-
const boundary = 90 * 86400000;
|
|
47
|
-
// cutoff 是在清理那一刻现算的,所以不骑刀刃——两侧各让开一小时。
|
|
48
|
-
seedFailure(store, new Date(Date.now() - boundary + 3600000).toISOString(), "just-inside");
|
|
49
|
-
seedFailure(store, new Date(Date.now() - boundary - 3600000).toISOString(), "just-outside");
|
|
50
|
-
|
|
51
|
-
const removed = store.deleteOldFailures(new Date(Date.now() - boundary).toISOString());
|
|
52
|
-
assert.equal(removed, 1, "只有 created_at < cutoff 的那一行该走");
|
|
53
|
-
assert.deepEqual(store.listFailures().map((r) => r.id), ["just-inside"]);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test("空表返回 0 且不抛", () => {
|
|
57
|
-
const store = createStore(":memory:");
|
|
58
|
-
assert.equal(store.deleteOldFailures(daysAgo(90)), 0);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("配置键 reflectionFailureRetentionDays:默认 90、单位是天、边界钉死", () => {
|
|
62
|
-
assert.equal(Config({}).reflectionFailureRetentionDays, 90, "默认值必须与旧行为一致");
|
|
63
|
-
assert.equal(Config({ reflectionFailureRetentionDays: 30 }).reflectionFailureRetentionDays, 30);
|
|
64
|
-
assert.equal(Config({ reflectionFailureRetentionDays: 3650 }).reflectionFailureRetentionDays, 3650);
|
|
65
|
-
// 0 天会把这张表压成「只留最近一次」,等于废掉「挖掘重复纠正模式」的用途
|
|
66
|
-
assert.throws(() => Config({ reflectionFailureRetentionDays: 0 }));
|
|
67
|
-
assert.throws(() => Config({ reflectionFailureRetentionDays: 3651 }));
|
|
68
|
-
assert.throws(() => Config({ reflectionFailureRetentionDays: 2.5 }));
|
|
69
|
-
|
|
70
|
-
// 形状锁:与 recallRetentionDays 一族同形,别各自演化
|
|
71
|
-
assert.match(
|
|
72
|
-
srcText("config.js"),
|
|
73
|
-
/reflectionFailureRetentionDays: z\.natural\(\)\.min\(1\)\.max\(3650\)\.default\(90\)/
|
|
74
|
-
);
|
|
75
|
-
// 文档面同步:README 的键表与 docs/CONFIGURATION.md 的键表是用户唯一能读到
|
|
76
|
-
// 这个键的地方。用布尔断言而不是 assert.match——断言失败时 node:test 会把整个
|
|
77
|
-
// 文件正文打进 diff,几百行文档刷满输出,反而看不见失败点。
|
|
78
|
-
for (const doc of ["README.md", "docs/CONFIGURATION.md"]) {
|
|
79
|
-
const text = readFileSync(join(here, "..", doc), "utf8");
|
|
80
|
-
assert.ok(
|
|
81
|
-
text.includes("`reflectionFailureRetentionDays`"),
|
|
82
|
-
`${doc} 必须列出 reflectionFailureRetentionDays —— 加了键不改文档正是这一族欠账的来源`
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("接线锁:启动期失败表清理排在 cfg 装配之后,读键而不是写死的 90 天", () => {
|
|
88
|
-
const index = srcText("index.js");
|
|
89
|
-
const callAt = index.indexOf("store.deleteOldFailures(");
|
|
90
|
-
assert.ok(callAt > 0, "index.js 必须调用 store.deleteOldFailures");
|
|
91
|
-
|
|
92
|
-
// 装配前读 rawCfg 会漏掉面板/预设合进来的值;失败表此前正好排在装配之前。
|
|
93
|
-
const cfgAt = index.indexOf("const cfg = { ...applyLightModePreset(");
|
|
94
|
-
assert.ok(cfgAt > 0 && cfgAt < callAt, "清理必须排在 cfg 装配之后,否则读不到配置值");
|
|
95
|
-
|
|
96
|
-
const block = index.slice(callAt - 700, callAt + 200);
|
|
97
|
-
assert.match(block, /cfg\.reflectionFailureRetentionDays/, "天数必须取自配置键");
|
|
98
|
-
assert.match(block, /Number\.isInteger\(/, "非法值要能落回默认,别让 NaN 传给 SQL");
|
|
99
|
-
assert.match(block, /failureRetentionDays \* 86400000/, "键的单位是天,换算在这儿");
|
|
100
|
-
|
|
101
|
-
assert.ok(
|
|
102
|
-
!/Date\.now\(\) - 90 \* 86400000/.test(index),
|
|
103
|
-
"写死的 90 天不能回来——这正是本批在修的那条欠账"
|
|
104
|
-
);
|
|
105
|
-
});
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { Config } from "../src/config.js";
|
|
7
|
+
import { createStore } from "../src/store.js";
|
|
8
|
+
|
|
9
|
+
// 与 test/recall-retention.test.js 同款,这组测试故意分两半,因为弄丢的正是「两半
|
|
10
|
+
// 都在」:
|
|
11
|
+
// 1. 行为锁——deleteOldFailures 真的删对行、比较方向正确、空表不炸。
|
|
12
|
+
// 2. 接线锁——src/index.js 的启动块真的调它,且读的是装配后的 cfg。第二半用源码
|
|
13
|
+
// 文本断言,理由与 test/client.test.js 的 bilingual 锁同款:启动期清理只在运维
|
|
14
|
+
// 时才会跑到,运行时冒烟测不到「这一行被挪回装配之前了」。
|
|
15
|
+
//
|
|
16
|
+
// 这一批补的是「写死」这条欠账:failure_memories 的清理此前排在 createStore 之后、
|
|
17
|
+
// cfg 装配之前,天数硬编码 90,是四张启动期清理表里唯一没有键可陈述的一张。
|
|
18
|
+
|
|
19
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const srcText = (name) => readFileSync(join(here, "..", "src", name), "utf8");
|
|
21
|
+
const daysAgo = (n) => new Date(Date.now() - n * 86400000).toISOString();
|
|
22
|
+
|
|
23
|
+
// saveFailure 只认当前时刻,所以插进去之后把 created_at 改写成指定时刻。
|
|
24
|
+
function seedFailure(store, createdAt, id) {
|
|
25
|
+
store.saveFailure({ id, failure_type: "user_correction", expected: "新值", actual: "旧值" });
|
|
26
|
+
store.db.prepare("UPDATE failure_memories SET created_at = ? WHERE id = ?").run(createdAt, id);
|
|
27
|
+
return id;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
test("deleteOldFailures 删掉窗口外的行、留下窗口内的行", () => {
|
|
31
|
+
const store = createStore(":memory:");
|
|
32
|
+
seedFailure(store, daysAgo(200), "old-1");
|
|
33
|
+
seedFailure(store, daysAgo(120), "old-2");
|
|
34
|
+
seedFailure(store, daysAgo(10), "fresh-1");
|
|
35
|
+
seedFailure(store, daysAgo(1), "fresh-2");
|
|
36
|
+
|
|
37
|
+
assert.equal(store.listFailures().length, 4);
|
|
38
|
+
const removed = store.deleteOldFailures(daysAgo(90));
|
|
39
|
+
assert.equal(removed, 2);
|
|
40
|
+
// assert 的是留下了哪两行,不是物理顺序
|
|
41
|
+
assert.deepEqual(store.listFailures().map((r) => r.id).sort(), ["fresh-1", "fresh-2"]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("边界两侧各留 1 小时裕量:锁的是比较方向不是毫秒级巧合", () => {
|
|
45
|
+
const store = createStore(":memory:");
|
|
46
|
+
const boundary = 90 * 86400000;
|
|
47
|
+
// cutoff 是在清理那一刻现算的,所以不骑刀刃——两侧各让开一小时。
|
|
48
|
+
seedFailure(store, new Date(Date.now() - boundary + 3600000).toISOString(), "just-inside");
|
|
49
|
+
seedFailure(store, new Date(Date.now() - boundary - 3600000).toISOString(), "just-outside");
|
|
50
|
+
|
|
51
|
+
const removed = store.deleteOldFailures(new Date(Date.now() - boundary).toISOString());
|
|
52
|
+
assert.equal(removed, 1, "只有 created_at < cutoff 的那一行该走");
|
|
53
|
+
assert.deepEqual(store.listFailures().map((r) => r.id), ["just-inside"]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("空表返回 0 且不抛", () => {
|
|
57
|
+
const store = createStore(":memory:");
|
|
58
|
+
assert.equal(store.deleteOldFailures(daysAgo(90)), 0);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("配置键 reflectionFailureRetentionDays:默认 90、单位是天、边界钉死", () => {
|
|
62
|
+
assert.equal(Config({}).reflectionFailureRetentionDays, 90, "默认值必须与旧行为一致");
|
|
63
|
+
assert.equal(Config({ reflectionFailureRetentionDays: 30 }).reflectionFailureRetentionDays, 30);
|
|
64
|
+
assert.equal(Config({ reflectionFailureRetentionDays: 3650 }).reflectionFailureRetentionDays, 3650);
|
|
65
|
+
// 0 天会把这张表压成「只留最近一次」,等于废掉「挖掘重复纠正模式」的用途
|
|
66
|
+
assert.throws(() => Config({ reflectionFailureRetentionDays: 0 }));
|
|
67
|
+
assert.throws(() => Config({ reflectionFailureRetentionDays: 3651 }));
|
|
68
|
+
assert.throws(() => Config({ reflectionFailureRetentionDays: 2.5 }));
|
|
69
|
+
|
|
70
|
+
// 形状锁:与 recallRetentionDays 一族同形,别各自演化
|
|
71
|
+
assert.match(
|
|
72
|
+
srcText("config.js"),
|
|
73
|
+
/reflectionFailureRetentionDays: z\.natural\(\)\.min\(1\)\.max\(3650\)\.default\(90\)/
|
|
74
|
+
);
|
|
75
|
+
// 文档面同步:README 的键表与 docs/CONFIGURATION.md 的键表是用户唯一能读到
|
|
76
|
+
// 这个键的地方。用布尔断言而不是 assert.match——断言失败时 node:test 会把整个
|
|
77
|
+
// 文件正文打进 diff,几百行文档刷满输出,反而看不见失败点。
|
|
78
|
+
for (const doc of ["README.md", "docs/CONFIGURATION.md"]) {
|
|
79
|
+
const text = readFileSync(join(here, "..", doc), "utf8");
|
|
80
|
+
assert.ok(
|
|
81
|
+
text.includes("`reflectionFailureRetentionDays`"),
|
|
82
|
+
`${doc} 必须列出 reflectionFailureRetentionDays —— 加了键不改文档正是这一族欠账的来源`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("接线锁:启动期失败表清理排在 cfg 装配之后,读键而不是写死的 90 天", () => {
|
|
88
|
+
const index = srcText("index.js");
|
|
89
|
+
const callAt = index.indexOf("store.deleteOldFailures(");
|
|
90
|
+
assert.ok(callAt > 0, "index.js 必须调用 store.deleteOldFailures");
|
|
91
|
+
|
|
92
|
+
// 装配前读 rawCfg 会漏掉面板/预设合进来的值;失败表此前正好排在装配之前。
|
|
93
|
+
const cfgAt = index.indexOf("const cfg = { ...applyLightModePreset(");
|
|
94
|
+
assert.ok(cfgAt > 0 && cfgAt < callAt, "清理必须排在 cfg 装配之后,否则读不到配置值");
|
|
95
|
+
|
|
96
|
+
const block = index.slice(callAt - 700, callAt + 200);
|
|
97
|
+
assert.match(block, /cfg\.reflectionFailureRetentionDays/, "天数必须取自配置键");
|
|
98
|
+
assert.match(block, /Number\.isInteger\(/, "非法值要能落回默认,别让 NaN 传给 SQL");
|
|
99
|
+
assert.match(block, /failureRetentionDays \* 86400000/, "键的单位是天,换算在这儿");
|
|
100
|
+
|
|
101
|
+
assert.ok(
|
|
102
|
+
!/Date\.now\(\) - 90 \* 86400000/.test(index),
|
|
103
|
+
"写死的 90 天不能回来——这正是本批在修的那条欠账"
|
|
104
|
+
);
|
|
105
|
+
});
|