akm-cli 0.9.16 → 0.9.17-alpha.1
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 +478 -0
- package/dist/assets/prompts/consolidate-system.md +4 -11
- package/dist/assets/prompts/graph-extract-user-prompt.md +5 -5
- package/dist/commands/health/accept-rate.js +6 -0
- package/dist/commands/health/checks.js +54 -0
- package/dist/commands/health/improve-metrics.js +1 -5
- package/dist/commands/health/report-view-model.js +0 -1
- package/dist/commands/health.js +10 -0
- package/dist/commands/improve/consolidate/chunking.js +19 -35
- package/dist/commands/improve/consolidate/merge.js +6 -9
- package/dist/commands/improve/consolidate.js +104 -91
- package/dist/commands/improve/distill/promote-memory.js +40 -2
- package/dist/commands/improve/distill/quality-gate.js +186 -23
- package/dist/commands/improve/distill.js +42 -8
- package/dist/commands/improve/eligibility.js +13 -3
- package/dist/commands/improve/improve-cli.js +32 -9
- package/dist/commands/improve/improve-strategies.js +23 -1
- package/dist/commands/improve/improve.js +121 -84
- package/dist/commands/improve/loop-stages.js +241 -108
- package/dist/commands/improve/preparation.js +50 -17
- package/dist/commands/improve/reflect.js +16 -5
- package/dist/commands/improve/shared.js +0 -10
- package/dist/commands/proposal/drain.js +79 -10
- package/dist/commands/proposal/proposal-types.js +21 -0
- package/dist/commands/proposal/repository.js +108 -29
- package/dist/core/asset/frontmatter.js +106 -1
- package/dist/core/config/schema/improve-processes.js +29 -2
- package/dist/core/improve-result.js +9 -0
- package/dist/core/paths.js +7 -0
- package/dist/indexer/ensure-index.js +52 -7
- package/dist/indexer/graph/graph-extraction.js +82 -8
- package/dist/indexer/passes/memory-inference.js +16 -1
- package/dist/llm/client.js +16 -2
- package/dist/llm/graph-extract.js +162 -18
- package/dist/scripts/akm-migrate-node.js +20 -4
- package/dist/scripts/akm-migrate.js +20 -4
- package/dist/storage/repositories/index-entries-repository.js +43 -0
- package/dist/storage/repositories/proposals-repository.js +4 -1
- package/dist/storage/state-db-integrity.js +123 -0
- package/dist/workflows/program/schema.js +1 -0
- package/docs/reference/cli.md +4 -3
- package/docs/reference/data-and-telemetry.md +1 -0
- package/package.json +1 -1
- package/schemas/akm-config.json +44 -0
- package/schemas/akm-workflow.json +1 -0
- package/dist/commands/improve/eval-cases.js +0 -52
|
@@ -18,11 +18,13 @@ import { info, warn, warnVerbose } from "../../core/warn.js";
|
|
|
18
18
|
import { beginWriteProvenance, relativeWrittenPath } from "../../core/write-provenance.js";
|
|
19
19
|
import { resolveWritable, resolveWriteTarget } from "../../core/write-source.js";
|
|
20
20
|
import { ensureIndex } from "../../indexer/ensure-index.js";
|
|
21
|
+
import { indexWrittenAssets } from "../../indexer/index-written-assets.js";
|
|
21
22
|
import { akmIndex } from "../../indexer/indexer.js";
|
|
22
23
|
import { collectPendingMemories } from "../../indexer/passes/memory-inference.js";
|
|
23
24
|
import { resolveEntryContentDir, resolveSourceEntries } from "../../indexer/search/search-source.js";
|
|
24
25
|
import { collectEngineCredentialValues } from "../../integrations/agent/engine-resolution.js";
|
|
25
26
|
import { installLlmUsagePersistence, LLM_USAGE_EVENT } from "../../llm/usage-persist.js";
|
|
27
|
+
import { withLlmStage } from "../../llm/usage-telemetry.js";
|
|
26
28
|
import { isGitBackedStash, listGitChangedPaths, resolveWritableOverride, saveGitStash, } from "../../sources/providers/git.js";
|
|
27
29
|
import { closeDatabase, openExistingDatabase } from "../../storage/repositories/index-connection.js";
|
|
28
30
|
import { getEntryCount } from "../../storage/repositories/index-entries-repository.js";
|
|
@@ -34,7 +36,6 @@ import { describeGatedLanes, isAutonomyLaneAllowed } from "./autonomy-gate.js";
|
|
|
34
36
|
import { akmDistill } from "./distill.js";
|
|
35
37
|
// Eligibility / candidate-selection predicates live in ./eligibility.
|
|
36
38
|
import { buildLatestProposalTsMap, collectEligibleRefs, collectEligibleRefsReadOnly, memoryCleanupParentRef, resolveImproveScope, shouldAnalyzeMemoryCleanup, } from "./eligibility.js";
|
|
37
|
-
import { countEvalCases } from "./eval-cases.js";
|
|
38
39
|
import { projectResolvedProcessRouting, resolveImprovePlan, resolveImproveStrategy, shouldSkipRef, } from "./improve-strategies.js";
|
|
39
40
|
import { buildImproveUsageReport } from "./improve-usage-report.js";
|
|
40
41
|
import { improveLockPath, releaseImproveLock, tryAcquireImproveLock } from "./locks.js";
|
|
@@ -149,6 +150,7 @@ export async function akmImprove(options = {}) {
|
|
|
149
150
|
let autonomyGatedDirectLanes = [];
|
|
150
151
|
let guidance;
|
|
151
152
|
let triageDrain;
|
|
153
|
+
let ensureIndexDurationMs;
|
|
152
154
|
let improveLockOwnership;
|
|
153
155
|
let exitBackstop;
|
|
154
156
|
// I1: open a single state.db connection for the main improve run so all
|
|
@@ -205,13 +207,33 @@ export async function akmImprove(options = {}) {
|
|
|
205
207
|
// #652: open AFTER the lock, so the journal covers exactly the window in
|
|
206
208
|
// which this run — and only this run — is allowed to write.
|
|
207
209
|
runJournal.open();
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
+
// R6: ensureIndex BEFORE triage, not after. Triage promotes proposals
|
|
211
|
+
// straight into the flat `knowledge/` root; running the blocking
|
|
212
|
+
// reindex only afterward (inside indexAndCollect, below) meant every
|
|
213
|
+
// triage promotion dirtied the stash right before the rescan that is
|
|
214
|
+
// supposed to precede it, so the "blocking" reindex always found fresh
|
|
215
|
+
// work and paid for a full walk on the very run it was meant to avoid.
|
|
216
|
+
const bootstrap = await runIndexBootstrapPass(setup, budgetAbortController.signal);
|
|
217
|
+
preEnsureCleanupWarnings.push(...bootstrap.warnings);
|
|
218
|
+
ensureIndexDurationMs = bootstrap.ensureIndexDurationMs;
|
|
219
|
+
// Drain the standing proposal backlog under the now-current index, so
|
|
220
|
+
// fresh proposal generation sees promotions from this same serialized
|
|
221
|
+
// run.
|
|
210
222
|
triageDrain = await runTriagePrePass(setup);
|
|
223
|
+
// R6: index triage's own writes incrementally (the R8
|
|
224
|
+
// `indexWrittenAssets` pattern) instead of letting them sit newer than
|
|
225
|
+
// `builtAt` until the next full reindex. `collectEligibleRefs` below
|
|
226
|
+
// still needs to see them, and per-file staleness (`ensure-index.ts`)
|
|
227
|
+
// needs their `content_hash` recorded so it does not re-trigger a full
|
|
228
|
+
// rescan next run for content it already has.
|
|
229
|
+
if (setup.primaryStashDir) {
|
|
230
|
+
const triageWrittenPaths = runJournal.current()?.writtenPaths() ?? [];
|
|
231
|
+
if (triageWrittenPaths.length > 0) {
|
|
232
|
+
await indexWrittenAssets(setup.primaryStashDir, triageWrittenPaths);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
211
235
|
}
|
|
212
|
-
|
|
213
|
-
// indexAndCollect helper).
|
|
214
|
-
const collected = await indexAndCollect({ run: setup, signal: budgetAbortController.signal });
|
|
236
|
+
const collected = await indexAndCollect({ run: setup });
|
|
215
237
|
plannedRefs = collected.plannedRefs;
|
|
216
238
|
memorySummary = collected.memorySummary;
|
|
217
239
|
strategyFilteredRefs = collected.strategyFilteredRefs;
|
|
@@ -219,7 +241,6 @@ export async function akmImprove(options = {}) {
|
|
|
219
241
|
memoryCleanupPlan = collected.memoryCleanupPlan;
|
|
220
242
|
autonomyGatedDirectLanes = collected.autonomyGatedDirectLanes;
|
|
221
243
|
guidance = collected.guidance;
|
|
222
|
-
preEnsureCleanupWarnings.push(...collected.warnings);
|
|
223
244
|
if (options.dryRun) {
|
|
224
245
|
const result = await runDryPlanningStage({
|
|
225
246
|
run: setup,
|
|
@@ -291,6 +312,7 @@ export async function akmImprove(options = {}) {
|
|
|
291
312
|
rawPlannedRefs: plannedRefs,
|
|
292
313
|
indexSnapshot,
|
|
293
314
|
triageDrain,
|
|
315
|
+
ensureIndexDurationMs,
|
|
294
316
|
eventsCtx,
|
|
295
317
|
});
|
|
296
318
|
// End-of-run BATCH auto-sync — the converged commit. Recognition is
|
|
@@ -620,83 +642,97 @@ function recordImproveFailure(err, run, eventsCtx) {
|
|
|
620
642
|
}, eventsCtx);
|
|
621
643
|
}
|
|
622
644
|
/**
|
|
623
|
-
* ensureIndex
|
|
624
|
-
*
|
|
625
|
-
*
|
|
645
|
+
* R6: ensureIndex bootstrap pass, hoisted out of `indexAndCollect` (below) so
|
|
646
|
+
* the caller can run it BEFORE the triage pre-pass instead of after it —
|
|
647
|
+
* triage promotes proposals straight into `knowledge/`, so ensureIndex must
|
|
648
|
+
* see a current index before triage dirties it, not after. Gated exactly as
|
|
649
|
+
* this logic was gated inside `indexAndCollect`: only for a resolved
|
|
650
|
+
* `primaryStashDir` on a non-dry-run.
|
|
651
|
+
*
|
|
652
|
+
* #339 fix carried over unchanged: ensureIndex MUST run before
|
|
653
|
+
* collectEligibleRefs. The eligible-ref query reads the `entries` table; if a
|
|
654
|
+
* DB version upgrade just dropped that table (or the index is otherwise
|
|
655
|
+
* empty), skipping this would silently return plannedRefs=[] and the improve
|
|
656
|
+
* loop would no-op.
|
|
626
657
|
*/
|
|
627
|
-
async function
|
|
628
|
-
const {
|
|
629
|
-
const { scope, options, primaryStashDir, improveProfile, _earlyConfig, ensureIndexFn, collectEligibleRefsImpl } = args.run;
|
|
658
|
+
async function runIndexBootstrapPass(run, signal) {
|
|
659
|
+
const { primaryStashDir, options, ensureIndexFn } = run;
|
|
630
660
|
const warnings = [];
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
//
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
const dbPath = getDbPath();
|
|
647
|
-
if (fs.existsSync(dbPath)) {
|
|
648
|
-
const probeDb = openExistingDatabase();
|
|
649
|
-
try {
|
|
650
|
-
preEnsureEntryCount = getEntryCount(probeDb);
|
|
651
|
-
}
|
|
652
|
-
finally {
|
|
653
|
-
closeDatabase(probeDb);
|
|
654
|
-
}
|
|
661
|
+
if (!primaryStashDir || options.dryRun)
|
|
662
|
+
return { warnings };
|
|
663
|
+
// Probe pre-ensureIndex entry count to drive the loud-fail warning below.
|
|
664
|
+
// Best-effort: a missing DB / unreadable schema is the fresh-install case
|
|
665
|
+
// and not a bug — we silently skip the probe.
|
|
666
|
+
let preEnsureEntryCount;
|
|
667
|
+
try {
|
|
668
|
+
const dbPath = getDbPath();
|
|
669
|
+
if (fs.existsSync(dbPath)) {
|
|
670
|
+
const probeDb = openExistingDatabase();
|
|
671
|
+
try {
|
|
672
|
+
preEnsureEntryCount = getEntryCount(probeDb);
|
|
673
|
+
}
|
|
674
|
+
finally {
|
|
675
|
+
closeDatabase(probeDb);
|
|
655
676
|
}
|
|
656
677
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
678
|
+
}
|
|
679
|
+
catch (err) {
|
|
680
|
+
rethrowIfTestIsolationError(err);
|
|
681
|
+
// best-effort; leave preEnsureEntryCount undefined
|
|
682
|
+
}
|
|
683
|
+
let ensureIndexDurationMs;
|
|
684
|
+
try {
|
|
685
|
+
await ensureIndexFn(primaryStashDir, {
|
|
686
|
+
mode: "blocking",
|
|
687
|
+
signal,
|
|
688
|
+
// R6: capture the implicit reindex's wall-clock cost (otherwise
|
|
689
|
+
// discarded) so the caller can surface it on the improve result.
|
|
690
|
+
onReindexTiming: ({ durationMs }) => {
|
|
691
|
+
ensureIndexDurationMs = durationMs;
|
|
692
|
+
},
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
catch (err) {
|
|
696
|
+
if (signal.aborted)
|
|
697
|
+
throw err;
|
|
698
|
+
warnings.push(`ensureIndex failed: ${errMessage(err)}`);
|
|
699
|
+
}
|
|
700
|
+
// #339 loud-fail: if the index was empty pre-ensureIndex but is now
|
|
701
|
+
// populated, a version-upgrade-triggered rebuild just happened. Surface
|
|
702
|
+
// that on stderr so the improve run is not silently masked by stale
|
|
703
|
+
// index state. Zero-before AND zero-after is the empty-stash case and
|
|
704
|
+
// is intentionally not warned (not a bug).
|
|
705
|
+
if (preEnsureEntryCount === 0) {
|
|
661
706
|
try {
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
catch (err) {
|
|
665
|
-
if (signal.aborted)
|
|
666
|
-
throw err;
|
|
667
|
-
warnings.push(`ensureIndex failed: ${errMessage(err)}`);
|
|
668
|
-
}
|
|
669
|
-
// #339 loud-fail: if the index was empty pre-ensureIndex but is now
|
|
670
|
-
// populated, a version-upgrade-triggered rebuild just happened. Surface
|
|
671
|
-
// that on stderr so the improve run is not silently masked by stale
|
|
672
|
-
// index state. Zero-before AND zero-after is the empty-stash case and
|
|
673
|
-
// is intentionally not warned (not a bug).
|
|
674
|
-
if (preEnsureEntryCount === 0) {
|
|
707
|
+
const probeDb = openExistingDatabase();
|
|
708
|
+
let postCount = 0;
|
|
675
709
|
try {
|
|
676
|
-
|
|
677
|
-
let postCount = 0;
|
|
678
|
-
try {
|
|
679
|
-
postCount = getEntryCount(probeDb);
|
|
680
|
-
}
|
|
681
|
-
finally {
|
|
682
|
-
closeDatabase(probeDb);
|
|
683
|
-
}
|
|
684
|
-
if (postCount > 0) {
|
|
685
|
-
warn("[improve] index was empty after DB version upgrade — repopulating before continuing");
|
|
686
|
-
}
|
|
710
|
+
postCount = getEntryCount(probeDb);
|
|
687
711
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
712
|
+
finally {
|
|
713
|
+
closeDatabase(probeDb);
|
|
714
|
+
}
|
|
715
|
+
if (postCount > 0) {
|
|
716
|
+
warn("[improve] index was empty after DB version upgrade — repopulating before continuing");
|
|
691
717
|
}
|
|
692
718
|
}
|
|
719
|
+
catch (err) {
|
|
720
|
+
rethrowIfTestIsolationError(err);
|
|
721
|
+
// best-effort
|
|
722
|
+
}
|
|
693
723
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
724
|
+
return { warnings, ensureIndexDurationMs };
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* collectEligibleRefs + the contradiction pre-pass + the memory-cleanup
|
|
728
|
+
* recompute. Formerly the runIndexAndCollect closure mutating outer `let`s;
|
|
729
|
+
* now a pure pass returning its results. The ensureIndex bootstrap this
|
|
730
|
+
* function used to open with now runs earlier, before triage — see
|
|
731
|
+
* {@link runIndexBootstrapPass} and its call site in `akmImprove`.
|
|
732
|
+
*/
|
|
733
|
+
async function indexAndCollect(args) {
|
|
734
|
+
const { scope, options, primaryStashDir, improveProfile, _earlyConfig, collectEligibleRefsImpl } = args.run;
|
|
735
|
+
const { plannedRefs, memorySummary, strategyFilteredRefs = [], indexSnapshot, } = await collectEligibleRefsImpl(scope, options.stashDir, improveProfile, _earlyConfig);
|
|
700
736
|
const cleanupParentRef = memoryCleanupParentRef(scope, options.stashDir);
|
|
701
737
|
// D8 — the two direct lanes share one eligibility predicate, which reads scope
|
|
702
738
|
// and eligible-memory count and no strategy flag at all. Compute it once: it
|
|
@@ -724,7 +760,6 @@ async function indexAndCollect(args) {
|
|
|
724
760
|
memoryCleanupPlan,
|
|
725
761
|
autonomyGatedDirectLanes,
|
|
726
762
|
guidance,
|
|
727
|
-
warnings,
|
|
728
763
|
};
|
|
729
764
|
}
|
|
730
765
|
/** The P2 lock-skipped envelope (graceful `skipIfLocked` early return). Exported for unit tests. */
|
|
@@ -810,6 +845,7 @@ export function buildDryRunResult(run, collected, preparation) {
|
|
|
810
845
|
: {}),
|
|
811
846
|
...(strategyFilteredRefs.length > 0 ? { strategyFilteredRefs } : {}),
|
|
812
847
|
...(run.resolvedPlan.engineUnavailable.length > 0 ? { skippedProcesses: run.resolvedPlan.engineUnavailable } : {}),
|
|
848
|
+
...(run.options.engineProbe !== undefined ? { engineProbe: run.options.engineProbe } : {}),
|
|
813
849
|
...(preparation?.proactiveMaintenance ? { proactiveMaintenance: preparation.proactiveMaintenance } : {}),
|
|
814
850
|
};
|
|
815
851
|
}
|
|
@@ -935,7 +971,7 @@ async function runTriagePrePass(run) {
|
|
|
935
971
|
const policy = resolveDrainPolicy(triageConfig?.policy);
|
|
936
972
|
const applyMode = triageConfig?.applyMode ?? "queue";
|
|
937
973
|
const maxAccepts = triageConfig?.maxAcceptsPerRun ?? 25;
|
|
938
|
-
triageDrain = await drainProposalsFn({
|
|
974
|
+
triageDrain = await withLlmStage("triage", () => drainProposalsFn({
|
|
939
975
|
stashDir: primaryStashDir,
|
|
940
976
|
...(options.target ? { target: options.target } : {}),
|
|
941
977
|
config: options.config,
|
|
@@ -946,7 +982,7 @@ async function runTriagePrePass(run) {
|
|
|
946
982
|
excludeIds: new Set(),
|
|
947
983
|
...(triageConfig?.maxDiffLines !== undefined ? { maxDiffLines: triageConfig.maxDiffLines } : {}),
|
|
948
984
|
judgment: resolvedPlan.triageJudgment,
|
|
949
|
-
});
|
|
985
|
+
}), { engine: resolvedPlan.triageJudgment?.engine, process: "triage.judgment" });
|
|
950
986
|
}
|
|
951
987
|
catch (err) {
|
|
952
988
|
warn(`[improve] triage pre-pass failed (non-fatal): ${errMessage(err)}`);
|
|
@@ -1123,7 +1159,7 @@ export function refilterProactiveLoopRefs(loopRefs, improveProfile) {
|
|
|
1123
1159
|
* `runImproveStageSequence` — fn-size decomposition, no logic change).
|
|
1124
1160
|
*/
|
|
1125
1161
|
async function runPostLoopStageOrSkip(args) {
|
|
1126
|
-
const { budgetAbortController, scope, options, primaryStashDir, preparation, memoryRefsForInference,
|
|
1162
|
+
const { budgetAbortController, scope, options, primaryStashDir, preparation, memoryRefsForInference, eventsCtx, improveProfile, resolvedPlan, runImprovePostLoopStageImpl, } = args;
|
|
1127
1163
|
// Do not start new post-loop work after the shared wall-clock budget. The
|
|
1128
1164
|
// result still finalizes normally, so scheduled budget exhaustion exits 0.
|
|
1129
1165
|
const emptyPostLoopResult = {
|
|
@@ -1144,7 +1180,6 @@ async function runPostLoopStageOrSkip(args) {
|
|
|
1144
1180
|
appliedCleanup: preparation.appliedCleanup,
|
|
1145
1181
|
cleanupWarnings: preparation.cleanupWarnings,
|
|
1146
1182
|
memoryRefsForInference,
|
|
1147
|
-
reindexFn,
|
|
1148
1183
|
eventsCtx,
|
|
1149
1184
|
budgetSignal: budgetAbortController.signal,
|
|
1150
1185
|
improveProfile,
|
|
@@ -1283,7 +1318,6 @@ async function runImproveStageSequence(args) {
|
|
|
1283
1318
|
primaryStashDir,
|
|
1284
1319
|
preparation,
|
|
1285
1320
|
memoryRefsForInference,
|
|
1286
|
-
reindexFn,
|
|
1287
1321
|
eventsCtx,
|
|
1288
1322
|
improveProfile,
|
|
1289
1323
|
resolvedPlan,
|
|
@@ -1343,8 +1377,8 @@ async function runImproveStageSequence(args) {
|
|
|
1343
1377
|
* side effects run between assembly and emit).
|
|
1344
1378
|
*/
|
|
1345
1379
|
function finalizeImproveResult(args) {
|
|
1346
|
-
const { guidance, memorySummary, memoryCleanupPlan, strategyFilteredRefs, rawPlannedRefs, indexSnapshot, triageDrain, eventsCtx, } = args;
|
|
1347
|
-
const { selectedStrategy, scope, options,
|
|
1380
|
+
const { guidance, memorySummary, memoryCleanupPlan, strategyFilteredRefs, rawPlannedRefs, indexSnapshot, triageDrain, ensureIndexDurationMs, eventsCtx, } = args;
|
|
1381
|
+
const { selectedStrategy, scope, options, startMs, resolvedPlan } = args.run;
|
|
1348
1382
|
const { preparation, consolidation, memoryInference, graphExtraction, cycleMetrics, reflectsWithErrorContext, memoryInferenceDurationMs, graphExtractionDurationMs, orphansPurged, proposalsExpired, allWarnings, deadUrls, deadUrlCoverage, finalActions, } = args.seq;
|
|
1349
1383
|
// C1 (13-bus-factor): fold the per-ref `distill-skipped` rows (~13k/run,
|
|
1350
1384
|
// ~91% of result_json bytes) into a bounded aggregate BEFORE persistence.
|
|
@@ -1416,6 +1450,7 @@ function finalizeImproveResult(args) {
|
|
|
1416
1450
|
: {}),
|
|
1417
1451
|
...(strategyFilteredRefs.length > 0 ? { strategyFilteredRefs } : {}),
|
|
1418
1452
|
...(resolvedPlan.engineUnavailable.length > 0 ? { skippedProcesses: resolvedPlan.engineUnavailable } : {}),
|
|
1453
|
+
...(options.engineProbe !== undefined ? { engineProbe: options.engineProbe } : {}),
|
|
1419
1454
|
...(usageReport ? { usageReport } : {}),
|
|
1420
1455
|
actions: persistedActions,
|
|
1421
1456
|
...(distillSkippedAggregate ? { distillSkipped: distillSkippedAggregate } : {}),
|
|
@@ -1426,7 +1461,6 @@ function finalizeImproveResult(args) {
|
|
|
1426
1461
|
...(preparation.memoryIndexHealth !== undefined ? { memoryIndexHealth: preparation.memoryIndexHealth } : {}),
|
|
1427
1462
|
...(preparation.coverageGaps.length > 0 ? { coverageGaps: preparation.coverageGaps } : {}),
|
|
1428
1463
|
...(preparation.extract && preparation.extract.length > 0 ? { extract: preparation.extract } : {}),
|
|
1429
|
-
...(primaryStashDir !== undefined ? { evalCasesWritten: countEvalCases(primaryStashDir) } : {}),
|
|
1430
1464
|
...(deadUrls !== undefined && deadUrls.length > 0 ? { deadUrls } : {}),
|
|
1431
1465
|
// Present whenever the check ran, unlike `deadUrls` above — a clean run
|
|
1432
1466
|
// (zero dead links) still needs to tell the health report how much of
|
|
@@ -1449,6 +1483,10 @@ function finalizeImproveResult(args) {
|
|
|
1449
1483
|
// `/tmp/akm-health-investigations/metrics-taxonomy-review.md` §1k / §3.
|
|
1450
1484
|
...(memoryInferenceDurationMs > 0 ? { memoryInferenceDurationMs } : {}),
|
|
1451
1485
|
...(graphExtractionDurationMs > 0 ? { graphExtractionDurationMs } : {}),
|
|
1486
|
+
// R6: the start-of-run implicit reindex's wall-clock cost, when one ran
|
|
1487
|
+
// (absent — not zero — when the index was already fresh and no inline
|
|
1488
|
+
// rebuild was needed).
|
|
1489
|
+
...(ensureIndexDurationMs !== undefined ? { ensureIndexDurationMs } : {}),
|
|
1452
1490
|
...(cycleMetrics ? { cycleMetrics } : {}),
|
|
1453
1491
|
...(orphansPurged !== undefined ? { orphansPurged } : {}),
|
|
1454
1492
|
...(proposalsExpired !== undefined && proposalsExpired > 0 ? { proposalsExpired } : {}),
|
|
@@ -1606,7 +1644,6 @@ function emitImproveCompletedEvent(result, durations, eventsCtx) {
|
|
|
1606
1644
|
noopActions: classCounts.noop,
|
|
1607
1645
|
reflectsWithErrorContext: result.reflectsWithErrorContext ?? 0,
|
|
1608
1646
|
coverageGapCount: result.coverageGaps?.length ?? 0,
|
|
1609
|
-
evalCasesWritten: result.evalCasesWritten ?? 0,
|
|
1610
1647
|
deadUrlCount: result.deadUrls?.length ?? 0,
|
|
1611
1648
|
deadUrlsChecked: result.deadUrlCoverage?.checked ?? 0,
|
|
1612
1649
|
deadUrlsTotal: result.deadUrlCoverage?.total ?? 0,
|