akm-cli 0.9.16 → 0.9.17-alpha.10
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/CHANGELOG.md +2101 -0
- package/STABILITY.md +11 -10
- package/dist/akm +124 -193
- package/dist/akm-migrate +38 -19
- package/dist/assets/hints/cli-hints-full.md +6 -7
- package/dist/assets/improve-strategies/catchup.json +0 -3
- package/dist/assets/improve-strategies/consolidate.json +0 -1
- package/dist/assets/improve-strategies/default.json +1 -2
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -2
- package/dist/assets/improve-strategies/quick.json +1 -2
- package/dist/assets/improve-strategies/reflect-distill.json +1 -2
- package/dist/assets/improve-strategies/thorough.json +0 -3
- package/dist/assets/prompts/consolidate-pair.md +20 -0
- package/dist/assets/prompts/consolidate-system.md +4 -11
- package/dist/assets/prompts/retrieval-relevance-judge.md +6 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +20 -20
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -2
- package/dist/assets/templates/html/health.html +3 -5
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +6 -2
- package/dist/cli/unknown-flags.js +24 -1
- package/dist/cli.js +68 -10
- package/dist/commands/agent/agent-dispatch.js +1 -1
- package/dist/commands/command/command-execution.js +24 -62
- package/dist/commands/feedback-cli.js +0 -1
- package/dist/commands/health/accept-rate.js +6 -0
- package/dist/commands/health/archive-usage.js +92 -0
- package/dist/commands/health/checks.js +83 -74
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/data-dir-usage.js +25 -13
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +1 -42
- package/dist/commands/health/improve-metrics.js +136 -591
- package/dist/commands/health/md-report.js +1 -6
- package/dist/commands/health/plugin-staleness.js +53 -3
- package/dist/commands/health/renderers.js +12 -4
- package/dist/commands/health/report-view-model.js +14 -120
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -74
- package/dist/commands/health.js +145 -143
- package/dist/commands/improve/consolidate/chunking.js +26 -117
- package/dist/commands/improve/consolidate/continuity-check.js +137 -0
- package/dist/commands/improve/consolidate/pair-pass.js +791 -0
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +589 -1127
- package/dist/commands/improve/content-hash.js +16 -24
- package/dist/commands/improve/distill/content-repair.js +18 -100
- package/dist/commands/improve/distill-guards.js +20 -81
- package/dist/commands/improve/distill-promotion-policy.js +23 -243
- package/dist/commands/improve/distill.js +608 -1041
- package/dist/commands/improve/eligibility.js +126 -390
- package/dist/commands/improve/execution.js +8 -10
- package/dist/commands/improve/extract-prompt.js +1 -2
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +75 -169
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +52 -4
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +480 -1074
- package/dist/commands/improve/ledger.js +119 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +415 -1073
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +16 -118
- package/dist/commands/improve/memory/memory-improve.js +266 -14
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -15
- package/dist/commands/improve/preparation.js +779 -2319
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +642 -1353
- package/dist/commands/improve/retrieval-gate.js +127 -0
- package/dist/commands/improve/retrieval-scope.js +92 -0
- package/dist/commands/improve/salience.js +41 -240
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +322 -0
- package/dist/commands/lint/base-linter.js +37 -15
- package/dist/commands/proposal/drain.js +261 -578
- package/dist/commands/proposal/proposal-cli.js +19 -20
- package/dist/commands/proposal/proposal-types.js +31 -24
- package/dist/commands/proposal/proposal.js +38 -8
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +1097 -1394
- package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
- package/dist/commands/proposal/validators/proposal-validators.js +1 -1
- package/dist/commands/proposal/validators/proposals.js +22 -89
- package/dist/commands/read/curate.js +105 -462
- package/dist/commands/read/knowledge.js +3 -2
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +57 -108
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +4 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +127 -29
- package/dist/commands/sources/installed-stashes.js +197 -746
- package/dist/commands/sources/schema-repair.js +98 -129
- package/dist/commands/sources/source-add.js +62 -12
- package/dist/commands/sources/source-manage.js +9 -2
- package/dist/commands/sources/stash-cli.js +24 -4
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +12 -13
- package/dist/commands/tasks/tasks.js +350 -936
- package/dist/commands/tasks/validate.js +26 -24
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +2 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +42 -12
- package/dist/core/adapter/adapters/akm-task-adapter.js +29 -8
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/asset-placement.js +4 -13
- package/dist/core/asset/frontmatter.js +106 -1
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +285 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +9 -34
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +184 -111
- package/dist/core/config/engine-semantics.js +0 -2
- package/dist/core/config/legacy-source-shape-shim.js +38 -9
- package/dist/core/config/schema/embedding.js +20 -5
- package/dist/core/config/schema/engines.js +5 -0
- package/dist/core/config/schema/execution.js +1 -1
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/improve-processes.js +54 -125
- package/dist/core/config/schema/improve.js +4 -42
- package/dist/core/config/schema/index-config.js +9 -48
- package/dist/core/config/schema/scheduler.js +12 -12
- package/dist/core/config/schema/search.js +6 -22
- package/dist/core/env-secret-ref.js +0 -1
- package/dist/core/errors.js +8 -9
- package/dist/core/file-change.js +13 -5
- package/dist/core/file-lock.js +76 -173
- package/dist/core/improve-result.js +35 -7
- package/dist/core/improve-types.js +0 -1
- package/dist/core/logs-db.js +2 -2
- package/dist/core/loopback.js +7 -12
- package/dist/core/non-task-input.js +20 -0
- package/dist/core/parse.js +13 -16
- package/dist/core/paths.js +0 -24
- package/dist/core/redaction.js +109 -2
- package/dist/core/run-lock.js +2 -5
- package/dist/core/spawn-env.js +1 -1
- package/dist/core/state/migrations.js +123 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/time.js +0 -20
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +294 -1005
- package/dist/execution/input-contract.js +1 -1
- package/dist/execution/resolved-request.js +135 -689
- package/dist/execution/source.js +63 -257
- package/dist/execution/target-ref.js +1 -1
- package/dist/indexer/bundle-identity-guard.js +2 -2
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/ensure-index.js +77 -73
- package/dist/indexer/index-rebuild-lock.js +3 -11
- package/dist/indexer/index-writer-lock.js +8 -17
- package/dist/indexer/index-written-assets.js +141 -154
- package/dist/indexer/indexer.js +400 -1124
- package/dist/indexer/links/declared-links.js +90 -0
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +96 -90
- package/dist/indexer/passes/metadata.js +132 -219
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +2 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +190 -590
- package/dist/indexer/search/fts-query.js +30 -41
- package/dist/indexer/search/ranking.js +28 -154
- package/dist/indexer/search/search-attribution.js +12 -32
- package/dist/indexer/search/search-fields.js +11 -15
- package/dist/indexer/search/search-hit-enrichers.js +54 -85
- package/dist/indexer/search/search-source.js +1 -4
- package/dist/indexer/usage/usage-events.js +36 -7
- package/dist/indexer/walk/walker.js +3 -4
- package/dist/integrations/agent/engine-fallback.js +23 -40
- package/dist/integrations/agent/engine-resolution.js +93 -183
- package/dist/integrations/agent/execution.js +507 -0
- package/dist/integrations/agent/model-map.js +28 -156
- package/dist/integrations/agent/request-lowering.js +66 -141
- package/dist/integrations/agent/runner-dispatch.js +143 -321
- package/dist/integrations/agent/runner.js +54 -14
- package/dist/integrations/lockfile.js +53 -101
- package/dist/llm/client.js +18 -6
- package/dist/llm/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +11 -17
- package/dist/llm/feature-gate.js +0 -8
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/structured-call.js +5 -24
- package/dist/output/generic-render.js +23 -11
- package/dist/output/html-render.js +13 -10
- package/dist/output/render-registry.js +3 -32
- package/dist/output/shapes/helpers.js +25 -38
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/graph/graph-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +69 -31
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +48 -3
- package/dist/output/text/show-format.js +13 -17
- package/dist/output/text/workflow-format.js +0 -32
- package/dist/output/text.js +2 -0
- package/dist/registry/factory.js +4 -19
- package/dist/registry/network.js +66 -220
- package/dist/registry/providers/index.js +0 -2
- package/dist/registry/providers/skills-sh.js +3 -14
- package/dist/registry/providers/static-index.js +24 -26
- package/dist/registry/resolve.js +55 -131
- package/dist/scripts/akm-migrate-node.js +42948 -92369
- package/dist/scripts/akm-migrate.js +42935 -92354
- package/dist/setup/registry-stash-loader.js +4 -13
- package/dist/setup/semantic-assets.js +3 -44
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/connection.js +5 -6
- package/dist/setup/steps/platforms.js +2 -2
- package/dist/setup/steps/tasks.js +25 -15
- package/dist/sources/provider-factory.js +17 -18
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +7 -1
- package/dist/sources/providers/git-provider.js +0 -3
- package/dist/sources/providers/git-stash.js +83 -21
- package/dist/sources/providers/npm.js +2 -4
- package/dist/sources/providers/provider-utils.js +5 -10
- package/dist/sources/providers/website.js +0 -2
- package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
- package/dist/sources/website-url.js +2 -2
- package/dist/storage/database.js +9 -35
- package/dist/storage/repositories/improve-ledger-repository.js +209 -0
- package/dist/storage/repositories/index-connection.js +39 -72
- package/dist/storage/repositories/index-entries-repository.js +131 -129
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +101 -268
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-links-repository.js +143 -0
- package/dist/storage/repositories/index-llm-cache-repository.js +7 -9
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +257 -325
- package/dist/storage/repositories/index-utility-repository.js +8 -29
- package/dist/storage/repositories/index-vec-repository.js +133 -414
- package/dist/storage/repositories/outcome-repository.js +2 -1
- package/dist/storage/repositories/proposals-repository.js +104 -1
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- package/dist/storage/repositories/salience-repository.js +1 -19
- package/dist/storage/repositories/task-history-repository.js +26 -4
- package/dist/storage/repositories/workflow-runs-repository.js +53 -244
- package/dist/storage/sqlite-migrations.js +136 -0
- package/dist/storage/sqlite-pragmas.js +11 -9
- package/dist/storage/sqlite-transaction.js +170 -0
- package/dist/storage/state-db-integrity.js +130 -0
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +191 -302
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +141 -748
- package/dist/tasks/backends/schtasks.js +119 -623
- package/dist/tasks/prepare/prepare-support.js +5 -15
- package/dist/tasks/prepare/prepare.js +0 -2
- package/dist/tasks/resolve-akm-bin.js +20 -79
- package/dist/tasks/run/attempt-lifecycle.js +0 -1
- package/dist/tasks/run/load-task.js +1 -1
- package/dist/tasks/scheduler-binding.js +20 -238
- package/dist/tasks/scheduler-invocation.js +136 -244
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +368 -679
- package/dist/tasks/source/parse-task-source.js +55 -9
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +464 -88
- package/dist/workflows/authoring/authoring.js +3 -12
- package/dist/workflows/compile.js +211 -0
- package/dist/workflows/concurrency-policy.js +13 -74
- package/dist/workflows/exec/child-invocation.js +3 -17
- package/dist/workflows/exec/child-workflow.js +32 -141
- package/dist/workflows/exec/dispatch-redaction.js +13 -53
- package/dist/workflows/exec/environment.js +98 -0
- package/dist/workflows/exec/exec-unit.js +33 -140
- package/dist/workflows/exec/frozen-judge.js +7 -59
- package/dist/workflows/exec/native-executor.js +82 -341
- package/dist/workflows/exec/param-secrets.js +29 -47
- package/dist/workflows/exec/run-workflow.js +154 -387
- package/dist/workflows/exec/scheduler.js +9 -36
- package/dist/workflows/exec/step-work.js +127 -430
- package/dist/workflows/exec/unit-dispatch.js +11 -63
- package/dist/workflows/exec/unit-writer.js +8 -52
- package/dist/workflows/exec/worktree.js +39 -273
- package/dist/workflows/freeze/child-output-references.js +4 -15
- package/dist/workflows/freeze/environment.js +99 -92
- package/dist/workflows/freeze/freeze.js +172 -0
- package/dist/workflows/freeze/step-values.js +19 -21
- package/dist/workflows/freeze/targets/child-workflow.js +23 -92
- package/dist/workflows/freeze/targets/command.js +10 -33
- package/dist/workflows/freeze/targets/script.js +5 -12
- package/dist/workflows/freeze/targets/shell.js +3 -6
- package/dist/workflows/freeze/targets/task.js +25 -80
- package/dist/workflows/freeze/task-bindings.js +20 -67
- package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
- package/dist/workflows/ir/params.js +6 -51
- package/dist/workflows/ir/plan-hash.js +2 -34
- package/dist/workflows/parser.js +140 -43
- package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
- package/dist/workflows/renderer.js +36 -69
- package/dist/workflows/resource-limits.js +12 -120
- package/dist/workflows/runtime/agent-identity.js +8 -40
- package/dist/workflows/runtime/run-outputs.js +3 -6
- package/dist/workflows/runtime/run-plan.js +316 -0
- package/dist/workflows/runtime/runs.js +48 -200
- package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
- package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/integration/bundling-akm.md +49 -42
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.17.md +43 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +23 -7
- package/docs/reference/cli.md +232 -135
- package/docs/reference/configuration.md +71 -57
- package/docs/reference/data-and-telemetry.md +20 -21
- package/docs/reference/tasks.md +105 -39
- package/docs/reference/workflow-schema.md +14 -18
- package/docs/reference/workflows.md +6 -9
- package/package.json +1 -1
- package/schemas/akm-config.json +115 -738
- package/schemas/akm-workflow.json +1 -0
- package/dist/assets/improve-strategies/graph-refresh.json +0 -15
- package/dist/assets/prompts/contradiction-judge.md +0 -33
- package/dist/assets/prompts/graph-extract-system.md +0 -1
- package/dist/assets/prompts/graph-extract-user-prompt.md +0 -35
- package/dist/assets/prompts/metadata-enhance-system.md +0 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +0 -4
- package/dist/commands/health/advisories.js +0 -150
- package/dist/commands/health/metrics.js +0 -329
- package/dist/commands/health/surfaces.js +0 -102
- package/dist/commands/improve/anti-collapse.js +0 -83
- package/dist/commands/improve/collapse-detector.js +0 -432
- package/dist/commands/improve/consolidate/eligibility.js +0 -48
- package/dist/commands/improve/consolidate/merge.js +0 -149
- package/dist/commands/improve/distill/promote-memory.js +0 -291
- package/dist/commands/improve/distill/quality-gate.js +0 -337
- package/dist/commands/improve/eval-cases.js +0 -52
- package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
- package/dist/commands/improve/proposal-envelope.js +0 -31
- package/dist/commands/improve/run-context.js +0 -123
- package/dist/commands/improve/shared.js +0 -31
- package/dist/commands/improve/source-identity.js +0 -28
- package/dist/commands/improve/triage.js +0 -96
- package/dist/commands/proposal/drain-policies.js +0 -151
- package/dist/commands/sources/update-transaction.js +0 -220
- package/dist/core/action-contributors.js +0 -28
- package/dist/core/config/config-version-shim.js +0 -101
- package/dist/core/fs-txn.js +0 -405
- package/dist/core/lexical-score.js +0 -25
- package/dist/core/maintenance-barrier.js +0 -167
- package/dist/execution/executable-identity.js +0 -105
- package/dist/execution/guarded-source.js +0 -427
- package/dist/indexer/db/graph-db.js +0 -444
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/graph/graph-extraction.js +0 -1108
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- package/dist/indexer/search/ranking-types.js +0 -4
- package/dist/indexer/walk/project-context.js +0 -192
- package/dist/integrations/agent/execution-cascade.js +0 -566
- package/dist/integrations/agent/execution-definitions.js +0 -202
- package/dist/integrations/agent/execution-lowering.js +0 -841
- package/dist/integrations/agent/execution-preparation.js +0 -98
- package/dist/integrations/agent/inline-execution.js +0 -74
- package/dist/llm/graph-extract.js +0 -728
- package/dist/llm/metadata-enhance.js +0 -96
- package/dist/registry/create-provider-registry.js +0 -29
- package/dist/registry/pinned-request-helper.js +0 -247
- package/dist/registry/pinned-transport.js +0 -717
- package/dist/sources/providers/index.js +0 -14
- package/dist/storage/engines/sqlite-migrations.js +0 -271
- package/dist/storage/repositories/canaries-repository.js +0 -107
- package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
- package/dist/storage/repositories/registry-cache.js +0 -113
- package/dist/tasks/scheduler-sync-preview.js +0 -52
- package/dist/tasks/source/task-to-v3.js +0 -507
- package/dist/workflows/freeze/resolve-steps.js +0 -86
- package/dist/workflows/freeze/source-freeze.js +0 -64
- package/dist/workflows/ir/compile.js +0 -321
- package/dist/workflows/ir/environment-v4.js +0 -330
- package/dist/workflows/ir/freeze-v4.js +0 -153
- package/dist/workflows/ir/schema-v4.js +0 -745
- package/dist/workflows/ir/schema.js +0 -354
- package/dist/workflows/program/schema.js +0 -77
- package/dist/workflows/runtime/checkin.js +0 -57
- package/dist/workflows/runtime/plan-classifier.js +0 -196
- package/dist/workflows/runtime/unit-checkin.js +0 -45
- package/dist/workflows/runtime/unit-phases.js +0 -20
- package/dist/workflows/schema.js +0 -4
- package/dist/workflows/source-ir/compile.js +0 -200
- package/dist/workflows/source-ir/program.js +0 -50
- package/dist/workflows/source-ir/result.js +0 -26
- package/dist/workflows/source-ir/schema.js +0 -786
- package/dist/workflows/source-ir/triggers.js +0 -79
- package/dist/workflows/source-ir/uses.js +0 -40
- package/dist/workflows/validator.js +0 -60
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* The retrieval regression gate (#722): a reflect rewrite of an existing asset
|
|
6
|
+
* must not grade lower on the queries that actually retrieved it.
|
|
7
|
+
*
|
|
8
|
+
* Measured before it was built: of 60 accepted reflect rewrites judged against
|
|
9
|
+
* their own queries, 14 graded lower (23%, 95% CI 14–35%) and 12 higher. The
|
|
10
|
+
* old and new content are graded one query at a time, blind, with the
|
|
11
|
+
* retrieval-eval judge's prompt (kappa 0.83 against human grades) and its
|
|
12
|
+
* document shape: type, ref, name, description and the first 1,500 characters
|
|
13
|
+
* of the body.
|
|
14
|
+
*/
|
|
15
|
+
import relevanceJudgePrompt from "../../assets/prompts/retrieval-relevance-judge.md" with { type: "text" };
|
|
16
|
+
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
17
|
+
import { parseRefInput } from "../../core/asset/resolve-ref.js";
|
|
18
|
+
import { nonTaskInput } from "../../core/non-task-input.js";
|
|
19
|
+
import { parseEmbeddedJsonResponse } from "../../core/parse.js";
|
|
20
|
+
import { listRetrievalQueries } from "../../indexer/usage/usage-events.js";
|
|
21
|
+
import { readLedgerDb, stripBundle } from "./ledger.js";
|
|
22
|
+
import { callStage } from "./stage.js";
|
|
23
|
+
/** Queries graded per rewrite, as measured. */
|
|
24
|
+
const MAX_QUERIES = 5;
|
|
25
|
+
/** The retrieval suite treats a longer input as a paste, not a query; the measurement did the same. */
|
|
26
|
+
const MAX_QUERY_CHARS = 2000;
|
|
27
|
+
/** The judge sees this much of the body, as in the retrieval eval. */
|
|
28
|
+
const MAX_DOC_CHARS = 1500;
|
|
29
|
+
const GRADE_SCHEMA = {
|
|
30
|
+
type: "object",
|
|
31
|
+
required: ["grade", "reason"],
|
|
32
|
+
additionalProperties: false,
|
|
33
|
+
properties: { grade: { type: "integer", minimum: 0, maximum: 3 }, reason: { type: "string" } },
|
|
34
|
+
};
|
|
35
|
+
/** Up to five distinct task queries, in the given order, whitespace collapsed. */
|
|
36
|
+
export function usableRetrievalQueries(raw) {
|
|
37
|
+
const out = [];
|
|
38
|
+
for (const text of raw) {
|
|
39
|
+
const query = text.replace(/\s+/g, " ").trim();
|
|
40
|
+
if (!query || query.length > MAX_QUERY_CHARS || nonTaskInput(query) || out.includes(query))
|
|
41
|
+
continue;
|
|
42
|
+
out.push(query);
|
|
43
|
+
if (out.length === MAX_QUERIES)
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
/** The asset's own retrieval queries from the usage log (none when state.db cannot be read). */
|
|
49
|
+
export function loadRetrievalQueries(access, ref) {
|
|
50
|
+
try {
|
|
51
|
+
return usableRetrievalQueries(readLedgerDb(access, (db) => listRetrievalQueries(db, stripBundle(ref))) ?? []);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function judgeDocument(ref, raw) {
|
|
58
|
+
const conceptId = stripBundle(ref);
|
|
59
|
+
const parsed = parseRefInput(conceptId);
|
|
60
|
+
const { data, content } = parseFrontmatter(raw);
|
|
61
|
+
const text = content
|
|
62
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
63
|
+
.trim()
|
|
64
|
+
.slice(0, MAX_DOC_CHARS);
|
|
65
|
+
const name = typeof data.name === "string" && data.name ? data.name : parsed.name;
|
|
66
|
+
const description = typeof data.description === "string" ? data.description : "";
|
|
67
|
+
return [
|
|
68
|
+
"Candidate asset:",
|
|
69
|
+
`Type: ${parsed.type}`,
|
|
70
|
+
`Ref: ${conceptId}`,
|
|
71
|
+
`Name: ${name}`,
|
|
72
|
+
`Description: ${description}`,
|
|
73
|
+
"",
|
|
74
|
+
"Content:",
|
|
75
|
+
text,
|
|
76
|
+
].join("\n");
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Grade `before` and `after` on each query; refuse the rewrite when the new
|
|
80
|
+
* content's mean grade is lower. Fails closed, like the quality judge: a grade
|
|
81
|
+
* that cannot be obtained refuses the rewrite.
|
|
82
|
+
*/
|
|
83
|
+
export async function runRetrievalRegressionGate(args) {
|
|
84
|
+
if (args.queries.length === 0)
|
|
85
|
+
return { pass: true, queries: 0, reason: "no retrieval queries to compare on" };
|
|
86
|
+
const documents = { old: judgeDocument(args.ref, args.before), new: judgeDocument(args.ref, args.after) };
|
|
87
|
+
const totals = { old: 0, new: 0 };
|
|
88
|
+
for (const query of args.queries) {
|
|
89
|
+
for (const version of ["old", "new"]) {
|
|
90
|
+
const outcome = await callStage({
|
|
91
|
+
feature: "proposal_quality_gate",
|
|
92
|
+
runner: args.runner,
|
|
93
|
+
system: relevanceJudgePrompt.trim(),
|
|
94
|
+
prompt: `Query: ${query}\n\n${documents[version]}`,
|
|
95
|
+
request: {
|
|
96
|
+
enableThinking: false,
|
|
97
|
+
temperature: 0,
|
|
98
|
+
responseSchema: GRADE_SCHEMA,
|
|
99
|
+
...(args.timeoutMs !== undefined ? { timeoutMs: args.timeoutMs } : {}),
|
|
100
|
+
...(args.signal ? { signal: args.signal } : {}),
|
|
101
|
+
...(args.chat ? { chat: args.chat } : {}),
|
|
102
|
+
},
|
|
103
|
+
...(args.onNotices ? { onNotices: args.onNotices } : {}),
|
|
104
|
+
});
|
|
105
|
+
const grade = outcome.ok ? parseEmbeddedJsonResponse(outcome.raw)?.grade : undefined;
|
|
106
|
+
if (typeof grade !== "number" || !Number.isInteger(grade) || grade < 0 || grade > 3) {
|
|
107
|
+
return {
|
|
108
|
+
pass: false,
|
|
109
|
+
queries: args.queries.length,
|
|
110
|
+
reason: `retrieval check could not grade the ${version} content${outcome.ok ? "" : ` (${outcome.reason})`}`,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
totals[version] += grade;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const oldMean = totals.old / args.queries.length;
|
|
117
|
+
const newMean = totals.new / args.queries.length;
|
|
118
|
+
const pass = newMean >= oldMean;
|
|
119
|
+
const grades = `${oldMean.toFixed(2)} -> ${newMean.toFixed(2)} over ${args.queries.length} retrieval ${args.queries.length === 1 ? "query" : "queries"}`;
|
|
120
|
+
return {
|
|
121
|
+
pass,
|
|
122
|
+
queries: args.queries.length,
|
|
123
|
+
oldMean,
|
|
124
|
+
newMean,
|
|
125
|
+
reason: pass ? `retrieval grade ${grades}` : `retrieval regression: grade ${grades}`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* What improve may rework (#986): an asset that retrieval returned inside the
|
|
6
|
+
* usage window, or newly captured material no improve stage has processed.
|
|
7
|
+
*
|
|
8
|
+
* Fresh feedback and an explicit `--scope <ref>` are usage evidence of their
|
|
9
|
+
* own, so the signal-delta and scope lanes need no check. The fallback lanes
|
|
10
|
+
* (proactive maintenance, high salience) and consolidation pick assets
|
|
11
|
+
* without such evidence, so they pick only inside this scope.
|
|
12
|
+
*/
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import { daysToMs } from "../../core/common.js";
|
|
15
|
+
import { warn } from "../../core/warn.js";
|
|
16
|
+
import { listUsedEntryRefs, USAGE_EVENT_RETENTION_DAYS } from "../../indexer/usage/usage-events.js";
|
|
17
|
+
import { listImproveLedgerRows } from "../../storage/repositories/improve-ledger-repository.js";
|
|
18
|
+
import { listProposalRefSources } from "../../storage/repositories/proposals-repository.js";
|
|
19
|
+
import { PAIR_PASS_LEDGER_SOURCE, readLedgerDb, stripBundle } from "./ledger.js";
|
|
20
|
+
/**
|
|
21
|
+
* Ledger and proposal sources that bring material in. Every other source is an
|
|
22
|
+
* improve stage reworking an asset (reflect, distill, consolidate, schema repair).
|
|
23
|
+
*/
|
|
24
|
+
const CAPTURE_SOURCES = new Set(["extract", "propose", "remember", "import"]);
|
|
25
|
+
/**
|
|
26
|
+
* Load the scope from state.db. The window is the usage log's retention: the
|
|
27
|
+
* log keeps nothing older, and anything shorter would drop assets read less
|
|
28
|
+
* often than the window. A `.derived` hit counts for its parent memory, whose
|
|
29
|
+
* facts it carries. `undefined` (every asset eligible, as before #986) only
|
|
30
|
+
* when state.db cannot be read.
|
|
31
|
+
*/
|
|
32
|
+
export function loadRetrievalScope(access, stashDir) {
|
|
33
|
+
const sinceMs = Date.now() - daysToMs(USAGE_EVENT_RETENTION_DAYS);
|
|
34
|
+
const used = new Set();
|
|
35
|
+
const processed = new Set();
|
|
36
|
+
try {
|
|
37
|
+
readLedgerDb(access, (db) => {
|
|
38
|
+
for (const entryRef of listUsedEntryRefs(db, new Date(sinceMs).toISOString())) {
|
|
39
|
+
const conceptId = stripBundle(entryRef);
|
|
40
|
+
used.add(conceptId);
|
|
41
|
+
if (conceptId.endsWith(".derived"))
|
|
42
|
+
used.add(conceptId.slice(0, -".derived".length));
|
|
43
|
+
}
|
|
44
|
+
if (!stashDir)
|
|
45
|
+
return;
|
|
46
|
+
// Blocker 1 (second review round): a pair-pass ledger row must NOT mark
|
|
47
|
+
// an asset "processed" — unlike every other stage, the pair pass judges
|
|
48
|
+
// material against its NEIGHBOURS, not on its own merits, so its own
|
|
49
|
+
// attempt is not usage evidence the fallback lanes (proactive,
|
|
50
|
+
// high-salience) or promotion retries should be starved by. Left in
|
|
51
|
+
// the ledger for the pair pass's OWN eligibility
|
|
52
|
+
// (selectInitiators reads content_hash directly, never this scope).
|
|
53
|
+
// Proposal rows are untouched: a MINTED retire proposal is real
|
|
54
|
+
// evidence something happened to the asset.
|
|
55
|
+
for (const row of listImproveLedgerRows(db, stashDir)) {
|
|
56
|
+
if (row.source === PAIR_PASS_LEDGER_SOURCE)
|
|
57
|
+
continue;
|
|
58
|
+
if (!CAPTURE_SOURCES.has(row.source))
|
|
59
|
+
processed.add(stripBundle(row.ref));
|
|
60
|
+
}
|
|
61
|
+
for (const row of listProposalRefSources(db, stashDir)) {
|
|
62
|
+
if (!CAPTURE_SOURCES.has(row.source))
|
|
63
|
+
processed.add(stripBundle(row.ref));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
warn(`[improve] usage history unreadable, so every asset stays eligible: ${error instanceof Error ? error.message : String(error)}`);
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
return { used, processed, sinceMs };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Whether improve may rework `ref` (whose file is `filePath`) under `scope`. An
|
|
75
|
+
* unprocessed asset whose file cannot be read is left to the disk check that
|
|
76
|
+
* follows, which reports it as missing.
|
|
77
|
+
*/
|
|
78
|
+
export function isInRetrievalScope(scope, ref, filePath) {
|
|
79
|
+
if (!scope)
|
|
80
|
+
return true;
|
|
81
|
+
const conceptId = stripBundle(ref);
|
|
82
|
+
if (scope.used.has(conceptId))
|
|
83
|
+
return true;
|
|
84
|
+
if (scope.processed.has(conceptId))
|
|
85
|
+
return false;
|
|
86
|
+
try {
|
|
87
|
+
return filePath === undefined || fs.statSync(filePath).mtimeMs >= scope.sinceMs;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -4,71 +4,25 @@
|
|
|
4
4
|
import { getAllEntries } from "../../storage/repositories/index-entries-repository.js";
|
|
5
5
|
import { getUtilityScoresByIds } from "../../storage/repositories/index-utility-repository.js";
|
|
6
6
|
import { WARM_START_CAP } from "./outcome-loop.js";
|
|
7
|
-
// ── One day in ms ─────────────────────────────────────────────────────────────
|
|
8
7
|
const DAY_MS = 86_400_000;
|
|
9
|
-
// ── Recency decay half-life (mirrors the proactive-maintenance prototype) ─────
|
|
10
8
|
const RECENCY_HALFLIFE_DAYS = 21;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// floor. This replaces the deleted homeostatic demotion pass (which was
|
|
16
|
-
// default-off and self-undoing — every salience recompute clobbered it);
|
|
17
|
-
// folding the decay into the always-applied recency term makes it persist by
|
|
18
|
-
// construction. At 180 days the floor halves; a 1-year-stale asset sits at
|
|
19
|
-
// ~0.025 instead of 0.1.
|
|
9
|
+
/**
|
|
10
|
+
* The recency floor itself halves every 180 days, so an asset nobody uses keeps
|
|
11
|
+
* drifting down instead of parking at the floor.
|
|
12
|
+
*/
|
|
20
13
|
const RECENCY_FLOOR_HALFLIFE_DAYS = 180;
|
|
21
|
-
|
|
22
|
-
// for assets whose last-use timestamp is unknown (utility_scores has no
|
|
23
|
-
// last_used_at) — without it their retrieval salience collapses to exactly 0
|
|
24
|
-
// and frequency ordering is lost for maintenance selection.
|
|
14
|
+
/** Keeps frequency ordinal for assets whose last use is unknown. */
|
|
25
15
|
const RECENCY_EPSILON = 0.01;
|
|
26
|
-
// ── Size proxy floor (avoids log10(0)) ────────────────────────────────────────
|
|
27
16
|
const SIZE_FLOOR_BYTES = 200;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// measures use; outcome provides a quality signal proportional to usefulness.
|
|
38
|
-
//
|
|
39
|
-
// Re-tune via the Part-V measurement protocol if the throughput/quality gate
|
|
40
|
-
// shows regression after enabling the outcome weight.
|
|
41
|
-
export const W_ENCODING = 0.25; // WS-2 target encoding weight (w_e)
|
|
42
|
-
export const W_OUTCOME = 0.15; // WS-2 target outcome weight (w_o)
|
|
43
|
-
export const W_RETRIEVAL = 0.6; // WS-2 target retrieval weight (w_r)
|
|
44
|
-
// Compile-time guard: weights must sum to 1.0 (±ε). The TS initializer runs
|
|
45
|
-
// at module load, not build time, so this acts as a startup assertion.
|
|
46
|
-
if (Math.abs(W_ENCODING + W_OUTCOME + W_RETRIEVAL - 1.0) > 1e-9) {
|
|
47
|
-
throw new Error(`salience.ts: W_ENCODING + W_OUTCOME + W_RETRIEVAL must equal 1.0 (got ${W_ENCODING + W_OUTCOME + W_RETRIEVAL})`);
|
|
48
|
-
}
|
|
49
|
-
// ── WS-1 parity weights ───────────────────────────────────────────────────────
|
|
50
|
-
//
|
|
51
|
-
// These constants reflect the WS-1 parity weights used when the operator
|
|
52
|
-
// explicitly opts out (`outcomeWeightEnabled: false`). They preserve the
|
|
53
|
-
// WS-1 two-way split (w_e=0.30, w_r=0.70) with w_o=0 so outcome does not
|
|
54
|
-
// affect rankScore in the opt-out mode.
|
|
55
|
-
//
|
|
56
|
-
// Named here (rather than inline literals in the else branch) so a future
|
|
57
|
-
// re-tune has a single source of truth and the sum-to-1 guard below catches
|
|
58
|
-
// any accidental mis-edit.
|
|
59
|
-
export const W_ENCODING_PARITY = 0.3; // WS-1 parity encoding weight
|
|
60
|
-
export const W_OUTCOME_PARITY = 0; // WS-1 parity outcome weight (0 = disabled)
|
|
61
|
-
export const W_RETRIEVAL_PARITY = 0.7; // WS-1 parity retrieval weight
|
|
62
|
-
// Startup guard: parity triple must also sum to 1.0 (±ε).
|
|
63
|
-
if (Math.abs(W_ENCODING_PARITY + W_OUTCOME_PARITY + W_RETRIEVAL_PARITY - 1.0) > 1e-9) {
|
|
64
|
-
throw new Error(`salience.ts: W_ENCODING_PARITY + W_OUTCOME_PARITY + W_RETRIEVAL_PARITY must equal 1.0 (got ${W_ENCODING_PARITY + W_OUTCOME_PARITY + W_RETRIEVAL_PARITY})`);
|
|
65
|
-
}
|
|
66
|
-
// ── Type-importance fallback weights (#608 landed) ────────────────────────────
|
|
67
|
-
//
|
|
68
|
-
// The real encoding salience estimator is `scoreEncodingSalience` in
|
|
69
|
-
// `encoding-salience.ts` (#608). These weights are the fallback used when
|
|
70
|
-
// `SalienceInputs.encodingSalience` is absent (pre-#608 assets without a
|
|
71
|
-
// frontmatter `salience:` field or a state.db row seeded by distill).
|
|
17
|
+
/** Default weights: the outcome term is on (opt out with `improve.salience.outcomeWeightEnabled: false`). */
|
|
18
|
+
export const W_ENCODING = 0.25;
|
|
19
|
+
export const W_OUTCOME = 0.15;
|
|
20
|
+
export const W_RETRIEVAL = 0.6;
|
|
21
|
+
/** Weights with the outcome term off. */
|
|
22
|
+
export const W_ENCODING_PARITY = 0.3;
|
|
23
|
+
export const W_OUTCOME_PARITY = 0;
|
|
24
|
+
export const W_RETRIEVAL_PARITY = 0.7;
|
|
25
|
+
/** Encoding salience by type, for assets with no content-derived score yet. */
|
|
72
26
|
export const DEFAULT_TYPE_ENCODING_WEIGHTS = Object.freeze({
|
|
73
27
|
skill: 0.9,
|
|
74
28
|
agent: 0.9,
|
|
@@ -79,218 +33,65 @@ export const DEFAULT_TYPE_ENCODING_WEIGHTS = Object.freeze({
|
|
|
79
33
|
script: 0.6,
|
|
80
34
|
memory: 0.5,
|
|
81
35
|
});
|
|
82
|
-
/** Default encoding salience for types not in the table above. */
|
|
83
36
|
export const DEFAULT_ENCODING_SALIENCE = 0.5;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Compute the salience vector for one asset.
|
|
87
|
-
*
|
|
88
|
-
* Pure function — no I/O. All inputs are pre-fetched by the caller.
|
|
89
|
-
*/
|
|
37
|
+
const clamp01 = (value) => Math.min(1, Math.max(0, value));
|
|
38
|
+
/** The salience vector for one asset (pure). */
|
|
90
39
|
export function computeSalience(inputs) {
|
|
91
40
|
const now = inputs.now ?? Date.now();
|
|
92
|
-
// ── Encoding salience ────────────────────────────────────────────────────────
|
|
93
|
-
//
|
|
94
|
-
// When `inputs.encodingSalience` is provided (computed by `scoreEncodingSalience`
|
|
95
|
-
// in encoding-salience.ts at extract/distill time, #608), use it directly.
|
|
96
|
-
// Fall back to the type-importance stub only when the caller has not yet
|
|
97
|
-
// computed a content-based score (e.g. on older assets before the first
|
|
98
|
-
// staleness refresh runs).
|
|
99
41
|
const encodingSource = inputs.encodingSalience !== undefined ? "content" : "type-stub";
|
|
100
42
|
const encoding = inputs.encodingSalience !== undefined
|
|
101
|
-
?
|
|
43
|
+
? clamp01(inputs.encodingSalience)
|
|
102
44
|
: (DEFAULT_TYPE_ENCODING_WEIGHTS[inputs.type] ?? DEFAULT_ENCODING_SALIENCE);
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
// from `utilityScore` clipped to [0, WARM_START_CAP], matching the seed
|
|
111
|
-
// value that `updateAssetOutcome` writes on first row creation. This ensures
|
|
112
|
-
// `outcomeSalience` is non-zero at launch for assets with utility history
|
|
113
|
-
// (avoiding the starvation problem described in the plan §WS-2 warm start).
|
|
114
|
-
let outcome;
|
|
115
|
-
if (inputs.outcomeSalience !== undefined) {
|
|
116
|
-
// Direct pass-through — caller already normalised via outcomeScoreToSalience.
|
|
117
|
-
outcome = Math.min(1, Math.max(0, inputs.outcomeSalience));
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
// Warm-start fallback: clip utility to [0, WARM_START_CAP] so the
|
|
121
|
-
// outcomeSalience term contributes a modest non-zero baseline.
|
|
122
|
-
outcome = Math.min(WARM_START_CAP, Math.max(0, inputs.utilityScore ?? 0));
|
|
123
|
-
}
|
|
124
|
-
// ── Retrieval salience ─────────────────────────────────────────────────────
|
|
125
|
-
//
|
|
126
|
-
// Formula: log(1 + freq) × recencyDecay
|
|
127
|
-
// log(1+freq): sub-linear frequency term (same as proactive-maintenance prototype).
|
|
128
|
-
// recencyDecay: max(ε, 0.1·0.5^(useAgeDays/180) + 0.5^(useAgeDays/21)) —
|
|
129
|
-
// the fast term halves every 21 days; the 0.1 floor itself halves every
|
|
130
|
-
// 180 days (R4: SHY-style continuous downscaling — an unreviewed-forever
|
|
131
|
-
// asset keeps drifting down instead of parking at the floor). The ε=0.01
|
|
132
|
-
// epsilon keeps the frequency term ordinal for unknown-last-use assets.
|
|
133
|
-
// lastUseMs=0/undefined → useAgeDays=9999 → recencyDecay=ε.
|
|
134
|
-
//
|
|
135
|
-
// The recency term is MANDATORY (plan requirement §WS-1 step 2). Without it
|
|
136
|
-
// retrievalSalience degenerates to a non-decaying frequency count. This
|
|
137
|
-
// always-applied decay replaces the deleted homeostatic demotion pass.
|
|
45
|
+
// Without an outcome row, utility (capped) seeds the outcome term — the same
|
|
46
|
+
// seed the first outcome row gets — so it is not zero at launch.
|
|
47
|
+
const outcome = inputs.outcomeSalience !== undefined
|
|
48
|
+
? clamp01(inputs.outcomeSalience)
|
|
49
|
+
: Math.min(WARM_START_CAP, Math.max(0, inputs.utilityScore ?? 0));
|
|
50
|
+
// log(1 + freq) × recency, where recency halves every 21 days above a floor
|
|
51
|
+
// that itself halves every 180 days; soft-capped to [0, 1).
|
|
138
52
|
const lastUseMs = inputs.lastUseMs ?? 0;
|
|
139
53
|
const useAgeDays = lastUseMs > 0 ? (now - lastUseMs) / DAY_MS : 9999;
|
|
140
54
|
const recencyDecay = Math.max(RECENCY_EPSILON, 0.1 * 0.5 ** (useAgeDays / RECENCY_FLOOR_HALFLIFE_DAYS) + 0.5 ** (useAgeDays / RECENCY_HALFLIFE_DAYS));
|
|
141
55
|
const rawRetrieval = Math.log(1 + inputs.retrievalFreq) * recencyDecay;
|
|
142
|
-
// ── Size penalty ─────────────────────────────────────────────────────────────
|
|
143
|
-
// 1/log10(size): larger assets are slightly deprioritized (same as proactive prototype).
|
|
144
|
-
const sizeProxy = Math.max(SIZE_FLOOR_BYTES, inputs.sizeBytes ?? 0);
|
|
145
|
-
const sizePenalty = 1 / Math.log10(sizeProxy);
|
|
146
|
-
// ── Projection → rankScore ────────────────────────────────────────────────
|
|
147
|
-
//
|
|
148
|
-
// Raw projection may be > 1 (log retrieval terms can exceed 1 for high freq + fresh use).
|
|
149
|
-
// Normalize by the theoretical maximum of the retrieval component:
|
|
150
|
-
// max retrievalRaw = log(1 + Infinity) × (0.1 + 1.0) = Infinity, so we
|
|
151
|
-
// cap instead — rankScore is clamped to [0,1] after applying the size penalty.
|
|
152
|
-
//
|
|
153
|
-
// Normalization approach: we scale the combined linear sum to [0,1] by clamping,
|
|
154
|
-
// after applying the size penalty. The encoding term is already in [0,1]; the
|
|
155
|
-
// retrieval term is open-ended but bounded in practice by log(1+N)×1.1 where N
|
|
156
|
-
// is the retrieval count. We normalize `retrieval` to [0,1] using a soft cap:
|
|
157
|
-
// retrieval_normalized = rawRetrieval / (rawRetrieval + 1)
|
|
158
|
-
// which asymptotes to 1 and equals 0.5 at rawRetrieval=1. This is the same
|
|
159
|
-
// formula used for MemRL utility updates.
|
|
160
56
|
const retrieval = rawRetrieval / (rawRetrieval + 1);
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
//
|
|
168
|
-
// When `outcomeWeightEnabled` is explicitly false (operator opt-out via
|
|
169
|
-
// `improve.salience.outcomeWeightEnabled: false`): fall back to the WS-1
|
|
170
|
-
// parity weights (w_e=0.30, w_r=0.70, w_o=0). The `outcome` sub-score is
|
|
171
|
-
// still computed and stored for observability in that mode.
|
|
172
|
-
let we;
|
|
173
|
-
let wo;
|
|
174
|
-
let wr;
|
|
175
|
-
if (inputs.outcomeWeightEnabled !== false) {
|
|
176
|
-
// WS-2 active (default): three-way split.
|
|
177
|
-
we = W_ENCODING; // 0.25
|
|
178
|
-
wo = W_OUTCOME; // 0.15
|
|
179
|
-
wr = W_RETRIEVAL; // 0.60
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
// WS-1 parity (opt-out): w_o=0, redistribute to WS-1 proportions.
|
|
183
|
-
// Original WS-1 split was w_e=0.30, w_r=0.70.
|
|
184
|
-
we = W_ENCODING_PARITY;
|
|
185
|
-
wo = W_OUTCOME_PARITY;
|
|
186
|
-
wr = W_RETRIEVAL_PARITY;
|
|
187
|
-
}
|
|
188
|
-
const rawRankScore = (we * encoding + wo * outcome + wr * retrieval) * sizePenalty;
|
|
189
|
-
const rankScore = Math.min(1, Math.max(0, rawRankScore));
|
|
57
|
+
// Larger assets rank slightly lower.
|
|
58
|
+
const sizePenalty = 1 / Math.log10(Math.max(SIZE_FLOOR_BYTES, inputs.sizeBytes ?? 0));
|
|
59
|
+
const [we, wo, wr] = inputs.outcomeWeightEnabled !== false
|
|
60
|
+
? [W_ENCODING, W_OUTCOME, W_RETRIEVAL]
|
|
61
|
+
: [W_ENCODING_PARITY, W_OUTCOME_PARITY, W_RETRIEVAL_PARITY];
|
|
62
|
+
const rankScore = clamp01((we * encoding + wo * outcome + wr * retrieval) * sizePenalty);
|
|
190
63
|
return { encoding, outcome, retrieval, rankScore, encodingSource };
|
|
191
64
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
// The three sub-scores live in state.db::asset_salience. Raw SQL now lives in
|
|
195
|
-
// storage/repositories/salience-repository.ts (#672 part 2) — extracted
|
|
196
|
-
// verbatim, only relocated behind the repository boundary. Re-exported here so
|
|
197
|
-
// existing importers of this module resolve unchanged. Migrations live in
|
|
198
|
-
// state-db.ts (migration 009).
|
|
199
|
-
export { getAllRankScores, getAssetSalience, getConsecutiveNoOps, recordNoOp, resetConsecutiveNoOps, upsertAssetSalience, } from "../../storage/repositories/salience-repository.js";
|
|
200
|
-
/**
|
|
201
|
-
* Does this row carry a genuine content-derived `encoding_salience` (#644)?
|
|
202
|
-
*
|
|
203
|
-
* Unknown provenance is not treated as content-derived.
|
|
204
|
-
*/
|
|
65
|
+
export { getAssetSalience, getConsecutiveNoOps, recordNoOp, resetConsecutiveNoOps, upsertAssetSalience, } from "../../storage/repositories/salience-repository.js";
|
|
66
|
+
/** Whether a stored row's encoding salience is content-derived (unknown provenance is not). */
|
|
205
67
|
export function isContentEncodingRow(row) {
|
|
206
68
|
return row.encoding_source === "content";
|
|
207
69
|
}
|
|
208
|
-
// ── Consolidation-selection dampener constants ────────────────────────────────
|
|
209
|
-
//
|
|
210
|
-
// Assets with consecutive_no_ops >= THRESHOLD are deprioritised in the
|
|
211
|
-
// SELECTION ORDER only. The persisted rank_score is intentionally left
|
|
212
|
-
// unchanged so stable assets remain fully retrievable by other callers.
|
|
213
|
-
//
|
|
214
|
-
// Tuning guidance:
|
|
215
|
-
// THRESHOLD — how many consecutive no-op runs before dampening kicks in.
|
|
216
|
-
// 3 means "skipped three times in a row", which signals the
|
|
217
|
-
// LLM consistently has nothing to say about this asset.
|
|
218
|
-
// FACTOR — multiplicative penalty on the effective selection score.
|
|
219
|
-
// 0.5 halves the apparent score so a dampened asset sorts
|
|
220
|
-
// after any peer with >= half its rankScore.
|
|
221
|
-
export const SALIENCE_NO_OP_DAMPEN_THRESHOLD = 3;
|
|
222
|
-
export const SALIENCE_NO_OP_DAMPEN_FACTOR = 0.5;
|
|
223
|
-
/**
|
|
224
|
-
* Emit the forgetting-safety rank-change distribution report.
|
|
225
|
-
*
|
|
226
|
-
* Compares the provided `newRanks` (Map<ref, position (1-indexed)>) against
|
|
227
|
-
* the provided `oldRanks` and flags refs that were in the old top-200 but
|
|
228
|
-
* are now below position 500 as "forgetting candidates".
|
|
229
|
-
*
|
|
230
|
-
* Caller is responsible for computing old/new rank positions before and after
|
|
231
|
-
* the WS-1 formula cutover. Called once at cutover, not every run.
|
|
232
|
-
*
|
|
233
|
-
* @param oldRanks - Map<ref, 1-indexed rank position> under the OLD formula.
|
|
234
|
-
* @param newRanks - Map<ref, 1-indexed rank position> under the NEW formula.
|
|
235
|
-
* @param oldTopN - Assets in old top-N to guard (default: 200).
|
|
236
|
-
* @param forgettingThreshold - New rank position below which a fall is flagged (default: 500).
|
|
237
|
-
*/
|
|
238
|
-
export function buildRankChangeReport(oldRanks, newRanks, oldTopN = 200, forgettingThreshold = 500) {
|
|
239
|
-
const allChanges = [];
|
|
240
|
-
const forgettingCandidates = [];
|
|
241
|
-
for (const [ref, oldRank] of oldRanks) {
|
|
242
|
-
const newRank = newRanks.get(ref);
|
|
243
|
-
if (newRank === undefined)
|
|
244
|
-
continue; // ref not in new ranking
|
|
245
|
-
const rankDelta = newRank - oldRank; // positive = fell in rank
|
|
246
|
-
allChanges.push({ ref, oldRank, newRank, rankDelta });
|
|
247
|
-
if (oldRank <= oldTopN && newRank > forgettingThreshold) {
|
|
248
|
-
forgettingCandidates.push({ ref, oldRank, newRank, rankDelta });
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
// Sort by magnitude of rank drop (most dramatic first).
|
|
252
|
-
forgettingCandidates.sort((a, b) => b.rankDelta - a.rankDelta);
|
|
253
|
-
return { forgettingCandidates, allChanges };
|
|
254
|
-
}
|
|
255
|
-
// ── Last-use timestamp lookup helper ─────────────────────────────────────────
|
|
256
|
-
//
|
|
257
|
-
// Wraps the index DB query to retrieve the last-retrieval timestamp per ref,
|
|
258
|
-
// so callers do not need to import the raw db helpers directly. Returns a Map
|
|
259
|
-
// keyed by the same ref strings passed in.
|
|
260
|
-
//
|
|
261
|
-
// Source: `utility_scores.last_used_at` (ISO-8601 string) joined to entries
|
|
262
|
-
// via entry_id. WS-2 may later supersede this with `asset_outcome.last_retrieved_at`.
|
|
263
70
|
/**
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
* Returns only refs that have a non-null `last_used_at`. Refs absent from the
|
|
267
|
-
* map should be treated as never retrieved (lastUseMs = 0).
|
|
268
|
-
*
|
|
269
|
-
* @param indexDb - An open read-capable index database connection.
|
|
270
|
-
* @param candidates - Planned refs carrying their canonical durable item_ref.
|
|
71
|
+
* Consolidation selection only: an asset whose last three runs were no-ops
|
|
72
|
+
* sorts at half its score. The stored rank is untouched.
|
|
271
73
|
*/
|
|
74
|
+
export const SALIENCE_NO_OP_DAMPEN_THRESHOLD = 3;
|
|
75
|
+
export const SALIENCE_NO_OP_DAMPEN_FACTOR = 0.5;
|
|
76
|
+
/** `ref → last retrieval (ms)` from the index's utility scores; absent means never retrieved. */
|
|
272
77
|
export function getLastUseMsByRef(indexDb, candidates) {
|
|
273
78
|
const result = new Map();
|
|
274
79
|
if (candidates.length === 0)
|
|
275
80
|
return result;
|
|
276
81
|
const refByItemRef = new Map(candidates.flatMap((candidate) => (candidate.itemRef ? [[candidate.itemRef, candidate.ref]] : [])));
|
|
277
|
-
const allEntries = getAllEntries(indexDb);
|
|
278
82
|
const idToRef = new Map();
|
|
279
|
-
for (const indexed of
|
|
83
|
+
for (const indexed of getAllEntries(indexDb)) {
|
|
280
84
|
const ref = refByItemRef.get(indexed.itemRef);
|
|
281
85
|
if (ref)
|
|
282
86
|
idToRef.set(indexed.id, ref);
|
|
283
87
|
}
|
|
284
|
-
|
|
285
|
-
if (ids.length === 0)
|
|
88
|
+
if (idToRef.size === 0)
|
|
286
89
|
return result;
|
|
287
|
-
const
|
|
90
|
+
const scores = getUtilityScoresByIds(indexDb, [...idToRef.keys()]);
|
|
288
91
|
for (const [id, row] of scores) {
|
|
289
92
|
const ref = idToRef.get(id);
|
|
290
|
-
if (!ref)
|
|
291
|
-
continue;
|
|
292
93
|
const lastUsedAt = row.lastUsedAt;
|
|
293
|
-
if (!lastUsedAt)
|
|
94
|
+
if (!ref || !lastUsedAt)
|
|
294
95
|
continue;
|
|
295
96
|
const ms = typeof lastUsedAt === "number" ? lastUsedAt : Date.parse(lastUsedAt);
|
|
296
97
|
if (ms > 0)
|