akm-cli 0.9.17-alpha.1 → 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 +1623 -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/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 +2 -2
- package/dist/commands/health/archive-usage.js +92 -0
- package/dist/commands/health/checks.js +30 -75
- 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 -587
- 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 -119
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -74
- package/dist/commands/health.js +135 -143
- package/dist/commands/improve/consolidate/chunking.js +25 -100
- 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 +573 -1124
- 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 -1075
- package/dist/commands/improve/eligibility.js +126 -400
- 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 +54 -171
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +35 -9
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +451 -1082
- package/dist/commands/improve/ledger.js +119 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +401 -1192
- 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 +776 -2349
- 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 -1364
- 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 +258 -644
- package/dist/commands/proposal/proposal-cli.js +19 -20
- package/dist/commands/proposal/proposal-types.js +27 -41
- package/dist/commands/proposal/proposal.js +38 -8
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +1099 -1475
- 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/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 +37 -135
- 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 +26 -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 -31
- 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 +46 -87
- 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 +81 -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 +8 -10
- 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 +42938 -92375
- package/dist/scripts/akm-migrate.js +42930 -92365
- 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 +88 -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 +100 -0
- 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 +34 -27
- 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 +229 -133
- package/docs/reference/configuration.md +71 -57
- package/docs/reference/data-and-telemetry.md +19 -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 +87 -754
- 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 -146
- package/dist/commands/improve/distill/promote-memory.js +0 -329
- package/dist/commands/improve/distill/quality-gate.js +0 -500
- 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 -21
- 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 -1182
- 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 -872
- 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 -78
- 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
|
@@ -7,24 +7,17 @@ import { decodeTaskHistoryMetadata } from "../../storage/repositories/task-histo
|
|
|
7
7
|
export function roundRate(value) {
|
|
8
8
|
return Number(value.toFixed(4));
|
|
9
9
|
}
|
|
10
|
-
export function parseTaskMetadata(row) {
|
|
11
|
-
const metadata = decodeTaskHistoryMetadata(row.metadata_json);
|
|
12
|
-
return {
|
|
13
|
-
...(metadata.durationMs !== undefined ? { durationMs: metadata.durationMs } : {}),
|
|
14
|
-
...(metadata.detail ? { detail: metadata.detail } : {}),
|
|
15
|
-
...(metadata.engine !== undefined ? { engine: metadata.engine } : {}),
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
10
|
/**
|
|
19
|
-
* `
|
|
20
|
-
* `listStateProposals`).
|
|
21
|
-
* legacy/additive shapes; only
|
|
22
|
-
*
|
|
23
|
-
* the whole `akm health`
|
|
11
|
+
* `task_history.metadata_json`'s `detail` field, decoded and skip-and-warn on
|
|
12
|
+
* corruption instead of throwing (mirrors `listStateProposals`).
|
|
13
|
+
* `decodeTaskHistoryMetadata` already tolerates legacy/additive shapes; only
|
|
14
|
+
* genuine corruption reaches this catch, and a corrupt row must degrade the
|
|
15
|
+
* metric (excluded, not fatal) rather than abort the whole `akm health`
|
|
16
|
+
* computation.
|
|
24
17
|
*/
|
|
25
18
|
export function taskFailureDetail(row) {
|
|
26
19
|
try {
|
|
27
|
-
return
|
|
20
|
+
return decodeTaskHistoryMetadata(row.metadata_json).detail ?? undefined;
|
|
28
21
|
}
|
|
29
22
|
catch (error) {
|
|
30
23
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -37,9 +30,8 @@ export function taskFailureDetail(row) {
|
|
|
37
30
|
* that represents a prepared command (agent/LLM) result. `target_kind` is
|
|
38
31
|
* read in the current (post-D8) vocabulary — the
|
|
39
32
|
* `025-task-history-vocabulary-backfill` state migration rewrites every
|
|
40
|
-
* legacy-vocabulary row
|
|
41
|
-
*
|
|
42
|
-
* it, so a `"command"` row here is unambiguously the agent/LLM arm.
|
|
33
|
+
* legacy-vocabulary row before this ever runs against it, so a `"command"`
|
|
34
|
+
* row here is unambiguously the agent/LLM arm.
|
|
43
35
|
*/
|
|
44
36
|
export function isAgentTaskHistoryRow(row) {
|
|
45
37
|
return row.target_kind === "command";
|
|
@@ -48,8 +40,7 @@ export function isAgentTaskHistoryRow(row) {
|
|
|
48
40
|
* #943: reason-value breakdown for a set of agent (command-kind) task
|
|
49
41
|
* failure rows — how much of the observed failures are `timeout` vs
|
|
50
42
|
* `non_zero_exit` vs `spawn_failed` etc., so `akm health`'s `task-fail-rate`
|
|
51
|
-
* advisory can say "timeout-dominant" from data rather than log grep.
|
|
52
|
-
* the existing `AgentFailureReason` vocabulary verbatim (spawn.ts) — a
|
|
43
|
+
* advisory can say "timeout-dominant" from data rather than log grep. A
|
|
53
44
|
* reason-per-row read failure (already warned by {@link taskFailureDetail})
|
|
54
45
|
* still counts under `"unknown"` rather than being dropped, so the total
|
|
55
46
|
* always equals `agentFailures.length`.
|
|
@@ -62,17 +53,35 @@ export function countAgentFailureReasons(agentFailures) {
|
|
|
62
53
|
}
|
|
63
54
|
return counts;
|
|
64
55
|
}
|
|
65
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Decode one `improve_runs.result_json` envelope, warning once per row on
|
|
58
|
+
* failure (mirrors {@link taskFailureDetail}'s handling of the analogous
|
|
59
|
+
* `task_history` case) and returning `undefined` instead of throwing.
|
|
60
|
+
* Callers count the `undefined` case themselves (`resultRows.skipped.invalid`
|
|
61
|
+
* / `resultStatus: "invalid"`) so a decode failure is never silent — the
|
|
62
|
+
* warning names *why* (corrupt data, or a decoder too strict for a shape an
|
|
63
|
+
* older release legitimately wrote), the counters say *how many*.
|
|
64
|
+
*/
|
|
65
|
+
function decodeImproveResultRow(row) {
|
|
66
|
+
try {
|
|
67
|
+
return decodeImproveResult(row.result_json).envelope;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
71
|
+
console.warn(`[akm] Skipping unparseable improve_runs row in health metrics (id=${row.id}, started_at=${row.started_at}): ${message}`);
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** A zeroed accumulator — also what health reports when it could not read state.db at all (#791). */
|
|
76
|
+
export function emptyImproveMetrics() {
|
|
66
77
|
return {
|
|
67
78
|
invoked: 0,
|
|
68
79
|
completed: 0,
|
|
69
80
|
skipped: 0,
|
|
70
81
|
skipReasons: {},
|
|
71
82
|
resultRows: { total: 0, included: 0, skipped: { invalid: 0 } },
|
|
72
|
-
plannedRefs: 0,
|
|
73
|
-
strategyFilteredRefs: 0,
|
|
74
83
|
actions: {
|
|
75
|
-
reflect: { ok: 0, failed: 0, cooldown: 0, skipped: 0
|
|
84
|
+
reflect: { ok: 0, failed: 0, cooldown: 0, skipped: 0 },
|
|
76
85
|
distill: {
|
|
77
86
|
queued: 0,
|
|
78
87
|
llmFailed: 0,
|
|
@@ -81,119 +90,30 @@ function createUnknownImproveMetrics() {
|
|
|
81
90
|
configDisabled: 0,
|
|
82
91
|
skipped: 0,
|
|
83
92
|
skippedByReason: {},
|
|
84
|
-
deferred: 0,
|
|
85
|
-
deferredByReason: {},
|
|
86
93
|
},
|
|
87
94
|
memoryPrune: 0,
|
|
88
95
|
memoryInference: 0,
|
|
89
|
-
graphExtraction: 0,
|
|
90
96
|
error: 0,
|
|
91
97
|
},
|
|
92
98
|
autoAccept: { promoted: 0, validationFailed: 0 },
|
|
93
|
-
reflectsWithErrorContext: 0,
|
|
94
|
-
coverageGapCount: 0,
|
|
95
|
-
deadUrlCount: 0,
|
|
96
|
-
deadUrlsChecked: 0,
|
|
97
|
-
deadUrlsTotal: 0,
|
|
98
|
-
deadUrlsSkipped: 0,
|
|
99
99
|
memorySummary: { eligible: 0, derived: 0 },
|
|
100
|
-
memoryCleanup: {
|
|
101
|
-
pruneCandidates: 0,
|
|
102
|
-
contradictionCandidates: 0,
|
|
103
|
-
beliefStateTransitions: 0,
|
|
104
|
-
consolidationCandidates: 0,
|
|
105
|
-
archived: 0,
|
|
106
|
-
warnings: 0,
|
|
107
|
-
},
|
|
108
100
|
consolidation: {
|
|
109
|
-
ran: false,
|
|
110
101
|
processed: 0,
|
|
111
102
|
promoted: 0,
|
|
112
103
|
merged: 0,
|
|
113
104
|
deleted: 0,
|
|
114
105
|
contradicted: 0,
|
|
115
106
|
judgedNoAction: 0,
|
|
116
|
-
mergedSecondaries: 0,
|
|
117
|
-
failedChunkMemories: 0,
|
|
118
|
-
skipReasons: {},
|
|
119
107
|
failedChunks: 0,
|
|
120
108
|
totalChunks: 0,
|
|
121
109
|
durationMs: 0,
|
|
122
110
|
},
|
|
123
|
-
memoryInference: {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
cacheHits: 0,
|
|
127
|
-
retryAttempts: 0,
|
|
128
|
-
freshAttempts: 0,
|
|
129
|
-
splitParents: 0,
|
|
130
|
-
written: 0,
|
|
131
|
-
skippedNoFacts: 0,
|
|
132
|
-
skippedChildExists: 0,
|
|
133
|
-
skippedAborted: 0,
|
|
134
|
-
unaccounted: 0,
|
|
135
|
-
htmlErrorCount: 0,
|
|
136
|
-
yieldRate: 0,
|
|
137
|
-
durationMs: 0,
|
|
138
|
-
},
|
|
139
|
-
graphExtraction: {
|
|
140
|
-
ran: false,
|
|
141
|
-
extractedFiles: 0,
|
|
142
|
-
consideredFiles: 0,
|
|
143
|
-
entities: 0,
|
|
144
|
-
relations: 0,
|
|
145
|
-
extractionCoverage: 0,
|
|
146
|
-
cacheHits: 0,
|
|
147
|
-
cacheMisses: 0,
|
|
148
|
-
cacheHitRate: 0,
|
|
149
|
-
truncations: 0,
|
|
150
|
-
failures: 0,
|
|
151
|
-
htmlErrors: 0,
|
|
152
|
-
retryAttempts: 0,
|
|
153
|
-
nonArrayBatchFailures: 0,
|
|
154
|
-
durationMs: 0,
|
|
155
|
-
},
|
|
156
|
-
sessionExtraction: {
|
|
157
|
-
ran: false,
|
|
158
|
-
sessionsScanned: 0,
|
|
159
|
-
sessionsExtracted: 0,
|
|
160
|
-
sessionsSkipped: 0,
|
|
161
|
-
proposalsCreated: 0,
|
|
162
|
-
warnings: 0,
|
|
163
|
-
durationMs: 0,
|
|
164
|
-
},
|
|
165
|
-
wallTime: {
|
|
166
|
-
count: 0,
|
|
167
|
-
medianMs: 0,
|
|
168
|
-
p95Ms: 0,
|
|
169
|
-
minMs: 0,
|
|
170
|
-
maxMs: 0,
|
|
171
|
-
byPhase: {
|
|
172
|
-
consolidation: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
173
|
-
memoryInference: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
174
|
-
graphExtraction: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
175
|
-
},
|
|
176
|
-
},
|
|
177
|
-
perfTelemetry: {
|
|
178
|
-
dedupPoolSize: 0,
|
|
179
|
-
llmPoolSize: 0,
|
|
180
|
-
embedMs: 0,
|
|
181
|
-
embedCacheHits: 0,
|
|
182
|
-
embedCacheMisses: 0,
|
|
183
|
-
overBudgetRuns: 0,
|
|
184
|
-
runsWithTelemetry: 0,
|
|
185
|
-
},
|
|
186
|
-
coverage: {
|
|
187
|
-
rate: Number.NaN,
|
|
188
|
-
eligibleFraction: Number.NaN,
|
|
189
|
-
acceptedProposals: 0,
|
|
190
|
-
distinctRefs: 0,
|
|
191
|
-
churnRatio: Number.NaN,
|
|
192
|
-
totalAssets: 0,
|
|
193
|
-
},
|
|
111
|
+
memoryInference: { considered: 0, freshAttempts: 0, written: 0, skippedNoFacts: 0, yieldRate: 0, durationMs: 0 },
|
|
112
|
+
wallTime: { medianMs: 0, p95Ms: 0 },
|
|
113
|
+
coverage: { acceptedProposals: 0, distinctRefs: 0 },
|
|
194
114
|
};
|
|
195
115
|
}
|
|
196
|
-
|
|
116
|
+
function toFiniteNumber(value) {
|
|
197
117
|
if (typeof value === "number" && Number.isFinite(value))
|
|
198
118
|
return value;
|
|
199
119
|
if (typeof value === "string" && value.trim()) {
|
|
@@ -203,47 +123,9 @@ export function toFiniteNumber(value) {
|
|
|
203
123
|
}
|
|
204
124
|
return 0;
|
|
205
125
|
}
|
|
206
|
-
/**
|
|
207
|
-
* Event-derived metrics. Only `completed` and skipReasons/invoked are sourced
|
|
208
|
-
* from events in v2 — the richer fields come from {@link summarizeImproveRuns}.
|
|
209
|
-
* The function still receives `improve_completed` events so that the completed
|
|
210
|
-
* count reflects the canonical event stream (it lines up 1:1 with improve_runs
|
|
211
|
-
* rows in practice, but the events table remains the system-of-record for the
|
|
212
|
-
* existence of a run).
|
|
213
|
-
*/
|
|
214
|
-
export function summarizeImproveCompleted(events) {
|
|
215
|
-
const metrics = createUnknownImproveMetrics();
|
|
216
|
-
metrics.completed = events.length;
|
|
217
|
-
return metrics;
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Read the machine-readable reason from a distill `outcome: "skipped"` result.
|
|
221
|
-
*/
|
|
222
|
-
function classifyDistillSkipReason(r) {
|
|
223
|
-
const explicitReason = typeof r?.skipReason === "string" ? r.skipReason : undefined;
|
|
224
|
-
return explicitReason || "unknown";
|
|
225
|
-
}
|
|
226
|
-
// ── projectRunMetrics phase helpers (chunk-9 WI-9.5c; file-level decompose of
|
|
227
|
-
// the single-envelope projection — each helper mutates its own disjoint
|
|
228
|
-
// subtree of the accumulator from the raw envelope, so call order does not
|
|
229
|
-
// matter; kept in envelope-field order for readability) ──────────────────────
|
|
230
|
-
/** plannedRefs / strategyFilteredRefs ref-count accounting. */
|
|
231
|
-
function applyPlannedRefs(metrics, result) {
|
|
232
|
-
// plannedRefs (array of {ref, reason})
|
|
233
|
-
const plannedRefs = result.plannedRefs;
|
|
234
|
-
if (Array.isArray(plannedRefs))
|
|
235
|
-
metrics.plannedRefs += plannedRefs.length;
|
|
236
|
-
// strategyFilteredRefs (array of {ref, reason}) — 2026-05-27: pre-filter
|
|
237
|
-
// bucket from `collectEligibleRefs` so the metric reflects work the
|
|
238
|
-
// planner dropped before signal-delta / per-pass dispatch.
|
|
239
|
-
const strategyFilteredRefs = result.strategyFilteredRefs;
|
|
240
|
-
if (Array.isArray(strategyFilteredRefs))
|
|
241
|
-
metrics.strategyFilteredRefs += strategyFilteredRefs.length;
|
|
242
|
-
}
|
|
243
|
-
/** One `actions[]` entry → the matching counter bucket (see ImproveHealthMetrics.actions jsdoc for the taxonomy). */
|
|
126
|
+
/** One `actions[]` entry → its counter bucket; unknown modes/outcomes are not counted. */
|
|
244
127
|
function applyAction(metrics, action) {
|
|
245
|
-
|
|
246
|
-
switch (mode) {
|
|
128
|
+
switch (typeof action.mode === "string" ? action.mode : "") {
|
|
247
129
|
case "reflect":
|
|
248
130
|
metrics.actions.reflect.ok += 1;
|
|
249
131
|
break;
|
|
@@ -253,20 +135,12 @@ function applyAction(metrics, action) {
|
|
|
253
135
|
case "reflect-cooldown":
|
|
254
136
|
metrics.actions.reflect.cooldown += 1;
|
|
255
137
|
break;
|
|
256
|
-
case "reflect-skipped":
|
|
138
|
+
case "reflect-skipped":
|
|
257
139
|
metrics.actions.reflect.skipped += 1;
|
|
258
|
-
const r = action.result;
|
|
259
|
-
const reason = typeof r?.reason === "string" && r.reason.trim() ? r.reason : "unknown";
|
|
260
|
-
metrics.actions.reflect.skippedByReason[reason] = (metrics.actions.reflect.skippedByReason[reason] ?? 0) + 1;
|
|
261
|
-
break;
|
|
262
|
-
}
|
|
263
|
-
case "reflect-guard-rejected":
|
|
264
|
-
metrics.actions.reflect.guardRejected += 1;
|
|
265
140
|
break;
|
|
266
141
|
case "distill": {
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
switch (outcome) {
|
|
142
|
+
const result = action.result;
|
|
143
|
+
switch (typeof result?.outcome === "string" ? result.outcome : "") {
|
|
270
144
|
case "queued":
|
|
271
145
|
metrics.actions.distill.queued += 1;
|
|
272
146
|
break;
|
|
@@ -283,21 +157,6 @@ function applyAction(metrics, action) {
|
|
|
283
157
|
case "config_disabled":
|
|
284
158
|
metrics.actions.distill.configDisabled += 1;
|
|
285
159
|
break;
|
|
286
|
-
case "skipped": {
|
|
287
|
-
// Previously dropped on the floor. The four sub-paths that emit
|
|
288
|
-
// `outcome: "skipped"` (see distill.ts:893, 1024, 1120, 1576):
|
|
289
|
-
// - recursive_lesson_input (type guard refused a lesson input)
|
|
290
|
-
// - conflict_noop (LLM resolved destination conflict as NOOP)
|
|
291
|
-
// - proposal-skipped cooldown / dedup at persistence
|
|
292
|
-
// 465 events/7d in the user's live stack. The result message
|
|
293
|
-
// typically encodes the reason; we also accept an explicit
|
|
294
|
-
// `skipReason` field when downstream code sets it.
|
|
295
|
-
metrics.actions.distill.deferred += 1;
|
|
296
|
-
const reason = classifyDistillSkipReason(r);
|
|
297
|
-
metrics.actions.distill.deferredByReason[reason] =
|
|
298
|
-
(metrics.actions.distill.deferredByReason[reason] ?? 0) + 1;
|
|
299
|
-
break;
|
|
300
|
-
}
|
|
301
160
|
default:
|
|
302
161
|
break;
|
|
303
162
|
}
|
|
@@ -309,267 +168,79 @@ function applyAction(metrics, action) {
|
|
|
309
168
|
case "memory-inference":
|
|
310
169
|
metrics.actions.memoryInference += 1;
|
|
311
170
|
break;
|
|
312
|
-
case "graph-extraction":
|
|
313
|
-
metrics.actions.graphExtraction += 1;
|
|
314
|
-
break;
|
|
315
171
|
case "error":
|
|
316
172
|
metrics.actions.error += 1;
|
|
317
173
|
break;
|
|
174
|
+
default:
|
|
175
|
+
break;
|
|
318
176
|
}
|
|
319
177
|
}
|
|
320
|
-
/**
|
|
321
|
-
function
|
|
322
|
-
const
|
|
323
|
-
if (
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
applyAction(metrics, action);
|
|
178
|
+
/** Project one `improve_runs.result_json` envelope into a single-run accumulator. */
|
|
179
|
+
function projectRunMetrics(result) {
|
|
180
|
+
const metrics = emptyImproveMetrics();
|
|
181
|
+
if (Array.isArray(result.actions)) {
|
|
182
|
+
for (const action of result.actions)
|
|
183
|
+
applyAction(metrics, action);
|
|
327
184
|
}
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Read the bounded `distillSkipped` aggregate into the corresponding total and
|
|
331
|
-
* per-reason health metrics.
|
|
332
|
-
*/
|
|
333
|
-
function applyDistillSkippedAggregate(metrics, result) {
|
|
334
185
|
const distillSkipped = result.distillSkipped;
|
|
335
|
-
if (
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const byReason = distillSkipped.byReason;
|
|
339
|
-
if (byReason && typeof byReason === "object") {
|
|
340
|
-
for (const [reason, count] of Object.entries(byReason)) {
|
|
186
|
+
if (distillSkipped && typeof distillSkipped === "object") {
|
|
187
|
+
metrics.actions.distill.skipped += toFiniteNumber(distillSkipped.total);
|
|
188
|
+
for (const [reason, count] of Object.entries(distillSkipped.byReason ?? {})) {
|
|
341
189
|
metrics.actions.distill.skippedByReason[reason] =
|
|
342
190
|
(metrics.actions.distill.skippedByReason[reason] ?? 0) + toFiniteNumber(count);
|
|
343
191
|
}
|
|
344
192
|
}
|
|
345
|
-
}
|
|
346
|
-
/** autoAccept + the small envelope-level counters (reflectsWithErrorContext, coverageGaps, deadUrls). */
|
|
347
|
-
function applyMiscCounters(metrics, result) {
|
|
348
193
|
metrics.autoAccept.promoted += toFiniteNumber(result.gateAutoAcceptedCount);
|
|
349
194
|
metrics.autoAccept.validationFailed += toFiniteNumber(result.gateAutoAcceptFailedCount);
|
|
350
|
-
metrics.reflectsWithErrorContext += toFiniteNumber(result.reflectsWithErrorContext);
|
|
351
|
-
if (Array.isArray(result.coverageGaps))
|
|
352
|
-
metrics.coverageGapCount += result.coverageGaps.length;
|
|
353
|
-
if (Array.isArray(result.deadUrls))
|
|
354
|
-
metrics.deadUrlCount += result.deadUrls.length;
|
|
355
|
-
const deadUrlCoverage = result.deadUrlCoverage;
|
|
356
|
-
if (deadUrlCoverage && typeof deadUrlCoverage === "object") {
|
|
357
|
-
metrics.deadUrlsChecked += toFiniteNumber(deadUrlCoverage.checked);
|
|
358
|
-
metrics.deadUrlsTotal += toFiniteNumber(deadUrlCoverage.total);
|
|
359
|
-
metrics.deadUrlsSkipped += toFiniteNumber(deadUrlCoverage.skipped);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
function applyMemorySummary(metrics, result) {
|
|
363
195
|
const memorySummary = result.memorySummary;
|
|
364
|
-
if (
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
metrics.memorySummary.derived += toFiniteNumber(memorySummary.derived);
|
|
368
|
-
}
|
|
369
|
-
function applyMemoryCleanup(metrics, result) {
|
|
370
|
-
const memoryCleanup = result.memoryCleanup;
|
|
371
|
-
if (!memoryCleanup)
|
|
372
|
-
return;
|
|
373
|
-
if (Array.isArray(memoryCleanup.pruneCandidates))
|
|
374
|
-
metrics.memoryCleanup.pruneCandidates += memoryCleanup.pruneCandidates.length;
|
|
375
|
-
if (Array.isArray(memoryCleanup.contradictionCandidates))
|
|
376
|
-
metrics.memoryCleanup.contradictionCandidates += memoryCleanup.contradictionCandidates.length;
|
|
377
|
-
if (Array.isArray(memoryCleanup.beliefStateTransitions))
|
|
378
|
-
metrics.memoryCleanup.beliefStateTransitions += memoryCleanup.beliefStateTransitions.length;
|
|
379
|
-
if (Array.isArray(memoryCleanup.consolidationCandidates))
|
|
380
|
-
metrics.memoryCleanup.consolidationCandidates += memoryCleanup.consolidationCandidates.length;
|
|
381
|
-
if (Array.isArray(memoryCleanup.archived))
|
|
382
|
-
metrics.memoryCleanup.archived += memoryCleanup.archived.length;
|
|
383
|
-
if (Array.isArray(memoryCleanup.warnings))
|
|
384
|
-
metrics.memoryCleanup.warnings += memoryCleanup.warnings.length;
|
|
385
|
-
}
|
|
386
|
-
function applyConsolidation(metrics, result) {
|
|
387
|
-
const consolidation = result.consolidation;
|
|
388
|
-
if (!consolidation)
|
|
389
|
-
return;
|
|
390
|
-
metrics.consolidation.processed += toFiniteNumber(consolidation.processed);
|
|
391
|
-
metrics.consolidation.merged += toFiniteNumber(consolidation.merged);
|
|
392
|
-
metrics.consolidation.deleted += toFiniteNumber(consolidation.deleted);
|
|
393
|
-
metrics.consolidation.contradicted += toFiniteNumber(consolidation.contradicted);
|
|
394
|
-
if (Array.isArray(consolidation.promoted))
|
|
395
|
-
metrics.consolidation.promoted += consolidation.promoted.length;
|
|
396
|
-
metrics.consolidation.failedChunks += toFiniteNumber(consolidation.failedChunks);
|
|
397
|
-
metrics.consolidation.totalChunks += toFiniteNumber(consolidation.totalChunks);
|
|
398
|
-
metrics.consolidation.durationMs += toFiniteNumber(consolidation.durationMs);
|
|
399
|
-
metrics.consolidation.judgedNoAction += toFiniteNumber(consolidation.judgedNoAction);
|
|
400
|
-
metrics.consolidation.mergedSecondaries += toFiniteNumber(consolidation.mergedSecondaries);
|
|
401
|
-
metrics.consolidation.failedChunkMemories += toFiniteNumber(consolidation.failedChunkMemories);
|
|
402
|
-
// Structured emitter (new on this branch): consolidate.ts now pushes
|
|
403
|
-
// per-ref grouped `{ref, skips: [{op, reason}]}` entries to `skipReasons`
|
|
404
|
-
// for every deterministic post-LLM rejection. Each ref appears once but
|
|
405
|
-
// may carry multiple skips; aggregate every reason. Pre-fix envelopes have
|
|
406
|
-
// neither field, so be defensive.
|
|
407
|
-
const skipReasons = consolidation.skipReasons;
|
|
408
|
-
if (Array.isArray(skipReasons)) {
|
|
409
|
-
for (const entry of skipReasons) {
|
|
410
|
-
if (!entry || typeof entry !== "object")
|
|
411
|
-
continue;
|
|
412
|
-
const skips = entry.skips;
|
|
413
|
-
if (!Array.isArray(skips))
|
|
414
|
-
continue;
|
|
415
|
-
for (const skip of skips) {
|
|
416
|
-
if (!skip || typeof skip !== "object")
|
|
417
|
-
continue;
|
|
418
|
-
const reason = skip.reason;
|
|
419
|
-
if (typeof reason !== "string" || !reason.trim())
|
|
420
|
-
continue;
|
|
421
|
-
metrics.consolidation.skipReasons[reason] = (metrics.consolidation.skipReasons[reason] ?? 0) + 1;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
196
|
+
if (memorySummary) {
|
|
197
|
+
metrics.memorySummary.eligible += toFiniteNumber(memorySummary.eligible);
|
|
198
|
+
metrics.memorySummary.derived += toFiniteNumber(memorySummary.derived);
|
|
424
199
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
200
|
+
const consolidation = result.consolidation;
|
|
201
|
+
if (consolidation) {
|
|
202
|
+
const cons = metrics.consolidation;
|
|
203
|
+
cons.processed += toFiniteNumber(consolidation.processed);
|
|
204
|
+
if (Array.isArray(consolidation.promoted))
|
|
205
|
+
cons.promoted += consolidation.promoted.length;
|
|
206
|
+
cons.merged += toFiniteNumber(consolidation.merged);
|
|
207
|
+
cons.deleted += toFiniteNumber(consolidation.deleted);
|
|
208
|
+
cons.contradicted += toFiniteNumber(consolidation.contradicted);
|
|
209
|
+
cons.judgedNoAction += toFiniteNumber(consolidation.judgedNoAction);
|
|
210
|
+
cons.failedChunks += toFiniteNumber(consolidation.failedChunks);
|
|
211
|
+
cons.totalChunks += toFiniteNumber(consolidation.totalChunks);
|
|
212
|
+
cons.durationMs += toFiniteNumber(consolidation.durationMs);
|
|
438
213
|
}
|
|
439
|
-
}
|
|
440
|
-
function applyMemoryInference(metrics, result) {
|
|
441
214
|
const memoryInference = result.memoryInference;
|
|
442
215
|
if (memoryInference) {
|
|
443
216
|
const considered = toFiniteNumber(memoryInference.considered);
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
metrics.memoryInference.skippedChildExists += toFiniteNumber(memoryInference.skippedChildExists);
|
|
452
|
-
metrics.memoryInference.skippedAborted += toFiniteNumber(memoryInference.skippedAborted);
|
|
453
|
-
metrics.memoryInference.unaccounted += toFiniteNumber(memoryInference.unaccounted);
|
|
454
|
-
metrics.memoryInference.htmlErrorCount += toFiniteNumber(memoryInference.htmlErrorCount);
|
|
217
|
+
const mi = metrics.memoryInference;
|
|
218
|
+
mi.considered += considered;
|
|
219
|
+
// Cache hits and budget-aborted records never reached the LLM; excluding
|
|
220
|
+
// them keeps the yield rate a statement about real inference attempts.
|
|
221
|
+
mi.freshAttempts += Math.max(0, considered - toFiniteNumber(memoryInference.cacheHits) - toFiniteNumber(memoryInference.skippedAborted));
|
|
222
|
+
mi.written += toFiniteNumber(memoryInference.writtenFacts);
|
|
223
|
+
mi.skippedNoFacts += toFiniteNumber(memoryInference.skippedNoFacts);
|
|
455
224
|
}
|
|
456
225
|
metrics.memoryInference.durationMs += toFiniteNumber(result.memoryInferenceDurationMs);
|
|
457
|
-
}
|
|
458
|
-
function applyGraphExtraction(metrics, result) {
|
|
459
|
-
const graphExtraction = result.graphExtraction;
|
|
460
|
-
if (graphExtraction) {
|
|
461
|
-
const quality = graphExtraction.quality;
|
|
462
|
-
if (quality) {
|
|
463
|
-
metrics.graphExtraction.extractedFiles += toFiniteNumber(quality.extractedFiles);
|
|
464
|
-
metrics.graphExtraction.consideredFiles += toFiniteNumber(quality.consideredFiles);
|
|
465
|
-
}
|
|
466
|
-
metrics.graphExtraction.entities += toFiniteNumber(graphExtraction.totalEntities);
|
|
467
|
-
metrics.graphExtraction.relations += toFiniteNumber(graphExtraction.totalRelations);
|
|
468
|
-
const telemetry = graphExtraction.telemetry;
|
|
469
|
-
if (telemetry) {
|
|
470
|
-
metrics.graphExtraction.cacheHits += toFiniteNumber(telemetry.cacheHits);
|
|
471
|
-
metrics.graphExtraction.cacheMisses += toFiniteNumber(telemetry.cacheMisses);
|
|
472
|
-
metrics.graphExtraction.truncations += toFiniteNumber(telemetry.truncationCount);
|
|
473
|
-
metrics.graphExtraction.failures += toFiniteNumber(telemetry.failureCount);
|
|
474
|
-
metrics.graphExtraction.htmlErrors += toFiniteNumber(telemetry.htmlErrorCount);
|
|
475
|
-
metrics.graphExtraction.retryAttempts += toFiniteNumber(telemetry.retryAttempts);
|
|
476
|
-
metrics.graphExtraction.nonArrayBatchFailures += toFiniteNumber(telemetry.nonArrayBatchFailures);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
metrics.graphExtraction.durationMs += toFiniteNumber(result.graphExtractionDurationMs);
|
|
480
|
-
}
|
|
481
|
-
function applySessionExtraction(metrics, result) {
|
|
482
|
-
if (!Array.isArray(result.extract))
|
|
483
|
-
return;
|
|
484
|
-
for (const e of result.extract) {
|
|
485
|
-
metrics.sessionExtraction.sessionsScanned += toFiniteNumber(e.sessionsProcessed);
|
|
486
|
-
metrics.sessionExtraction.sessionsSkipped += toFiniteNumber(e.sessionsSkipped);
|
|
487
|
-
if (Array.isArray(e.sessions)) {
|
|
488
|
-
metrics.sessionExtraction.sessionsExtracted += e.sessions.filter((s) => Array.isArray(s.proposalIds) && s.proposalIds.length > 0).length;
|
|
489
|
-
}
|
|
490
|
-
metrics.sessionExtraction.proposalsCreated += Array.isArray(e.proposals) ? e.proposals.length : 0;
|
|
491
|
-
metrics.sessionExtraction.warnings += Array.isArray(e.warnings) ? e.warnings.length : 0;
|
|
492
|
-
metrics.sessionExtraction.durationMs += toFiniteNumber(e.durationMs);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
/**
|
|
496
|
-
* Project a single `improve_runs.result_json` envelope into an accumulator-shaped
|
|
497
|
-
* ImproveHealthMetrics. The aggregator merges these per-row metrics into one
|
|
498
|
-
* window-level metric. File-level decomposed (chunk-9 WI-9.5c) into one
|
|
499
|
-
* `apply*` helper per envelope section above; each mutates its own disjoint
|
|
500
|
-
* subtree of the accumulator so the call order below is not load-bearing.
|
|
501
|
-
*/
|
|
502
|
-
function projectRunMetrics(result) {
|
|
503
|
-
const metrics = createUnknownImproveMetrics();
|
|
504
|
-
applyPlannedRefs(metrics, result);
|
|
505
|
-
applyActionsList(metrics, result);
|
|
506
|
-
applyDistillSkippedAggregate(metrics, result);
|
|
507
|
-
applyMiscCounters(metrics, result);
|
|
508
|
-
applyMemorySummary(metrics, result);
|
|
509
|
-
applyMemoryCleanup(metrics, result);
|
|
510
|
-
applyConsolidation(metrics, result);
|
|
511
|
-
applyMemoryInference(metrics, result);
|
|
512
|
-
applyGraphExtraction(metrics, result);
|
|
513
|
-
applySessionExtraction(metrics, result);
|
|
514
226
|
return metrics;
|
|
515
227
|
}
|
|
516
|
-
/**
|
|
517
|
-
* Finalize derived flags and rates on an accumulator. Used both for the
|
|
518
|
-
* window-level aggregate and for each per-run row in --detail per-run mode
|
|
519
|
-
* so the single-row metrics still expose `ran` / `yieldRate` / `cacheHitRate`.
|
|
520
|
-
*/
|
|
228
|
+
/** Derived rates on an accumulator (window aggregate or single run). */
|
|
521
229
|
function finalizeImproveMetrics(metrics) {
|
|
522
|
-
metrics.
|
|
523
|
-
|
|
524
|
-
metrics.consolidation.durationMs > 0 ||
|
|
525
|
-
metrics.consolidation.promoted > 0 ||
|
|
526
|
-
metrics.consolidation.merged > 0 ||
|
|
527
|
-
metrics.consolidation.deleted > 0 ||
|
|
528
|
-
metrics.consolidation.contradicted > 0 ||
|
|
529
|
-
metrics.consolidation.totalChunks > 0;
|
|
530
|
-
metrics.memoryInference.ran =
|
|
531
|
-
metrics.memoryInference.considered > 0 ||
|
|
532
|
-
metrics.memoryInference.written > 0 ||
|
|
533
|
-
metrics.memoryInference.durationMs > 0;
|
|
534
|
-
// Yield denominator excludes cache hits and aborted records.
|
|
535
|
-
metrics.memoryInference.freshAttempts = Math.max(0, metrics.memoryInference.considered - metrics.memoryInference.cacheHits - metrics.memoryInference.skippedAborted);
|
|
536
|
-
metrics.memoryInference.yieldRate =
|
|
537
|
-
metrics.memoryInference.freshAttempts > 0
|
|
538
|
-
? roundRate(metrics.memoryInference.written / metrics.memoryInference.freshAttempts)
|
|
539
|
-
: 0;
|
|
540
|
-
metrics.graphExtraction.ran =
|
|
541
|
-
metrics.graphExtraction.extractedFiles > 0 ||
|
|
542
|
-
metrics.graphExtraction.entities > 0 ||
|
|
543
|
-
metrics.graphExtraction.durationMs > 0;
|
|
544
|
-
const cacheTotal = metrics.graphExtraction.cacheHits + metrics.graphExtraction.cacheMisses;
|
|
545
|
-
metrics.graphExtraction.cacheHitRate = cacheTotal > 0 ? roundRate(metrics.graphExtraction.cacheHits / cacheTotal) : 0;
|
|
546
|
-
metrics.graphExtraction.extractionCoverage =
|
|
547
|
-
metrics.graphExtraction.consideredFiles > 0
|
|
548
|
-
? roundRate(metrics.graphExtraction.extractedFiles / metrics.graphExtraction.consideredFiles)
|
|
549
|
-
: 0;
|
|
550
|
-
metrics.sessionExtraction.ran =
|
|
551
|
-
metrics.sessionExtraction.sessionsScanned > 0 ||
|
|
552
|
-
metrics.sessionExtraction.proposalsCreated > 0 ||
|
|
553
|
-
metrics.sessionExtraction.durationMs > 0;
|
|
230
|
+
const mi = metrics.memoryInference;
|
|
231
|
+
mi.yieldRate = mi.freshAttempts > 0 ? roundRate(mi.written / mi.freshAttempts) : 0;
|
|
554
232
|
}
|
|
555
233
|
/**
|
|
556
|
-
* Merge per-
|
|
557
|
-
*
|
|
234
|
+
* Merge per-run metrics from `src` into accumulator `dst`. Every counter is
|
|
235
|
+
* additive; `memorySummary` is a whole-stash snapshot and is deliberately NOT
|
|
236
|
+
* merged (summing it across runs inflated it ~N× — the 1.2M-eligible bug), and
|
|
237
|
+
* the derived rate is recomputed by {@link finalizeImproveMetrics}.
|
|
558
238
|
*/
|
|
559
239
|
function mergeImproveMetrics(dst, src) {
|
|
560
|
-
dst.plannedRefs += src.plannedRefs;
|
|
561
|
-
// strategyFilteredRefs is the count of refs the planner drops up-front for the
|
|
562
|
-
// active strategy — recomputed against the (stable) stash every run, so it is a
|
|
563
|
-
// snapshot, NOT a per-run increment. Summing it re-counts the same refs each
|
|
564
|
-
// run (the ~2.4M bug). Set from the most recent run in summarizeImproveRuns.
|
|
565
240
|
dst.actions.reflect.ok += src.actions.reflect.ok;
|
|
566
241
|
dst.actions.reflect.failed += src.actions.reflect.failed;
|
|
567
242
|
dst.actions.reflect.cooldown += src.actions.reflect.cooldown;
|
|
568
243
|
dst.actions.reflect.skipped += src.actions.reflect.skipped;
|
|
569
|
-
dst.actions.reflect.guardRejected += src.actions.reflect.guardRejected;
|
|
570
|
-
for (const [reason, count] of Object.entries(src.actions.reflect.skippedByReason)) {
|
|
571
|
-
dst.actions.reflect.skippedByReason[reason] = (dst.actions.reflect.skippedByReason[reason] ?? 0) + count;
|
|
572
|
-
}
|
|
573
244
|
dst.actions.distill.queued += src.actions.distill.queued;
|
|
574
245
|
dst.actions.distill.llmFailed += src.actions.distill.llmFailed;
|
|
575
246
|
dst.actions.distill.judgeRejected += src.actions.distill.judgeRejected;
|
|
@@ -579,86 +250,25 @@ function mergeImproveMetrics(dst, src) {
|
|
|
579
250
|
for (const [reason, count] of Object.entries(src.actions.distill.skippedByReason)) {
|
|
580
251
|
dst.actions.distill.skippedByReason[reason] = (dst.actions.distill.skippedByReason[reason] ?? 0) + count;
|
|
581
252
|
}
|
|
582
|
-
dst.actions.distill.deferred += src.actions.distill.deferred;
|
|
583
|
-
for (const [reason, count] of Object.entries(src.actions.distill.deferredByReason)) {
|
|
584
|
-
dst.actions.distill.deferredByReason[reason] = (dst.actions.distill.deferredByReason[reason] ?? 0) + count;
|
|
585
|
-
}
|
|
586
253
|
dst.actions.memoryPrune += src.actions.memoryPrune;
|
|
587
254
|
dst.actions.memoryInference += src.actions.memoryInference;
|
|
588
|
-
dst.actions.graphExtraction += src.actions.graphExtraction;
|
|
589
255
|
dst.actions.error += src.actions.error;
|
|
590
256
|
dst.autoAccept.promoted += src.autoAccept.promoted;
|
|
591
257
|
dst.autoAccept.validationFailed += src.autoAccept.validationFailed;
|
|
592
|
-
dst.reflectsWithErrorContext += src.reflectsWithErrorContext;
|
|
593
|
-
dst.coverageGapCount += src.coverageGapCount;
|
|
594
|
-
dst.deadUrlCount += src.deadUrlCount;
|
|
595
|
-
dst.deadUrlsChecked += src.deadUrlsChecked;
|
|
596
|
-
dst.deadUrlsTotal += src.deadUrlsTotal;
|
|
597
|
-
dst.deadUrlsSkipped += src.deadUrlsSkipped;
|
|
598
|
-
// NOTE: memorySummary (derived/eligible) is a WHOLE-STASH snapshot recorded on
|
|
599
|
-
// every run, NOT a per-run increment — summing it across the window inflates
|
|
600
|
-
// it ~N× (the 1.2M-eligible bug). It is set from the most recent run in
|
|
601
|
-
// summarizeImproveRuns instead, so it is intentionally not merged here.
|
|
602
|
-
dst.memoryCleanup.pruneCandidates += src.memoryCleanup.pruneCandidates;
|
|
603
|
-
dst.memoryCleanup.contradictionCandidates += src.memoryCleanup.contradictionCandidates;
|
|
604
|
-
dst.memoryCleanup.beliefStateTransitions += src.memoryCleanup.beliefStateTransitions;
|
|
605
|
-
dst.memoryCleanup.consolidationCandidates += src.memoryCleanup.consolidationCandidates;
|
|
606
|
-
dst.memoryCleanup.archived += src.memoryCleanup.archived;
|
|
607
|
-
dst.memoryCleanup.warnings += src.memoryCleanup.warnings;
|
|
608
258
|
dst.consolidation.processed += src.consolidation.processed;
|
|
609
259
|
dst.consolidation.promoted += src.consolidation.promoted;
|
|
610
260
|
dst.consolidation.merged += src.consolidation.merged;
|
|
611
261
|
dst.consolidation.deleted += src.consolidation.deleted;
|
|
612
262
|
dst.consolidation.contradicted += src.consolidation.contradicted;
|
|
263
|
+
dst.consolidation.judgedNoAction += src.consolidation.judgedNoAction;
|
|
613
264
|
dst.consolidation.failedChunks += src.consolidation.failedChunks;
|
|
614
265
|
dst.consolidation.totalChunks += src.consolidation.totalChunks;
|
|
615
266
|
dst.consolidation.durationMs += src.consolidation.durationMs;
|
|
616
|
-
dst.consolidation.judgedNoAction += src.consolidation.judgedNoAction;
|
|
617
|
-
dst.consolidation.mergedSecondaries += src.consolidation.mergedSecondaries;
|
|
618
|
-
dst.consolidation.failedChunkMemories += src.consolidation.failedChunkMemories;
|
|
619
|
-
for (const [reason, count] of Object.entries(src.consolidation.skipReasons)) {
|
|
620
|
-
dst.consolidation.skipReasons[reason] = (dst.consolidation.skipReasons[reason] ?? 0) + count;
|
|
621
|
-
}
|
|
622
267
|
dst.memoryInference.considered += src.memoryInference.considered;
|
|
623
|
-
dst.memoryInference.
|
|
624
|
-
dst.memoryInference.splitParents += src.memoryInference.splitParents;
|
|
268
|
+
dst.memoryInference.freshAttempts += src.memoryInference.freshAttempts;
|
|
625
269
|
dst.memoryInference.written += src.memoryInference.written;
|
|
626
270
|
dst.memoryInference.skippedNoFacts += src.memoryInference.skippedNoFacts;
|
|
627
|
-
dst.memoryInference.skippedChildExists += src.memoryInference.skippedChildExists;
|
|
628
|
-
dst.memoryInference.skippedAborted += src.memoryInference.skippedAborted;
|
|
629
|
-
dst.memoryInference.unaccounted += src.memoryInference.unaccounted;
|
|
630
|
-
dst.memoryInference.htmlErrorCount += src.memoryInference.htmlErrorCount;
|
|
631
|
-
dst.memoryInference.retryAttempts += src.memoryInference.retryAttempts;
|
|
632
271
|
dst.memoryInference.durationMs += src.memoryInference.durationMs;
|
|
633
|
-
dst.graphExtraction.extractedFiles += src.graphExtraction.extractedFiles;
|
|
634
|
-
dst.graphExtraction.consideredFiles += src.graphExtraction.consideredFiles;
|
|
635
|
-
dst.graphExtraction.entities += src.graphExtraction.entities;
|
|
636
|
-
dst.graphExtraction.relations += src.graphExtraction.relations;
|
|
637
|
-
dst.graphExtraction.cacheHits += src.graphExtraction.cacheHits;
|
|
638
|
-
dst.graphExtraction.cacheMisses += src.graphExtraction.cacheMisses;
|
|
639
|
-
dst.graphExtraction.truncations += src.graphExtraction.truncations;
|
|
640
|
-
dst.graphExtraction.failures += src.graphExtraction.failures;
|
|
641
|
-
dst.graphExtraction.htmlErrors += src.graphExtraction.htmlErrors;
|
|
642
|
-
dst.graphExtraction.nonArrayBatchFailures += src.graphExtraction.nonArrayBatchFailures;
|
|
643
|
-
dst.graphExtraction.retryAttempts += src.graphExtraction.retryAttempts;
|
|
644
|
-
dst.graphExtraction.durationMs += src.graphExtraction.durationMs;
|
|
645
|
-
dst.sessionExtraction.sessionsScanned += src.sessionExtraction.sessionsScanned;
|
|
646
|
-
dst.sessionExtraction.sessionsExtracted += src.sessionExtraction.sessionsExtracted;
|
|
647
|
-
dst.sessionExtraction.sessionsSkipped += src.sessionExtraction.sessionsSkipped;
|
|
648
|
-
dst.sessionExtraction.proposalsCreated += src.sessionExtraction.proposalsCreated;
|
|
649
|
-
dst.sessionExtraction.warnings += src.sessionExtraction.warnings;
|
|
650
|
-
dst.sessionExtraction.durationMs += src.sessionExtraction.durationMs;
|
|
651
|
-
// WS-5: merge perf telemetry (additive sums).
|
|
652
|
-
dst.perfTelemetry.dedupPoolSize += src.perfTelemetry.dedupPoolSize;
|
|
653
|
-
dst.perfTelemetry.llmPoolSize += src.perfTelemetry.llmPoolSize;
|
|
654
|
-
dst.perfTelemetry.embedMs += src.perfTelemetry.embedMs;
|
|
655
|
-
dst.perfTelemetry.embedCacheHits += src.perfTelemetry.embedCacheHits;
|
|
656
|
-
dst.perfTelemetry.embedCacheMisses += src.perfTelemetry.embedCacheMisses;
|
|
657
|
-
dst.perfTelemetry.overBudgetRuns += src.perfTelemetry.overBudgetRuns;
|
|
658
|
-
dst.perfTelemetry.runsWithTelemetry += src.perfTelemetry.runsWithTelemetry;
|
|
659
|
-
// coverage: acceptedProposals is additive; totalAssets is a snapshot (like memorySummary).
|
|
660
|
-
// totalAssets is intentionally NOT merged here — set from the most recent run in summarizeImproveRuns.
|
|
661
|
-
dst.coverage.acceptedProposals += src.coverage.acceptedProposals;
|
|
662
272
|
}
|
|
663
273
|
function compareImproveRunRecency(a, b) {
|
|
664
274
|
const started = a.started_at.localeCompare(b.started_at);
|
|
@@ -669,114 +279,52 @@ function compareImproveRunRecency(a, b) {
|
|
|
669
279
|
return completed;
|
|
670
280
|
return a.id.localeCompare(b.id);
|
|
671
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Aggregate the window's `improve_runs` rows. `runCount` is every non-dry-run
|
|
284
|
+
* row in the window; rows whose envelope does not decode are counted under
|
|
285
|
+
* `resultRows.skipped.invalid` and excluded from the result-derived metrics.
|
|
286
|
+
*/
|
|
672
287
|
export function summarizeImproveRuns(db, since, until) {
|
|
673
|
-
const accum =
|
|
288
|
+
const accum = emptyImproveMetrics();
|
|
674
289
|
const rows = queryImproveRuns(db, since, until);
|
|
675
|
-
|
|
676
|
-
// that phase. Phases that did not run on a given envelope are simply
|
|
677
|
-
// omitted (NOT counted as 0) so the median/p95 reflect actual phase work.
|
|
678
|
-
const phaseDurations = {
|
|
679
|
-
consolidation: [],
|
|
680
|
-
memoryInference: [],
|
|
681
|
-
graphExtraction: [],
|
|
682
|
-
};
|
|
290
|
+
const resultRows = { total: rows.length, included: 0, skipped: { invalid: 0 } };
|
|
683
291
|
// memorySummary is a whole-stash snapshot per run, so the window value is the
|
|
684
|
-
//
|
|
685
|
-
let
|
|
686
|
-
let latestMemorySummary;
|
|
687
|
-
let latestStrategyFilteredRefs = 0;
|
|
688
|
-
if (!accum.resultRows)
|
|
689
|
-
throw new Error("invariant: improve result-row accounting was not initialized");
|
|
690
|
-
accum.resultRows.total = rows.length;
|
|
292
|
+
// newest complete run's snapshot (current state) — not a sum across runs.
|
|
293
|
+
let latest;
|
|
691
294
|
for (const row of rows) {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
}
|
|
696
|
-
catch {
|
|
697
|
-
accum.resultRows.skipped.invalid += 1;
|
|
295
|
+
const result = decodeImproveResultRow(row);
|
|
296
|
+
if (!result) {
|
|
297
|
+
resultRows.skipped.invalid += 1;
|
|
698
298
|
continue;
|
|
699
299
|
}
|
|
700
|
-
|
|
701
|
-
const result = decoded.envelope;
|
|
300
|
+
resultRows.included += 1;
|
|
702
301
|
const perRow = projectRunMetrics(result);
|
|
703
302
|
mergeImproveMetrics(accum, perRow);
|
|
704
|
-
const startMs = new Date(row.started_at).getTime();
|
|
705
303
|
if (result.terminated === undefined &&
|
|
706
|
-
Number.isFinite(
|
|
707
|
-
(
|
|
708
|
-
|
|
709
|
-
latestMemorySummary = perRow.memorySummary;
|
|
710
|
-
latestStrategyFilteredRefs = perRow.strategyFilteredRefs;
|
|
304
|
+
Number.isFinite(new Date(row.started_at).getTime()) &&
|
|
305
|
+
(latest === undefined || compareImproveRunRecency(row, latest.row) > 0)) {
|
|
306
|
+
latest = { row, memorySummary: perRow.memorySummary };
|
|
711
307
|
}
|
|
712
|
-
// Collect per-phase durations directly off the envelope. consolidation's
|
|
713
|
-
// duration lives inside the sub-object; memoryInference and graphExtraction
|
|
714
|
-
// expose top-level *DurationMs keys (`memoryInferenceDurationMs`,
|
|
715
|
-
// `graphExtractionDurationMs`) when they actually ran on that envelope.
|
|
716
|
-
const consol = result.consolidation;
|
|
717
|
-
const consolMs = toFiniteNumber(consol?.durationMs);
|
|
718
|
-
if (consolMs > 0)
|
|
719
|
-
phaseDurations.consolidation.push(consolMs);
|
|
720
|
-
const memMs = toFiniteNumber(result.memoryInferenceDurationMs);
|
|
721
|
-
if (memMs > 0)
|
|
722
|
-
phaseDurations.memoryInference.push(memMs);
|
|
723
|
-
const graphMs = toFiniteNumber(result.graphExtractionDurationMs);
|
|
724
|
-
if (graphMs > 0)
|
|
725
|
-
phaseDurations.graphExtraction.push(graphMs);
|
|
726
308
|
}
|
|
727
309
|
finalizeImproveMetrics(accum);
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
accum.wallTime.byPhase = {
|
|
732
|
-
consolidation: summarizePhaseDurations(phaseDurations.consolidation),
|
|
733
|
-
memoryInference: summarizePhaseDurations(phaseDurations.memoryInference),
|
|
734
|
-
graphExtraction: summarizePhaseDurations(phaseDurations.graphExtraction),
|
|
735
|
-
};
|
|
310
|
+
accum.resultRows = resultRows;
|
|
311
|
+
if (latest)
|
|
312
|
+
accum.memorySummary = latest.memorySummary;
|
|
736
313
|
return { metrics: accum, runCount: rows.length };
|
|
737
314
|
}
|
|
738
|
-
/**
|
|
739
|
-
* Aggregate a list of per-envelope phase durations into the
|
|
740
|
-
* `wallTime.byPhase.*` shape: count, total, median, p95. Median/p95 use the
|
|
741
|
-
* same nearest-rank picker as the top-level wallTime stats so the two are
|
|
742
|
-
* comparable.
|
|
743
|
-
*/
|
|
744
|
-
export function summarizePhaseDurations(samples) {
|
|
745
|
-
if (samples.length === 0)
|
|
746
|
-
return { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 };
|
|
747
|
-
const sorted = [...samples].sort((a, b) => a - b);
|
|
748
|
-
const pick = (q) => sorted[Math.min(sorted.length - 1, Math.floor(q * sorted.length))] ?? 0;
|
|
749
|
-
const totalMs = sorted.reduce((acc, n) => acc + n, 0);
|
|
750
|
-
return {
|
|
751
|
-
count: sorted.length,
|
|
752
|
-
totalMs,
|
|
753
|
-
medianMs: pick(0.5),
|
|
754
|
-
p95Ms: pick(0.95),
|
|
755
|
-
};
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* Project an improve_runs row + wall-time lookup into a single ImproveRunSummary.
|
|
759
|
-
* Used by `akm health --detail per-run`.
|
|
760
|
-
*/
|
|
315
|
+
/** Project an improve_runs row + wall time + task attribution into one {@link ImproveRunSummary}. */
|
|
761
316
|
export function projectImproveRunSummary(row, wallTimeMs, taskId) {
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
result = decoded.envelope;
|
|
767
|
-
resultStatus = "valid";
|
|
768
|
-
}
|
|
769
|
-
catch {
|
|
317
|
+
const decoded = decodeImproveResultRow(row);
|
|
318
|
+
const result = decoded ?? {};
|
|
319
|
+
const resultStatus = decoded ? "valid" : "invalid";
|
|
320
|
+
if (!decoded) {
|
|
770
321
|
// Keep the persisted row visible in per-run output, but do not project its
|
|
771
322
|
// unknown payload or admit its duration to result-derived denominators.
|
|
772
323
|
wallTimeMs = 0;
|
|
773
324
|
}
|
|
774
325
|
const perRow = projectRunMetrics(result);
|
|
775
326
|
finalizeImproveMetrics(perRow);
|
|
776
|
-
const orphansPurged = toFiniteNumber(result.orphansPurged);
|
|
777
327
|
const lintSummary = result.lintSummary;
|
|
778
|
-
const lintFixed = lintSummary ? toFiniteNumber(lintSummary.fixed) : 0;
|
|
779
|
-
const lintFlagged = lintSummary ? toFiniteNumber(lintSummary.flagged) : 0;
|
|
780
328
|
return {
|
|
781
329
|
id: row.id,
|
|
782
330
|
startedAt: row.started_at,
|
|
@@ -793,37 +341,20 @@ export function projectImproveRunSummary(row, wallTimeMs, taskId) {
|
|
|
793
341
|
taskId,
|
|
794
342
|
actions: perRow.actions,
|
|
795
343
|
memorySummary: perRow.memorySummary,
|
|
796
|
-
memoryCleanup: perRow.memoryCleanup,
|
|
797
344
|
consolidation: perRow.consolidation,
|
|
798
345
|
memoryInference: perRow.memoryInference,
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
lintFixed,
|
|
803
|
-
lintFlagged,
|
|
346
|
+
orphansPurged: toFiniteNumber(result.orphansPurged),
|
|
347
|
+
lintFixed: lintSummary ? toFiniteNumber(lintSummary.fixed) : 0,
|
|
348
|
+
lintFlagged: lintSummary ? toFiniteNumber(lintSummary.flagged) : 0,
|
|
804
349
|
};
|
|
805
350
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
consolidation: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
809
|
-
memoryInference: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
810
|
-
graphExtraction: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
811
|
-
};
|
|
812
|
-
}
|
|
813
|
-
export function computeWallTimeStats(durationsMs, byPhase) {
|
|
814
|
-
const phase = byPhase ?? emptyPhaseStats();
|
|
351
|
+
/** Nearest-rank median and p95 of the window's run wall times. */
|
|
352
|
+
export function computeWallTimeStats(durationsMs) {
|
|
815
353
|
if (durationsMs.length === 0)
|
|
816
|
-
return {
|
|
354
|
+
return { medianMs: 0, p95Ms: 0 };
|
|
817
355
|
const sorted = [...durationsMs].sort((a, b) => a - b);
|
|
818
356
|
const pick = (q) => sorted[Math.min(sorted.length - 1, Math.floor(q * sorted.length))] ?? 0;
|
|
819
|
-
return {
|
|
820
|
-
count: sorted.length,
|
|
821
|
-
medianMs: pick(0.5),
|
|
822
|
-
p95Ms: pick(0.95),
|
|
823
|
-
minMs: sorted[0] ?? 0,
|
|
824
|
-
maxMs: sorted[sorted.length - 1] ?? 0,
|
|
825
|
-
byPhase: phase,
|
|
826
|
-
};
|
|
357
|
+
return { medianMs: pick(0.5), p95Ms: pick(0.95) };
|
|
827
358
|
}
|
|
828
359
|
export function buildImproveSkipSummary(events) {
|
|
829
360
|
// Two kinds of skip events:
|
|
@@ -833,9 +364,9 @@ export function buildImproveSkipSummary(events) {
|
|
|
833
364
|
// (`no_new_signal`, `strategy_filtered_all_passes`). Each run re-counts the
|
|
834
365
|
// same stable set, so summing across the window re-counts it N times (the
|
|
835
366
|
// 2.7M / 3M inflation). For these we keep the MOST RECENT run's count — the
|
|
836
|
-
// current snapshot — matching how memorySummary
|
|
837
|
-
//
|
|
838
|
-
//
|
|
367
|
+
// current snapshot — matching how memorySummary is handled. Events arrive
|
|
368
|
+
// in chronological (offset) order, so the last count-bearing event per
|
|
369
|
+
// reason is the latest run's value.
|
|
839
370
|
const summed = {};
|
|
840
371
|
const latestSnapshot = {};
|
|
841
372
|
for (const event of events) {
|
|
@@ -855,3 +386,21 @@ export function buildImproveSkipSummary(events) {
|
|
|
855
386
|
const skipped = Object.values(skipReasons).reduce((a, b) => a + b, 0);
|
|
856
387
|
return { skipped, skipReasons };
|
|
857
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Proposals accepted in `[since, until)` (by `updated_at`) and the distinct
|
|
391
|
+
* refs among them — N accepted rewrites of one asset touch one ref. A single
|
|
392
|
+
* SQL aggregate; proposal bodies are never loaded. Fails open to zeros when
|
|
393
|
+
* the table is absent.
|
|
394
|
+
*/
|
|
395
|
+
export function computeWindowProposalCoverage(db, since, until) {
|
|
396
|
+
try {
|
|
397
|
+
const row = db
|
|
398
|
+
.prepare("SELECT COUNT(*) AS accepted, COUNT(DISTINCT ref) AS refs FROM proposals " +
|
|
399
|
+
"WHERE status = 'accepted' AND updated_at >= ? AND (? IS NULL OR updated_at < ?)")
|
|
400
|
+
.get(since, until ?? null, until ?? null);
|
|
401
|
+
return { acceptedProposals: row?.accepted ?? 0, distinctRefs: row?.refs ?? 0 };
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
return { acceptedProposals: 0, distinctRefs: 0 };
|
|
405
|
+
}
|
|
406
|
+
}
|