akm-cli 0.9.0-beta.5 → 0.9.0-beta.51
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 +711 -0
- package/README.md +12 -4
- package/dist/akm +38 -0
- package/dist/akm-migrate-storage +38 -0
- package/dist/assets/profiles/default.json +9 -4
- package/dist/assets/profiles/frequent.json +1 -1
- package/dist/assets/profiles/memory-focus.json +1 -1
- package/dist/assets/profiles/quick.json +1 -1
- package/dist/assets/profiles/synthesize.json +15 -0
- package/dist/assets/profiles/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +23 -0
- package/dist/assets/prompts/contradiction-judge.md +33 -0
- package/dist/assets/prompts/distill-knowledge-system.md +22 -0
- package/dist/assets/prompts/distill-lesson-system.md +36 -0
- package/dist/assets/prompts/extract-session.md +6 -2
- package/dist/assets/prompts/graph-extract-system.md +1 -0
- package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
- package/dist/assets/prompts/memory-infer-system.md +1 -0
- package/dist/assets/prompts/memory-infer-user.md +5 -0
- package/dist/assets/prompts/metadata-enhance-system.md +1 -0
- package/dist/assets/prompts/procedural-system.md +44 -0
- package/dist/assets/prompts/recombine-system.md +40 -0
- package/dist/assets/prompts/staleness-detect-system.md +6 -0
- package/dist/assets/prompts/validate-summary-judge.md +1 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
- package/dist/assets/templates/html/health.html +281 -111
- package/dist/assets/wiki/ingest-workflow-template.md +38 -10
- package/dist/cli/parse-args.js +46 -1
- package/dist/cli/shared.js +28 -0
- package/dist/cli.js +27 -11
- package/dist/commands/agent/agent-dispatch.js +2 -2
- package/dist/commands/agent/agent-support.js +0 -7
- package/dist/commands/agent/contribute-cli.js +17 -4
- package/dist/commands/config-cli.js +18 -2
- package/dist/commands/env/child-env.js +47 -0
- package/dist/commands/env/env-cli.js +33 -26
- package/dist/commands/env/secret-cli.js +36 -22
- package/dist/commands/feedback-cli.js +15 -6
- package/dist/commands/graph/graph-cli.js +5 -13
- package/dist/commands/graph/graph.js +76 -72
- package/dist/commands/health/checks.js +49 -1
- package/dist/commands/health/html-report.js +422 -80
- package/dist/commands/health.js +386 -9
- package/dist/commands/improve/calibration.js +161 -0
- package/dist/commands/improve/consolidate/chunking.js +141 -0
- package/dist/commands/improve/consolidate/eligibility.js +81 -0
- package/dist/commands/improve/consolidate/merge.js +145 -0
- package/dist/commands/improve/consolidate/sanitize.js +231 -0
- package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
- package/dist/commands/improve/consolidate.js +635 -660
- package/dist/commands/improve/dedup.js +482 -0
- package/dist/commands/improve/distill.js +159 -69
- package/dist/commands/improve/eligibility.js +434 -0
- package/dist/commands/improve/encoding-salience.js +205 -0
- package/dist/commands/improve/extract-cli.js +124 -2
- package/dist/commands/improve/extract-prompt.js +39 -2
- package/dist/commands/improve/extract-watch.js +140 -0
- package/dist/commands/improve/extract.js +389 -40
- package/dist/commands/improve/feedback-valence.js +54 -0
- package/dist/commands/improve/homeostatic.js +467 -0
- package/dist/commands/improve/improve-auto-accept.js +138 -7
- package/dist/commands/improve/improve-cli.js +36 -61
- package/dist/commands/improve/improve-profiles.js +14 -0
- package/dist/commands/improve/improve-result-file.js +14 -25
- package/dist/commands/improve/improve-session.js +58 -0
- package/dist/commands/improve/improve.js +485 -2498
- package/dist/commands/improve/locks.js +154 -0
- package/dist/commands/improve/loop-stages.js +1083 -0
- package/dist/commands/improve/memory/memory-contradiction-detect.js +23 -28
- package/dist/commands/improve/outcome-loop.js +256 -0
- package/dist/commands/improve/preparation.js +1966 -0
- package/dist/commands/improve/proactive-maintenance.js +115 -0
- package/dist/commands/improve/procedural.js +418 -0
- package/dist/commands/improve/recombine.js +850 -0
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/improve/reflect.js +183 -40
- package/dist/commands/improve/salience.js +438 -0
- package/dist/commands/improve/triage.js +93 -0
- package/dist/commands/lint/agent-linter.js +19 -24
- package/dist/commands/lint/base-linter.js +173 -60
- package/dist/commands/lint/command-linter.js +19 -24
- package/dist/commands/lint/env-key-rules.js +38 -1
- package/dist/commands/lint/fact-linter.js +39 -0
- package/dist/commands/lint/index.js +31 -13
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +7 -2
- package/dist/commands/lint/task-linter.js +3 -3
- package/dist/commands/lint/workflow-linter.js +26 -1
- package/dist/commands/proposal/drain-policies.js +5 -0
- package/dist/commands/proposal/drain.js +43 -50
- package/dist/commands/proposal/proposal-cli.js +21 -31
- package/dist/commands/proposal/proposal.js +5 -0
- package/dist/commands/proposal/propose.js +7 -2
- package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
- package/dist/commands/proposal/validators/proposals.js +189 -63
- package/dist/commands/read/curate.js +414 -94
- package/dist/commands/read/knowledge.js +6 -3
- package/dist/commands/read/search-cli.js +9 -4
- package/dist/commands/read/search.js +10 -6
- package/dist/commands/read/show.js +86 -7
- package/dist/commands/sources/init.js +49 -17
- package/dist/commands/sources/installed-stashes.js +11 -3
- package/dist/commands/sources/schema-repair.js +43 -45
- package/dist/commands/sources/self-update.js +2 -2
- package/dist/commands/sources/source-add.js +7 -3
- package/dist/commands/sources/stash-cli.js +28 -40
- package/dist/commands/sources/stash-skeleton.js +23 -8
- package/dist/commands/tasks/tasks-cli.js +19 -27
- package/dist/commands/tasks/tasks.js +39 -11
- package/dist/commands/wiki-cli.js +21 -35
- package/dist/core/asset/asset-registry.js +3 -1
- package/dist/core/asset/asset-spec.js +18 -2
- package/dist/core/asset/frontmatter.js +166 -167
- package/dist/core/asset/markdown.js +8 -0
- package/dist/core/authoring-rules.js +92 -0
- package/dist/core/common.js +0 -5
- package/dist/core/config/config-migration.js +12 -11
- package/dist/core/config/config-schema.js +340 -56
- package/dist/core/config/config-types.js +3 -3
- package/dist/core/config/config.js +28 -7
- package/dist/core/events.js +3 -7
- package/dist/core/improve-types.js +11 -8
- package/dist/core/logs-db.js +10 -66
- package/dist/core/parse.js +36 -16
- package/dist/core/paths.js +3 -0
- package/dist/core/standards/resolve-standards-context.js +87 -0
- package/dist/core/standards/resolve-stash-standards.js +99 -0
- package/dist/core/standards/resolve-type-conventions.js +66 -0
- package/dist/core/state/migrations.js +714 -0
- package/dist/core/state-db.js +525 -474
- package/dist/indexer/db/db.js +439 -247
- package/dist/indexer/db/graph-db.js +129 -86
- package/dist/indexer/ensure-index.js +152 -17
- package/dist/indexer/graph/graph-boost.js +51 -41
- package/dist/indexer/graph/graph-extraction.js +218 -4
- package/dist/indexer/index-writer-lock.js +99 -0
- package/dist/indexer/indexer.js +123 -221
- package/dist/indexer/passes/dir-staleness.js +114 -0
- package/dist/indexer/passes/memory-inference.js +13 -5
- package/dist/indexer/passes/staleness-detect.js +2 -5
- package/dist/indexer/search/db-search.js +19 -6
- package/dist/indexer/search/ranking-contributors.js +22 -0
- package/dist/indexer/search/ranking.js +4 -0
- package/dist/indexer/search/search-source.js +17 -18
- package/dist/indexer/search/semantic-status.js +4 -0
- package/dist/indexer/walk/matchers.js +9 -0
- package/dist/integrations/agent/config.js +6 -53
- package/dist/integrations/agent/index.js +2 -18
- package/dist/integrations/agent/prompts.js +75 -9
- package/dist/integrations/agent/runner-dispatch.js +59 -0
- package/dist/integrations/harnesses/claude/session-log.js +11 -1
- package/dist/integrations/harnesses/index.js +2 -3
- package/dist/integrations/harnesses/opencode/session-log.js +173 -3
- package/dist/integrations/harnesses/opencode-sdk/index.js +2 -2
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +0 -2
- package/dist/integrations/session-logs/index.js +16 -0
- package/dist/llm/client.js +45 -15
- package/dist/llm/embedder.js +42 -3
- package/dist/llm/embedders/deterministic.js +66 -0
- package/dist/llm/embedders/local.js +66 -2
- package/dist/llm/feature-gate.js +8 -4
- package/dist/llm/graph-extract.js +67 -44
- package/dist/llm/memory-infer-impl.js +138 -0
- package/dist/llm/memory-infer.js +1 -127
- package/dist/llm/metadata-enhance.js +44 -31
- package/dist/llm/structured-call.js +49 -0
- package/dist/migrate-storage-node.mjs +8 -0
- package/dist/output/context.js +5 -5
- package/dist/output/renderers.js +74 -2
- package/dist/output/shapes/curate.js +14 -2
- package/dist/output/shapes/passthrough.js +0 -1
- package/dist/output/text/helpers.js +16 -1
- package/dist/registry/providers/skills-sh.js +21 -147
- package/dist/registry/providers/static-index.js +15 -157
- package/dist/registry/resolve.js +22 -9
- package/dist/runtime.js +25 -1
- package/dist/scripts/migrate-storage.js +2617 -1961
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +759 -510
- package/dist/setup/setup.js +29 -8
- package/dist/sources/include.js +6 -2
- package/dist/sources/providers/filesystem.js +0 -1
- package/dist/sources/providers/git-install.js +210 -0
- package/dist/sources/providers/git-provider.js +234 -0
- package/dist/sources/providers/git-stash.js +248 -0
- package/dist/sources/providers/git.js +10 -661
- package/dist/sources/providers/npm.js +2 -6
- package/dist/sources/providers/provider-utils.js +13 -7
- package/dist/sources/providers/sync-from-ref.js +9 -1
- package/dist/sources/providers/tar-utils.js +16 -8
- package/dist/sources/providers/website.js +9 -5
- package/dist/sources/website-ingest.js +187 -29
- package/dist/sources/wiki-fetchers/registry.js +53 -0
- package/dist/sources/wiki-fetchers/youtube.js +239 -0
- package/dist/storage/database.js +45 -10
- package/dist/storage/managed-db.js +82 -0
- package/dist/storage/repositories/registry-cache.js +92 -0
- package/dist/storage/sqlite-pragmas.js +146 -0
- package/dist/tasks/backends/cron.js +1 -1
- package/dist/tasks/backends/launchd.js +1 -1
- package/dist/tasks/backends/schtasks.js +1 -1
- package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
- package/dist/tasks/runner.js +5 -13
- package/dist/text-import-hook.mjs +0 -0
- package/dist/wiki/wiki.js +37 -0
- package/dist/workflows/db.js +3 -4
- package/dist/workflows/runtime/runs.js +1 -117
- package/dist/workflows/runtime/workflow-asset-loader.js +125 -0
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/data-and-telemetry.md +3 -2
- package/docs/migration/release-notes/0.9.0.md +39 -0
- package/package.json +13 -11
- package/dist/commands/db-cli.js +0 -23
- package/dist/indexer/db/db-backup.js +0 -376
package/dist/commands/health.js
CHANGED
|
@@ -6,12 +6,13 @@ import { ConfigError, UsageError } from "../core/errors.js";
|
|
|
6
6
|
import { appendEvent, readEvents } from "../core/events.js";
|
|
7
7
|
import { buildTaskRunId, getLoggedRunIds, openLogsDatabase } from "../core/logs-db.js";
|
|
8
8
|
import { getStateDbPathInDataDir } from "../core/paths.js";
|
|
9
|
-
import { listExistingTableNames, openStateDatabase, queryCompletedTaskIntervals, queryImproveRuns, queryTaskHistory, } from "../core/state-db.js";
|
|
9
|
+
import { listExistingTableNames, listProposalGateDecisions, listStateProposals, openStateDatabase, queryCompletedTaskIntervals, queryImproveRuns, queryTaskHistory, } from "../core/state-db.js";
|
|
10
10
|
import { parseSinceToIso } from "../core/time.js";
|
|
11
11
|
import { readSemanticStatus } from "../indexer/search/semantic-status.js";
|
|
12
12
|
import { getExecutionLogCandidates } from "../integrations/session-logs/index.js";
|
|
13
13
|
import { LLM_USAGE_EVENT } from "../llm/usage-persist.js";
|
|
14
14
|
import { HEALTH_CHECKS } from "./health/checks.js";
|
|
15
|
+
import { gateDecisionsToSamples, summarizeCalibration } from "./improve/calibration.js";
|
|
15
16
|
const DEFAULT_SINCE_MS = 24 * 60 * 60 * 1000;
|
|
16
17
|
const IMPROVE_COMPLETED_EVENT = "improve_completed";
|
|
17
18
|
const HEALTH_PROBE_EVENT = "health_probe";
|
|
@@ -72,6 +73,7 @@ function createUnknownImproveMetrics() {
|
|
|
72
73
|
error: 0,
|
|
73
74
|
},
|
|
74
75
|
autoAccept: { promoted: 0, validationFailed: 0 },
|
|
76
|
+
calibration: summarizeCalibration([]),
|
|
75
77
|
reflectsWithErrorContext: 0,
|
|
76
78
|
coverageGapCount: 0,
|
|
77
79
|
evalCasesWritten: 0,
|
|
@@ -132,6 +134,7 @@ function createUnknownImproveMetrics() {
|
|
|
132
134
|
failures: 0,
|
|
133
135
|
htmlErrors: 0,
|
|
134
136
|
retryAttempts: 0,
|
|
137
|
+
nonArrayBatchFailures: 0,
|
|
135
138
|
durationMs: 0,
|
|
136
139
|
},
|
|
137
140
|
sessionExtraction: {
|
|
@@ -155,6 +158,22 @@ function createUnknownImproveMetrics() {
|
|
|
155
158
|
graphExtraction: { count: 0, totalMs: 0, medianMs: 0, p95Ms: 0 },
|
|
156
159
|
},
|
|
157
160
|
},
|
|
161
|
+
perfTelemetry: {
|
|
162
|
+
dedupPoolSize: 0,
|
|
163
|
+
llmPoolSize: 0,
|
|
164
|
+
judgedCacheSkipped: 0,
|
|
165
|
+
embedMs: 0,
|
|
166
|
+
embedCacheHits: 0,
|
|
167
|
+
embedCacheMisses: 0,
|
|
168
|
+
overBudgetRuns: 0,
|
|
169
|
+
runsWithTelemetry: 0,
|
|
170
|
+
},
|
|
171
|
+
coverage: {
|
|
172
|
+
rate: Number.NaN,
|
|
173
|
+
eligibleFraction: Number.NaN,
|
|
174
|
+
acceptedProposals: 0,
|
|
175
|
+
totalAssets: 0,
|
|
176
|
+
},
|
|
158
177
|
};
|
|
159
178
|
}
|
|
160
179
|
function toFiniteNumber(value) {
|
|
@@ -363,6 +382,21 @@ function projectRunMetrics(result) {
|
|
|
363
382
|
}
|
|
364
383
|
}
|
|
365
384
|
}
|
|
385
|
+
// WS-5: extract perf telemetry from the consolidation envelope.
|
|
386
|
+
// Pre-WS-5 envelopes lack `perfTelemetry`; be defensive.
|
|
387
|
+
const perf = consolidation.perfTelemetry;
|
|
388
|
+
if (perf) {
|
|
389
|
+
metrics.perfTelemetry.runsWithTelemetry += 1;
|
|
390
|
+
metrics.perfTelemetry.dedupPoolSize += toFiniteNumber(perf.dedupPoolSize);
|
|
391
|
+
metrics.perfTelemetry.llmPoolSize += toFiniteNumber(perf.llmPoolSize);
|
|
392
|
+
metrics.perfTelemetry.judgedCacheSkipped += toFiniteNumber(perf.judgedCacheSkipped);
|
|
393
|
+
metrics.perfTelemetry.embedMs += toFiniteNumber(perf.embedMs);
|
|
394
|
+
metrics.perfTelemetry.embedCacheHits += toFiniteNumber(perf.embedCacheHits);
|
|
395
|
+
metrics.perfTelemetry.embedCacheMisses += toFiniteNumber(perf.embedCacheMisses);
|
|
396
|
+
const budgetFrac = toFiniteNumber(perf.estimatedBudgetFractionUsed);
|
|
397
|
+
if (budgetFrac > 1.0)
|
|
398
|
+
metrics.perfTelemetry.overBudgetRuns += 1;
|
|
399
|
+
}
|
|
366
400
|
}
|
|
367
401
|
const memoryInference = result.memoryInference;
|
|
368
402
|
if (memoryInference) {
|
|
@@ -407,6 +441,7 @@ function projectRunMetrics(result) {
|
|
|
407
441
|
metrics.graphExtraction.failures += toFiniteNumber(telemetry.failureCount);
|
|
408
442
|
metrics.graphExtraction.htmlErrors += toFiniteNumber(telemetry.htmlErrorCount);
|
|
409
443
|
metrics.graphExtraction.retryAttempts += toFiniteNumber(telemetry.retryAttempts);
|
|
444
|
+
metrics.graphExtraction.nonArrayBatchFailures += toFiniteNumber(telemetry.nonArrayBatchFailures);
|
|
410
445
|
}
|
|
411
446
|
}
|
|
412
447
|
metrics.graphExtraction.durationMs += toFiniteNumber(result.graphExtractionDurationMs);
|
|
@@ -473,7 +508,10 @@ function finalizeImproveMetrics(metrics) {
|
|
|
473
508
|
*/
|
|
474
509
|
function mergeImproveMetrics(dst, src) {
|
|
475
510
|
dst.plannedRefs += src.plannedRefs;
|
|
476
|
-
|
|
511
|
+
// profileFilteredRefs is the count of refs the planner drops up-front for the
|
|
512
|
+
// active profile — recomputed against the (stable) stash every run, so it is a
|
|
513
|
+
// snapshot, NOT a per-run increment. Summing it re-counts the same refs each
|
|
514
|
+
// run (the ~2.4M bug). Set from the most recent run in summarizeImproveRuns.
|
|
477
515
|
dst.actions.reflect.ok += src.actions.reflect.ok;
|
|
478
516
|
dst.actions.reflect.failed += src.actions.reflect.failed;
|
|
479
517
|
dst.actions.reflect.cooldown += src.actions.reflect.cooldown;
|
|
@@ -506,8 +544,10 @@ function mergeImproveMetrics(dst, src) {
|
|
|
506
544
|
dst.coverageGapCount += src.coverageGapCount;
|
|
507
545
|
dst.evalCasesWritten += src.evalCasesWritten;
|
|
508
546
|
dst.deadUrlCount += src.deadUrlCount;
|
|
509
|
-
|
|
510
|
-
|
|
547
|
+
// NOTE: memorySummary (derived/eligible) is a WHOLE-STASH snapshot recorded on
|
|
548
|
+
// every run, NOT a per-run increment — summing it across the window inflates
|
|
549
|
+
// it ~N× (the 1.2M-eligible bug). It is set from the most recent run in
|
|
550
|
+
// summarizeImproveRuns instead, so it is intentionally not merged here.
|
|
511
551
|
dst.memoryCleanup.pruneCandidates += src.memoryCleanup.pruneCandidates;
|
|
512
552
|
dst.memoryCleanup.contradictionCandidates += src.memoryCleanup.contradictionCandidates;
|
|
513
553
|
dst.memoryCleanup.beliefStateTransitions += src.memoryCleanup.beliefStateTransitions;
|
|
@@ -549,6 +589,7 @@ function mergeImproveMetrics(dst, src) {
|
|
|
549
589
|
dst.graphExtraction.truncations += src.graphExtraction.truncations;
|
|
550
590
|
dst.graphExtraction.failures += src.graphExtraction.failures;
|
|
551
591
|
dst.graphExtraction.htmlErrors += src.graphExtraction.htmlErrors;
|
|
592
|
+
dst.graphExtraction.nonArrayBatchFailures += src.graphExtraction.nonArrayBatchFailures;
|
|
552
593
|
dst.graphExtraction.durationMs += src.graphExtraction.durationMs;
|
|
553
594
|
dst.sessionExtraction.sessionsScanned += src.sessionExtraction.sessionsScanned;
|
|
554
595
|
dst.sessionExtraction.sessionsExtracted += src.sessionExtraction.sessionsExtracted;
|
|
@@ -556,6 +597,18 @@ function mergeImproveMetrics(dst, src) {
|
|
|
556
597
|
dst.sessionExtraction.proposalsCreated += src.sessionExtraction.proposalsCreated;
|
|
557
598
|
dst.sessionExtraction.warnings += src.sessionExtraction.warnings;
|
|
558
599
|
dst.sessionExtraction.durationMs += src.sessionExtraction.durationMs;
|
|
600
|
+
// WS-5: merge perf telemetry (additive sums).
|
|
601
|
+
dst.perfTelemetry.dedupPoolSize += src.perfTelemetry.dedupPoolSize;
|
|
602
|
+
dst.perfTelemetry.llmPoolSize += src.perfTelemetry.llmPoolSize;
|
|
603
|
+
dst.perfTelemetry.judgedCacheSkipped += src.perfTelemetry.judgedCacheSkipped;
|
|
604
|
+
dst.perfTelemetry.embedMs += src.perfTelemetry.embedMs;
|
|
605
|
+
dst.perfTelemetry.embedCacheHits += src.perfTelemetry.embedCacheHits;
|
|
606
|
+
dst.perfTelemetry.embedCacheMisses += src.perfTelemetry.embedCacheMisses;
|
|
607
|
+
dst.perfTelemetry.overBudgetRuns += src.perfTelemetry.overBudgetRuns;
|
|
608
|
+
dst.perfTelemetry.runsWithTelemetry += src.perfTelemetry.runsWithTelemetry;
|
|
609
|
+
// coverage: acceptedProposals is additive; totalAssets is a snapshot (like memorySummary).
|
|
610
|
+
// totalAssets is intentionally NOT merged here — set from the most recent run in summarizeImproveRuns.
|
|
611
|
+
dst.coverage.acceptedProposals += src.coverage.acceptedProposals;
|
|
559
612
|
}
|
|
560
613
|
function summarizeImproveRuns(db, since, until) {
|
|
561
614
|
const accum = createUnknownImproveMetrics();
|
|
@@ -568,6 +621,11 @@ function summarizeImproveRuns(db, since, until) {
|
|
|
568
621
|
memoryInference: [],
|
|
569
622
|
graphExtraction: [],
|
|
570
623
|
};
|
|
624
|
+
// memorySummary is a whole-stash snapshot per run, so the window value is the
|
|
625
|
+
// MOST RECENT run's snapshot (current state) — not a sum across runs.
|
|
626
|
+
let latestStartMs = Number.NEGATIVE_INFINITY;
|
|
627
|
+
let latestMemorySummary;
|
|
628
|
+
let latestProfileFilteredRefs = 0;
|
|
571
629
|
for (const row of rows) {
|
|
572
630
|
let result;
|
|
573
631
|
try {
|
|
@@ -578,6 +636,12 @@ function summarizeImproveRuns(db, since, until) {
|
|
|
578
636
|
}
|
|
579
637
|
const perRow = projectRunMetrics(result);
|
|
580
638
|
mergeImproveMetrics(accum, perRow);
|
|
639
|
+
const startMs = new Date(row.started_at).getTime();
|
|
640
|
+
if (Number.isFinite(startMs) && startMs >= latestStartMs) {
|
|
641
|
+
latestStartMs = startMs;
|
|
642
|
+
latestMemorySummary = perRow.memorySummary;
|
|
643
|
+
latestProfileFilteredRefs = perRow.profileFilteredRefs;
|
|
644
|
+
}
|
|
581
645
|
// Collect per-phase durations directly off the envelope. consolidation's
|
|
582
646
|
// duration lives inside the sub-object; memoryInference and graphExtraction
|
|
583
647
|
// expose top-level *DurationMs keys (`memoryInferenceDurationMs`,
|
|
@@ -594,6 +658,9 @@ function summarizeImproveRuns(db, since, until) {
|
|
|
594
658
|
phaseDurations.graphExtraction.push(graphMs);
|
|
595
659
|
}
|
|
596
660
|
finalizeImproveMetrics(accum);
|
|
661
|
+
if (latestMemorySummary)
|
|
662
|
+
accum.memorySummary = latestMemorySummary;
|
|
663
|
+
accum.profileFilteredRefs = latestProfileFilteredRefs;
|
|
597
664
|
accum.wallTime.byPhase = {
|
|
598
665
|
consolidation: summarizePhaseDurations(phaseDurations.consolidation),
|
|
599
666
|
memoryInference: summarizePhaseDurations(phaseDurations.memoryInference),
|
|
@@ -624,7 +691,7 @@ function summarizePhaseDurations(samples) {
|
|
|
624
691
|
* Project an improve_runs row + wall-time lookup into a single ImproveRunSummary.
|
|
625
692
|
* Used by `akm health --detail per-run`.
|
|
626
693
|
*/
|
|
627
|
-
function projectImproveRunSummary(row, wallTimeMs) {
|
|
694
|
+
function projectImproveRunSummary(row, wallTimeMs, taskId) {
|
|
628
695
|
let result = {};
|
|
629
696
|
try {
|
|
630
697
|
result = JSON.parse(row.result_json);
|
|
@@ -648,6 +715,7 @@ function projectImproveRunSummary(row, wallTimeMs) {
|
|
|
648
715
|
mode: row.scope_mode,
|
|
649
716
|
...(row.scope_value ? { value: row.scope_value } : {}),
|
|
650
717
|
},
|
|
718
|
+
taskId,
|
|
651
719
|
actions: perRow.actions,
|
|
652
720
|
memorySummary: perRow.memorySummary,
|
|
653
721
|
memoryCleanup: perRow.memoryCleanup,
|
|
@@ -710,9 +778,62 @@ function findContainingTaskInterval(timestampMs, intervals) {
|
|
|
710
778
|
}
|
|
711
779
|
return undefined;
|
|
712
780
|
}
|
|
781
|
+
/**
|
|
782
|
+
* Load `task_history` rows whose `task_id` begins `akm-improve` (the scheduled
|
|
783
|
+
* improve tasks: `akm-improve-frequent`, `akm-improve-proactive-weekly`, …) in
|
|
784
|
+
* the window, widened ±5 min so a task that fired just before the window opened
|
|
785
|
+
* still matches a run inside it. Used to attribute each improve run to the task
|
|
786
|
+
* that launched it.
|
|
787
|
+
*/
|
|
788
|
+
function loadImproveTaskRuns(db, since, until) {
|
|
789
|
+
const sinceMs = new Date(since).getTime();
|
|
790
|
+
const untilMs = until ? new Date(until).getTime() : undefined;
|
|
791
|
+
const widenedSince = new Date(sinceMs - 5 * 60 * 1000).toISOString();
|
|
792
|
+
const widenedUntil = untilMs !== undefined ? new Date(untilMs + 5 * 60 * 1000).toISOString() : undefined;
|
|
793
|
+
const runs = [];
|
|
794
|
+
for (const row of queryTaskHistory(db, { since: widenedSince, until: widenedUntil })) {
|
|
795
|
+
if (!row.task_id.startsWith("akm-improve"))
|
|
796
|
+
continue;
|
|
797
|
+
const startMs = new Date(row.started_at).getTime();
|
|
798
|
+
if (!Number.isFinite(startMs))
|
|
799
|
+
continue;
|
|
800
|
+
const endIso = row.completed_at ?? row.failed_at;
|
|
801
|
+
const endMs = endIso ? new Date(endIso).getTime() : Number.NaN;
|
|
802
|
+
runs.push({ taskId: row.task_id, startMs, endMs });
|
|
803
|
+
}
|
|
804
|
+
return runs;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Attribute an improve run to the scheduled task that launched it by matching
|
|
808
|
+
* start times within ±5 min, scored by start delta (plus end delta when both
|
|
809
|
+
* ends are known). Port of the health-report skill's `match_task_id`. Returns
|
|
810
|
+
* `"manual"` when no scheduled improve task matches.
|
|
811
|
+
*/
|
|
812
|
+
function matchImproveTaskId(startedAt, completedAt, taskRuns) {
|
|
813
|
+
const startMs = new Date(startedAt).getTime();
|
|
814
|
+
if (!Number.isFinite(startMs))
|
|
815
|
+
return "manual";
|
|
816
|
+
const endMs = completedAt ? new Date(completedAt).getTime() : Number.NaN;
|
|
817
|
+
let best;
|
|
818
|
+
let bestScore = Number.POSITIVE_INFINITY;
|
|
819
|
+
for (const task of taskRuns) {
|
|
820
|
+
const startDelta = Math.abs(task.startMs - startMs);
|
|
821
|
+
if (startDelta > 5 * 60 * 1000)
|
|
822
|
+
continue;
|
|
823
|
+
let score = startDelta;
|
|
824
|
+
if (Number.isFinite(endMs) && Number.isFinite(task.endMs))
|
|
825
|
+
score += Math.abs(task.endMs - endMs);
|
|
826
|
+
if (score < bestScore) {
|
|
827
|
+
bestScore = score;
|
|
828
|
+
best = task.taskId;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return best ?? "manual";
|
|
832
|
+
}
|
|
713
833
|
function buildPerRunSummaries(db, since, until) {
|
|
714
834
|
const rows = queryImproveRuns(db, since, until);
|
|
715
835
|
const taskIntervals = loadTaskIntervals(db, since, until);
|
|
836
|
+
const improveTaskRuns = loadImproveTaskRuns(db, since, until);
|
|
716
837
|
const summaries = [];
|
|
717
838
|
for (const row of rows) {
|
|
718
839
|
const startMs = new Date(row.started_at).getTime();
|
|
@@ -732,7 +853,8 @@ function buildPerRunSummaries(db, since, until) {
|
|
|
732
853
|
const interval = Number.isFinite(startMs) ? findContainingTaskInterval(startMs, taskIntervals) : undefined;
|
|
733
854
|
wallTimeMs = interval?.durationMs ?? 0;
|
|
734
855
|
}
|
|
735
|
-
|
|
856
|
+
const taskId = matchImproveTaskId(row.started_at, row.completed_at, improveTaskRuns);
|
|
857
|
+
summaries.push(projectImproveRunSummary(row, wallTimeMs, taskId));
|
|
736
858
|
}
|
|
737
859
|
return summaries;
|
|
738
860
|
}
|
|
@@ -759,12 +881,34 @@ function computeWallTimeStats(durationsMs, byPhase) {
|
|
|
759
881
|
};
|
|
760
882
|
}
|
|
761
883
|
function buildImproveSkipSummary(events) {
|
|
762
|
-
|
|
884
|
+
// Two kinds of skip events:
|
|
885
|
+
// - Per-occurrence (no `count`): one event per skipped ref → SUM is correct.
|
|
886
|
+
// - Aggregated snapshot (carries `count`): a single per-run event whose count
|
|
887
|
+
// is the number of refs that hit a STABLE, whole-stash condition that run
|
|
888
|
+
// (`no_new_signal`, `profile_filtered_all_passes`). Each run re-counts the
|
|
889
|
+
// same stable set, so summing across the window re-counts it N times (the
|
|
890
|
+
// 2.7M / 3M inflation). For these we keep the MOST RECENT run's count — the
|
|
891
|
+
// current snapshot — matching how memorySummary/profileFilteredRefs are
|
|
892
|
+
// handled. Events arrive in chronological (offset) order, so the last
|
|
893
|
+
// count-bearing event per reason is the latest run's value.
|
|
894
|
+
const summed = {};
|
|
895
|
+
const latestSnapshot = {};
|
|
763
896
|
for (const event of events) {
|
|
764
897
|
const reason = typeof event.metadata?.reason === "string" && event.metadata.reason.trim() ? event.metadata.reason : "unknown";
|
|
765
|
-
|
|
898
|
+
const rawCount = event.metadata?.count;
|
|
899
|
+
if (typeof rawCount === "number" && Number.isFinite(rawCount) && rawCount > 0) {
|
|
900
|
+
latestSnapshot[reason] = rawCount; // overwrite → keeps the latest run's snapshot
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
summed[reason] = (summed[reason] ?? 0) + 1;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
const skipReasons = { ...summed };
|
|
907
|
+
for (const [reason, count] of Object.entries(latestSnapshot)) {
|
|
908
|
+
skipReasons[reason] = (skipReasons[reason] ?? 0) + count;
|
|
766
909
|
}
|
|
767
|
-
|
|
910
|
+
const skipped = Object.values(skipReasons).reduce((a, b) => a + b, 0);
|
|
911
|
+
return { skipped, skipReasons };
|
|
768
912
|
}
|
|
769
913
|
function probeStateDbRoundTrip(stateDbPath) {
|
|
770
914
|
const before = readEvents({}, { dbPath: stateDbPath }).nextOffset;
|
|
@@ -849,6 +993,7 @@ const INTERESTING_DELTA_PATHS = [
|
|
|
849
993
|
"improve.graphExtraction.cacheHitRate",
|
|
850
994
|
"improve.graphExtraction.failures",
|
|
851
995
|
"improve.graphExtraction.htmlErrors",
|
|
996
|
+
"improve.graphExtraction.nonArrayBatchFailures",
|
|
852
997
|
"improve.sessionExtraction.sessionsScanned",
|
|
853
998
|
"improve.sessionExtraction.proposalsCreated",
|
|
854
999
|
"improve.autoAccept.promoted",
|
|
@@ -955,6 +1100,197 @@ function readLlmUsageAggregate(stateDbPath, since, until) {
|
|
|
955
1100
|
});
|
|
956
1101
|
return summarizeLlmUsage(events);
|
|
957
1102
|
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Read the auto-accept gate calibration summary (#612) over `[since, until)`.
|
|
1105
|
+
* Reads every proposal's `gateDecision` from the open state.db, projects the
|
|
1106
|
+
* acted-on (auto-accepted / auto-rejected) decisions into calibration samples
|
|
1107
|
+
* within the window, and aggregates them deterministically.
|
|
1108
|
+
*/
|
|
1109
|
+
function readCalibration(db, since, until) {
|
|
1110
|
+
const decisions = listProposalGateDecisions(db);
|
|
1111
|
+
const samples = gateDecisionsToSamples(decisions, { since, ...(until !== undefined ? { until } : {}) });
|
|
1112
|
+
return summarizeCalibration(samples);
|
|
1113
|
+
}
|
|
1114
|
+
// ── WS-5 Observability helpers ───────────────────────────────────────────────
|
|
1115
|
+
/**
|
|
1116
|
+
* Compute WS-5 denominator-fixed coverage metrics.
|
|
1117
|
+
*
|
|
1118
|
+
* `coverage = accepted_proposals / total_assets` (Part V §3).
|
|
1119
|
+
* The denominator is the TOTAL stash size (not the moving eligible set) so
|
|
1120
|
+
* more-inclusive WS-1 ranking cannot spuriously inflate coverage.
|
|
1121
|
+
* `eligibleFraction = eligible_assets / total_assets` is reported separately.
|
|
1122
|
+
*
|
|
1123
|
+
* Proposals are counted only when their `updatedAt` falls within `[since, until)`
|
|
1124
|
+
* so the rate is genuinely window-scoped (matching the JSDoc on the type).
|
|
1125
|
+
*
|
|
1126
|
+
* @param db - Open state.db connection.
|
|
1127
|
+
* @param totalAssets - Total stash asset count (eligible + derived) from the
|
|
1128
|
+
* most recent run's memorySummary. 0 = denominator unknown, returns NaN rates.
|
|
1129
|
+
* @param eligibleAssets - Eligible (non-derived) asset count from the most recent run.
|
|
1130
|
+
* @param since - Window start (ISO-8601). Proposals accepted before this are excluded.
|
|
1131
|
+
* @param until - Window end (ISO-8601, exclusive). Absent = open-ended (up to now).
|
|
1132
|
+
* @param stashDir - Optional: scope accepted proposals to one stash. Absent = all stashes.
|
|
1133
|
+
*/
|
|
1134
|
+
function computeDenominatorFixedCoverage(db, totalAssets, eligibleAssets, since, until, stashDir) {
|
|
1135
|
+
let acceptedProposals = 0;
|
|
1136
|
+
try {
|
|
1137
|
+
const proposals = listStateProposals(db, {
|
|
1138
|
+
status: "accepted",
|
|
1139
|
+
...(stashDir ? { stashDir } : {}),
|
|
1140
|
+
}).filter((p) => {
|
|
1141
|
+
const updatedAt = p.updatedAt ?? "";
|
|
1142
|
+
if (updatedAt < since)
|
|
1143
|
+
return false;
|
|
1144
|
+
if (until !== undefined && updatedAt >= until)
|
|
1145
|
+
return false;
|
|
1146
|
+
return true;
|
|
1147
|
+
});
|
|
1148
|
+
acceptedProposals = proposals.length;
|
|
1149
|
+
}
|
|
1150
|
+
catch {
|
|
1151
|
+
// Fail open: table may not exist on older installs.
|
|
1152
|
+
}
|
|
1153
|
+
if (totalAssets === 0) {
|
|
1154
|
+
return {
|
|
1155
|
+
rate: Number.NaN,
|
|
1156
|
+
eligibleFraction: Number.NaN,
|
|
1157
|
+
acceptedProposals,
|
|
1158
|
+
totalAssets: 0,
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
return {
|
|
1162
|
+
rate: roundRate(acceptedProposals / totalAssets),
|
|
1163
|
+
eligibleFraction: roundRate(eligibleAssets / totalAssets),
|
|
1164
|
+
acceptedProposals,
|
|
1165
|
+
totalAssets,
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Compute WS-5 per-run degradation metrics (Part V §4).
|
|
1170
|
+
*
|
|
1171
|
+
* Health VIEWS only — reads from state.db tables populated by prior improve
|
|
1172
|
+
* runs. Gracefully returns partial data when tables are absent (pre-WS-1/2).
|
|
1173
|
+
*
|
|
1174
|
+
* @param db - Open state.db connection.
|
|
1175
|
+
* @param since - Window start (ISO-8601).
|
|
1176
|
+
* @param until - Window end (ISO-8601).
|
|
1177
|
+
*/
|
|
1178
|
+
function computeDegradationMetrics(db, since, until) {
|
|
1179
|
+
// (a) Corpus diversity — salience rank distribution of the top-100 assets.
|
|
1180
|
+
// We use the Gini coefficient of retrieval_salience scores as an intra-corpus
|
|
1181
|
+
// diversity proxy. A Gini close to 1 = highly concentrated (entrenched top
|
|
1182
|
+
// assets), Gini near 0 = flat/diverse. This is a single-snapshot metric;
|
|
1183
|
+
// consecutive-run centroid distance requires cross-run history not yet stored.
|
|
1184
|
+
let corpusCentroidDistance = Number.NaN;
|
|
1185
|
+
let entrenchmentFlagged;
|
|
1186
|
+
try {
|
|
1187
|
+
const rows = db
|
|
1188
|
+
.prepare(`SELECT retrieval_salience FROM asset_salience
|
|
1189
|
+
ORDER BY rank_score DESC LIMIT 100`)
|
|
1190
|
+
.all();
|
|
1191
|
+
if (rows.length >= 5) {
|
|
1192
|
+
const vals = rows.map((r) => r.retrieval_salience).sort((a, b) => a - b);
|
|
1193
|
+
const n = vals.length;
|
|
1194
|
+
const sumAbsDiff = vals.reduce((acc, xi, i) => {
|
|
1195
|
+
return acc + vals.slice(i + 1).reduce((a, xj) => a + Math.abs(xi - xj), 0);
|
|
1196
|
+
}, 0);
|
|
1197
|
+
const mean = vals.reduce((a, b) => a + b, 0) / n;
|
|
1198
|
+
// Gini = (sum |xi - xj|) / (2 n^2 mean); 0 = perfect equality, 1 = perfect inequality.
|
|
1199
|
+
const gini = mean > 0 ? sumAbsDiff / (2 * n * n * mean) : 0;
|
|
1200
|
+
// Re-express as a diversity proxy in [0,1]: high gini = low diversity.
|
|
1201
|
+
// corpusCentroidDistance approximation: gini is "distance from uniform".
|
|
1202
|
+
// Note: retrieval_salience values are in [0,1], so the max achievable Gini
|
|
1203
|
+
// with this formula is ~0.5 (when one asset dominates and others are near 0).
|
|
1204
|
+
// Threshold: >0.35 flags entrenchment (robustly above the ~0.1 uniform baseline).
|
|
1205
|
+
corpusCentroidDistance = roundRate(gini);
|
|
1206
|
+
entrenchmentFlagged = gini > 0.35;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
catch {
|
|
1210
|
+
// Table not present (pre-WS-1 install) — leave NaN.
|
|
1211
|
+
}
|
|
1212
|
+
// (b) Merge fidelity — fraction of consolidate accepted proposals in the window
|
|
1213
|
+
// whose ref also has a consolidate skip-reason of "contradict_target_missing"
|
|
1214
|
+
// or an event indicating contradiction. Uses the improve_runs result_json
|
|
1215
|
+
// consolidation.contradicted count as a proxy.
|
|
1216
|
+
// Simple implementation: contradictionRate = total_contradicted / max(1, total_processed)
|
|
1217
|
+
// sourced from the window's consolidation envelope.
|
|
1218
|
+
// (The full "merge proposal → later contradiction" correlation requires cross-run
|
|
1219
|
+
// history; this is the available proxy.)
|
|
1220
|
+
let mergeFidelityContradictionRate = 0;
|
|
1221
|
+
try {
|
|
1222
|
+
const runs = queryImproveRuns(db, since, until);
|
|
1223
|
+
let totalContradicted = 0;
|
|
1224
|
+
let totalProcessed = 0;
|
|
1225
|
+
for (const row of runs) {
|
|
1226
|
+
try {
|
|
1227
|
+
const result = JSON.parse(row.result_json);
|
|
1228
|
+
const cons = result.consolidation;
|
|
1229
|
+
if (cons) {
|
|
1230
|
+
totalContradicted += toFiniteNumber(cons.contradicted);
|
|
1231
|
+
totalProcessed += toFiniteNumber(cons.processed);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
catch {
|
|
1235
|
+
// Skip malformed rows.
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
if (totalProcessed > 0) {
|
|
1239
|
+
mergeFidelityContradictionRate = roundRate(totalContradicted / totalProcessed);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
catch {
|
|
1243
|
+
// Fail open.
|
|
1244
|
+
}
|
|
1245
|
+
// (c) Generation distribution — fraction of asset_salience rows with
|
|
1246
|
+
// generation >= 2. Generation is NOT currently stored in asset_salience
|
|
1247
|
+
// (it's in frontmatter). We approximate using consecutive_no_ops as a
|
|
1248
|
+
// maturity proxy: assets that have never been no-op'd are "fresh".
|
|
1249
|
+
// TODO(0.10+): store generation in asset_salience for proper tracking.
|
|
1250
|
+
let highGenerationFraction = Number.NaN;
|
|
1251
|
+
try {
|
|
1252
|
+
const genRows = db.prepare("SELECT consecutive_no_ops FROM asset_salience").all();
|
|
1253
|
+
if (genRows.length > 0) {
|
|
1254
|
+
// Use consecutive_no_ops >= 2 as a proxy for "has been through merge cycles".
|
|
1255
|
+
const highGen = genRows.filter((r) => r.consecutive_no_ops >= 2).length;
|
|
1256
|
+
highGenerationFraction = roundRate(highGen / genRows.length);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
catch {
|
|
1260
|
+
// Table not present.
|
|
1261
|
+
}
|
|
1262
|
+
// (d) Oracle spot-check — up to 5 recently accepted proposals in the window.
|
|
1263
|
+
const oracleSpotCheck = [];
|
|
1264
|
+
try {
|
|
1265
|
+
const accepted = listStateProposals(db, { status: "accepted" }).filter((p) => {
|
|
1266
|
+
const updatedAt = p.updatedAt ?? "";
|
|
1267
|
+
return updatedAt >= since && updatedAt < until;
|
|
1268
|
+
});
|
|
1269
|
+
// Sample up to 5: pick evenly spaced (not just the first 5).
|
|
1270
|
+
const step = Math.max(1, Math.floor(accepted.length / 5));
|
|
1271
|
+
for (let i = 0; i < accepted.length && oracleSpotCheck.length < 5; i += step) {
|
|
1272
|
+
const p = accepted[i];
|
|
1273
|
+
if (p) {
|
|
1274
|
+
oracleSpotCheck.push({
|
|
1275
|
+
proposalId: p.id,
|
|
1276
|
+
ref: p.ref,
|
|
1277
|
+
source: p.source ?? "unknown",
|
|
1278
|
+
acceptedAt: p.updatedAt ?? p.createdAt ?? "",
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
catch {
|
|
1284
|
+
// Fail open.
|
|
1285
|
+
}
|
|
1286
|
+
return {
|
|
1287
|
+
corpusCentroidDistance,
|
|
1288
|
+
entrenchmentFlagged,
|
|
1289
|
+
mergeFidelityContradictionRate,
|
|
1290
|
+
highGenerationFraction,
|
|
1291
|
+
oracleSpotCheck,
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
958
1294
|
function buildWindowMetrics(db, stateDbPath, since, until, now = () => Date.now(), logsDb) {
|
|
959
1295
|
const taskRows = queryTaskHistory(db, { since }).filter((row) => {
|
|
960
1296
|
const startMs = new Date(row.started_at).getTime();
|
|
@@ -989,6 +1325,17 @@ function buildWindowMetrics(db, stateDbPath, since, until, now = () => Date.now(
|
|
|
989
1325
|
const perRunSummaries = buildPerRunSummaries(db, since, until);
|
|
990
1326
|
const wallTimes = perRunSummaries.map((run) => run.wallTimeMs).filter((ms) => Number.isFinite(ms) && ms > 0);
|
|
991
1327
|
improveSummary.wallTime = computeWallTimeStats(wallTimes, improveSummary.wallTime.byPhase);
|
|
1328
|
+
improveSummary.calibration = readCalibration(db, since, until);
|
|
1329
|
+
// WS-5: Compute denominator-fixed coverage from the most recent run's
|
|
1330
|
+
// memorySummary (totalAssets = eligible + derived — the fixed denominator).
|
|
1331
|
+
const totalAssets = improveSummary.memorySummary.eligible + improveSummary.memorySummary.derived;
|
|
1332
|
+
improveSummary.coverage = computeDenominatorFixedCoverage(db, totalAssets, improveSummary.memorySummary.eligible, since, until);
|
|
1333
|
+
// WS-5: Compute per-run degradation metrics (corpus diversity, merge fidelity,
|
|
1334
|
+
// generation distribution, oracle spot-check). Health VIEWS only.
|
|
1335
|
+
const degradation = computeDegradationMetrics(db, since, until);
|
|
1336
|
+
if (degradation) {
|
|
1337
|
+
improveSummary.degradation = degradation;
|
|
1338
|
+
}
|
|
992
1339
|
const metrics = {
|
|
993
1340
|
taskFailRate: roundRate(taskFailRate),
|
|
994
1341
|
agentFailureRate: roundRate(agentFailureRate),
|
|
@@ -1077,6 +1424,35 @@ export function akmHealth(options = {}) {
|
|
|
1077
1424
|
const perRunSummaries = buildPerRunSummaries(db, since);
|
|
1078
1425
|
const wallTimes = perRunSummaries.map((run) => run.wallTimeMs).filter((ms) => Number.isFinite(ms) && ms > 0);
|
|
1079
1426
|
improveSummary.wallTime = computeWallTimeStats(wallTimes, improveSummary.wallTime.byPhase);
|
|
1427
|
+
improveSummary.calibration = readCalibration(db, since);
|
|
1428
|
+
// WS-5: Compute denominator-fixed coverage and per-run degradation metrics
|
|
1429
|
+
// for the main health path (not just window-compare mode).
|
|
1430
|
+
const until = new Date(now()).toISOString();
|
|
1431
|
+
const totalAssetsMain = improveSummary.memorySummary.eligible + improveSummary.memorySummary.derived;
|
|
1432
|
+
improveSummary.coverage = computeDenominatorFixedCoverage(db, totalAssetsMain, improveSummary.memorySummary.eligible, since, until);
|
|
1433
|
+
const degradationMain = computeDegradationMetrics(db, since, until);
|
|
1434
|
+
if (degradationMain) {
|
|
1435
|
+
improveSummary.degradation = degradationMain;
|
|
1436
|
+
}
|
|
1437
|
+
// WS-2 proxy-adequacy tripwire: surface any outcome_proxy_inverted events
|
|
1438
|
+
// in the health window as an advisory so operators know when the 0.10+
|
|
1439
|
+
// rich in-session signal is no longer deferrable.
|
|
1440
|
+
const proxyInvertedEvents = readEvents({ since, type: "outcome_proxy_inverted" }, { dbPath: stateDbPath }).events;
|
|
1441
|
+
if (proxyInvertedEvents.length > 0) {
|
|
1442
|
+
const lastEvent = proxyInvertedEvents[proxyInvertedEvents.length - 1];
|
|
1443
|
+
const correlation = typeof lastEvent.metadata?.correlation === "number" ? lastEvent.metadata.correlation.toFixed(3) : "unknown";
|
|
1444
|
+
advisories.push({
|
|
1445
|
+
name: "outcome-proxy-adequacy",
|
|
1446
|
+
status: "warn",
|
|
1447
|
+
kind: "deterministic",
|
|
1448
|
+
confidence: "high",
|
|
1449
|
+
message: `WS-2 outcome proxy inverted (${proxyInvertedEvents.length} event(s) in window). ` +
|
|
1450
|
+
`corr(outcome_score, accepted_change_rate) = ${correlation} < −0.3. ` +
|
|
1451
|
+
"Popular assets are also the most-needing-improvement assets — " +
|
|
1452
|
+
"the retrieval-based proxy is inverted. " +
|
|
1453
|
+
"The 0.10+ rich in-session outcome signal is no longer deferrable. See plan §WS-2.",
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1080
1456
|
let sessionLogEntries = [];
|
|
1081
1457
|
try {
|
|
1082
1458
|
const sinceDays = Math.max(0, Math.ceil((now() - new Date(since).getTime()) / (24 * 60 * 60 * 1000)));
|
|
@@ -1283,6 +1659,7 @@ export function renderWindowCompareMd(windows, deltas) {
|
|
|
1283
1659
|
"improve.actions.reflect.failed",
|
|
1284
1660
|
"improve.actions.distill.llmFailed",
|
|
1285
1661
|
"improve.graphExtraction.failures",
|
|
1662
|
+
"improve.graphExtraction.nonArrayBatchFailures",
|
|
1286
1663
|
"improve.wallTime.medianMs",
|
|
1287
1664
|
"improve.wallTime.p95Ms",
|
|
1288
1665
|
"improve.memoryInference.skippedNoFacts",
|