akm-cli 0.9.1 → 0.9.2-alpha.2
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 +103 -28
- package/README.md +3 -1
- package/SECURITY.md +1 -1
- package/STABILITY.md +1 -1
- package/dist/akm +2 -2
- package/dist/akm-migrate +2 -2
- package/dist/assets/hints/cli-hints-full.md +14 -9
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/models.json +35 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +3 -4
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
- package/dist/assets/tasks/core/extract.yml +6 -5
- package/dist/assets/tasks/core/improve.yml +6 -5
- package/dist/assets/tasks/core/index-refresh.yml +6 -5
- package/dist/assets/tasks/core/sync.yml +6 -5
- package/dist/assets/tasks/core/version-check.yml +6 -5
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
- package/dist/cli/confirm.js +2 -2
- package/dist/cli/parse-args.js +3 -24
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +2 -2
- package/dist/cli.js +11 -9
- package/dist/commands/agent/agent-dispatch.js +55 -89
- package/dist/commands/agent/contribute-cli.js +12 -45
- package/dist/commands/command/builtin-action.js +32 -0
- package/dist/commands/command/command-cli.js +99 -0
- package/dist/commands/command/command-execution.js +308 -0
- package/dist/commands/command/execution-source-loader.js +176 -0
- package/dist/commands/command/portable-template.js +60 -0
- package/dist/commands/config-cli.js +10 -4
- package/dist/commands/env/env.js +4 -2
- package/dist/commands/feedback-cli.js +1 -1
- package/dist/commands/health/checks.js +241 -29
- package/dist/commands/health/html-report.js +0 -14
- package/dist/commands/health/report-view-model.js +0 -1
- package/dist/commands/health/surfaces.js +6 -7
- package/dist/commands/health/types.js +0 -2
- package/dist/commands/health.js +63 -18
- package/dist/commands/improve/collapse-detector.js +5 -6
- package/dist/commands/improve/consolidate.js +251 -214
- package/dist/commands/improve/distill/promote-memory.js +71 -34
- package/dist/commands/improve/distill/quality-gate.js +17 -5
- package/dist/commands/improve/distill.js +232 -155
- package/dist/commands/improve/eligibility.js +112 -79
- package/dist/commands/improve/execution.js +57 -0
- package/dist/commands/improve/extract-cli.js +5 -5
- package/dist/commands/improve/extract-prompt.js +64 -22
- package/dist/commands/improve/extract.js +608 -360
- package/dist/commands/improve/improve-strategies.js +43 -14
- package/dist/commands/improve/improve.js +249 -29
- package/dist/commands/improve/loop-stages.js +11 -17
- package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
- package/dist/commands/improve/outcome-loop.js +22 -38
- package/dist/commands/improve/planner.js +134 -0
- package/dist/commands/improve/preparation.js +730 -409
- package/dist/commands/improve/reflect.js +386 -223
- package/dist/commands/improve/run-context.js +3 -4
- package/dist/commands/improve/salience.js +6 -58
- package/dist/commands/improve/session-asset.js +12 -12
- package/dist/commands/lint/index.js +101 -29
- package/dist/commands/migrate-cli.js +11 -69
- package/dist/commands/migration-tool.js +6 -9
- package/dist/commands/models-cli.js +27 -0
- package/dist/commands/proposal/drain.js +258 -186
- package/dist/commands/proposal/proposal-cli.js +32 -10
- package/dist/commands/proposal/proposal.js +2 -5
- package/dist/commands/proposal/propose.js +192 -172
- package/dist/commands/proposal/repository.js +54 -91
- package/dist/commands/proposal/validators/proposal-validators.js +9 -7
- package/dist/commands/read/curate.js +53 -22
- package/dist/commands/read/registry-search.js +25 -9
- package/dist/commands/read/remember-cli.js +14 -2
- package/dist/commands/read/search.js +10 -4
- package/dist/commands/read/show.js +139 -153
- package/dist/commands/registry-cli.js +16 -7
- package/dist/commands/remember.js +33 -18
- package/dist/commands/sources/add-cli.js +19 -178
- package/dist/commands/sources/bundle-cli.js +15 -3
- package/dist/commands/sources/dangerous-env-audit.js +135 -0
- package/dist/commands/sources/info.js +2 -1
- package/dist/commands/sources/installed-stashes.js +901 -177
- package/dist/commands/sources/schema-repair.js +174 -95
- package/dist/commands/sources/self-update.js +30 -74
- package/dist/commands/sources/source-add.js +3 -5
- package/dist/commands/sources/sources-cli.js +2 -15
- package/dist/commands/sources/update-transaction.js +220 -0
- package/dist/commands/tasks/tasks-cli.js +3 -3
- package/dist/commands/tasks/tasks.js +736 -317
- package/dist/commands/workflow-cli.js +2 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
- package/dist/core/adapter/adapters/akm-adapter.js +85 -35
- package/dist/core/adapter/adapters/akm-lint.js +54 -39
- package/dist/core/adapter/adapters/akm-metadata.js +45 -45
- package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
- package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
- package/dist/core/adapter/adapters/index.js +0 -9
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
- package/dist/core/adapter/adapters/okf-adapter.js +4 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
- package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
- package/dist/core/adapter/execution-source.js +308 -0
- package/dist/core/adapter/recognize-match.js +36 -13
- package/dist/core/adapter/registry.js +0 -9
- package/dist/core/asset/stash-meta.js +94 -4
- package/dist/core/common.js +6 -11
- package/dist/core/config/config-io.js +3 -3
- package/dist/core/config/config-schema.js +18 -40
- package/dist/core/config/config-sources.js +11 -21
- package/dist/core/config/config-walker.js +31 -13
- package/dist/core/config/config.js +23 -26
- package/dist/core/config/schema/engines.js +8 -7
- package/dist/core/config/schema/improve-processes.js +29 -5
- package/dist/core/config/schema/index-config.js +0 -27
- package/dist/core/config/schema/primitives.js +1 -23
- package/dist/core/config/schema/sources-bundles.js +13 -16
- package/dist/core/errors.js +2 -0
- package/dist/core/events.js +68 -32
- package/dist/core/extra-params.js +1 -0
- package/dist/core/improve-result.js +315 -0
- package/dist/core/lesson-lint.js +0 -6
- package/dist/core/maintenance-barrier.js +4 -4
- package/dist/core/network-policy.js +152 -0
- package/dist/core/paths.js +1 -1
- package/dist/core/recognition-util.js +4 -4
- package/dist/core/registry-url.js +456 -0
- package/dist/core/state/migrations.js +161 -47
- package/dist/core/state-db.js +453 -80
- package/dist/core/system-error.js +32 -0
- package/dist/core/time.js +2 -12
- package/dist/core/write-source.js +0 -18
- package/dist/execution/directory-identity.js +52 -0
- package/dist/execution/executable-identity.js +107 -0
- package/dist/execution/guarded-source.js +398 -0
- package/dist/execution/json.js +95 -0
- package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
- package/dist/execution/record.js +55 -0
- package/dist/execution/resolved-request.js +730 -0
- package/dist/execution/source.js +320 -0
- package/dist/indexer/bundle-identity-guard.js +5 -4
- package/dist/indexer/db/graph-db.js +33 -0
- package/dist/indexer/graph/graph-boost.js +3 -4
- package/dist/indexer/graph/graph-extraction.js +562 -373
- package/dist/indexer/index-written-assets.js +78 -39
- package/dist/indexer/indexer.js +471 -432
- package/dist/indexer/installations.js +6 -0
- package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
- package/dist/indexer/materialize-embeddings.js +155 -0
- package/dist/indexer/passes/memory-inference.js +227 -174
- package/dist/indexer/passes/metadata.js +263 -118
- package/dist/indexer/scan/doc-to-entry.js +7 -10
- package/dist/indexer/scan/drain-dir.js +51 -23
- package/dist/indexer/search/db-search.js +156 -50
- package/dist/indexer/search/fts-query.js +40 -40
- package/dist/indexer/search/ranking.js +36 -1
- package/dist/indexer/search/search-attribution.js +3 -1
- package/dist/indexer/search/search-fields.js +23 -14
- package/dist/indexer/search/search-hit-enrichers.js +1 -1
- package/dist/indexer/search/search-source.js +7 -16
- package/dist/indexer/search/semantic-status.js +10 -1
- package/dist/indexer/usage/show-usage.js +105 -0
- package/dist/indexer/usage/usage-events.js +7 -2
- package/dist/indexer/walk/matchers.js +40 -10
- package/dist/indexer/walk/path-resolver.js +5 -2
- package/dist/indexer/walk/walker.js +20 -2
- package/dist/integrations/agent/builder-shared.js +3 -6
- package/dist/integrations/agent/conversation-fallback.js +16 -0
- package/dist/integrations/agent/engine-resolution.js +87 -87
- package/dist/integrations/agent/execution-cascade.js +566 -0
- package/dist/integrations/agent/execution-definitions.js +211 -0
- package/dist/integrations/agent/execution-lowering.js +811 -0
- package/dist/integrations/agent/execution-preparation.js +67 -0
- package/dist/integrations/agent/index.js +0 -2
- package/dist/integrations/agent/inline-execution.js +74 -0
- package/dist/integrations/agent/model-map.js +515 -0
- package/dist/integrations/agent/persona-fallback.js +30 -0
- package/dist/integrations/agent/request-lowering.js +186 -0
- package/dist/integrations/agent/runner-dispatch.js +230 -37
- package/dist/integrations/agent/runner.js +12 -83
- package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
- package/dist/integrations/harnesses/aider/index.js +0 -1
- package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
- package/dist/integrations/harnesses/amazonq/index.js +0 -1
- package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
- package/dist/integrations/harnesses/claude/index.js +1 -5
- package/dist/integrations/harnesses/claude/session-log.js +3 -33
- package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
- package/dist/integrations/harnesses/codex/index.js +0 -1
- package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
- package/dist/integrations/harnesses/copilot/index.js +0 -1
- package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
- package/dist/integrations/harnesses/gemini/index.js +0 -1
- package/dist/integrations/harnesses/index.js +4 -44
- package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
- package/dist/integrations/harnesses/opencode/index.js +0 -2
- package/dist/integrations/harnesses/opencode/session-log.js +14 -204
- package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
- package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
- package/dist/integrations/harnesses/openhands/index.js +0 -1
- package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
- package/dist/integrations/harnesses/pi/index.js +0 -1
- package/dist/integrations/harnesses/shared.js +0 -1
- package/dist/integrations/harnesses/types.js +1 -3
- package/dist/integrations/lockfile.js +82 -79
- package/dist/integrations/session-logs/index.js +6 -17
- package/dist/integrations/session-logs/provider-base.js +1 -29
- package/dist/llm/client.js +10 -5
- package/dist/llm/embedder.js +6 -7
- package/dist/llm/embedders/local.js +37 -88
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/graph-extract.js +75 -50
- package/dist/llm/index-passes.js +43 -5
- package/dist/llm/memory-infer.js +8 -6
- package/dist/llm/metadata-enhance.js +5 -3
- package/dist/llm/structured-call.js +122 -25
- package/dist/output/format-exempt.js +1 -1
- package/dist/output/render-registry.js +0 -16
- package/dist/output/renderers.js +12 -7
- package/dist/output/shapes/curate.js +1 -0
- package/dist/output/shapes/helpers.js +10 -2
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/output/text/command-format.js +31 -33
- package/dist/output/text/health-format.js +1 -29
- package/dist/output/text/migrate.js +6 -56
- package/dist/output/text/proposal-format.js +16 -1
- package/dist/output/text/workflow-format.js +16 -0
- package/dist/registry/network.js +279 -0
- package/dist/registry/pinned-request-helper.js +247 -0
- package/dist/registry/pinned-transport.js +717 -0
- package/dist/registry/providers/skills-sh.js +18 -6
- package/dist/registry/providers/static-index.js +20 -7
- package/dist/registry/resolve.js +53 -28
- package/dist/scripts/akm-migrate-node.js +19334 -52269
- package/dist/scripts/akm-migrate.js +19270 -51612
- package/dist/setup/registry-stash-loader.js +64 -20
- package/dist/setup/semantic-assets.js +9 -34
- package/dist/setup/setup.js +12 -30
- package/dist/setup/source-identity.js +17 -0
- package/dist/setup/steps/sources.js +36 -15
- package/dist/setup/steps/tasks.js +39 -11
- package/dist/sources/providers/git-provider.js +3 -3
- package/dist/sources/providers/npm.js +2 -2
- package/dist/sources/providers/provider-utils.js +4 -3
- package/dist/sources/providers/website.js +11 -7
- package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
- package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
- package/dist/sources/website-url.js +73 -0
- package/dist/storage/engines/sqlite-migrations.js +81 -26
- package/dist/storage/managed-db.js +27 -24
- package/dist/storage/repositories/events-repository.js +3 -0
- package/dist/storage/repositories/index-connection.js +42 -10
- package/dist/storage/repositories/index-entries-repository.js +203 -229
- package/dist/storage/repositories/index-entry-mapper.js +8 -12
- package/dist/storage/repositories/index-entry-schema.js +255 -0
- package/dist/storage/repositories/index-fts-repository.js +64 -71
- package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
- package/dist/storage/repositories/index-meta-repository.js +0 -11
- package/dist/storage/repositories/index-schema.js +74 -350
- package/dist/storage/repositories/index-utility-repository.js +12 -17
- package/dist/storage/repositories/index-vec-repository.js +56 -7
- package/dist/storage/repositories/proposals-repository.js +4 -127
- package/dist/storage/repositories/registry-cache.js +2 -1
- package/dist/storage/repositories/task-history-repository.js +20 -40
- package/dist/storage/repositories/workflow-runs-repository.js +228 -129
- package/dist/storage/sqlite-read-snapshot.js +148 -0
- package/dist/tasks/backends/cron.js +170 -42
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +787 -202
- package/dist/tasks/backends/schtasks.js +282 -83
- package/dist/tasks/embedded.js +7 -7
- package/dist/tasks/frozen-script.js +50 -0
- package/dist/tasks/resolve-akm-bin.js +5 -1
- package/dist/tasks/runner.js +239 -251
- package/dist/tasks/runtime-v3.js +281 -0
- package/dist/tasks/scheduler-binding.js +272 -0
- package/dist/tasks/scheduler-invocation.js +57 -43
- package/dist/tasks/scheduler-sync.js +654 -0
- package/dist/tasks/source-v3.js +752 -0
- package/dist/tasks/standalone-script-entry.js +5 -0
- package/dist/tasks/task-id.js +29 -0
- package/dist/workflows/authoring/authoring.js +15 -32
- package/dist/workflows/exec/dispatch-redaction.js +14 -8
- package/dist/workflows/exec/exec-unit.js +7 -28
- package/dist/workflows/exec/frozen-judge.js +57 -89
- package/dist/workflows/exec/lowering-notices.js +23 -0
- package/dist/workflows/exec/native-executor.js +301 -458
- package/dist/workflows/exec/param-secrets.js +4 -3
- package/dist/workflows/exec/run-workflow.js +26 -32
- package/dist/workflows/exec/step-work.js +105 -109
- package/dist/workflows/exec/unit-dispatch.js +103 -27
- package/dist/workflows/exec/unit-writer.js +3 -3
- package/dist/workflows/exec/worktree.js +2 -2
- package/dist/workflows/ir/compile.js +86 -72
- package/dist/workflows/ir/environment-v4.js +328 -0
- package/dist/workflows/ir/freeze-v4.js +122 -0
- package/dist/workflows/ir/plan-hash.js +13 -7
- package/dist/workflows/ir/schema-v4.js +525 -0
- package/dist/workflows/ir/schema.js +25 -284
- package/dist/workflows/ir/source-freeze-v4.js +506 -0
- package/dist/workflows/parser.js +27 -24
- package/dist/workflows/program/schema.js +1 -2
- package/dist/workflows/renderer.js +42 -29
- package/dist/workflows/resource-limits.js +4 -5
- package/dist/workflows/runtime/agent-identity.js +11 -13
- package/dist/workflows/runtime/plan-classifier.js +8 -8
- package/dist/workflows/runtime/runs.js +27 -43
- package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
- package/dist/workflows/source-files.js +373 -0
- package/dist/workflows/source-ir/compile.js +196 -0
- package/dist/workflows/source-ir/github-yaml.js +577 -0
- package/dist/workflows/source-ir/ordering.js +38 -0
- package/dist/workflows/source-ir/program.js +50 -0
- package/dist/workflows/source-ir/result.js +26 -0
- package/dist/workflows/source-ir/schema.js +772 -0
- package/dist/workflows/source-ir/semantics.js +242 -0
- package/dist/workflows/source-ir/uses.js +14 -0
- package/docs/README.md +2 -0
- package/docs/migration/README.md +3 -1
- package/docs/migration/release-notes/0.9.2.md +55 -0
- package/docs/migration/release-notes/README.md +5 -0
- package/docs/migration/v0.8-to-v0.9.md +76 -1077
- package/docs/migration/v0.9.0-troubleshooting.md +104 -516
- package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
- package/docs/reference/README.md +1 -0
- package/docs/reference/cli.md +230 -98
- package/docs/reference/configuration.md +159 -36
- package/docs/reference/data-and-telemetry.md +19 -1
- package/docs/reference/supported-formats.md +23 -3
- package/docs/reference/tasks.md +182 -0
- package/docs/reference/workflow-schema.md +91 -40
- package/docs/reference/workflows.md +33 -6
- package/package.json +10 -6
- package/schemas/akm-config.json +372 -224
- package/schemas/akm-task.json +324 -80
- package/schemas/akm-workflow.json +6 -9
- package/dist/core/migration-operation.js +0 -75
- package/dist/integrations/agent/model-aliases.js +0 -74
- package/dist/tasks/parser.js +0 -380
- package/dist/tasks/schema.js +0 -123
- package/dist/tasks/validator.js +0 -80
- package/dist/workflows/ir/freeze.js +0 -320
- package/dist/workflows/runtime/document-cache.js +0 -13
|
@@ -38,10 +38,9 @@ import path from "node:path";
|
|
|
38
38
|
import contradictionJudgeTemplate from "../../../assets/prompts/contradiction-judge.md" with { type: "text" };
|
|
39
39
|
import { mutateFrontmatter, parseFrontmatter } from "../../../core/asset/frontmatter.js";
|
|
40
40
|
import { parseEmbeddedJsonResponse } from "../../../core/parse.js";
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import { callStructured } from "../../../llm/structured-call.js";
|
|
41
|
+
import { disposeLoweredExecutionDispatchLease } from "../../../integrations/agent/execution-lowering.js";
|
|
42
|
+
import { callStructured, preflightStructuredLlmRunner } from "../../../llm/structured-call.js";
|
|
43
|
+
import { resolveImproveLlmExecution } from "../execution.js";
|
|
45
44
|
import { isDerivedMemory, memoryIdentityRef, resolveParentRef } from "./derived-ref.js";
|
|
46
45
|
// ── Constants ────────────────────────────────────────────────────────────────
|
|
47
46
|
/**
|
|
@@ -153,23 +152,30 @@ function pickContradictionLoser(a, b) {
|
|
|
153
152
|
*
|
|
154
153
|
* @param stashDir - Root stash directory.
|
|
155
154
|
* @param config - Loaded AKM config (used to access LLM settings).
|
|
156
|
-
* @param chat - Optional chat seam
|
|
155
|
+
* @param chat - Optional test-only chat seam.
|
|
157
156
|
*/
|
|
158
|
-
export async function detectAndWriteContradictions(stashDir, config, chat
|
|
157
|
+
export async function detectAndWriteContradictions(stashDir, config, chat, strategy, resolvedRunner) {
|
|
159
158
|
const result = {
|
|
160
159
|
familiesExamined: 0,
|
|
161
160
|
pairsChecked: 0,
|
|
162
161
|
edgesWritten: 0,
|
|
163
162
|
warnings: [],
|
|
164
163
|
};
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
164
|
+
if (!(strategy?.processes?.consolidate?.contradictionDetection?.enabled ?? false))
|
|
165
|
+
return result;
|
|
166
|
+
const noticesByKey = new Map();
|
|
167
|
+
const resolvedExecution = resolvedRunner === undefined
|
|
168
|
+
? resolveImproveLlmExecution({
|
|
169
|
+
config,
|
|
170
|
+
profile: strategy,
|
|
171
|
+
process: strategy?.processes?.consolidate,
|
|
172
|
+
processName: "memory-contradiction-detection",
|
|
173
|
+
})
|
|
174
|
+
: null;
|
|
175
|
+
for (const notice of resolvedExecution?.notices ?? [])
|
|
176
|
+
noticesByKey.set(JSON.stringify(notice), notice);
|
|
177
|
+
const contradictionRunner = resolvedRunner === null ? undefined : (resolvedRunner ?? resolvedExecution?.runner);
|
|
178
|
+
if (!contradictionRunner)
|
|
173
179
|
return result;
|
|
174
180
|
// Collect derived memories grouped by parent.
|
|
175
181
|
const memoriesDir = path.join(stashDir, "memories");
|
|
@@ -208,7 +214,7 @@ export async function detectAndWriteContradictions(stashDir, config, chat = chat
|
|
|
208
214
|
family.push(entry);
|
|
209
215
|
byParent.set(parentRef, family);
|
|
210
216
|
}
|
|
211
|
-
|
|
217
|
+
const candidatePairs = [];
|
|
212
218
|
for (const [, family] of byParent) {
|
|
213
219
|
if (family.length < 2)
|
|
214
220
|
continue;
|
|
@@ -219,7 +225,7 @@ export async function detectAndWriteContradictions(stashDir, config, chat = chat
|
|
|
219
225
|
result.familiesExamined++;
|
|
220
226
|
for (let i = 0; i < family.length - 1; i++) {
|
|
221
227
|
for (let j = i + 1; j < family.length; j++) {
|
|
222
|
-
if (
|
|
228
|
+
if (candidatePairs.length >= MAX_PAIRS_PER_RUN)
|
|
223
229
|
break;
|
|
224
230
|
const a = family[i];
|
|
225
231
|
const b = family[j];
|
|
@@ -237,58 +243,76 @@ export async function detectAndWriteContradictions(stashDir, config, chat = chat
|
|
|
237
243
|
const loserCB = Array.isArray(loserData.contradictedBy) ? loserData.contradictedBy : [];
|
|
238
244
|
if (loserCB.includes(winnerRef))
|
|
239
245
|
continue;
|
|
240
|
-
|
|
241
|
-
const judgeResult = await callStructured({
|
|
242
|
-
feature: "memory_contradiction_detection",
|
|
243
|
-
akmConfig: config,
|
|
244
|
-
// Resolver-less key: the strategy decision IS the gate (default-off).
|
|
245
|
-
enabled: strategy?.processes?.consolidate?.contradictionDetection?.enabled ?? false,
|
|
246
|
-
config: contradictionLlm,
|
|
247
|
-
messages: [
|
|
248
|
-
{ role: "system", content: "Return only valid JSON. No prose." },
|
|
249
|
-
{ role: "user", content: prompt },
|
|
250
|
-
],
|
|
251
|
-
request: { chat },
|
|
252
|
-
parse: (raw) => raw ?? null,
|
|
253
|
-
// A transport throw used to escape the gated fn into the gate's
|
|
254
|
-
// catch and take the null fallback ("skip"); onError reproduces it.
|
|
255
|
-
onError: () => null,
|
|
256
|
-
fallback: null, // null means "skip" — gate disabled or LLM call failed.
|
|
257
|
-
});
|
|
258
|
-
totalPairsChecked++;
|
|
259
|
-
result.pairsChecked++;
|
|
260
|
-
if (!judgeResult)
|
|
261
|
-
continue; // Feature gate disabled or LLM call failed.
|
|
262
|
-
let parsed = null;
|
|
263
|
-
try {
|
|
264
|
-
parsed = parseEmbeddedJsonResponse(judgeResult);
|
|
265
|
-
}
|
|
266
|
-
catch {
|
|
267
|
-
result.warnings.push(`Could not parse contradiction judge response for pair ${a.ref} / ${b.ref}`);
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
if (!parsed?.contradicts)
|
|
271
|
-
continue;
|
|
272
|
-
const confidence = typeof parsed.confidence === "number" ? parsed.confidence : 0;
|
|
273
|
-
if (confidence < CONTRADICT_CONFIDENCE_THRESHOLD) {
|
|
274
|
-
result.warnings.push(`Pair ${a.ref} / ${b.ref}: confidence ${confidence.toFixed(2)} below ${CONTRADICT_CONFIDENCE_THRESHOLD} threshold — skipped.`);
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
// Write a SINGLE directed contradiction edge: the losing (older) memory
|
|
278
|
-
// gets `contradictedBy` pointing to the winner. A mutual A↔B pair forms
|
|
279
|
-
// a 2-cycle that the SCC resolver refreshes back to active, erasing the
|
|
280
|
-
// contradiction every run (see pickContradictionLoser).
|
|
281
|
-
try {
|
|
282
|
-
const wrote = writeContradictedByEdge(loser.filePath, winnerRef);
|
|
283
|
-
result.edgesWritten += wrote ? 1 : 0;
|
|
284
|
-
}
|
|
285
|
-
catch (err) {
|
|
286
|
-
result.warnings.push(`Failed to write contradiction edge ${loser.ref} -> ${winnerRef}: ${err instanceof Error ? err.message : String(err)}`);
|
|
287
|
-
}
|
|
246
|
+
candidatePairs.push({ a, b, loser, winnerRef });
|
|
288
247
|
}
|
|
289
|
-
if (
|
|
248
|
+
if (candidatePairs.length >= MAX_PAIRS_PER_RUN)
|
|
290
249
|
break;
|
|
291
250
|
}
|
|
292
251
|
}
|
|
293
|
-
|
|
252
|
+
if (candidatePairs.length === 0) {
|
|
253
|
+
const notices = Object.freeze([...noticesByKey.values()]);
|
|
254
|
+
return notices.length > 0 ? { ...result, notices } : result;
|
|
255
|
+
}
|
|
256
|
+
const dispatchLease = await preflightStructuredLlmRunner(contradictionRunner);
|
|
257
|
+
try {
|
|
258
|
+
for (const { a, b, loser, winnerRef } of candidatePairs) {
|
|
259
|
+
const prompt = buildContradictionJudgePrompt(a, b);
|
|
260
|
+
const judgeResult = await callStructured({
|
|
261
|
+
feature: "memory_contradiction_detection",
|
|
262
|
+
akmConfig: config,
|
|
263
|
+
// Resolver-less key: the strategy decision IS the gate (default-off).
|
|
264
|
+
enabled: true,
|
|
265
|
+
runner: contradictionRunner,
|
|
266
|
+
lease: dispatchLease,
|
|
267
|
+
messages: [
|
|
268
|
+
{ role: "system", content: "Return only valid JSON. No prose." },
|
|
269
|
+
{ role: "user", content: prompt },
|
|
270
|
+
],
|
|
271
|
+
...(chat ? { request: { chat } } : {}),
|
|
272
|
+
onNotices: (notices) => {
|
|
273
|
+
for (const notice of notices)
|
|
274
|
+
noticesByKey.set(JSON.stringify(notice), notice);
|
|
275
|
+
},
|
|
276
|
+
parse: (raw) => raw ?? null,
|
|
277
|
+
// A transport throw used to escape the gated fn into the gate's
|
|
278
|
+
// catch and take the null fallback ("skip"); onError reproduces it.
|
|
279
|
+
onError: () => null,
|
|
280
|
+
fallback: null, // null means "skip" — gate disabled or LLM call failed.
|
|
281
|
+
});
|
|
282
|
+
result.pairsChecked++;
|
|
283
|
+
if (!judgeResult)
|
|
284
|
+
continue; // Feature gate disabled or LLM call failed.
|
|
285
|
+
let parsed = null;
|
|
286
|
+
try {
|
|
287
|
+
parsed = parseEmbeddedJsonResponse(judgeResult);
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
result.warnings.push(`Could not parse contradiction judge response for pair ${a.ref} / ${b.ref}`);
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (!parsed?.contradicts)
|
|
294
|
+
continue;
|
|
295
|
+
const confidence = typeof parsed.confidence === "number" ? parsed.confidence : 0;
|
|
296
|
+
if (confidence < CONTRADICT_CONFIDENCE_THRESHOLD) {
|
|
297
|
+
result.warnings.push(`Pair ${a.ref} / ${b.ref}: confidence ${confidence.toFixed(2)} below ${CONTRADICT_CONFIDENCE_THRESHOLD} threshold — skipped.`);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
// Write a SINGLE directed contradiction edge: the losing (older) memory
|
|
301
|
+
// gets `contradictedBy` pointing to the winner. A mutual A↔B pair forms
|
|
302
|
+
// a 2-cycle that the SCC resolver refreshes back to active, erasing the
|
|
303
|
+
// contradiction every run (see pickContradictionLoser).
|
|
304
|
+
try {
|
|
305
|
+
const wrote = writeContradictedByEdge(loser.filePath, winnerRef);
|
|
306
|
+
result.edgesWritten += wrote ? 1 : 0;
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
result.warnings.push(`Failed to write contradiction edge ${loser.ref} -> ${winnerRef}: ${err instanceof Error ? err.message : String(err)}`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
finally {
|
|
314
|
+
disposeLoweredExecutionDispatchLease(dispatchLease);
|
|
315
|
+
}
|
|
316
|
+
const notices = Object.freeze([...noticesByKey.values()]);
|
|
317
|
+
return notices.length > 0 ? { ...result, notices } : result;
|
|
294
318
|
}
|
|
@@ -44,61 +44,45 @@ export const OUTCOME_SCORE_MAX = 1.5;
|
|
|
44
44
|
*/
|
|
45
45
|
export const DIVERSITY_FLOOR_FRACTION = 0.1;
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* On subsequent calls: applies the differential update formula.
|
|
51
|
-
*
|
|
52
|
-
* Returns the resulting `outcome_score` so the caller can pass it to
|
|
53
|
-
* `computeSalience` without a second read.
|
|
47
|
+
* Project the next outcome values without touching storage. Dry planning and
|
|
48
|
+
* the live writer both call this function, so rank inputs cannot drift merely
|
|
49
|
+
* because one caller persists the projection and the other does not.
|
|
54
50
|
*/
|
|
55
|
-
export function
|
|
56
|
-
const now = inputs.now ?? Date.now();
|
|
51
|
+
export function projectAssetOutcome(existing, inputs) {
|
|
57
52
|
const valence = inputs.valence ?? 0;
|
|
58
|
-
// Fetch existing row (or undefined for first insert).
|
|
59
|
-
const existing = getAssetOutcome(db, inputs.ref);
|
|
60
53
|
const isNewRow = existing === undefined;
|
|
61
54
|
let outcomeScore;
|
|
62
55
|
let expectedRetrievalRate;
|
|
63
56
|
if (isNewRow) {
|
|
64
|
-
// ── Warm-start ─────────────────────────────────────────────────────────
|
|
65
|
-
// Seed from utility EMA, clipped to [0, WARM_START_CAP].
|
|
66
|
-
// The warm-start is a non-negative seed; the first real differential update
|
|
67
|
-
// will adjust it up or down from there.
|
|
68
57
|
const seedScore = Math.min(WARM_START_CAP, Math.max(0, inputs.utilityScore ?? 0));
|
|
69
58
|
outcomeScore = seedScore;
|
|
70
|
-
// Seed expected_retrieval_rate = 0 (no delta history yet).
|
|
71
|
-
// Seeding with currentRetrievalCount would produce a large spurious negative
|
|
72
|
-
// prediction error on the first real cycle (delta ≪ cumulative count).
|
|
73
59
|
expectedRetrievalRate = 0;
|
|
74
60
|
}
|
|
75
61
|
else {
|
|
76
|
-
// ── Differential update ────────────────────────────────────────────────
|
|
77
|
-
//
|
|
78
|
-
// retrieval_delta = current − stored (non-negative — we never go backwards)
|
|
79
62
|
const retrievalDelta = Math.max(0, inputs.currentRetrievalCount - existing.retrieval_count);
|
|
80
|
-
// Differential prediction-error term:
|
|
81
|
-
// outcome = (retrieval_delta − expected_delta) + valence
|
|
82
|
-
//
|
|
83
|
-
// Prediction error is computed against the PRIOR stored EMA (before folding
|
|
84
|
-
// in this cycle's observation), so the current delta cannot leak into its own
|
|
85
|
-
// expectation. Negative values are intentional — they signal below-average cycles.
|
|
86
63
|
const expectedDelta = existing.expected_retrieval_rate;
|
|
87
64
|
const predictionError = retrievalDelta - expectedDelta;
|
|
88
|
-
// Advance the EMA over the OBSERVED delta (not the cumulative count).
|
|
89
|
-
// expected' = α × delta + (1−α) × prior_expected
|
|
90
65
|
expectedRetrievalRate =
|
|
91
66
|
OUTCOME_EMA_ALPHA * retrievalDelta + (1 - OUTCOME_EMA_ALPHA) * existing.expected_retrieval_rate;
|
|
92
|
-
// Running sum (EMA approach): new score = α × update + (1−α) × old
|
|
93
|
-
// so the score tracks the moving signal, not the cumulative sum.
|
|
94
67
|
const rawUpdate = predictionError + valence;
|
|
95
68
|
const newScore = OUTCOME_EMA_ALPHA * rawUpdate + (1 - OUTCOME_EMA_ALPHA) * existing.outcome_score;
|
|
96
|
-
// Clip to [OUTCOME_SCORE_MIN, OUTCOME_SCORE_MAX] — the ceiling is the RPE
|
|
97
|
-
// saturation analog (G2): without it, long-lived popular assets accumulate
|
|
98
|
-
// unbounded positive mass and would dominate rank_score when outcome weight
|
|
99
|
-
// is enabled.
|
|
100
69
|
outcomeScore = Math.min(OUTCOME_SCORE_MAX, Math.max(OUTCOME_SCORE_MIN, newScore));
|
|
101
70
|
}
|
|
71
|
+
return { outcomeScore, expectedRetrievalRate, isNewRow };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Upsert one asset's outcome row.
|
|
75
|
+
*
|
|
76
|
+
* On first call for a ref (no prior row): warm-starts from `utilityScore`.
|
|
77
|
+
* On subsequent calls: applies the differential update formula.
|
|
78
|
+
*
|
|
79
|
+
* Returns the resulting `outcome_score` so the caller can pass it to
|
|
80
|
+
* `computeSalience` without a second read.
|
|
81
|
+
*/
|
|
82
|
+
export function updateAssetOutcome(db, inputs) {
|
|
83
|
+
const now = inputs.now ?? Date.now();
|
|
84
|
+
const existing = getAssetOutcome(db, inputs.ref);
|
|
85
|
+
const projection = projectAssetOutcome(existing, inputs);
|
|
102
86
|
// Upsert the row. See `upsertAssetOutcome` in
|
|
103
87
|
// storage/repositories/outcome-repository.ts (#672 part 2) for the SQL text
|
|
104
88
|
// and the `review_pressure` omission rationale — this call site is
|
|
@@ -107,13 +91,13 @@ export function updateAssetOutcome(db, inputs) {
|
|
|
107
91
|
ref: inputs.ref,
|
|
108
92
|
lastRetrievedAt: inputs.lastRetrievedAt,
|
|
109
93
|
retrievalCount: inputs.currentRetrievalCount,
|
|
110
|
-
expectedRetrievalRate,
|
|
94
|
+
expectedRetrievalRate: projection.expectedRetrievalRate,
|
|
111
95
|
negativeFeedbackCount: inputs.negativeFeedbackCount,
|
|
112
96
|
acceptedChangeCount: inputs.acceptedChangeCount,
|
|
113
|
-
outcomeScore,
|
|
97
|
+
outcomeScore: projection.outcomeScore,
|
|
114
98
|
updatedAt: now,
|
|
115
99
|
});
|
|
116
|
-
return { outcomeScore, isNewRow };
|
|
100
|
+
return { outcomeScore: projection.outcomeScore, isNewRow: projection.isNewRow };
|
|
117
101
|
}
|
|
118
102
|
// ── Reader ────────────────────────────────────────────────────────────────────
|
|
119
103
|
//
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* Pure improve planning projections.
|
|
6
|
+
*
|
|
7
|
+
* Filesystem/database snapshot collection stays in `preparation.ts`; this leaf
|
|
8
|
+
* receives immutable values and is shared by dry preview and live execution.
|
|
9
|
+
* Keeping the limit/lane projection here prevents the two entry paths from
|
|
10
|
+
* independently reconstructing "what would run".
|
|
11
|
+
*/
|
|
12
|
+
import { conceptIdFromTypeName } from "../../core/asset/resolve-ref.js";
|
|
13
|
+
import { parseMemoryName } from "./memory/derived-ref.js";
|
|
14
|
+
function canonicalMemoryConceptRef(ref) {
|
|
15
|
+
const name = parseMemoryName(ref);
|
|
16
|
+
return name === undefined ? undefined : conceptIdFromTypeName("memory", name);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Project the refs that survive memory cleanup from either the planned archive
|
|
20
|
+
* candidates (dry estimate) or the archives that actually succeeded (live
|
|
21
|
+
* execution). Cleanup records use the legacy `memory:<name>` identity channel,
|
|
22
|
+
* while improve candidates use canonical `memories/<name>` concept refs, so
|
|
23
|
+
* both sides are normalized before comparison.
|
|
24
|
+
*/
|
|
25
|
+
export function projectMemoryCleanup(input) {
|
|
26
|
+
const cleanupRefs = input.allowApply ? (input.mode === "estimate" ? input.candidateRefs : input.archivedRefs) : [];
|
|
27
|
+
const removed = new Set(cleanupRefs.map(canonicalMemoryConceptRef).filter((ref) => ref !== undefined));
|
|
28
|
+
const postCleanupRefs = input.plannedRefs.filter((entry) => {
|
|
29
|
+
const canonical = canonicalMemoryConceptRef(entry.ref);
|
|
30
|
+
return canonical === undefined || !removed.has(canonical);
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
postCleanupRefs,
|
|
34
|
+
gate: {
|
|
35
|
+
name: "cleanup",
|
|
36
|
+
removed: input.plannedRefs.length - postCleanupRefs.length,
|
|
37
|
+
reason: !input.allowApply
|
|
38
|
+
? "memory cleanup archive application is autonomy-gated"
|
|
39
|
+
: input.mode === "estimate"
|
|
40
|
+
? "would be archived by memory cleanup"
|
|
41
|
+
: "archived by memory cleanup",
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Apply the final global cap to an already-ranked candidate snapshot.
|
|
47
|
+
* Replay remains additive to the ordinary cap, matching the live #610 rule.
|
|
48
|
+
*/
|
|
49
|
+
export function selectEffectiveImproveRefs(args) {
|
|
50
|
+
const distillOnlySet = new Set(args.distillOnlyRefs.map((entry) => entry.ref));
|
|
51
|
+
const reflectAndDistill = args.rankedRefs.filter((entry) => !distillOnlySet.has(entry.ref));
|
|
52
|
+
const distillOnly = args.rankedRefs.filter((entry) => distillOnlySet.has(entry.ref));
|
|
53
|
+
// Preserve the established live ordering: ordinary reflect-path refs first,
|
|
54
|
+
// then distill-only refs, with the rank order stable inside each partition.
|
|
55
|
+
const allLoopRefs = [...reflectAndDistill, ...distillOnly];
|
|
56
|
+
const replay = allLoopRefs.filter((entry) => entry.eligibilitySource === "replay");
|
|
57
|
+
const ordinary = allLoopRefs.filter((entry) => entry.eligibilitySource !== "replay");
|
|
58
|
+
const selectedOrdinary = args.limit === undefined ? ordinary : ordinary.slice(0, args.limit);
|
|
59
|
+
const loopRefs = [...selectedOrdinary, ...replay.slice(0, args.replayBudget)];
|
|
60
|
+
return {
|
|
61
|
+
loopRefs,
|
|
62
|
+
distillOnlyRefs: distillOnly,
|
|
63
|
+
limitRemoved: allLoopRefs.length - loopRefs.length,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Build the stable public plan DTO from one invocation's selector observation. */
|
|
67
|
+
export function buildImproveExecutionPlan(input) {
|
|
68
|
+
const effectiveRefs = input.effectiveRefs.map((entry) => ({
|
|
69
|
+
ref: entry.ref,
|
|
70
|
+
lane: input.distillOnlyRefs.has(entry.ref) ? "distill-only" : (entry.eligibilitySource ?? "unknown"),
|
|
71
|
+
reason: entry.reason,
|
|
72
|
+
}));
|
|
73
|
+
return {
|
|
74
|
+
mode: input.dryRun ? "estimate" : "execution",
|
|
75
|
+
dispatch: !input.dryRun,
|
|
76
|
+
snapshot: { ...input.snapshot },
|
|
77
|
+
candidates: {
|
|
78
|
+
rawInScope: input.rawInScope,
|
|
79
|
+
selected: input.selectedRefs.length,
|
|
80
|
+
effective: effectiveRefs.length,
|
|
81
|
+
},
|
|
82
|
+
limits: {
|
|
83
|
+
configured: { ...input.configuredLimits },
|
|
84
|
+
...(input.effectiveLimit !== undefined ? { effective: input.effectiveLimit } : {}),
|
|
85
|
+
additiveReplayAllowance: input.replayBudget,
|
|
86
|
+
...(input.effectiveLimit !== undefined ? { totalCeiling: input.effectiveLimit + input.replayBudget } : {}),
|
|
87
|
+
},
|
|
88
|
+
gates: input.gates.map((gate) => ({ ...gate })),
|
|
89
|
+
effectiveRefs,
|
|
90
|
+
...(input.proactive
|
|
91
|
+
? {
|
|
92
|
+
proactive: {
|
|
93
|
+
...input.proactive,
|
|
94
|
+
configured: { ...input.proactive.configured },
|
|
95
|
+
effective: { ...input.proactive.effective },
|
|
96
|
+
selectedRefs: [...input.proactive.selectedRefs],
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
: {}),
|
|
100
|
+
consolidation: {
|
|
101
|
+
...input.consolidation,
|
|
102
|
+
configured: { ...input.consolidation.configured },
|
|
103
|
+
effective: { ...input.consolidation.effective },
|
|
104
|
+
gates: {
|
|
105
|
+
profile: { ...input.consolidation.gates.profile },
|
|
106
|
+
minimumPool: { ...input.consolidation.gates.minimumPool },
|
|
107
|
+
delta: { ...input.consolidation.gates.delta },
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
stages: [
|
|
111
|
+
{
|
|
112
|
+
name: "consolidation",
|
|
113
|
+
wouldRun: input.consolidation.wouldRun,
|
|
114
|
+
reason: input.consolidation.reason,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: "extract",
|
|
118
|
+
wouldRun: input.stageConfig.extract.enabled,
|
|
119
|
+
reason: input.stageConfig.extract.reason,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "graph-extraction",
|
|
123
|
+
wouldRun: input.stageConfig.graphExtraction.enabled,
|
|
124
|
+
reason: input.stageConfig.graphExtraction.reason,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "memory-inference",
|
|
128
|
+
wouldRun: input.stageConfig.memoryInference.enabled,
|
|
129
|
+
reason: input.stageConfig.memoryInference.reason,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
triage: { ...input.triage },
|
|
133
|
+
};
|
|
134
|
+
}
|