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
|
@@ -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,120 +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
|
-
evalCasesWritten: 0,
|
|
96
|
-
deadUrlCount: 0,
|
|
97
|
-
deadUrlsChecked: 0,
|
|
98
|
-
deadUrlsTotal: 0,
|
|
99
|
-
deadUrlsSkipped: 0,
|
|
100
99
|
memorySummary: { eligible: 0, derived: 0 },
|
|
101
|
-
memoryCleanup: {
|
|
102
|
-
pruneCandidates: 0,
|
|
103
|
-
contradictionCandidates: 0,
|
|
104
|
-
beliefStateTransitions: 0,
|
|
105
|
-
consolidationCandidates: 0,
|
|
106
|
-
archived: 0,
|
|
107
|
-
warnings: 0,
|
|
108
|
-
},
|
|
109
100
|
consolidation: {
|
|
110
|
-
ran: false,
|
|
111
101
|
processed: 0,
|
|
112
102
|
promoted: 0,
|
|
113
103
|
merged: 0,
|
|
114
104
|
deleted: 0,
|
|
115
105
|
contradicted: 0,
|
|
116
106
|
judgedNoAction: 0,
|
|
117
|
-
mergedSecondaries: 0,
|
|
118
|
-
failedChunkMemories: 0,
|
|
119
|
-
skipReasons: {},
|
|
120
107
|
failedChunks: 0,
|
|
121
108
|
totalChunks: 0,
|
|
122
109
|
durationMs: 0,
|
|
123
110
|
},
|
|
124
|
-
memoryInference: {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
cacheHits: 0,
|
|
128
|
-
retryAttempts: 0,
|
|
129
|
-
freshAttempts: 0,
|
|
130
|
-
splitParents: 0,
|
|
131
|
-
written: 0,
|
|
132
|
-
skippedNoFacts: 0,
|
|
133
|
-
skippedChildExists: 0,
|
|
134
|
-
skippedAborted: 0,
|
|
135
|
-
unaccounted: 0,
|
|
136
|
-
htmlErrorCount: 0,
|
|
137
|
-
yieldRate: 0,
|
|
138
|
-
durationMs: 0,
|
|
139
|
-
},
|
|
140
|
-
graphExtraction: {
|
|
141
|
-
ran: false,
|
|
142
|
-
extractedFiles: 0,
|
|
143
|
-
consideredFiles: 0,
|
|
144
|
-
entities: 0,
|
|
145
|
-
relations: 0,
|
|
146
|
-
extractionCoverage: 0,
|
|
147
|
-
cacheHits: 0,
|
|
148
|
-
cacheMisses: 0,
|
|
149
|
-
cacheHitRate: 0,
|
|
150
|
-
truncations: 0,
|
|
151
|
-
failures: 0,
|
|
152
|
-
htmlErrors: 0,
|
|
153
|
-
retryAttempts: 0,
|
|
154
|
-
nonArrayBatchFailures: 0,
|
|
155
|
-
durationMs: 0,
|
|
156
|
-
},
|
|
157
|
-
sessionExtraction: {
|
|
158
|
-
ran: false,
|
|
159
|
-
sessionsScanned: 0,
|
|
160
|
-
sessionsExtracted: 0,
|
|
161
|
-
sessionsSkipped: 0,
|
|
162
|
-
proposalsCreated: 0,
|
|
163
|
-
warnings: 0,
|
|
164
|
-
durationMs: 0,
|
|
165
|
-
},
|
|
166
|
-
wallTime: {
|
|
167
|
-
count: 0,
|
|
168
|
-
medianMs: 0,
|
|
169
|
-
p95Ms: 0,
|
|
170
|
-
minMs: 0,
|
|
171
|
-
maxMs: 0,
|
|
172
|
-
byPhase: {
|
|
173
|
-
consolidation: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
174
|
-
memoryInference: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
175
|
-
graphExtraction: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
perfTelemetry: {
|
|
179
|
-
dedupPoolSize: 0,
|
|
180
|
-
llmPoolSize: 0,
|
|
181
|
-
embedMs: 0,
|
|
182
|
-
embedCacheHits: 0,
|
|
183
|
-
embedCacheMisses: 0,
|
|
184
|
-
overBudgetRuns: 0,
|
|
185
|
-
runsWithTelemetry: 0,
|
|
186
|
-
},
|
|
187
|
-
coverage: {
|
|
188
|
-
rate: Number.NaN,
|
|
189
|
-
eligibleFraction: Number.NaN,
|
|
190
|
-
acceptedProposals: 0,
|
|
191
|
-
distinctRefs: 0,
|
|
192
|
-
churnRatio: Number.NaN,
|
|
193
|
-
totalAssets: 0,
|
|
194
|
-
},
|
|
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 },
|
|
195
114
|
};
|
|
196
115
|
}
|
|
197
|
-
|
|
116
|
+
function toFiniteNumber(value) {
|
|
198
117
|
if (typeof value === "number" && Number.isFinite(value))
|
|
199
118
|
return value;
|
|
200
119
|
if (typeof value === "string" && value.trim()) {
|
|
@@ -204,47 +123,9 @@ export function toFiniteNumber(value) {
|
|
|
204
123
|
}
|
|
205
124
|
return 0;
|
|
206
125
|
}
|
|
207
|
-
/**
|
|
208
|
-
* Event-derived metrics. Only `completed` and skipReasons/invoked are sourced
|
|
209
|
-
* from events in v2 — the richer fields come from {@link summarizeImproveRuns}.
|
|
210
|
-
* The function still receives `improve_completed` events so that the completed
|
|
211
|
-
* count reflects the canonical event stream (it lines up 1:1 with improve_runs
|
|
212
|
-
* rows in practice, but the events table remains the system-of-record for the
|
|
213
|
-
* existence of a run).
|
|
214
|
-
*/
|
|
215
|
-
export function summarizeImproveCompleted(events) {
|
|
216
|
-
const metrics = createUnknownImproveMetrics();
|
|
217
|
-
metrics.completed = events.length;
|
|
218
|
-
return metrics;
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Read the machine-readable reason from a distill `outcome: "skipped"` result.
|
|
222
|
-
*/
|
|
223
|
-
function classifyDistillSkipReason(r) {
|
|
224
|
-
const explicitReason = typeof r?.skipReason === "string" ? r.skipReason : undefined;
|
|
225
|
-
return explicitReason || "unknown";
|
|
226
|
-
}
|
|
227
|
-
// ── projectRunMetrics phase helpers (chunk-9 WI-9.5c; file-level decompose of
|
|
228
|
-
// the single-envelope projection — each helper mutates its own disjoint
|
|
229
|
-
// subtree of the accumulator from the raw envelope, so call order does not
|
|
230
|
-
// matter; kept in envelope-field order for readability) ──────────────────────
|
|
231
|
-
/** plannedRefs / strategyFilteredRefs ref-count accounting. */
|
|
232
|
-
function applyPlannedRefs(metrics, result) {
|
|
233
|
-
// plannedRefs (array of {ref, reason})
|
|
234
|
-
const plannedRefs = result.plannedRefs;
|
|
235
|
-
if (Array.isArray(plannedRefs))
|
|
236
|
-
metrics.plannedRefs += plannedRefs.length;
|
|
237
|
-
// strategyFilteredRefs (array of {ref, reason}) — 2026-05-27: pre-filter
|
|
238
|
-
// bucket from `collectEligibleRefs` so the metric reflects work the
|
|
239
|
-
// planner dropped before signal-delta / per-pass dispatch.
|
|
240
|
-
const strategyFilteredRefs = result.strategyFilteredRefs;
|
|
241
|
-
if (Array.isArray(strategyFilteredRefs))
|
|
242
|
-
metrics.strategyFilteredRefs += strategyFilteredRefs.length;
|
|
243
|
-
}
|
|
244
|
-
/** 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. */
|
|
245
127
|
function applyAction(metrics, action) {
|
|
246
|
-
|
|
247
|
-
switch (mode) {
|
|
128
|
+
switch (typeof action.mode === "string" ? action.mode : "") {
|
|
248
129
|
case "reflect":
|
|
249
130
|
metrics.actions.reflect.ok += 1;
|
|
250
131
|
break;
|
|
@@ -254,20 +135,12 @@ function applyAction(metrics, action) {
|
|
|
254
135
|
case "reflect-cooldown":
|
|
255
136
|
metrics.actions.reflect.cooldown += 1;
|
|
256
137
|
break;
|
|
257
|
-
case "reflect-skipped":
|
|
138
|
+
case "reflect-skipped":
|
|
258
139
|
metrics.actions.reflect.skipped += 1;
|
|
259
|
-
const r = action.result;
|
|
260
|
-
const reason = typeof r?.reason === "string" && r.reason.trim() ? r.reason : "unknown";
|
|
261
|
-
metrics.actions.reflect.skippedByReason[reason] = (metrics.actions.reflect.skippedByReason[reason] ?? 0) + 1;
|
|
262
|
-
break;
|
|
263
|
-
}
|
|
264
|
-
case "reflect-guard-rejected":
|
|
265
|
-
metrics.actions.reflect.guardRejected += 1;
|
|
266
140
|
break;
|
|
267
141
|
case "distill": {
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
switch (outcome) {
|
|
142
|
+
const result = action.result;
|
|
143
|
+
switch (typeof result?.outcome === "string" ? result.outcome : "") {
|
|
271
144
|
case "queued":
|
|
272
145
|
metrics.actions.distill.queued += 1;
|
|
273
146
|
break;
|
|
@@ -284,21 +157,6 @@ function applyAction(metrics, action) {
|
|
|
284
157
|
case "config_disabled":
|
|
285
158
|
metrics.actions.distill.configDisabled += 1;
|
|
286
159
|
break;
|
|
287
|
-
case "skipped": {
|
|
288
|
-
// Previously dropped on the floor. The four sub-paths that emit
|
|
289
|
-
// `outcome: "skipped"` (see distill.ts:893, 1024, 1120, 1576):
|
|
290
|
-
// - recursive_lesson_input (type guard refused a lesson input)
|
|
291
|
-
// - conflict_noop (LLM resolved destination conflict as NOOP)
|
|
292
|
-
// - proposal-skipped cooldown / dedup at persistence
|
|
293
|
-
// 465 events/7d in the user's live stack. The result message
|
|
294
|
-
// typically encodes the reason; we also accept an explicit
|
|
295
|
-
// `skipReason` field when downstream code sets it.
|
|
296
|
-
metrics.actions.distill.deferred += 1;
|
|
297
|
-
const reason = classifyDistillSkipReason(r);
|
|
298
|
-
metrics.actions.distill.deferredByReason[reason] =
|
|
299
|
-
(metrics.actions.distill.deferredByReason[reason] ?? 0) + 1;
|
|
300
|
-
break;
|
|
301
|
-
}
|
|
302
160
|
default:
|
|
303
161
|
break;
|
|
304
162
|
}
|
|
@@ -310,268 +168,79 @@ function applyAction(metrics, action) {
|
|
|
310
168
|
case "memory-inference":
|
|
311
169
|
metrics.actions.memoryInference += 1;
|
|
312
170
|
break;
|
|
313
|
-
case "graph-extraction":
|
|
314
|
-
metrics.actions.graphExtraction += 1;
|
|
315
|
-
break;
|
|
316
171
|
case "error":
|
|
317
172
|
metrics.actions.error += 1;
|
|
318
173
|
break;
|
|
174
|
+
default:
|
|
175
|
+
break;
|
|
319
176
|
}
|
|
320
177
|
}
|
|
321
|
-
/**
|
|
322
|
-
function
|
|
323
|
-
const
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
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);
|
|
328
184
|
}
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Read the bounded `distillSkipped` aggregate into the corresponding total and
|
|
332
|
-
* per-reason health metrics.
|
|
333
|
-
*/
|
|
334
|
-
function applyDistillSkippedAggregate(metrics, result) {
|
|
335
185
|
const distillSkipped = result.distillSkipped;
|
|
336
|
-
if (
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const byReason = distillSkipped.byReason;
|
|
340
|
-
if (byReason && typeof byReason === "object") {
|
|
341
|
-
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 ?? {})) {
|
|
342
189
|
metrics.actions.distill.skippedByReason[reason] =
|
|
343
190
|
(metrics.actions.distill.skippedByReason[reason] ?? 0) + toFiniteNumber(count);
|
|
344
191
|
}
|
|
345
192
|
}
|
|
346
|
-
}
|
|
347
|
-
/** autoAccept + the small envelope-level counters (reflectsWithErrorContext, coverageGaps, evalCasesWritten, deadUrls). */
|
|
348
|
-
function applyMiscCounters(metrics, result) {
|
|
349
193
|
metrics.autoAccept.promoted += toFiniteNumber(result.gateAutoAcceptedCount);
|
|
350
194
|
metrics.autoAccept.validationFailed += toFiniteNumber(result.gateAutoAcceptFailedCount);
|
|
351
|
-
metrics.reflectsWithErrorContext += toFiniteNumber(result.reflectsWithErrorContext);
|
|
352
|
-
if (Array.isArray(result.coverageGaps))
|
|
353
|
-
metrics.coverageGapCount += result.coverageGaps.length;
|
|
354
|
-
metrics.evalCasesWritten += toFiniteNumber(result.evalCasesWritten);
|
|
355
|
-
if (Array.isArray(result.deadUrls))
|
|
356
|
-
metrics.deadUrlCount += result.deadUrls.length;
|
|
357
|
-
const deadUrlCoverage = result.deadUrlCoverage;
|
|
358
|
-
if (deadUrlCoverage && typeof deadUrlCoverage === "object") {
|
|
359
|
-
metrics.deadUrlsChecked += toFiniteNumber(deadUrlCoverage.checked);
|
|
360
|
-
metrics.deadUrlsTotal += toFiniteNumber(deadUrlCoverage.total);
|
|
361
|
-
metrics.deadUrlsSkipped += toFiniteNumber(deadUrlCoverage.skipped);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
function applyMemorySummary(metrics, result) {
|
|
365
195
|
const memorySummary = result.memorySummary;
|
|
366
|
-
if (
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
metrics.memorySummary.derived += toFiniteNumber(memorySummary.derived);
|
|
370
|
-
}
|
|
371
|
-
function applyMemoryCleanup(metrics, result) {
|
|
372
|
-
const memoryCleanup = result.memoryCleanup;
|
|
373
|
-
if (!memoryCleanup)
|
|
374
|
-
return;
|
|
375
|
-
if (Array.isArray(memoryCleanup.pruneCandidates))
|
|
376
|
-
metrics.memoryCleanup.pruneCandidates += memoryCleanup.pruneCandidates.length;
|
|
377
|
-
if (Array.isArray(memoryCleanup.contradictionCandidates))
|
|
378
|
-
metrics.memoryCleanup.contradictionCandidates += memoryCleanup.contradictionCandidates.length;
|
|
379
|
-
if (Array.isArray(memoryCleanup.beliefStateTransitions))
|
|
380
|
-
metrics.memoryCleanup.beliefStateTransitions += memoryCleanup.beliefStateTransitions.length;
|
|
381
|
-
if (Array.isArray(memoryCleanup.consolidationCandidates))
|
|
382
|
-
metrics.memoryCleanup.consolidationCandidates += memoryCleanup.consolidationCandidates.length;
|
|
383
|
-
if (Array.isArray(memoryCleanup.archived))
|
|
384
|
-
metrics.memoryCleanup.archived += memoryCleanup.archived.length;
|
|
385
|
-
if (Array.isArray(memoryCleanup.warnings))
|
|
386
|
-
metrics.memoryCleanup.warnings += memoryCleanup.warnings.length;
|
|
387
|
-
}
|
|
388
|
-
function applyConsolidation(metrics, result) {
|
|
389
|
-
const consolidation = result.consolidation;
|
|
390
|
-
if (!consolidation)
|
|
391
|
-
return;
|
|
392
|
-
metrics.consolidation.processed += toFiniteNumber(consolidation.processed);
|
|
393
|
-
metrics.consolidation.merged += toFiniteNumber(consolidation.merged);
|
|
394
|
-
metrics.consolidation.deleted += toFiniteNumber(consolidation.deleted);
|
|
395
|
-
metrics.consolidation.contradicted += toFiniteNumber(consolidation.contradicted);
|
|
396
|
-
if (Array.isArray(consolidation.promoted))
|
|
397
|
-
metrics.consolidation.promoted += consolidation.promoted.length;
|
|
398
|
-
metrics.consolidation.failedChunks += toFiniteNumber(consolidation.failedChunks);
|
|
399
|
-
metrics.consolidation.totalChunks += toFiniteNumber(consolidation.totalChunks);
|
|
400
|
-
metrics.consolidation.durationMs += toFiniteNumber(consolidation.durationMs);
|
|
401
|
-
metrics.consolidation.judgedNoAction += toFiniteNumber(consolidation.judgedNoAction);
|
|
402
|
-
metrics.consolidation.mergedSecondaries += toFiniteNumber(consolidation.mergedSecondaries);
|
|
403
|
-
metrics.consolidation.failedChunkMemories += toFiniteNumber(consolidation.failedChunkMemories);
|
|
404
|
-
// Structured emitter (new on this branch): consolidate.ts now pushes
|
|
405
|
-
// per-ref grouped `{ref, skips: [{op, reason}]}` entries to `skipReasons`
|
|
406
|
-
// for every deterministic post-LLM rejection. Each ref appears once but
|
|
407
|
-
// may carry multiple skips; aggregate every reason. Pre-fix envelopes have
|
|
408
|
-
// neither field, so be defensive.
|
|
409
|
-
const skipReasons = consolidation.skipReasons;
|
|
410
|
-
if (Array.isArray(skipReasons)) {
|
|
411
|
-
for (const entry of skipReasons) {
|
|
412
|
-
if (!entry || typeof entry !== "object")
|
|
413
|
-
continue;
|
|
414
|
-
const skips = entry.skips;
|
|
415
|
-
if (!Array.isArray(skips))
|
|
416
|
-
continue;
|
|
417
|
-
for (const skip of skips) {
|
|
418
|
-
if (!skip || typeof skip !== "object")
|
|
419
|
-
continue;
|
|
420
|
-
const reason = skip.reason;
|
|
421
|
-
if (typeof reason !== "string" || !reason.trim())
|
|
422
|
-
continue;
|
|
423
|
-
metrics.consolidation.skipReasons[reason] = (metrics.consolidation.skipReasons[reason] ?? 0) + 1;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
196
|
+
if (memorySummary) {
|
|
197
|
+
metrics.memorySummary.eligible += toFiniteNumber(memorySummary.eligible);
|
|
198
|
+
metrics.memorySummary.derived += toFiniteNumber(memorySummary.derived);
|
|
426
199
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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);
|
|
440
213
|
}
|
|
441
|
-
}
|
|
442
|
-
function applyMemoryInference(metrics, result) {
|
|
443
214
|
const memoryInference = result.memoryInference;
|
|
444
215
|
if (memoryInference) {
|
|
445
216
|
const considered = toFiniteNumber(memoryInference.considered);
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
metrics.memoryInference.skippedChildExists += toFiniteNumber(memoryInference.skippedChildExists);
|
|
454
|
-
metrics.memoryInference.skippedAborted += toFiniteNumber(memoryInference.skippedAborted);
|
|
455
|
-
metrics.memoryInference.unaccounted += toFiniteNumber(memoryInference.unaccounted);
|
|
456
|
-
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);
|
|
457
224
|
}
|
|
458
225
|
metrics.memoryInference.durationMs += toFiniteNumber(result.memoryInferenceDurationMs);
|
|
459
|
-
}
|
|
460
|
-
function applyGraphExtraction(metrics, result) {
|
|
461
|
-
const graphExtraction = result.graphExtraction;
|
|
462
|
-
if (graphExtraction) {
|
|
463
|
-
const quality = graphExtraction.quality;
|
|
464
|
-
if (quality) {
|
|
465
|
-
metrics.graphExtraction.extractedFiles += toFiniteNumber(quality.extractedFiles);
|
|
466
|
-
metrics.graphExtraction.consideredFiles += toFiniteNumber(quality.consideredFiles);
|
|
467
|
-
}
|
|
468
|
-
metrics.graphExtraction.entities += toFiniteNumber(graphExtraction.totalEntities);
|
|
469
|
-
metrics.graphExtraction.relations += toFiniteNumber(graphExtraction.totalRelations);
|
|
470
|
-
const telemetry = graphExtraction.telemetry;
|
|
471
|
-
if (telemetry) {
|
|
472
|
-
metrics.graphExtraction.cacheHits += toFiniteNumber(telemetry.cacheHits);
|
|
473
|
-
metrics.graphExtraction.cacheMisses += toFiniteNumber(telemetry.cacheMisses);
|
|
474
|
-
metrics.graphExtraction.truncations += toFiniteNumber(telemetry.truncationCount);
|
|
475
|
-
metrics.graphExtraction.failures += toFiniteNumber(telemetry.failureCount);
|
|
476
|
-
metrics.graphExtraction.htmlErrors += toFiniteNumber(telemetry.htmlErrorCount);
|
|
477
|
-
metrics.graphExtraction.retryAttempts += toFiniteNumber(telemetry.retryAttempts);
|
|
478
|
-
metrics.graphExtraction.nonArrayBatchFailures += toFiniteNumber(telemetry.nonArrayBatchFailures);
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
metrics.graphExtraction.durationMs += toFiniteNumber(result.graphExtractionDurationMs);
|
|
482
|
-
}
|
|
483
|
-
function applySessionExtraction(metrics, result) {
|
|
484
|
-
if (!Array.isArray(result.extract))
|
|
485
|
-
return;
|
|
486
|
-
for (const e of result.extract) {
|
|
487
|
-
metrics.sessionExtraction.sessionsScanned += toFiniteNumber(e.sessionsProcessed);
|
|
488
|
-
metrics.sessionExtraction.sessionsSkipped += toFiniteNumber(e.sessionsSkipped);
|
|
489
|
-
if (Array.isArray(e.sessions)) {
|
|
490
|
-
metrics.sessionExtraction.sessionsExtracted += e.sessions.filter((s) => Array.isArray(s.proposalIds) && s.proposalIds.length > 0).length;
|
|
491
|
-
}
|
|
492
|
-
metrics.sessionExtraction.proposalsCreated += Array.isArray(e.proposals) ? e.proposals.length : 0;
|
|
493
|
-
metrics.sessionExtraction.warnings += Array.isArray(e.warnings) ? e.warnings.length : 0;
|
|
494
|
-
metrics.sessionExtraction.durationMs += toFiniteNumber(e.durationMs);
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* Project a single `improve_runs.result_json` envelope into an accumulator-shaped
|
|
499
|
-
* ImproveHealthMetrics. The aggregator merges these per-row metrics into one
|
|
500
|
-
* window-level metric. File-level decomposed (chunk-9 WI-9.5c) into one
|
|
501
|
-
* `apply*` helper per envelope section above; each mutates its own disjoint
|
|
502
|
-
* subtree of the accumulator so the call order below is not load-bearing.
|
|
503
|
-
*/
|
|
504
|
-
function projectRunMetrics(result) {
|
|
505
|
-
const metrics = createUnknownImproveMetrics();
|
|
506
|
-
applyPlannedRefs(metrics, result);
|
|
507
|
-
applyActionsList(metrics, result);
|
|
508
|
-
applyDistillSkippedAggregate(metrics, result);
|
|
509
|
-
applyMiscCounters(metrics, result);
|
|
510
|
-
applyMemorySummary(metrics, result);
|
|
511
|
-
applyMemoryCleanup(metrics, result);
|
|
512
|
-
applyConsolidation(metrics, result);
|
|
513
|
-
applyMemoryInference(metrics, result);
|
|
514
|
-
applyGraphExtraction(metrics, result);
|
|
515
|
-
applySessionExtraction(metrics, result);
|
|
516
226
|
return metrics;
|
|
517
227
|
}
|
|
518
|
-
/**
|
|
519
|
-
* Finalize derived flags and rates on an accumulator. Used both for the
|
|
520
|
-
* window-level aggregate and for each per-run row in --detail per-run mode
|
|
521
|
-
* so the single-row metrics still expose `ran` / `yieldRate` / `cacheHitRate`.
|
|
522
|
-
*/
|
|
228
|
+
/** Derived rates on an accumulator (window aggregate or single run). */
|
|
523
229
|
function finalizeImproveMetrics(metrics) {
|
|
524
|
-
metrics.
|
|
525
|
-
|
|
526
|
-
metrics.consolidation.durationMs > 0 ||
|
|
527
|
-
metrics.consolidation.promoted > 0 ||
|
|
528
|
-
metrics.consolidation.merged > 0 ||
|
|
529
|
-
metrics.consolidation.deleted > 0 ||
|
|
530
|
-
metrics.consolidation.contradicted > 0 ||
|
|
531
|
-
metrics.consolidation.totalChunks > 0;
|
|
532
|
-
metrics.memoryInference.ran =
|
|
533
|
-
metrics.memoryInference.considered > 0 ||
|
|
534
|
-
metrics.memoryInference.written > 0 ||
|
|
535
|
-
metrics.memoryInference.durationMs > 0;
|
|
536
|
-
// Yield denominator excludes cache hits and aborted records.
|
|
537
|
-
metrics.memoryInference.freshAttempts = Math.max(0, metrics.memoryInference.considered - metrics.memoryInference.cacheHits - metrics.memoryInference.skippedAborted);
|
|
538
|
-
metrics.memoryInference.yieldRate =
|
|
539
|
-
metrics.memoryInference.freshAttempts > 0
|
|
540
|
-
? roundRate(metrics.memoryInference.written / metrics.memoryInference.freshAttempts)
|
|
541
|
-
: 0;
|
|
542
|
-
metrics.graphExtraction.ran =
|
|
543
|
-
metrics.graphExtraction.extractedFiles > 0 ||
|
|
544
|
-
metrics.graphExtraction.entities > 0 ||
|
|
545
|
-
metrics.graphExtraction.durationMs > 0;
|
|
546
|
-
const cacheTotal = metrics.graphExtraction.cacheHits + metrics.graphExtraction.cacheMisses;
|
|
547
|
-
metrics.graphExtraction.cacheHitRate = cacheTotal > 0 ? roundRate(metrics.graphExtraction.cacheHits / cacheTotal) : 0;
|
|
548
|
-
metrics.graphExtraction.extractionCoverage =
|
|
549
|
-
metrics.graphExtraction.consideredFiles > 0
|
|
550
|
-
? roundRate(metrics.graphExtraction.extractedFiles / metrics.graphExtraction.consideredFiles)
|
|
551
|
-
: 0;
|
|
552
|
-
metrics.sessionExtraction.ran =
|
|
553
|
-
metrics.sessionExtraction.sessionsScanned > 0 ||
|
|
554
|
-
metrics.sessionExtraction.proposalsCreated > 0 ||
|
|
555
|
-
metrics.sessionExtraction.durationMs > 0;
|
|
230
|
+
const mi = metrics.memoryInference;
|
|
231
|
+
mi.yieldRate = mi.freshAttempts > 0 ? roundRate(mi.written / mi.freshAttempts) : 0;
|
|
556
232
|
}
|
|
557
233
|
/**
|
|
558
|
-
* Merge per-
|
|
559
|
-
*
|
|
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}.
|
|
560
238
|
*/
|
|
561
239
|
function mergeImproveMetrics(dst, src) {
|
|
562
|
-
dst.plannedRefs += src.plannedRefs;
|
|
563
|
-
// strategyFilteredRefs is the count of refs the planner drops up-front for the
|
|
564
|
-
// active strategy — recomputed against the (stable) stash every run, so it is a
|
|
565
|
-
// snapshot, NOT a per-run increment. Summing it re-counts the same refs each
|
|
566
|
-
// run (the ~2.4M bug). Set from the most recent run in summarizeImproveRuns.
|
|
567
240
|
dst.actions.reflect.ok += src.actions.reflect.ok;
|
|
568
241
|
dst.actions.reflect.failed += src.actions.reflect.failed;
|
|
569
242
|
dst.actions.reflect.cooldown += src.actions.reflect.cooldown;
|
|
570
243
|
dst.actions.reflect.skipped += src.actions.reflect.skipped;
|
|
571
|
-
dst.actions.reflect.guardRejected += src.actions.reflect.guardRejected;
|
|
572
|
-
for (const [reason, count] of Object.entries(src.actions.reflect.skippedByReason)) {
|
|
573
|
-
dst.actions.reflect.skippedByReason[reason] = (dst.actions.reflect.skippedByReason[reason] ?? 0) + count;
|
|
574
|
-
}
|
|
575
244
|
dst.actions.distill.queued += src.actions.distill.queued;
|
|
576
245
|
dst.actions.distill.llmFailed += src.actions.distill.llmFailed;
|
|
577
246
|
dst.actions.distill.judgeRejected += src.actions.distill.judgeRejected;
|
|
@@ -581,87 +250,25 @@ function mergeImproveMetrics(dst, src) {
|
|
|
581
250
|
for (const [reason, count] of Object.entries(src.actions.distill.skippedByReason)) {
|
|
582
251
|
dst.actions.distill.skippedByReason[reason] = (dst.actions.distill.skippedByReason[reason] ?? 0) + count;
|
|
583
252
|
}
|
|
584
|
-
dst.actions.distill.deferred += src.actions.distill.deferred;
|
|
585
|
-
for (const [reason, count] of Object.entries(src.actions.distill.deferredByReason)) {
|
|
586
|
-
dst.actions.distill.deferredByReason[reason] = (dst.actions.distill.deferredByReason[reason] ?? 0) + count;
|
|
587
|
-
}
|
|
588
253
|
dst.actions.memoryPrune += src.actions.memoryPrune;
|
|
589
254
|
dst.actions.memoryInference += src.actions.memoryInference;
|
|
590
|
-
dst.actions.graphExtraction += src.actions.graphExtraction;
|
|
591
255
|
dst.actions.error += src.actions.error;
|
|
592
256
|
dst.autoAccept.promoted += src.autoAccept.promoted;
|
|
593
257
|
dst.autoAccept.validationFailed += src.autoAccept.validationFailed;
|
|
594
|
-
dst.reflectsWithErrorContext += src.reflectsWithErrorContext;
|
|
595
|
-
dst.coverageGapCount += src.coverageGapCount;
|
|
596
|
-
dst.evalCasesWritten += src.evalCasesWritten;
|
|
597
|
-
dst.deadUrlCount += src.deadUrlCount;
|
|
598
|
-
dst.deadUrlsChecked += src.deadUrlsChecked;
|
|
599
|
-
dst.deadUrlsTotal += src.deadUrlsTotal;
|
|
600
|
-
dst.deadUrlsSkipped += src.deadUrlsSkipped;
|
|
601
|
-
// NOTE: memorySummary (derived/eligible) is a WHOLE-STASH snapshot recorded on
|
|
602
|
-
// every run, NOT a per-run increment — summing it across the window inflates
|
|
603
|
-
// it ~N× (the 1.2M-eligible bug). It is set from the most recent run in
|
|
604
|
-
// summarizeImproveRuns instead, so it is intentionally not merged here.
|
|
605
|
-
dst.memoryCleanup.pruneCandidates += src.memoryCleanup.pruneCandidates;
|
|
606
|
-
dst.memoryCleanup.contradictionCandidates += src.memoryCleanup.contradictionCandidates;
|
|
607
|
-
dst.memoryCleanup.beliefStateTransitions += src.memoryCleanup.beliefStateTransitions;
|
|
608
|
-
dst.memoryCleanup.consolidationCandidates += src.memoryCleanup.consolidationCandidates;
|
|
609
|
-
dst.memoryCleanup.archived += src.memoryCleanup.archived;
|
|
610
|
-
dst.memoryCleanup.warnings += src.memoryCleanup.warnings;
|
|
611
258
|
dst.consolidation.processed += src.consolidation.processed;
|
|
612
259
|
dst.consolidation.promoted += src.consolidation.promoted;
|
|
613
260
|
dst.consolidation.merged += src.consolidation.merged;
|
|
614
261
|
dst.consolidation.deleted += src.consolidation.deleted;
|
|
615
262
|
dst.consolidation.contradicted += src.consolidation.contradicted;
|
|
263
|
+
dst.consolidation.judgedNoAction += src.consolidation.judgedNoAction;
|
|
616
264
|
dst.consolidation.failedChunks += src.consolidation.failedChunks;
|
|
617
265
|
dst.consolidation.totalChunks += src.consolidation.totalChunks;
|
|
618
266
|
dst.consolidation.durationMs += src.consolidation.durationMs;
|
|
619
|
-
dst.consolidation.judgedNoAction += src.consolidation.judgedNoAction;
|
|
620
|
-
dst.consolidation.mergedSecondaries += src.consolidation.mergedSecondaries;
|
|
621
|
-
dst.consolidation.failedChunkMemories += src.consolidation.failedChunkMemories;
|
|
622
|
-
for (const [reason, count] of Object.entries(src.consolidation.skipReasons)) {
|
|
623
|
-
dst.consolidation.skipReasons[reason] = (dst.consolidation.skipReasons[reason] ?? 0) + count;
|
|
624
|
-
}
|
|
625
267
|
dst.memoryInference.considered += src.memoryInference.considered;
|
|
626
|
-
dst.memoryInference.
|
|
627
|
-
dst.memoryInference.splitParents += src.memoryInference.splitParents;
|
|
268
|
+
dst.memoryInference.freshAttempts += src.memoryInference.freshAttempts;
|
|
628
269
|
dst.memoryInference.written += src.memoryInference.written;
|
|
629
270
|
dst.memoryInference.skippedNoFacts += src.memoryInference.skippedNoFacts;
|
|
630
|
-
dst.memoryInference.skippedChildExists += src.memoryInference.skippedChildExists;
|
|
631
|
-
dst.memoryInference.skippedAborted += src.memoryInference.skippedAborted;
|
|
632
|
-
dst.memoryInference.unaccounted += src.memoryInference.unaccounted;
|
|
633
|
-
dst.memoryInference.htmlErrorCount += src.memoryInference.htmlErrorCount;
|
|
634
|
-
dst.memoryInference.retryAttempts += src.memoryInference.retryAttempts;
|
|
635
271
|
dst.memoryInference.durationMs += src.memoryInference.durationMs;
|
|
636
|
-
dst.graphExtraction.extractedFiles += src.graphExtraction.extractedFiles;
|
|
637
|
-
dst.graphExtraction.consideredFiles += src.graphExtraction.consideredFiles;
|
|
638
|
-
dst.graphExtraction.entities += src.graphExtraction.entities;
|
|
639
|
-
dst.graphExtraction.relations += src.graphExtraction.relations;
|
|
640
|
-
dst.graphExtraction.cacheHits += src.graphExtraction.cacheHits;
|
|
641
|
-
dst.graphExtraction.cacheMisses += src.graphExtraction.cacheMisses;
|
|
642
|
-
dst.graphExtraction.truncations += src.graphExtraction.truncations;
|
|
643
|
-
dst.graphExtraction.failures += src.graphExtraction.failures;
|
|
644
|
-
dst.graphExtraction.htmlErrors += src.graphExtraction.htmlErrors;
|
|
645
|
-
dst.graphExtraction.nonArrayBatchFailures += src.graphExtraction.nonArrayBatchFailures;
|
|
646
|
-
dst.graphExtraction.retryAttempts += src.graphExtraction.retryAttempts;
|
|
647
|
-
dst.graphExtraction.durationMs += src.graphExtraction.durationMs;
|
|
648
|
-
dst.sessionExtraction.sessionsScanned += src.sessionExtraction.sessionsScanned;
|
|
649
|
-
dst.sessionExtraction.sessionsExtracted += src.sessionExtraction.sessionsExtracted;
|
|
650
|
-
dst.sessionExtraction.sessionsSkipped += src.sessionExtraction.sessionsSkipped;
|
|
651
|
-
dst.sessionExtraction.proposalsCreated += src.sessionExtraction.proposalsCreated;
|
|
652
|
-
dst.sessionExtraction.warnings += src.sessionExtraction.warnings;
|
|
653
|
-
dst.sessionExtraction.durationMs += src.sessionExtraction.durationMs;
|
|
654
|
-
// WS-5: merge perf telemetry (additive sums).
|
|
655
|
-
dst.perfTelemetry.dedupPoolSize += src.perfTelemetry.dedupPoolSize;
|
|
656
|
-
dst.perfTelemetry.llmPoolSize += src.perfTelemetry.llmPoolSize;
|
|
657
|
-
dst.perfTelemetry.embedMs += src.perfTelemetry.embedMs;
|
|
658
|
-
dst.perfTelemetry.embedCacheHits += src.perfTelemetry.embedCacheHits;
|
|
659
|
-
dst.perfTelemetry.embedCacheMisses += src.perfTelemetry.embedCacheMisses;
|
|
660
|
-
dst.perfTelemetry.overBudgetRuns += src.perfTelemetry.overBudgetRuns;
|
|
661
|
-
dst.perfTelemetry.runsWithTelemetry += src.perfTelemetry.runsWithTelemetry;
|
|
662
|
-
// coverage: acceptedProposals is additive; totalAssets is a snapshot (like memorySummary).
|
|
663
|
-
// totalAssets is intentionally NOT merged here — set from the most recent run in summarizeImproveRuns.
|
|
664
|
-
dst.coverage.acceptedProposals += src.coverage.acceptedProposals;
|
|
665
272
|
}
|
|
666
273
|
function compareImproveRunRecency(a, b) {
|
|
667
274
|
const started = a.started_at.localeCompare(b.started_at);
|
|
@@ -672,114 +279,52 @@ function compareImproveRunRecency(a, b) {
|
|
|
672
279
|
return completed;
|
|
673
280
|
return a.id.localeCompare(b.id);
|
|
674
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
|
+
*/
|
|
675
287
|
export function summarizeImproveRuns(db, since, until) {
|
|
676
|
-
const accum =
|
|
288
|
+
const accum = emptyImproveMetrics();
|
|
677
289
|
const rows = queryImproveRuns(db, since, until);
|
|
678
|
-
|
|
679
|
-
// that phase. Phases that did not run on a given envelope are simply
|
|
680
|
-
// omitted (NOT counted as 0) so the median/p95 reflect actual phase work.
|
|
681
|
-
const phaseDurations = {
|
|
682
|
-
consolidation: [],
|
|
683
|
-
memoryInference: [],
|
|
684
|
-
graphExtraction: [],
|
|
685
|
-
};
|
|
290
|
+
const resultRows = { total: rows.length, included: 0, skipped: { invalid: 0 } };
|
|
686
291
|
// memorySummary is a whole-stash snapshot per run, so the window value is the
|
|
687
|
-
//
|
|
688
|
-
let
|
|
689
|
-
let latestMemorySummary;
|
|
690
|
-
let latestStrategyFilteredRefs = 0;
|
|
691
|
-
if (!accum.resultRows)
|
|
692
|
-
throw new Error("invariant: improve result-row accounting was not initialized");
|
|
693
|
-
accum.resultRows.total = rows.length;
|
|
292
|
+
// newest complete run's snapshot (current state) — not a sum across runs.
|
|
293
|
+
let latest;
|
|
694
294
|
for (const row of rows) {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
}
|
|
699
|
-
catch {
|
|
700
|
-
accum.resultRows.skipped.invalid += 1;
|
|
295
|
+
const result = decodeImproveResultRow(row);
|
|
296
|
+
if (!result) {
|
|
297
|
+
resultRows.skipped.invalid += 1;
|
|
701
298
|
continue;
|
|
702
299
|
}
|
|
703
|
-
|
|
704
|
-
const result = decoded.envelope;
|
|
300
|
+
resultRows.included += 1;
|
|
705
301
|
const perRow = projectRunMetrics(result);
|
|
706
302
|
mergeImproveMetrics(accum, perRow);
|
|
707
|
-
const startMs = new Date(row.started_at).getTime();
|
|
708
303
|
if (result.terminated === undefined &&
|
|
709
|
-
Number.isFinite(
|
|
710
|
-
(
|
|
711
|
-
|
|
712
|
-
latestMemorySummary = perRow.memorySummary;
|
|
713
|
-
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 };
|
|
714
307
|
}
|
|
715
|
-
// Collect per-phase durations directly off the envelope. consolidation's
|
|
716
|
-
// duration lives inside the sub-object; memoryInference and graphExtraction
|
|
717
|
-
// expose top-level *DurationMs keys (`memoryInferenceDurationMs`,
|
|
718
|
-
// `graphExtractionDurationMs`) when they actually ran on that envelope.
|
|
719
|
-
const consol = result.consolidation;
|
|
720
|
-
const consolMs = toFiniteNumber(consol?.durationMs);
|
|
721
|
-
if (consolMs > 0)
|
|
722
|
-
phaseDurations.consolidation.push(consolMs);
|
|
723
|
-
const memMs = toFiniteNumber(result.memoryInferenceDurationMs);
|
|
724
|
-
if (memMs > 0)
|
|
725
|
-
phaseDurations.memoryInference.push(memMs);
|
|
726
|
-
const graphMs = toFiniteNumber(result.graphExtractionDurationMs);
|
|
727
|
-
if (graphMs > 0)
|
|
728
|
-
phaseDurations.graphExtraction.push(graphMs);
|
|
729
308
|
}
|
|
730
309
|
finalizeImproveMetrics(accum);
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
accum.wallTime.byPhase = {
|
|
735
|
-
consolidation: summarizePhaseDurations(phaseDurations.consolidation),
|
|
736
|
-
memoryInference: summarizePhaseDurations(phaseDurations.memoryInference),
|
|
737
|
-
graphExtraction: summarizePhaseDurations(phaseDurations.graphExtraction),
|
|
738
|
-
};
|
|
310
|
+
accum.resultRows = resultRows;
|
|
311
|
+
if (latest)
|
|
312
|
+
accum.memorySummary = latest.memorySummary;
|
|
739
313
|
return { metrics: accum, runCount: rows.length };
|
|
740
314
|
}
|
|
741
|
-
/**
|
|
742
|
-
* Aggregate a list of per-envelope phase durations into the
|
|
743
|
-
* `wallTime.byPhase.*` shape: count, total, median, p95. Median/p95 use the
|
|
744
|
-
* same nearest-rank picker as the top-level wallTime stats so the two are
|
|
745
|
-
* comparable.
|
|
746
|
-
*/
|
|
747
|
-
export function summarizePhaseDurations(samples) {
|
|
748
|
-
if (samples.length === 0)
|
|
749
|
-
return { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 };
|
|
750
|
-
const sorted = [...samples].sort((a, b) => a - b);
|
|
751
|
-
const pick = (q) => sorted[Math.min(sorted.length - 1, Math.floor(q * sorted.length))] ?? 0;
|
|
752
|
-
const totalMs = sorted.reduce((acc, n) => acc + n, 0);
|
|
753
|
-
return {
|
|
754
|
-
count: sorted.length,
|
|
755
|
-
totalMs,
|
|
756
|
-
medianMs: pick(0.5),
|
|
757
|
-
p95Ms: pick(0.95),
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
/**
|
|
761
|
-
* Project an improve_runs row + wall-time lookup into a single ImproveRunSummary.
|
|
762
|
-
* Used by `akm health --detail per-run`.
|
|
763
|
-
*/
|
|
315
|
+
/** Project an improve_runs row + wall time + task attribution into one {@link ImproveRunSummary}. */
|
|
764
316
|
export function projectImproveRunSummary(row, wallTimeMs, taskId) {
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
result = decoded.envelope;
|
|
770
|
-
resultStatus = "valid";
|
|
771
|
-
}
|
|
772
|
-
catch {
|
|
317
|
+
const decoded = decodeImproveResultRow(row);
|
|
318
|
+
const result = decoded ?? {};
|
|
319
|
+
const resultStatus = decoded ? "valid" : "invalid";
|
|
320
|
+
if (!decoded) {
|
|
773
321
|
// Keep the persisted row visible in per-run output, but do not project its
|
|
774
322
|
// unknown payload or admit its duration to result-derived denominators.
|
|
775
323
|
wallTimeMs = 0;
|
|
776
324
|
}
|
|
777
325
|
const perRow = projectRunMetrics(result);
|
|
778
326
|
finalizeImproveMetrics(perRow);
|
|
779
|
-
const orphansPurged = toFiniteNumber(result.orphansPurged);
|
|
780
327
|
const lintSummary = result.lintSummary;
|
|
781
|
-
const lintFixed = lintSummary ? toFiniteNumber(lintSummary.fixed) : 0;
|
|
782
|
-
const lintFlagged = lintSummary ? toFiniteNumber(lintSummary.flagged) : 0;
|
|
783
328
|
return {
|
|
784
329
|
id: row.id,
|
|
785
330
|
startedAt: row.started_at,
|
|
@@ -796,38 +341,20 @@ export function projectImproveRunSummary(row, wallTimeMs, taskId) {
|
|
|
796
341
|
taskId,
|
|
797
342
|
actions: perRow.actions,
|
|
798
343
|
memorySummary: perRow.memorySummary,
|
|
799
|
-
memoryCleanup: perRow.memoryCleanup,
|
|
800
344
|
consolidation: perRow.consolidation,
|
|
801
345
|
memoryInference: perRow.memoryInference,
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
orphansPurged,
|
|
806
|
-
lintFixed,
|
|
807
|
-
lintFlagged,
|
|
346
|
+
orphansPurged: toFiniteNumber(result.orphansPurged),
|
|
347
|
+
lintFixed: lintSummary ? toFiniteNumber(lintSummary.fixed) : 0,
|
|
348
|
+
lintFlagged: lintSummary ? toFiniteNumber(lintSummary.flagged) : 0,
|
|
808
349
|
};
|
|
809
350
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
consolidation: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
813
|
-
memoryInference: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
814
|
-
graphExtraction: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
815
|
-
};
|
|
816
|
-
}
|
|
817
|
-
export function computeWallTimeStats(durationsMs, byPhase) {
|
|
818
|
-
const phase = byPhase ?? emptyPhaseStats();
|
|
351
|
+
/** Nearest-rank median and p95 of the window's run wall times. */
|
|
352
|
+
export function computeWallTimeStats(durationsMs) {
|
|
819
353
|
if (durationsMs.length === 0)
|
|
820
|
-
return {
|
|
354
|
+
return { medianMs: 0, p95Ms: 0 };
|
|
821
355
|
const sorted = [...durationsMs].sort((a, b) => a - b);
|
|
822
356
|
const pick = (q) => sorted[Math.min(sorted.length - 1, Math.floor(q * sorted.length))] ?? 0;
|
|
823
|
-
return {
|
|
824
|
-
count: sorted.length,
|
|
825
|
-
medianMs: pick(0.5),
|
|
826
|
-
p95Ms: pick(0.95),
|
|
827
|
-
minMs: sorted[0] ?? 0,
|
|
828
|
-
maxMs: sorted[sorted.length - 1] ?? 0,
|
|
829
|
-
byPhase: phase,
|
|
830
|
-
};
|
|
357
|
+
return { medianMs: pick(0.5), p95Ms: pick(0.95) };
|
|
831
358
|
}
|
|
832
359
|
export function buildImproveSkipSummary(events) {
|
|
833
360
|
// Two kinds of skip events:
|
|
@@ -837,9 +364,9 @@ export function buildImproveSkipSummary(events) {
|
|
|
837
364
|
// (`no_new_signal`, `strategy_filtered_all_passes`). Each run re-counts the
|
|
838
365
|
// same stable set, so summing across the window re-counts it N times (the
|
|
839
366
|
// 2.7M / 3M inflation). For these we keep the MOST RECENT run's count — the
|
|
840
|
-
// current snapshot — matching how memorySummary
|
|
841
|
-
//
|
|
842
|
-
//
|
|
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.
|
|
843
370
|
const summed = {};
|
|
844
371
|
const latestSnapshot = {};
|
|
845
372
|
for (const event of events) {
|
|
@@ -859,3 +386,21 @@ export function buildImproveSkipSummary(events) {
|
|
|
859
386
|
const skipped = Object.values(skipReasons).reduce((a, b) => a + b, 0);
|
|
860
387
|
return { skipped, skipReasons };
|
|
861
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
|
+
}
|