akm-cli 0.9.30 → 0.10.26101001-alpha
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 +282 -0
- package/README.md +10 -10
- package/ROADMAP.md +112 -0
- package/STABILITY.md +79 -53
- package/dist/api-node.mjs +20 -0
- package/dist/api.d.ts +23 -0
- package/dist/api.js +45 -0
- package/dist/assets/hints/cli-hints-full.md +13 -27
- package/dist/assets/hints/cli-hints-short.md +1 -1
- package/dist/assets/improve-strategies/default.json +3 -3
- package/dist/assets/prompts/consolidate-pair.md +9 -7
- package/dist/cli/shared.js +31 -48
- package/dist/cli/unknown-flags.js +6 -43
- package/dist/cli.js +8 -34
- package/dist/commands/agent/contribute-cli.js +1 -1
- package/dist/commands/completions.js +1 -2
- package/dist/commands/config-cli.js +5 -28
- package/dist/commands/env/env-cli.js +5 -5
- package/dist/commands/env/secret-cli.js +2 -2
- package/dist/commands/health/checks.js +41 -16
- package/dist/commands/health/plugin-staleness.js +52 -22
- package/dist/commands/improve/autonomy-gate.js +5 -3
- package/dist/commands/improve/consolidate/pair-pass.js +7 -1
- package/dist/commands/improve/consolidate.js +6 -35
- package/dist/commands/improve/distill/lesson-update.js +91 -0
- package/dist/commands/improve/distill-guards.js +1 -43
- package/dist/commands/improve/distill.js +140 -20
- package/dist/commands/improve/extract-cli.js +1 -1
- package/dist/commands/improve/improve-cli.js +120 -114
- package/dist/commands/improve/improve-strategies.js +8 -12
- package/dist/commands/improve/loop-stages.js +0 -1
- package/dist/commands/improve/planner.js +0 -1
- package/dist/commands/improve/preparation.js +40 -99
- package/dist/commands/improve/proactive-maintenance.js +2 -2
- package/dist/commands/improve/reflect-noise.js +3 -55
- package/dist/commands/improve/reflect.js +3 -8
- package/dist/commands/improve/retrieval-scope.js +2 -2
- package/dist/commands/improve/salience.js +2 -9
- package/dist/commands/improve/stage.js +14 -9
- package/dist/commands/lint/index.js +5 -20
- package/dist/commands/observability-cli.js +3 -9
- package/dist/commands/proposal/drain.js +39 -6
- package/dist/commands/proposal/proposal-cli.js +10 -30
- package/dist/commands/proposal/repository.js +3 -3
- package/dist/commands/read/knowledge.js +3 -3
- package/dist/commands/read/remember-cli.js +0 -13
- package/dist/commands/read/search-cli.js +29 -97
- package/dist/commands/read/search.js +0 -11
- package/dist/commands/read/show.js +0 -19
- package/dist/commands/sources/plugin-upgrade.js +164 -101
- package/dist/commands/sources/sources-cli.js +1 -15
- package/dist/commands/sources/stash-cli.js +4 -12
- package/dist/commands/tasks/tasks-cli.js +4 -115
- package/dist/commands/workflow/plan.js +11 -33
- package/dist/commands/workflow-cli.js +2 -7
- package/dist/core/adapter/adapter-ids.js +1 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
- package/dist/core/adapter/adapters/akm-adapter.js +9 -48
- package/dist/core/adapter/adapters/akm-lint.js +10 -26
- package/dist/core/adapter/adapters/akm-metadata.js +2 -72
- package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
- package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
- package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
- package/dist/core/adapter/recognize-match.js +3 -4
- package/dist/core/common.js +18 -2
- package/dist/core/config/config-schema.js +12 -15
- package/dist/core/config/config-types.js +6 -15
- package/dist/core/config/config-walker.js +6 -23
- package/dist/core/config/config.js +17 -80
- package/dist/core/config/engine-semantics.js +7 -3
- package/dist/core/config/schema/engines.js +7 -7
- package/dist/core/config/schema/improve-processes.js +8 -61
- package/dist/core/config/schema/improve.js +2 -21
- package/dist/core/config/schema/index-config.js +6 -39
- package/dist/core/env-secret-ref.js +2 -45
- package/dist/core/errors.js +1 -2
- package/dist/core/extra-params.js +2 -86
- package/dist/core/file-lock.js +10 -1
- package/dist/core/improve-result.js +11 -1
- package/dist/core/mutation-target.js +2 -2
- package/dist/core/recognition-util.js +4 -5
- package/dist/core/warn.js +21 -4
- package/dist/core/write-source.js +3 -3
- package/dist/execution/target-ref.js +1 -2
- package/dist/indexer/search/db-search.js +4 -19
- package/dist/indexer/search/fts-query.js +0 -19
- package/dist/integrations/agent/engine-resolution.js +5 -2
- package/dist/integrations/agent/index.js +1 -1
- package/dist/integrations/agent/profiles.js +41 -98
- package/dist/integrations/agent/request-lowering.js +3 -3
- package/dist/integrations/harnesses/aider/index.js +5 -0
- package/dist/integrations/harnesses/amazonq/index.js +1 -0
- package/dist/integrations/harnesses/claude/config-import.js +2 -3
- package/dist/integrations/harnesses/claude/index.js +5 -0
- package/dist/integrations/harnesses/codex/index.js +1 -0
- package/dist/integrations/harnesses/copilot/index.js +1 -0
- package/dist/integrations/harnesses/gemini/index.js +1 -0
- package/dist/integrations/harnesses/index.js +18 -39
- package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
- package/dist/integrations/harnesses/opencode/config-import.js +121 -52
- package/dist/integrations/harnesses/opencode/index.js +22 -0
- package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
- package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
- package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
- package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
- package/dist/integrations/harnesses/opencode/session-log.js +104 -115
- package/dist/integrations/harnesses/opencode/version.js +98 -0
- package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
- package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
- package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +228 -0
- package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
- package/dist/integrations/harnesses/openhands/index.js +1 -0
- package/dist/integrations/harnesses/pi/index.js +1 -0
- package/dist/integrations/harnesses/shared.js +2 -0
- package/dist/integrations/harnesses/types.js +2 -0
- package/dist/llm/client.js +74 -14
- package/dist/output/cli-hints.js +1 -1
- package/dist/output/context.js +10 -19
- package/dist/output/format-exempt.js +5 -8
- package/dist/output/shapes/helpers.js +1 -22
- package/dist/output/shapes/passthrough.js +0 -1
- package/dist/output/shapes.js +3 -31
- package/dist/output/stdout.js +5 -1
- package/dist/output/text/command-format.js +6 -1
- package/dist/output/text/workflow-format.js +4 -22
- package/dist/scripts/akm-migrate-node.js +15746 -16706
- package/dist/scripts/akm-migrate.js +16319 -17275
- package/dist/setup/detect.js +10 -4
- package/dist/setup/harness-config-import.js +5 -14
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +12 -13
- package/dist/storage/repositories/task-history-repository.js +0 -5
- package/dist/storage/repositories/workflow-runs-repository.js +5 -15
- package/dist/tasks/embedded.js +2 -1
- package/dist/tasks/run/task-history.js +0 -2
- package/dist/tasks/schedule-gates.js +39 -0
- package/dist/tasks/scheduler-binding.js +0 -16
- package/dist/tasks/scheduler-sync.js +3 -97
- package/dist/tasks/source/bounded-document.js +1 -1
- package/dist/tasks/source/task-source-v4.js +2 -12
- package/dist/tasks/task-run-reserved-flags.js +2 -31
- package/dist/workflows/authoring/authoring.js +6 -6
- package/dist/workflows/compile.js +8 -65
- package/dist/workflows/exec/child-workflow.js +22 -3
- package/dist/workflows/exec/native-executor.js +12 -147
- package/dist/workflows/exec/run-workflow.js +31 -103
- package/dist/workflows/exec/step-work.js +9 -178
- package/dist/workflows/exec/unit-dispatch.js +0 -10
- package/dist/workflows/freeze/environment.js +3 -44
- package/dist/workflows/freeze/freeze.js +8 -41
- package/dist/workflows/freeze/targets/child-workflow.js +27 -63
- package/dist/workflows/freeze/targets/command.js +2 -16
- package/dist/workflows/freeze/targets/shell.js +0 -2
- package/dist/workflows/freeze/task-bindings.js +2 -28
- package/dist/workflows/ir/params.js +12 -2
- package/dist/workflows/parser.js +82 -232
- package/dist/workflows/plan.js +1 -1
- package/dist/workflows/renderer.js +10 -19
- package/dist/workflows/runtime/run-plan.js +11 -53
- package/dist/workflows/runtime/runs.js +4 -27
- package/dist/workflows/source-files.js +12 -16
- package/dist/workflows/source-semantics.js +1 -93
- package/docs/README.md +43 -42
- package/docs/agents/README.md +15 -0
- package/docs/agents/agent-install.md +14 -0
- package/docs/architecture/README.md +67 -0
- package/docs/architecture/adapters.md +258 -0
- package/docs/architecture/akm-architecture-decision-history.md +2055 -0
- package/docs/architecture/akm-core-principles.md +126 -0
- package/docs/architecture/architecture.md +578 -0
- package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +550 -0
- package/docs/architecture/decisions/0001-no-interpolation-attached-structured-context.md +72 -0
- package/docs/architecture/decisions/0002-unit-reuse-and-input-hash-scope.md +142 -0
- package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +189 -0
- package/docs/architecture/decisions/0004-task-input-contract-and-flag-coercion.md +97 -0
- package/docs/architecture/decisions/0005-task-result-vocabulary-and-legacy-read-mapping.md +108 -0
- package/docs/architecture/decisions/0006-task-source-version-routing.md +124 -0
- package/docs/architecture/decisions/0007-workflow-composition-bounds.md +83 -0
- package/docs/architecture/decisions/0008-task-binding-normalization.md +88 -0
- package/docs/architecture/decisions/0009-child-run-publication-column-parity.md +80 -0
- package/docs/architecture/decisions/0010-driver-protocol-cut.md +36 -0
- package/docs/architecture/decisions/0011-engine-run-loop-invariants.md +125 -0
- package/docs/architecture/decisions/README.md +62 -0
- package/docs/architecture/improvement.md +471 -0
- package/docs/architecture/internals/classification.md +154 -0
- package/docs/architecture/internals/fresh-host-rebuild-runbook.md +40 -0
- package/docs/architecture/internals/functional-contract-patterns.md +340 -0
- package/docs/architecture/internals/health-advisories.md +110 -0
- package/docs/architecture/internals/improve-workflow.md +720 -0
- package/docs/architecture/internals/indexing.md +498 -0
- package/docs/architecture/internals/registry-network-boundary.md +57 -0
- package/docs/architecture/internals/search.md +248 -0
- package/docs/architecture/internals/storage-locations.md +943 -0
- package/docs/architecture/persisted-data-compat.md +68 -0
- package/docs/architecture/reviews/env-secret-access.md +319 -0
- package/docs/architecture/runtime-boundary-design.md +153 -0
- package/docs/architecture/specs/0.9.0-close-out-plan.md +361 -0
- package/docs/architecture/specs/0.9.0-decisions.md +532 -0
- package/docs/architecture/specs/0.9.0-docs-code-drift-register.md +745 -0
- package/docs/architecture/specs/0.9.0-open-items-register.md +135 -0
- package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +740 -0
- package/docs/architecture/specs/0.9.0-release-surface-review.md +636 -0
- package/docs/architecture/specs/agent-command-engine-model-design.md +513 -0
- package/docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md +501 -0
- package/docs/architecture/specs/akm-0.9.0-ref-grammar-decision.md +291 -0
- package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +2059 -0
- package/docs/architecture/specs/di-seams-plan.md +539 -0
- package/docs/architecture/specs/driver-protocol-keep-or-cut.md +275 -0
- package/docs/architecture/specs/fact-asset-type.md +142 -0
- package/docs/architecture/specs/improve-collapse-churn-detector-design.md +634 -0
- package/docs/architecture/specs/okf-support.md +148 -0
- package/docs/architecture/specs/ref.md +329 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/README.md +72 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/findings-consolidated.md +152 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-alternatives.md +352 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-bunqueue.md +300 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-openworkflow.md +402 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-1.md +758 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-2.md +645 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-3.md +602 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-adversarial.md +27 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-architecture.md +27 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-coverage.md +74 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-security.md +15 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-adversarial.md +132 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-verification.md +147 -0
- package/docs/architecture/specs/stash-conventions-code-spec.md +275 -0
- package/docs/architecture/specs/stash-organization-conventions.md +377 -0
- package/docs/architecture/specs/task-workflow-format-unification.md +721 -0
- package/docs/architecture/specs/workflow-engine-buy-vs-build.md +231 -0
- package/docs/architecture/specs/workflow-format-unification.md +432 -0
- package/docs/architecture/testing/manual-testing-checklist.md +3411 -0
- package/docs/architecture/testing/okf-v0.2-conformance-runbook.md +924 -0
- package/docs/architecture/testing/task-workflow-manual-tests.md +1720 -0
- package/docs/architecture/testing/testing-workflow.md +446 -0
- package/docs/architecture/workflow-engine.md +223 -0
- package/docs/guides/README.md +33 -0
- package/docs/guides/author-bundles.md +310 -0
- package/docs/guides/author-workflows.md +490 -0
- package/docs/guides/bundles.md +321 -0
- package/docs/guides/capture-knowledge.md +136 -0
- package/docs/guides/claude-code-vs-akm-workflows.md +29 -0
- package/docs/guides/concepts.md +93 -0
- package/docs/guides/discover-and-load.md +158 -0
- package/docs/guides/getting-started.md +240 -0
- package/docs/guides/improve-the-library.md +246 -0
- package/docs/guides/knowledge-management.md +18 -0
- package/docs/guides/recipes/headless-install.md +97 -0
- package/docs/guides/recipes/website-source.md +28 -0
- package/docs/guides/run-workflows.md +279 -0
- package/docs/guides/scheduling.md +123 -0
- package/docs/guides/use-with-any-agent.md +174 -0
- package/docs/guides/wikis.md +81 -0
- package/docs/integration/bundling-akm.md +7 -6
- package/docs/maintainers/README.md +19 -0
- package/docs/maintainers/curate-workmap.md +335 -0
- package/docs/maintainers/eval.md +3 -0
- package/docs/maintainers/local-development.md +108 -0
- package/docs/maintainers/release-checklist.md +132 -0
- package/docs/migration/README.md +2 -2
- package/docs/migration/release-notes/0.0.13.md +1 -1
- package/docs/migration/release-notes/0.1.0.md +1 -1
- package/docs/migration/release-notes/0.2.0.md +1 -1
- package/docs/migration/release-notes/0.3.0.md +1 -1
- package/docs/migration/release-notes/0.5.0.md +1 -1
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.7.3.md +2 -2
- package/docs/migration/release-notes/0.7.4.md +1 -1
- package/docs/migration/release-notes/0.7.5.md +1 -1
- package/docs/migration/release-notes/0.8.0.md +1 -1
- package/docs/migration/release-notes/0.9.0.md +1 -1
- package/docs/migration/release-notes/0.9.14.md +1 -1
- package/docs/migration/release-notes/0.9.15.md +1 -1
- package/docs/migration/release-notes/0.9.16.md +1 -1
- package/docs/migration/release-notes/0.9.17.md +1 -1
- package/docs/migration/release-notes/0.9.19.md +1 -1
- package/docs/migration/release-notes/0.9.2.md +1 -1
- package/docs/migration/release-notes/README.md +27 -31
- package/docs/migration/v0.5-to-v0.6.md +759 -0
- package/docs/migration/v0.8-to-v0.9.md +1 -1
- package/docs/plans/0.9.2-agent-command-workflow-plan.md +423 -0
- package/docs/posts/README.md +30 -0
- package/docs/posts/akm-command-tour.md +495 -0
- package/docs/posts/akm-logo-sized.webp +0 -0
- package/docs/posts/belief-aware-memory-12.md +139 -0
- package/docs/posts/config-v2-lessons-16.md +191 -0
- package/docs/posts/improve-loop-autonomous-10.md +225 -0
- package/docs/posts/improve-pipeline-debugging-0803.md +179 -0
- package/docs/posts/intro-part-01.md +76 -0
- package/docs/posts/intro-part-02.md +221 -0
- package/docs/posts/intro-part-03.md +190 -0
- package/docs/posts/intro-part-04.md +221 -0
- package/docs/posts/llm-mode-reflect-13.md +166 -0
- package/docs/posts/openpalm-built-on-akm.md +86 -0
- package/docs/posts/progressive-disclosure-06.md +129 -0
- package/docs/posts/proposal-safety-net-15.md +112 -0
- package/docs/posts/release-0.5.0.md +247 -0
- package/docs/posts/release-0.6.0.md +117 -0
- package/docs/posts/release-0.7.0.md +159 -0
- package/docs/posts/release-0.8.0.md +332 -0
- package/docs/posts/scattered-skills-05.md +100 -0
- package/docs/posts/task-assets-persistent-workflows-11.md +222 -0
- package/docs/posts/team-skills-07.md +198 -0
- package/docs/posts/wiki-agent-knowledge-08.md +223 -0
- package/docs/posts/workflows-vaults-09.md +321 -0
- package/docs/product-surface.md +54 -0
- package/docs/reference/README.md +2 -2
- package/docs/reference/api.md +65 -0
- package/docs/reference/asset-types.md +166 -0
- package/docs/reference/bundle-types.md +2 -4
- package/docs/reference/cli.md +129 -175
- package/docs/reference/configuration.md +84 -19
- package/docs/reference/data-and-telemetry.md +1 -1
- package/docs/reference/env-and-secrets.md +126 -0
- package/docs/reference/memory.md +124 -0
- package/docs/reference/refs.md +156 -0
- package/docs/reference/registry.md +489 -0
- package/docs/reference/supported-formats.md +3 -4
- package/docs/reference/tasks.md +12 -19
- package/docs/reference/website-sources.md +141 -0
- package/docs/reference/workflow-schema.md +89 -317
- package/docs/reference/workflows.md +20 -48
- package/package.json +23 -16
- package/schemas/akm-config.json +2 -243
- package/schemas/akm-task.json +2 -3
- package/schemas/akm-workflow.json +47 -84
- package/dist/assets/improve-strategies/catchup.json +0 -41
- package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
- package/dist/assets/improve-strategies/quick.json +0 -17
- package/dist/assets/improve-strategies/reflect-distill.json +0 -29
- package/dist/assets/improve-strategies/thorough.json +0 -49
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
- package/dist/cli/retired-commands.js +0 -118
- package/dist/commands/tasks/validate.js +0 -176
- package/dist/core/config/legacy-source-shape-shim.js +0 -117
- package/dist/integrations/harnesses/ids.js +0 -28
- package/dist/tasks/source/task-source-v3-frozen.js +0 -424
- package/dist/tasks/source/task-to-v4.js +0 -863
- package/dist/workflows/exec/worktree.js +0 -372
- package/dist/workflows/freeze/child-output-references.js +0 -83
- package/dist/workflows/freeze/identity.js +0 -22
- package/dist/workflows/freeze/targets/script.js +0 -50
- package/dist/workflows/freeze/targets/task.js +0 -124
- package/dist/workflows/github-yaml.js +0 -506
- package/dist/workflows/runtime/run-outputs.js +0 -80
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* Candidate selection reads the improve ledger plus one set of signals: a ref
|
|
10
10
|
* is eligible for a source when feedback newer than its last attempt landed and
|
|
11
11
|
* no ledger window holds it, and reflect reads only negative feedback. Refs
|
|
12
|
-
* without recent feedback can still be picked by the
|
|
13
|
-
*
|
|
12
|
+
* without recent feedback can still be picked by the proactive-maintenance
|
|
13
|
+
* lane, which plans them with the rest; the survivors are ranked
|
|
14
14
|
* by salience, checked on disk and capped. A plan-only run evaluates the same
|
|
15
15
|
* selectors against read snapshots and writes nothing.
|
|
16
16
|
*/
|
|
@@ -35,7 +35,7 @@ import { isAutonomyLaneAllowed } from "./autonomy-gate.js";
|
|
|
35
35
|
import { akmConsolidate, inspectConsolidationPool, loadExistingKnowledgeBodyHashes, makeConsolidateResult, } from "./consolidate.js";
|
|
36
36
|
import { computeSafeChunkSize, DEFAULT_CONTEXT_LENGTH_TOKENS } from "./consolidate/chunking.js";
|
|
37
37
|
import { contentHash } from "./content-hash.js";
|
|
38
|
-
import { assetTypeOf, buildUtilityMap, dedupeRefs, findAssetFilePath, isDistillCandidateRef, isLessonCandidate,
|
|
38
|
+
import { assetTypeOf, buildUtilityMap, dedupeRefs, findAssetFilePath, isDistillCandidateRef, isLessonCandidate, withIndexDb, } from "./eligibility.js";
|
|
39
39
|
import { akmExtract, countNewExtractCandidates } from "./extract.js";
|
|
40
40
|
import { computeValenceScore } from "./feedback-valence.js";
|
|
41
41
|
import { isLedgerBlocked, lastAttemptByRef, ledgerRowFor, loadLedgerSnapshot, stateKey, } from "./ledger.js";
|
|
@@ -81,7 +81,7 @@ export function pickDefined(source, keys) {
|
|
|
81
81
|
out[key] = source[key];
|
|
82
82
|
return out;
|
|
83
83
|
}
|
|
84
|
-
export const CONSOLIDATION_CONFIG_KEYS = ["enabled", "
|
|
84
|
+
export const CONSOLIDATION_CONFIG_KEYS = ["enabled", "limit", "maxChunkSize"];
|
|
85
85
|
/** Emit an aggregate `improve_skipped` row (never one per ref). */
|
|
86
86
|
export function recordImproveSkip(eventsCtx, ref, metadata) {
|
|
87
87
|
appendEvent({ eventType: "improve_skipped", ref, metadata }, eventsCtx);
|
|
@@ -96,19 +96,13 @@ export function pushRecentError(recentErrors, originator, msg) {
|
|
|
96
96
|
}
|
|
97
97
|
// ── Consolidation ────────────────────────────────────────────────────────────
|
|
98
98
|
/**
|
|
99
|
-
* The consolidation gates and pool, with no model call: the profile toggle
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* judged recently and unchanged since means nothing to do).
|
|
99
|
+
* The consolidation gates and pool, with no model call: the profile toggle
|
|
100
|
+
* and the ledger delta (every memory judged recently and unchanged since
|
|
101
|
+
* means nothing to do).
|
|
103
102
|
*/
|
|
104
103
|
function planConsolidationPass(args) {
|
|
105
|
-
const { options, primaryStashDir,
|
|
104
|
+
const { options, primaryStashDir, resolvedPlan } = args;
|
|
106
105
|
const processConfig = args.improveProfile?.processes?.consolidate;
|
|
107
|
-
const volumeTriggered = memorySummary.eligible > 100 && resolvedPlan.processes.consolidate.runner !== null;
|
|
108
|
-
const minPoolSize = typeof processConfig?.minPoolSize === "number" ? processConfig.minPoolSize : 0;
|
|
109
|
-
const eligiblePoolSize = typeof memorySummary.eligible === "number" ? memorySummary.eligible : 0;
|
|
110
|
-
const userNamed = options.strategy !== undefined || resolveImproveScope(options.scope).mode === "ref";
|
|
111
|
-
const poolBelowMinSize = !volumeTriggered && !userNamed && minPoolSize > 0 && eligiblePoolSize < minPoolSize;
|
|
112
106
|
const pool = primaryStashDir
|
|
113
107
|
? inspectConsolidationPool({
|
|
114
108
|
config: options.config,
|
|
@@ -127,18 +121,13 @@ function planConsolidationPass(args) {
|
|
|
127
121
|
DEFAULT_CONTEXT_LENGTH_TOKENS, 500, processConfig?.maxChunkSize);
|
|
128
122
|
const profilePassed = processConfig?.enabled !== false;
|
|
129
123
|
const deltaPassed = pool.candidatePoolSize > 0 || pool.judgedUnchanged === 0;
|
|
130
|
-
const wouldRun = profilePassed &&
|
|
131
|
-
const belowMin = `pool ${eligiblePoolSize} is below minPoolSize ${minPoolSize}`;
|
|
124
|
+
const wouldRun = profilePassed && deltaPassed && pool.candidatePoolSize > 0;
|
|
132
125
|
const unchanged = "every memory was judged recently and is unchanged since";
|
|
133
126
|
return {
|
|
134
|
-
poolBelowMinSize,
|
|
135
|
-
eligiblePoolSize,
|
|
136
|
-
minPoolSize,
|
|
137
127
|
plan: {
|
|
138
128
|
configured: pickDefined(processConfig, CONSOLIDATION_CONFIG_KEYS),
|
|
139
129
|
effective: {
|
|
140
130
|
enabled: profilePassed,
|
|
141
|
-
minPoolSize,
|
|
142
131
|
...(processConfig?.limit !== undefined ? { limit: processConfig.limit } : {}),
|
|
143
132
|
chunkSize,
|
|
144
133
|
},
|
|
@@ -149,10 +138,6 @@ function planConsolidationPass(args) {
|
|
|
149
138
|
passed: profilePassed,
|
|
150
139
|
reason: profilePassed ? "consolidation enabled" : "disabled by improve profile",
|
|
151
140
|
},
|
|
152
|
-
minimumPool: {
|
|
153
|
-
passed: !poolBelowMinSize,
|
|
154
|
-
reason: poolBelowMinSize ? belowMin : `pool satisfies minPoolSize ${minPoolSize}`,
|
|
155
|
-
},
|
|
156
141
|
delta: {
|
|
157
142
|
passed: deltaPassed,
|
|
158
143
|
reason: !deltaPassed
|
|
@@ -165,13 +150,11 @@ function planConsolidationPass(args) {
|
|
|
165
150
|
wouldRun,
|
|
166
151
|
reason: !profilePassed
|
|
167
152
|
? "disabled by improve profile"
|
|
168
|
-
:
|
|
169
|
-
?
|
|
170
|
-
:
|
|
171
|
-
?
|
|
172
|
-
:
|
|
173
|
-
? "candidate pool is empty after narrowing"
|
|
174
|
-
: "all consolidation gates pass",
|
|
153
|
+
: !deltaPassed
|
|
154
|
+
? unchanged
|
|
155
|
+
: pool.candidatePoolSize === 0
|
|
156
|
+
? "candidate pool is empty after narrowing"
|
|
157
|
+
: "all consolidation gates pass",
|
|
175
158
|
estimatedChunks: wouldRun ? Math.ceil(pool.candidatePoolSize / chunkSize) : 0,
|
|
176
159
|
},
|
|
177
160
|
};
|
|
@@ -186,14 +169,6 @@ async function runConsolidationPass(args) {
|
|
|
186
169
|
if (!planned.plan.gates.profile.passed) {
|
|
187
170
|
info("[improve] consolidation skipped (disabled by improve profile)");
|
|
188
171
|
}
|
|
189
|
-
else if (planned.poolBelowMinSize) {
|
|
190
|
-
recordImproveSkip(eventsCtx, "memories/_consolidation", {
|
|
191
|
-
reason: "pool_below_min_size",
|
|
192
|
-
poolSize: planned.eligiblePoolSize,
|
|
193
|
-
minPoolSize: planned.minPoolSize,
|
|
194
|
-
});
|
|
195
|
-
info(`[improve] consolidation skipped (pool ${planned.eligiblePoolSize} < minPoolSize ${planned.minPoolSize})`);
|
|
196
|
-
}
|
|
197
172
|
else if (!planned.plan.gates.delta.passed) {
|
|
198
173
|
recordImproveSkip(eventsCtx, "memories/_consolidation", { reason: "consolidation_no_memory_updates" });
|
|
199
174
|
info("[improve] consolidation skipped (every memory was judged recently and is unchanged)");
|
|
@@ -212,7 +187,6 @@ async function runConsolidationPass(args) {
|
|
|
212
187
|
limit: processConfig?.limit,
|
|
213
188
|
maxChunkSize: processConfig?.maxChunkSize,
|
|
214
189
|
signal: args.budgetSignal,
|
|
215
|
-
p90ChunkSecondsDefault: processConfig?.p90ChunkSecondsDefault,
|
|
216
190
|
// Its read-only proposal lookups go through the run's own state.db handle.
|
|
217
191
|
...(eventsCtx?.db ? { proposalsCtx: { db: eventsCtx.db } } : {}),
|
|
218
192
|
}));
|
|
@@ -671,7 +645,7 @@ export function buildSnapshotManifest(args) {
|
|
|
671
645
|
* - distillOnlyRefs: only distill's passes (any signal, a positive or a note
|
|
672
646
|
* included), on a distill candidate;
|
|
673
647
|
* - noFeedbackPool: no recent feedback and no reflect window, left to the
|
|
674
|
-
*
|
|
648
|
+
* proactive-maintenance lane;
|
|
675
649
|
* - fullySkippedCount: feedback on record but nothing new, or a live window.
|
|
676
650
|
* An explicit `--scope <ref>` bypasses every gate.
|
|
677
651
|
*/
|
|
@@ -722,12 +696,12 @@ export function partitionBySignalDelta(args) {
|
|
|
722
696
|
return out;
|
|
723
697
|
}
|
|
724
698
|
/**
|
|
725
|
-
* Pick the loop's refs: signal delta, the
|
|
726
|
-
* `--require-feedback-signal
|
|
727
|
-
*
|
|
699
|
+
* Pick the loop's refs: signal delta, the proactive-maintenance lane (unless
|
|
700
|
+
* `--require-feedback-signal`), lane attribution, salience, the no-op-dampened
|
|
701
|
+
* ranking, the disk check and the limit.
|
|
728
702
|
*/
|
|
729
703
|
async function selectLoopCandidates(args, postCleanupRefs, validationFailureRefs, actions, persist) {
|
|
730
|
-
const { scope, options, primaryStashDir, eventsCtx
|
|
704
|
+
const { scope, options, primaryStashDir, eventsCtx } = args;
|
|
731
705
|
const snapshot = buildSnapshotManifest({
|
|
732
706
|
postCleanupRefs,
|
|
733
707
|
validationFailureRefs,
|
|
@@ -739,9 +713,8 @@ async function selectLoopCandidates(args, postCleanupRefs, validationFailureRefs
|
|
|
739
713
|
const processableRefs = [...partition.eligibleRefs, ...partition.distillOnlyRefs];
|
|
740
714
|
const signalFiltered = processableRefs.filter((c) => snapshot.feedback.get(c.ref)?.hasSignal === true);
|
|
741
715
|
const signalBearingSet = new Set(signalFiltered.map((r) => r.ref));
|
|
742
|
-
// The
|
|
743
|
-
//
|
|
744
|
-
// never processed (#986). Evaluated once per candidate.
|
|
716
|
+
// The proactive lane has no usage evidence of its own: it picks only what
|
|
717
|
+
// retrieval returned or new material improve never processed (#986). Evaluated once per candidate.
|
|
745
718
|
const fallbackEligible = postCleanupRefs.filter((c) => !validationFailureRefs.has(c.ref));
|
|
746
719
|
const allowFallbacks = options.requireFeedbackSignal !== true;
|
|
747
720
|
const retrievalScope = scope.mode === "ref" || !allowFallbacks
|
|
@@ -753,22 +726,20 @@ async function selectLoopCandidates(args, postCleanupRefs, validationFailureRefs
|
|
|
753
726
|
...partition.noFeedbackPool,
|
|
754
727
|
]);
|
|
755
728
|
const noFeedbackCandidates = noFeedbackPool.filter((r) => !unscoped.has(r.ref));
|
|
756
|
-
// Only a ref
|
|
729
|
+
// Only a ref the proactive lane may not pick is charged to the retrieval gate.
|
|
757
730
|
const outOfScope = new Set(noFeedbackPool.filter((r) => unscoped.has(r.ref)).map((r) => r.ref));
|
|
758
731
|
const retrieval = fetchRetrievalSignals(options, signalFiltered, noFeedbackCandidates, eventsCtx, persist);
|
|
759
732
|
const proactive = allowFallbacks
|
|
760
733
|
? selectProactiveMaintenanceLane(args, noFeedbackCandidates, snapshot, retrieval, persist)
|
|
761
734
|
: { proactiveRefs: [] };
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
//
|
|
766
|
-
//
|
|
767
|
-
const signalAndRetrievalRefs = dedupeRefs([...signalFiltered, ...proactive.proactiveRefs, ...highSalienceRefs]);
|
|
768
|
-
const mergedRefs = scope.mode === "ref" ? processableRefs : signalFiltered;
|
|
769
|
-
const scoredRefs = scope.mode === "ref" ? processableRefs : signalAndRetrievalRefs;
|
|
770
|
-
// Lane attribution: signal-delta, and an explicit ref scope over it.
|
|
735
|
+
// Planned: signal-delta refs plus the proactive lane's picks (whole-stash / type scope); an explicit ref scope
|
|
736
|
+
// acts on its own refs.
|
|
737
|
+
const mergedRefs = scope.mode === "ref" ? processableRefs : dedupeRefs([...signalFiltered, ...proactive.proactiveRefs]);
|
|
738
|
+
// Lane attribution, weakest first so the strongest wins: proactive < signal-delta, and an explicit ref scope
|
|
739
|
+
// over everything.
|
|
771
740
|
const sourceByRef = new Map();
|
|
741
|
+
for (const r of proactive.proactiveRefs)
|
|
742
|
+
sourceByRef.set(r.ref, "proactive");
|
|
772
743
|
for (const r of signalFiltered)
|
|
773
744
|
sourceByRef.set(r.ref, "signal-delta");
|
|
774
745
|
if (scope.mode === "ref")
|
|
@@ -776,7 +747,7 @@ async function selectLoopCandidates(args, postCleanupRefs, validationFailureRefs
|
|
|
776
747
|
sourceByRef.set(r.ref, "scope");
|
|
777
748
|
for (const r of mergedRefs)
|
|
778
749
|
r.eligibilitySource = sourceByRef.get(r.ref) ?? "unknown";
|
|
779
|
-
const salienceMap = scoreSalience(args,
|
|
750
|
+
const salienceMap = scoreSalience(args, mergedRefs, snapshot.feedback, retrieval.retrievalCounts, persist);
|
|
780
751
|
// Rank by salience; a ref skipped as a no-op repeatedly sorts lower (its stored rank is untouched).
|
|
781
752
|
const noOps = new Map();
|
|
782
753
|
withRunState(eventsCtx, persist, (db) => {
|
|
@@ -795,8 +766,8 @@ async function selectLoopCandidates(args, postCleanupRefs, validationFailureRefs
|
|
|
795
766
|
distillOnlyRefs: partition.distillOnlyRefs,
|
|
796
767
|
limit: options.limit,
|
|
797
768
|
});
|
|
798
|
-
if (
|
|
799
|
-
info(`[improve] ${
|
|
769
|
+
if (mergedRefs.length > 0) {
|
|
770
|
+
info(`[improve] ${mergedRefs.length} refs with usage signals (${signalFiltered.length} feedback)`);
|
|
800
771
|
}
|
|
801
772
|
if (validationFailureRefs.size > 0)
|
|
802
773
|
info(`[improve] ${validationFailureRefs.size} with validation failures excluded`);
|
|
@@ -883,11 +854,11 @@ function fetchRetrievalSignals(options, signalFiltered, noFeedbackCandidates, ev
|
|
|
883
854
|
return out;
|
|
884
855
|
}
|
|
885
856
|
/**
|
|
886
|
-
* Proactive maintenance (default
|
|
887
|
-
* assets due for a revisit
|
|
888
|
-
*
|
|
889
|
-
*
|
|
890
|
-
*
|
|
857
|
+
* Proactive maintenance (default on, whole-stash/type runs): pick stable
|
|
858
|
+
* assets due for a revisit and plan them with the feedback-bearing refs. The
|
|
859
|
+
* cap against a proposal flood: `maxPerRun` limits the picks per run, the due
|
|
860
|
+
* gate admits only an asset not reflected or distilled for `dueDays` (so each
|
|
861
|
+
* comes up at most once per `dueDays`), and reflect's `limit` bounds the run.
|
|
891
862
|
*/
|
|
892
863
|
function selectProactiveMaintenanceLane(args, candidates, snapshot, retrieval, persist) {
|
|
893
864
|
if (args.scope.mode === "ref" || !args.resolvedPlan.processes.proactiveMaintenance.enabled) {
|
|
@@ -895,7 +866,7 @@ function selectProactiveMaintenanceLane(args, candidates, snapshot, retrieval, p
|
|
|
895
866
|
}
|
|
896
867
|
const pmCfg = args.improveProfile.processes?.proactiveMaintenance;
|
|
897
868
|
const dueDays = pmCfg?.dueDays ?? DEFAULT_DUE_DAYS;
|
|
898
|
-
const maxPerRun = pmCfg?.maxPerRun ??
|
|
869
|
+
const maxPerRun = pmCfg?.maxPerRun ?? DEFAULT_MAX_PER_RUN;
|
|
899
870
|
const selection = selectProactiveMaintenanceRefs({
|
|
900
871
|
candidates,
|
|
901
872
|
lastReflectTs: snapshot.lastReflectAttemptAt,
|
|
@@ -927,7 +898,7 @@ function selectProactiveMaintenanceLane(args, candidates, snapshot, retrieval, p
|
|
|
927
898
|
proactiveRefs: selection.selected,
|
|
928
899
|
proactiveMaintenanceSummary: { ...summary, selectedRefs },
|
|
929
900
|
proactivePlan: {
|
|
930
|
-
configured: pickDefined(pmCfg, ["dueDays", "maxPerRun"
|
|
901
|
+
configured: pickDefined(pmCfg, ["dueDays", "maxPerRun"]),
|
|
931
902
|
effective: { dueDays, maxPerRun },
|
|
932
903
|
candidatePool: candidates.length,
|
|
933
904
|
...summary,
|
|
@@ -935,41 +906,13 @@ function selectProactiveMaintenanceLane(args, candidates, snapshot, retrieval, p
|
|
|
935
906
|
},
|
|
936
907
|
};
|
|
937
908
|
}
|
|
938
|
-
/**
|
|
939
|
-
* High salience: zero-feedback refs whose content-derived encoding score (not
|
|
940
|
-
* a per-type stub) reaches `salienceThreshold` and that were never reflected,
|
|
941
|
-
* top-N by score, capped at 10% of the effective limit. The picks are scored,
|
|
942
|
-
* never planned.
|
|
943
|
-
*/
|
|
944
|
-
function selectHighSalienceLane(options, improveProfile, eventsCtx, candidates, lastReflectAttemptAt, persist) {
|
|
945
|
-
const threshold = (options.config ?? loadConfig()).improve?.salience?.salienceThreshold ?? 0.75;
|
|
946
|
-
const effectiveLimit = options.limit ?? improveProfile?.processes?.reflect?.limit ?? improveProfile.limit ?? 10;
|
|
947
|
-
const selected = withRunState(eventsCtx, persist, (db) => candidates
|
|
948
|
-
.flatMap((r) => {
|
|
949
|
-
const row = getAssetSalience(db, keyOf(r));
|
|
950
|
-
return row &&
|
|
951
|
-
isContentEncodingRow(row) &&
|
|
952
|
-
row.encoding_salience >= threshold &&
|
|
953
|
-
!lastReflectAttemptAt.has(r.ref)
|
|
954
|
-
? [{ ref: r, score: row.encoding_salience }]
|
|
955
|
-
: [];
|
|
956
|
-
})
|
|
957
|
-
.sort((a, b) => b.score - a.score)
|
|
958
|
-
.slice(0, Math.max(1, Math.floor(effectiveLimit * 0.1)))
|
|
959
|
-
.map((q) => q.ref)) ?? [];
|
|
960
|
-
if (selected.length > 0) {
|
|
961
|
-
info(`[improve] high-salience lane admitted ${selected.length} content-scored ref(s) ` +
|
|
962
|
-
`(threshold=${threshold}, requires content-derived encoding_source)`);
|
|
963
|
-
}
|
|
964
|
-
return selected;
|
|
965
|
-
}
|
|
966
909
|
/**
|
|
967
910
|
* Score the merged refs: update `asset_outcome` (projected on a plan-only
|
|
968
911
|
* run), compute each salience vector (keeping a stored content-derived
|
|
969
912
|
* encoding score), then persist it.
|
|
970
913
|
*/
|
|
971
914
|
function scoreSalience(args, mergedRefs, feedback, retrievalCounts, persist) {
|
|
972
|
-
const {
|
|
915
|
+
const { eventsCtx } = args;
|
|
973
916
|
const utilityMap = buildUtilityMap(mergedRefs, !persist);
|
|
974
917
|
const lastUseMsByRef = withIndexDb(!persist, (db) => getLastUseMsByRef(db, mergedRefs)) ?? new Map();
|
|
975
918
|
const outcomeSalience = updateOutcomeScores({
|
|
@@ -982,7 +925,6 @@ function scoreSalience(args, mergedRefs, feedback, retrievalCounts, persist) {
|
|
|
982
925
|
eventsCtx,
|
|
983
926
|
persist,
|
|
984
927
|
});
|
|
985
|
-
const outcomeWeightEnabled = (options.config ?? loadConfig()).improve?.salience?.outcomeWeightEnabled !== false;
|
|
986
928
|
const storedEncoding = new Map();
|
|
987
929
|
withRunState(eventsCtx, persist, (db) => {
|
|
988
930
|
for (const r of mergedRefs) {
|
|
@@ -1005,7 +947,6 @@ function scoreSalience(args, mergedRefs, feedback, retrievalCounts, persist) {
|
|
|
1005
947
|
outcomeSalience: outcomeSalience.get(r.ref),
|
|
1006
948
|
sizeBytes: fileSize(r.filePath),
|
|
1007
949
|
now,
|
|
1008
|
-
outcomeWeightEnabled,
|
|
1009
950
|
}));
|
|
1010
951
|
}
|
|
1011
952
|
if (persist) {
|
|
@@ -6,8 +6,8 @@ import { computeSalience } from "./salience.js";
|
|
|
6
6
|
const DAY_MS = 86_400_000;
|
|
7
7
|
/** An asset is due when last reflected/distilled more than this many days ago (or never). */
|
|
8
8
|
export const DEFAULT_DUE_DAYS = 30;
|
|
9
|
-
/**
|
|
10
|
-
export const DEFAULT_MAX_PER_RUN =
|
|
9
|
+
/** Fallback for `maxPerRun`; the same as the shipped `default` strategy. */
|
|
10
|
+
export const DEFAULT_MAX_PER_RUN = 15;
|
|
11
11
|
/** Size floor for the cost term, so tiny files don't divide by ~0. */
|
|
12
12
|
const SIZE_FLOOR_BYTES = 200;
|
|
13
13
|
/**
|
|
@@ -19,8 +19,7 @@ import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
|
19
19
|
/**
|
|
20
20
|
* `noop` (identical up to trailing whitespace) and `cosmetic` (identical after
|
|
21
21
|
* normalizing frontmatter as parsed YAML and prose as unwrapped text) never
|
|
22
|
-
* become proposals.
|
|
23
|
-
* words, nothing structural; the caller decides (off by default).
|
|
22
|
+
* become proposals.
|
|
24
23
|
*/
|
|
25
24
|
export function classifyReflectChange(sourceContent, candidateContent) {
|
|
26
25
|
if (normalizeTrailingWhitespace(sourceContent) === normalizeTrailingWhitespace(candidateContent))
|
|
@@ -32,13 +31,6 @@ export function classifyReflectChange(sourceContent, candidateContent) {
|
|
|
32
31
|
catch {
|
|
33
32
|
// unprovable → substantive
|
|
34
33
|
}
|
|
35
|
-
try {
|
|
36
|
-
if (isLowValueChange(sourceContent, candidateContent))
|
|
37
|
-
return "low-value";
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
// unprovable → substantive
|
|
41
|
-
}
|
|
42
34
|
return "substantive";
|
|
43
35
|
}
|
|
44
36
|
/** Not TODO, TBD or FIXME: an asset may carry those on purpose, and the owner does not want them refused. */
|
|
@@ -136,7 +128,7 @@ function frontmatterCopiedIntoBody(source, candidate, keys) {
|
|
|
136
128
|
if (keys.length === 0)
|
|
137
129
|
return false;
|
|
138
130
|
const keyLine = new RegExp(`^(?:${keys.map(escapeRegExp).join("|")}):(?:[ \\t].*)?$`);
|
|
139
|
-
const keyLines = (text) =>
|
|
131
|
+
const keyLines = (text) => parseSections(text).proseLines.filter((line) => keyLine.test(line)).length;
|
|
140
132
|
if (keyLines(candidate) > keyLines(source))
|
|
141
133
|
return true;
|
|
142
134
|
const sourceBody = lettersAndDigits(splitFrontmatter(source).body);
|
|
@@ -166,44 +158,8 @@ export function splitFrontmatter(raw) {
|
|
|
166
158
|
const m = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
167
159
|
return m ? { fmText: m[1] ?? "", body: m[2] ?? "" } : { fmText: null, body: raw };
|
|
168
160
|
}
|
|
169
|
-
/** At most this many changed words (and at least 2 — one word may be a flag flip) is low-value. */
|
|
170
|
-
const LOW_VALUE_TOKEN_THRESHOLD = 4;
|
|
171
|
-
/** A change to any of these is never low-value. */
|
|
172
|
-
const NEGATION_WORDS = new Set(["never", "not", "no", "don't", "avoid", "cannot", "can't"]);
|
|
173
|
-
/** Lines recording a decision or outcome are always significant; their words are not counted. */
|
|
174
|
-
const DECISION_MARKER_RE = /\b(decision|outcome)\b/i;
|
|
175
|
-
const STRUCTURAL_LINE_RE = /^\s*(#{1,6}\s|[-*+]\s|\d{1,9}[.)]\s|---+|===+|\|\s)/;
|
|
176
|
-
function isLowValueChange(source, candidate) {
|
|
177
|
-
const src = parseLowValueSections(source);
|
|
178
|
-
const cnd = parseLowValueSections(candidate);
|
|
179
|
-
// Code and frontmatter changes are always substantive.
|
|
180
|
-
if (src.codeFences.join("\n") !== cnd.codeFences.join("\n") || src.frontmatter !== cnd.frontmatter)
|
|
181
|
-
return false;
|
|
182
|
-
if (Math.abs(src.proseLines.length - cnd.proseLines.length) > 2)
|
|
183
|
-
return false;
|
|
184
|
-
let changedTokens = 0;
|
|
185
|
-
for (let i = 0; i < Math.max(src.proseLines.length, cnd.proseLines.length); i++) {
|
|
186
|
-
const srcLine = src.proseLines[i] ?? "";
|
|
187
|
-
const cndLine = cnd.proseLines[i] ?? "";
|
|
188
|
-
if (srcLine === cndLine || DECISION_MARKER_RE.test(srcLine) || DECISION_MARKER_RE.test(cndLine))
|
|
189
|
-
continue;
|
|
190
|
-
if (STRUCTURAL_LINE_RE.test(cndLine) || STRUCTURAL_LINE_RE.test(srcLine))
|
|
191
|
-
return false;
|
|
192
|
-
const srcTokens = tokenize(srcLine);
|
|
193
|
-
const cndTokens = tokenize(cndLine);
|
|
194
|
-
const srcNeg = new Set(srcTokens.filter((t) => NEGATION_WORDS.has(t)));
|
|
195
|
-
const cndNeg = new Set(cndTokens.filter((t) => NEGATION_WORDS.has(t)));
|
|
196
|
-
if (srcNeg.size !== cndNeg.size || [...srcNeg].some((t) => !cndNeg.has(t)))
|
|
197
|
-
return false;
|
|
198
|
-
// max(added, removed) approximates substitutions: "is→runs" counts once.
|
|
199
|
-
const srcSet = new Set(srcTokens);
|
|
200
|
-
const cndSet = new Set(cndTokens);
|
|
201
|
-
changedTokens += Math.max(cndTokens.filter((t) => !srcSet.has(t)).length, srcTokens.filter((t) => !cndSet.has(t)).length);
|
|
202
|
-
}
|
|
203
|
-
return changedTokens >= 2 && changedTokens < LOW_VALUE_TOKEN_THRESHOLD;
|
|
204
|
-
}
|
|
205
161
|
/** Frontmatter text, fenced code blocks, and prose lines (an unclosed fence counts as prose). */
|
|
206
|
-
function
|
|
162
|
+
function parseSections(text) {
|
|
207
163
|
const { fmText, body } = splitFrontmatter(normalizeTrailingWhitespace(text));
|
|
208
164
|
const codeFences = [];
|
|
209
165
|
const proseLines = [];
|
|
@@ -230,14 +186,6 @@ function parseLowValueSections(text) {
|
|
|
230
186
|
proseLines.push(...fence.lines);
|
|
231
187
|
return { frontmatter: fmText ?? "", codeFences, proseLines };
|
|
232
188
|
}
|
|
233
|
-
function tokenize(line) {
|
|
234
|
-
return line
|
|
235
|
-
.toLowerCase()
|
|
236
|
-
.replace(/’/g, "'") // curly apostrophes still match "don't"
|
|
237
|
-
.replace(/[^a-z0-9'-]/g, " ")
|
|
238
|
-
.split(/\s+/)
|
|
239
|
-
.filter((t) => t.length > 0);
|
|
240
|
-
}
|
|
241
189
|
/** CRLF → LF, no trailing spaces per line, no trailing newlines. */
|
|
242
190
|
export function normalizeTrailingWhitespace(text) {
|
|
243
191
|
return text
|
|
@@ -782,10 +782,9 @@ async function runReflectRefineIterations(args) {
|
|
|
782
782
|
const NOISE_SUBREASONS = {
|
|
783
783
|
noop: "reflect_skipped_noop",
|
|
784
784
|
cosmetic: "reflect_skipped_cosmetic",
|
|
785
|
-
"low-value": "reflect_skipped_low_value",
|
|
786
785
|
};
|
|
787
786
|
/**
|
|
788
|
-
* Apply the patch, drop a no-op/cosmetic
|
|
787
|
+
* Apply the patch, drop a no-op/cosmetic change,
|
|
789
788
|
* judge the exact content that would be persisted, then mint. A revision with a
|
|
790
789
|
* deterministic defect is refused before the judge runs, whether or not the
|
|
791
790
|
* gate is on.
|
|
@@ -798,15 +797,11 @@ async function finalizeReflectProposal(args) {
|
|
|
798
797
|
// A patch that changes nothing leaves the asset as it is: an empty diff.
|
|
799
798
|
const content = patched?.content ?? assetContent;
|
|
800
799
|
const changeKind = classifyReflectChange(assetContent, content);
|
|
801
|
-
if (changeKind === "noop" ||
|
|
802
|
-
changeKind === "cosmetic" ||
|
|
803
|
-
(changeKind === "low-value" && options.lowValueFilter === true)) {
|
|
800
|
+
if (changeKind === "noop" || changeKind === "cosmetic") {
|
|
804
801
|
run.emitFailed("no_change", NOISE_SUBREASONS[changeKind], options.ref, { changeKind, ...telemetry });
|
|
805
802
|
const what = changeKind === "noop"
|
|
806
803
|
? "identical to the current asset (empty diff)"
|
|
807
|
-
:
|
|
808
|
-
? "a low-value prose micro-rewrite (few changed tokens, no structural changes)"
|
|
809
|
-
: "a cosmetic-only reformat of the current asset (whitespace/fence/YAML-folding changes)";
|
|
804
|
+
: "a cosmetic-only reformat of the current asset (whitespace/fence/YAML-folding changes)";
|
|
810
805
|
return reflectFailure(run, result, "no_change", `Reflect skipped: proposed content for ${payload.ref} is ${what}; no proposal created.`, false);
|
|
811
806
|
}
|
|
812
807
|
/** A judge refused the revision: record it for the ledger's rejection window and stop. */
|
|
@@ -46,8 +46,8 @@ export function loadRetrievalScope(access, stashDir) {
|
|
|
46
46
|
// Blocker 1 (second review round): a pair-pass ledger row must NOT mark
|
|
47
47
|
// an asset "processed" — unlike every other stage, the pair pass judges
|
|
48
48
|
// material against its NEIGHBOURS, not on its own merits, so its own
|
|
49
|
-
// attempt is not usage evidence the
|
|
50
|
-
//
|
|
49
|
+
// attempt is not usage evidence the proactive lane
|
|
50
|
+
// or promotion retries should be starved by. Left in
|
|
51
51
|
// the ledger for the pair pass's OWN eligibility
|
|
52
52
|
// (selectInitiators reads content_hash directly, never this scope).
|
|
53
53
|
// Proposal rows are untouched: a MINTED retire proposal is real
|
|
@@ -14,14 +14,10 @@ const RECENCY_FLOOR_HALFLIFE_DAYS = 180;
|
|
|
14
14
|
/** Keeps frequency ordinal for assets whose last use is unknown. */
|
|
15
15
|
const RECENCY_EPSILON = 0.01;
|
|
16
16
|
const SIZE_FLOOR_BYTES = 200;
|
|
17
|
-
/**
|
|
17
|
+
/** Rank-score weights. */
|
|
18
18
|
export const W_ENCODING = 0.25;
|
|
19
19
|
export const W_OUTCOME = 0.15;
|
|
20
20
|
export const W_RETRIEVAL = 0.6;
|
|
21
|
-
/** Weights with the outcome term off. */
|
|
22
|
-
export const W_ENCODING_PARITY = 0.3;
|
|
23
|
-
export const W_OUTCOME_PARITY = 0;
|
|
24
|
-
export const W_RETRIEVAL_PARITY = 0.7;
|
|
25
21
|
/** Encoding salience by type, for assets with no content-derived score yet. */
|
|
26
22
|
export const DEFAULT_TYPE_ENCODING_WEIGHTS = Object.freeze({
|
|
27
23
|
skill: 0.9,
|
|
@@ -56,10 +52,7 @@ export function computeSalience(inputs) {
|
|
|
56
52
|
const retrieval = rawRetrieval / (rawRetrieval + 1);
|
|
57
53
|
// Larger assets rank slightly lower.
|
|
58
54
|
const sizePenalty = 1 / Math.log10(Math.max(SIZE_FLOOR_BYTES, inputs.sizeBytes ?? 0));
|
|
59
|
-
const
|
|
60
|
-
? [W_ENCODING, W_OUTCOME, W_RETRIEVAL]
|
|
61
|
-
: [W_ENCODING_PARITY, W_OUTCOME_PARITY, W_RETRIEVAL_PARITY];
|
|
62
|
-
const rankScore = clamp01((we * encoding + wo * outcome + wr * retrieval) * sizePenalty);
|
|
55
|
+
const rankScore = clamp01((W_ENCODING * encoding + W_OUTCOME * outcome + W_RETRIEVAL * retrieval) * sizePenalty);
|
|
63
56
|
return { encoding, outcome, retrieval, rankScore, encodingSource };
|
|
64
57
|
}
|
|
65
58
|
export { getAssetSalience, getConsecutiveNoOps, recordNoOp, resetConsecutiveNoOps, upsertAssetSalience, } from "../../storage/repositories/salience-repository.js";
|
|
@@ -217,14 +217,18 @@ export function resolveQualityGateJudge(config, profile, processName, onNotices)
|
|
|
217
217
|
return resolved.runner;
|
|
218
218
|
}
|
|
219
219
|
/** Lesson judge prompt: what the writer was given (the source and its feedback), the assets nearest the new lesson, the lesson. */
|
|
220
|
-
export function buildJudgePrompt(lessonContent, sourceContent, related, feedback) {
|
|
220
|
+
export function buildJudgePrompt(lessonContent, sourceContent, related, feedback, extending) {
|
|
221
221
|
const lines = [
|
|
222
222
|
"You are evaluating a lesson an agent wrote from a memory and the feedback about it, for an akm knowledge base.",
|
|
223
223
|
"",
|
|
224
224
|
"Score this lesson on each criterion from 1 (poor) to 5 (excellent):",
|
|
225
225
|
"1. REUSABLE: Does the lesson state a rule an agent can use on another occasion, with the reason it holds? Score 1-2 when it only records what was done, shipped, decided, found or is pending, on a date or for one build, machine or project, or how a system is set up now, however it is phrased. Score 4-5 for a rule with its reason.",
|
|
226
|
-
|
|
227
|
-
|
|
226
|
+
extending !== undefined
|
|
227
|
+
? "2. NON-REDUNDANCY: The proposed lesson is the existing lesson below with lines added. Compare each added line (a line the existing lesson does not have) only with the existing lesson, never with the source memory. Redundancy means the information is already in the existing lesson. Score 1-2 when an added line only says again what the existing lesson says: its rule or cause in other words, or the same rule applied to an example from the memory. Score 4-5 when every added line states a fact the existing lesson does not contain (a cause, number, version, limit, consequence or observation), however specific or tied to one incident it is: whether the lesson is general enough is REUSABLE's question, asked of the whole lesson, never of this criterion."
|
|
228
|
+
: '2. NON-REDUNDANCY: Compare the lesson only with the assets listed under "Existing assets nearest the new lesson" (each starts with "Existing asset ref:"); never with the source memory. When that list is absent, score 5. Score 1-2 when a listed asset already states the same rule, or states most of what the lesson says in broader words. Score 4-5 when the lesson gives a rule none of the listed assets gives, or when they are on other subjects.',
|
|
229
|
+
extending !== undefined
|
|
230
|
+
? "3. GROUNDING: Is every statement in the lesson stated by the source, its feedback or the existing lesson below, in any words? Check each cause, step, number, rule and limit in the lesson against them. Score 4-5 when each is stated. Score 3 when one stretches what they say. Score 1-2 when any is in none of them, when it contradicts the existing lesson, or when it is about another subject than the source."
|
|
231
|
+
: "3. GROUNDING: Is every statement in the lesson stated by the source or its feedback, in any words? Check each cause, step, number, rule and limit in the lesson against them. Score 4-5 when each is stated. Score 3 when one stretches what the source says. Score 1-2 when any is in neither, when the lesson drops a limit the source states (one place checked, not confirmed, a guess) and says more than it, or when it is about another subject than the source.",
|
|
228
232
|
"",
|
|
229
233
|
"Source memory:",
|
|
230
234
|
"```",
|
|
@@ -235,7 +239,10 @@ export function buildJudgePrompt(lessonContent, sourceContent, related, feedback
|
|
|
235
239
|
if (feedback && feedback.length > 0) {
|
|
236
240
|
lines.push("", "Feedback recorded about the memory (the writer saw it too):", "```", feedback.join("\n").slice(0, 1500), "```");
|
|
237
241
|
}
|
|
238
|
-
if (
|
|
242
|
+
if (extending !== undefined) {
|
|
243
|
+
lines.push("", "Existing lesson that the proposed lesson extends (it is already in the library):", "```", extending.slice(0, 2000), "```");
|
|
244
|
+
}
|
|
245
|
+
else if (related && related.length > 0) {
|
|
239
246
|
lines.push("", "Existing assets nearest the new lesson (they may be on another subject):");
|
|
240
247
|
for (const asset of related)
|
|
241
248
|
lines.push(`\nExisting asset ref: ${asset.ref}`, "```", asset.content.slice(0, 600), "```");
|
|
@@ -326,12 +333,10 @@ export function buildReflectJudgePrompt(candidateContent, sourceContent, feedbac
|
|
|
326
333
|
* 17 of 19 of them bad on 2026-10-05. The rubric reserves 1-2 for a lesson that
|
|
327
334
|
* records what was done instead of a rule, repeats an asset the library holds,
|
|
328
335
|
* or states what neither its source nor its feedback does. The judge is shown
|
|
329
|
-
* the feedback the writer saw, so a statement it supports is not an invention.
|
|
330
|
-
* contradiction of the source is the optional fidelity check's to send to a
|
|
331
|
-
* human (`judgeAndQueue` in distill.ts).
|
|
336
|
+
* the feedback the writer saw, so a statement it supports is not an invention.
|
|
332
337
|
*/
|
|
333
338
|
const GROUNDING_CRITERION = "grounding";
|
|
334
|
-
const LESSON_REJECT_MAX_SCORE = 2;
|
|
339
|
+
export const LESSON_REJECT_MAX_SCORE = 2;
|
|
335
340
|
const LESSON_JUDGE_CRITERIA = ["reusable", "nonRedundancy", GROUNDING_CRITERION];
|
|
336
341
|
const REFLECT_JUDGE_CRITERIA = ["need", "preservation", "quality"];
|
|
337
342
|
/**
|
|
@@ -439,7 +444,7 @@ async function runQualityJudge(feature, config, prompt, keys, chat, options) {
|
|
|
439
444
|
}
|
|
440
445
|
/** Judge a proposed lesson (or knowledge promotion) against its source. */
|
|
441
446
|
export function runLessonQualityJudge(config, lessonContent, sourceContent, chat, options = {}) {
|
|
442
|
-
const prompt = buildJudgePrompt(lessonContent, sourceContent, options.related, options.feedback);
|
|
447
|
+
const prompt = buildJudgePrompt(lessonContent, sourceContent, options.related, options.feedback, options.extending);
|
|
443
448
|
return runQualityJudge("lesson_quality_gate", config, prompt, LESSON_JUDGE_CRITERIA, chat, options);
|
|
444
449
|
}
|
|
445
450
|
/** Judge an in-place reflect revision without new-lesson novelty criteria. */
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import { factDiagnostics, matchWorkflowPlaceholder, memoryOrphanStubApplies, nameOrTypeDiagnostics, ORPHANED_STUB_DETAIL, taskDiagnostics, workflowFrontendDiagnostics,
|
|
6
|
+
import { factDiagnostics, matchWorkflowPlaceholder, memoryOrphanStubApplies, nameOrTypeDiagnostics, ORPHANED_STUB_DETAIL, taskDiagnostics, workflowFrontendDiagnostics, } from "../../core/adapter/adapters/akm-lint.js";
|
|
7
7
|
import { detectAdapterId } from "../../core/adapter/detect-adapter.js";
|
|
8
8
|
import { adapterForId } from "../../core/adapter/registry.js";
|
|
9
9
|
import { createValidateContext } from "../../core/adapter/validate-context.js";
|
|
@@ -79,7 +79,7 @@ function collectMarkdownFiles(dir, caseInsensitive = false) {
|
|
|
79
79
|
}
|
|
80
80
|
return results;
|
|
81
81
|
}
|
|
82
|
-
/**
|
|
82
|
+
/** Workflow sources: Markdown only. */
|
|
83
83
|
function collectWorkflowFiles(dir) {
|
|
84
84
|
if (!fs.existsSync(dir))
|
|
85
85
|
return [];
|
|
@@ -99,7 +99,7 @@ function collectWorkflowFiles(dir) {
|
|
|
99
99
|
if (!entry.isFile() && !entry.isSymbolicLink())
|
|
100
100
|
continue;
|
|
101
101
|
const extension = path.extname(entry.name).toLowerCase();
|
|
102
|
-
if (extension === ".md"
|
|
102
|
+
if (extension === ".md")
|
|
103
103
|
results.push(full);
|
|
104
104
|
}
|
|
105
105
|
return results.sort(compareCodePoints);
|
|
@@ -532,8 +532,8 @@ function lintAkmSweep(stashRoot, extraStashRoots, cfg, sources, options) {
|
|
|
532
532
|
const dirsToScan = options.typeFilter ? STASH_SUBDIRS.filter((d) => d === options.typeFilter) : STASH_SUBDIRS;
|
|
533
533
|
for (const subdir of dirsToScan) {
|
|
534
534
|
const dirPath = path.join(stashRoot, subdir);
|
|
535
|
-
// Tasks have their own `.yml` plus near-miss collector
|
|
536
|
-
//
|
|
535
|
+
// Tasks have their own `.yml` plus near-miss collector; every other AKM
|
|
536
|
+
// subdir is Markdown.
|
|
537
537
|
const files = subdir === "tasks"
|
|
538
538
|
? collectTaskFiles(dirPath)
|
|
539
539
|
: subdir === "workflows"
|
|
@@ -580,21 +580,6 @@ function lintAkmSweep(stashRoot, extraStashRoots, cfg, sources, options) {
|
|
|
580
580
|
catch {
|
|
581
581
|
continue;
|
|
582
582
|
}
|
|
583
|
-
// GitHub-shaped YAML is a peer workflow source, not a Markdown document:
|
|
584
|
-
// no frontmatter/base/stub checks and no `--fix` mutation apply. Compile
|
|
585
|
-
// once through the shared source-IR frontend and route its findings.
|
|
586
|
-
if (subdir === "workflows" && path.extname(filePath).toLowerCase() === ".yml") {
|
|
587
|
-
const frontend = workflowYamlSourceDiagnostics(relPath, raw, filePath, stashRoot);
|
|
588
|
-
for (const finding of [...frontend.errors, ...frontend.warnings]) {
|
|
589
|
-
if (isAdvisoryLintIssue(finding)) {
|
|
590
|
-
warnings.push(finding);
|
|
591
|
-
}
|
|
592
|
-
else {
|
|
593
|
-
flagged.push(finding);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
continue;
|
|
597
|
-
}
|
|
598
583
|
let data;
|
|
599
584
|
let body;
|
|
600
585
|
let frontmatter;
|