akm-cli 0.9.17-alpha.3 → 0.9.17-alpha.4
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 +731 -0
- package/dist/akm +94 -196
- package/dist/cli/shared.js +6 -2
- package/dist/cli.js +22 -9
- package/dist/commands/agent/agent-dispatch.js +1 -1
- package/dist/commands/command/command-execution.js +24 -62
- package/dist/commands/feedback-cli.js +0 -1
- package/dist/commands/health/accept-rate.js +2 -2
- package/dist/commands/health/checks.js +30 -75
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +0 -38
- package/dist/commands/health/improve-metrics.js +123 -562
- package/dist/commands/health/plugin-staleness.js +53 -3
- package/dist/commands/health/renderers.js +12 -4
- package/dist/commands/health/report-view-model.js +11 -106
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -73
- package/dist/commands/health.js +122 -143
- package/dist/commands/improve/consolidate/chunking.js +25 -100
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +538 -1075
- package/dist/commands/improve/content-hash.js +16 -24
- package/dist/commands/improve/distill/content-repair.js +18 -100
- package/dist/commands/improve/distill-guards.js +20 -81
- package/dist/commands/improve/distill-promotion-policy.js +23 -243
- package/dist/commands/improve/distill.js +608 -1075
- package/dist/commands/improve/eligibility.js +126 -400
- package/dist/commands/improve/execution.js +3 -5
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +29 -166
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +12 -7
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +443 -1063
- package/dist/commands/improve/ledger.js +114 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +459 -1172
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +14 -118
- package/dist/commands/improve/memory/memory-improve.js +4 -3
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -10
- package/dist/commands/improve/preparation.js +851 -2339
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +621 -1367
- package/dist/commands/improve/salience.js +46 -232
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +323 -0
- package/dist/commands/proposal/drain.js +251 -644
- package/dist/commands/proposal/proposal-cli.js +3 -18
- package/dist/commands/proposal/proposal-types.js +20 -41
- package/dist/commands/proposal/proposal.js +1 -2
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +502 -1487
- package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
- package/dist/commands/proposal/validators/proposal-validators.js +1 -1
- package/dist/commands/proposal/validators/proposals.js +13 -89
- package/dist/commands/read/curate.js +63 -413
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +2 -13
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +7 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +2 -11
- package/dist/commands/sources/installed-stashes.js +197 -746
- package/dist/commands/sources/schema-repair.js +98 -129
- package/dist/commands/sources/source-add.js +62 -12
- package/dist/commands/sources/stash-cli.js +1 -1
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +9 -8
- package/dist/commands/tasks/tasks.js +326 -930
- package/dist/commands/tasks/validate.js +42 -21
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +0 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +11 -12
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +291 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +1 -33
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +163 -68
- package/dist/core/config/legacy-source-shape-shim.js +38 -9
- package/dist/core/config/schema/embedding.js +20 -5
- package/dist/core/config/schema/engines.js +5 -0
- package/dist/core/config/schema/execution.js +1 -1
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/improve-processes.js +21 -95
- package/dist/core/config/schema/improve.js +4 -42
- package/dist/core/config/schema/scheduler.js +12 -12
- package/dist/core/config/schema/search.js +6 -22
- package/dist/core/env-secret-ref.js +0 -1
- package/dist/core/errors.js +8 -9
- package/dist/core/file-lock.js +76 -173
- package/dist/core/logs-db.js +2 -2
- package/dist/core/paths.js +0 -27
- package/dist/core/redaction.js +109 -2
- package/dist/core/run-lock.js +2 -5
- package/dist/core/spawn-env.js +1 -1
- package/dist/core/state/migrations.js +108 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +293 -1012
- package/dist/execution/input-contract.js +1 -1
- package/dist/execution/resolved-request.js +135 -689
- package/dist/execution/source.js +63 -257
- package/dist/execution/target-ref.js +1 -1
- package/dist/indexer/bundle-identity-guard.js +2 -2
- package/dist/indexer/db/graph-db.js +106 -46
- package/dist/indexer/ensure-index.js +44 -85
- package/dist/indexer/graph/graph-extraction.js +340 -562
- package/dist/indexer/graph/graph-related.js +130 -0
- package/dist/indexer/index-rebuild-lock.js +3 -11
- package/dist/indexer/index-writer-lock.js +8 -17
- package/dist/indexer/index-written-assets.js +139 -151
- package/dist/indexer/indexer.js +524 -846
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +81 -90
- package/dist/indexer/passes/metadata.js +132 -200
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +1 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +181 -590
- package/dist/indexer/search/fts-query.js +30 -41
- package/dist/indexer/search/ranking.js +28 -154
- package/dist/indexer/search/search-attribution.js +12 -32
- package/dist/indexer/search/search-fields.js +11 -15
- package/dist/indexer/search/search-hit-enrichers.js +54 -85
- package/dist/indexer/search/search-source.js +1 -4
- package/dist/indexer/usage/usage-events.js +2 -7
- package/dist/integrations/agent/engine-fallback.js +23 -40
- package/dist/integrations/agent/engine-resolution.js +93 -183
- package/dist/integrations/agent/execution.js +507 -0
- package/dist/integrations/agent/model-map.js +28 -156
- package/dist/integrations/agent/request-lowering.js +66 -141
- package/dist/integrations/agent/runner-dispatch.js +143 -321
- package/dist/integrations/agent/runner.js +54 -14
- package/dist/integrations/lockfile.js +53 -101
- package/dist/llm/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +10 -15
- package/dist/llm/graph-extract.js +3 -12
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/metadata-enhance.js +1 -2
- package/dist/llm/structured-call.js +5 -24
- package/dist/output/generic-render.js +23 -11
- package/dist/output/html-render.js +13 -10
- package/dist/output/render-registry.js +3 -32
- package/dist/output/shapes/helpers.js +2 -34
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +60 -23
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +1 -2
- package/dist/output/text/workflow-format.js +0 -32
- package/dist/output/text.js +2 -0
- package/dist/registry/factory.js +4 -19
- package/dist/registry/network.js +66 -220
- package/dist/registry/providers/index.js +0 -2
- package/dist/registry/providers/skills-sh.js +3 -14
- package/dist/registry/providers/static-index.js +24 -26
- package/dist/registry/resolve.js +55 -131
- package/dist/scripts/akm-migrate-node.js +43937 -93313
- package/dist/scripts/akm-migrate.js +43697 -93071
- package/dist/setup/registry-stash-loader.js +4 -13
- package/dist/setup/semantic-assets.js +3 -44
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +25 -15
- package/dist/sources/provider-factory.js +17 -18
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +7 -1
- package/dist/sources/providers/git-provider.js +0 -3
- package/dist/sources/providers/git-stash.js +0 -17
- package/dist/sources/providers/npm.js +2 -4
- package/dist/sources/providers/provider-utils.js +5 -10
- package/dist/sources/providers/website.js +0 -2
- package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
- package/dist/sources/website-url.js +2 -2
- package/dist/storage/database.js +9 -35
- package/dist/storage/repositories/improve-ledger-repository.js +168 -0
- package/dist/storage/repositories/index-connection.js +34 -70
- package/dist/storage/repositories/index-entries-repository.js +69 -111
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +83 -269
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +192 -220
- package/dist/storage/repositories/index-utility-repository.js +8 -29
- package/dist/storage/repositories/index-vec-repository.js +133 -414
- package/dist/storage/repositories/outcome-repository.js +2 -1
- package/dist/storage/repositories/proposals-repository.js +35 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- package/dist/storage/repositories/task-history-repository.js +26 -4
- package/dist/storage/repositories/workflow-runs-repository.js +53 -244
- package/dist/storage/sqlite-migrations.js +136 -0
- package/dist/storage/sqlite-pragmas.js +11 -9
- package/dist/storage/sqlite-transaction.js +170 -0
- package/dist/storage/state-db-integrity.js +34 -27
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +129 -277
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +125 -745
- package/dist/tasks/backends/schtasks.js +101 -620
- package/dist/tasks/prepare/prepare-support.js +5 -15
- package/dist/tasks/prepare/prepare.js +0 -2
- package/dist/tasks/resolve-akm-bin.js +20 -79
- package/dist/tasks/run/attempt-lifecycle.js +0 -1
- package/dist/tasks/scheduler-binding.js +18 -238
- package/dist/tasks/scheduler-invocation.js +52 -52
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +361 -751
- package/dist/tasks/source/parse-task-source.js +160 -10
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +2 -2
- package/dist/workflows/authoring/authoring.js +3 -12
- package/dist/workflows/compile.js +211 -0
- package/dist/workflows/concurrency-policy.js +13 -74
- package/dist/workflows/exec/child-invocation.js +3 -17
- package/dist/workflows/exec/child-workflow.js +32 -141
- package/dist/workflows/exec/dispatch-redaction.js +13 -53
- package/dist/workflows/exec/environment.js +98 -0
- package/dist/workflows/exec/exec-unit.js +33 -140
- package/dist/workflows/exec/frozen-judge.js +7 -59
- package/dist/workflows/exec/native-executor.js +82 -341
- package/dist/workflows/exec/param-secrets.js +29 -47
- package/dist/workflows/exec/run-workflow.js +154 -387
- package/dist/workflows/exec/scheduler.js +9 -36
- package/dist/workflows/exec/step-work.js +127 -430
- package/dist/workflows/exec/unit-dispatch.js +11 -63
- package/dist/workflows/exec/unit-writer.js +8 -52
- package/dist/workflows/exec/worktree.js +39 -273
- package/dist/workflows/freeze/child-output-references.js +4 -15
- package/dist/workflows/freeze/environment.js +99 -92
- package/dist/workflows/freeze/freeze.js +172 -0
- package/dist/workflows/freeze/step-values.js +19 -21
- package/dist/workflows/freeze/targets/child-workflow.js +23 -92
- package/dist/workflows/freeze/targets/command.js +10 -33
- package/dist/workflows/freeze/targets/script.js +5 -12
- package/dist/workflows/freeze/targets/shell.js +3 -6
- package/dist/workflows/freeze/targets/task.js +25 -80
- package/dist/workflows/freeze/task-bindings.js +20 -67
- package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
- package/dist/workflows/ir/params.js +6 -51
- package/dist/workflows/ir/plan-hash.js +2 -34
- package/dist/workflows/parser.js +140 -43
- package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
- package/dist/workflows/renderer.js +36 -69
- package/dist/workflows/resource-limits.js +12 -120
- package/dist/workflows/runtime/agent-identity.js +8 -40
- package/dist/workflows/runtime/run-outputs.js +3 -6
- package/dist/workflows/runtime/run-plan.js +316 -0
- package/dist/workflows/runtime/runs.js +48 -200
- package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
- package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/integration/bundling-akm.md +49 -42
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.17.md +41 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
- package/docs/reference/cli.md +182 -125
- package/docs/reference/configuration.md +49 -56
- package/docs/reference/data-and-telemetry.md +19 -20
- package/docs/reference/tasks.md +86 -38
- package/docs/reference/workflow-schema.md +14 -18
- package/docs/reference/workflows.md +6 -9
- package/package.json +1 -1
- package/schemas/akm-config.json +87 -406
- package/dist/commands/health/advisories.js +0 -150
- package/dist/commands/health/metrics.js +0 -329
- package/dist/commands/health/surfaces.js +0 -102
- package/dist/commands/improve/anti-collapse.js +0 -83
- package/dist/commands/improve/collapse-detector.js +0 -432
- package/dist/commands/improve/consolidate/eligibility.js +0 -48
- package/dist/commands/improve/consolidate/merge.js +0 -146
- package/dist/commands/improve/distill/promote-memory.js +0 -329
- package/dist/commands/improve/distill/quality-gate.js +0 -500
- package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
- package/dist/commands/improve/proposal-envelope.js +0 -31
- package/dist/commands/improve/run-context.js +0 -123
- package/dist/commands/improve/shared.js +0 -21
- package/dist/commands/improve/source-identity.js +0 -28
- package/dist/commands/improve/triage.js +0 -96
- package/dist/commands/proposal/drain-policies.js +0 -151
- package/dist/commands/sources/update-transaction.js +0 -220
- package/dist/core/action-contributors.js +0 -28
- package/dist/core/config/config-version-shim.js +0 -101
- package/dist/core/config/retired-experimental-keys-shim.js +0 -62
- package/dist/core/fs-txn.js +0 -405
- package/dist/core/lexical-score.js +0 -25
- package/dist/core/maintenance-barrier.js +0 -167
- package/dist/execution/executable-identity.js +0 -105
- package/dist/execution/guarded-source.js +0 -441
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- package/dist/indexer/walk/project-context.js +0 -192
- package/dist/integrations/agent/execution-cascade.js +0 -566
- package/dist/integrations/agent/execution-definitions.js +0 -202
- package/dist/integrations/agent/execution-lowering.js +0 -841
- package/dist/integrations/agent/execution-preparation.js +0 -98
- package/dist/integrations/agent/inline-execution.js +0 -74
- package/dist/registry/create-provider-registry.js +0 -29
- package/dist/registry/pinned-request-helper.js +0 -247
- package/dist/registry/pinned-transport.js +0 -717
- package/dist/sources/providers/index.js +0 -14
- package/dist/storage/engines/sqlite-migrations.js +0 -271
- package/dist/storage/repositories/canaries-repository.js +0 -107
- package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
- package/dist/storage/repositories/registry-cache.js +0 -113
- package/dist/tasks/scheduler-sync-preview.js +0 -52
- package/dist/workflows/freeze/resolve-steps.js +0 -86
- package/dist/workflows/freeze/source-freeze.js +0 -64
- package/dist/workflows/ir/compile.js +0 -321
- package/dist/workflows/ir/environment-v4.js +0 -330
- package/dist/workflows/ir/freeze-v4.js +0 -153
- package/dist/workflows/ir/schema-v4.js +0 -745
- package/dist/workflows/ir/schema.js +0 -354
- package/dist/workflows/program/schema.js +0 -78
- package/dist/workflows/runtime/checkin.js +0 -57
- package/dist/workflows/runtime/plan-classifier.js +0 -196
- package/dist/workflows/runtime/unit-checkin.js +0 -45
- package/dist/workflows/runtime/unit-phases.js +0 -20
- package/dist/workflows/schema.js +0 -4
- package/dist/workflows/source-ir/compile.js +0 -200
- package/dist/workflows/source-ir/program.js +0 -50
- package/dist/workflows/source-ir/result.js +0 -26
- package/dist/workflows/source-ir/schema.js +0 -786
- package/dist/workflows/source-ir/triggers.js +0 -79
- package/dist/workflows/source-ir/uses.js +0 -40
- package/dist/workflows/validator.js +0 -60
|
@@ -1,500 +0,0 @@
|
|
|
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
|
-
* Distill quality-gate cluster — LLM-as-judge, quality-rejection envelope
|
|
6
|
-
* writer, and output-salience persistence. Extracted verbatim from
|
|
7
|
-
* `distill.ts` so the main `akmDistill` orchestrator and the memory→knowledge
|
|
8
|
-
* promotion branch (`promote-memory.ts`) can share the same helpers without a
|
|
9
|
-
* circular import. Logic is byte-identical to the pre-extraction inline code.
|
|
10
|
-
*/
|
|
11
|
-
import fs from "node:fs";
|
|
12
|
-
import path from "node:path";
|
|
13
|
-
import { parseRefInput } from "../../../core/asset/resolve-ref.js";
|
|
14
|
-
import { timestampForFilename } from "../../../core/common.js";
|
|
15
|
-
import { ConfigError } from "../../../core/errors.js";
|
|
16
|
-
import { appendEvent } from "../../../core/events.js";
|
|
17
|
-
import { parseEmbeddedJsonResponse } from "../../../core/parse.js";
|
|
18
|
-
import { getDistillRejectedDir } from "../../../core/paths.js";
|
|
19
|
-
import { withStateDb } from "../../../core/state-db.js";
|
|
20
|
-
import { warn } from "../../../core/warn.js";
|
|
21
|
-
import { recordWrittenPath } from "../../../core/write-provenance.js";
|
|
22
|
-
import { callStructured } from "../../../llm/structured-call.js";
|
|
23
|
-
import { archiveProposal, isProposalSkipped, recordGateDecision, } from "../../proposal/repository.js";
|
|
24
|
-
import { akmSearch } from "../../read/search.js";
|
|
25
|
-
import { scoreEncodingSalience } from "../encoding-salience.js";
|
|
26
|
-
import { resolveImproveLlmExecution } from "../execution.js";
|
|
27
|
-
import { emitProposal } from "../proposal-envelope.js";
|
|
28
|
-
import { computeSalience, upsertAssetSalience } from "../salience.js";
|
|
29
|
-
// ── D-4 / #390: Top-3 similar lessons retrieval ──────────────────────────────
|
|
30
|
-
/**
|
|
31
|
-
* Default implementation: use akmSearch to find top-N similar lesson assets.
|
|
32
|
-
* Returns empty array when search fails or returns no results.
|
|
33
|
-
* Requires embedding configured for semantic similarity; degrades gracefully.
|
|
34
|
-
*/
|
|
35
|
-
export async function fetchTopSimilarLessons(query, n, _stashDir) {
|
|
36
|
-
try {
|
|
37
|
-
const result = await akmSearch({
|
|
38
|
-
query,
|
|
39
|
-
type: "lesson",
|
|
40
|
-
limit: n,
|
|
41
|
-
skipLogging: true,
|
|
42
|
-
eventSource: "improve",
|
|
43
|
-
});
|
|
44
|
-
const hits = result?.hits ?? [];
|
|
45
|
-
return hits
|
|
46
|
-
.filter((h) => "path" in h && typeof h.path === "string")
|
|
47
|
-
.slice(0, n)
|
|
48
|
-
.map((h) => {
|
|
49
|
-
let content = "";
|
|
50
|
-
try {
|
|
51
|
-
if (h.path && fs.existsSync(h.path)) {
|
|
52
|
-
content = fs.readFileSync(h.path, "utf8");
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
/* best-effort */
|
|
57
|
-
}
|
|
58
|
-
return { ref: h.ref, content };
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return [];
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
// ── LLM-as-judge quality gate (P2-B) ────────────────────────────────────────
|
|
66
|
-
/**
|
|
67
|
-
* D-4 / #390: Build the LLM-as-judge prompt.
|
|
68
|
-
*
|
|
69
|
-
* When similarLessons are provided (top-3 by embedding similarity), they are
|
|
70
|
-
* included in the context so the judge can lower the score for near-duplicates.
|
|
71
|
-
* Voyager arXiv:2305.16291 — skill library admission requires similarity check
|
|
72
|
-
* against the existing library. A-MEM arXiv:2502.12110 — new notes are checked
|
|
73
|
-
* against existing notes before linking.
|
|
74
|
-
*/
|
|
75
|
-
export function buildJudgePrompt(lessonContent, sourceContent, similarLessons) {
|
|
76
|
-
const lines = [
|
|
77
|
-
"You are evaluating a proposed lesson asset for an akm knowledge base.",
|
|
78
|
-
"",
|
|
79
|
-
"Score this lesson on each criterion from 1 (poor) to 5 (excellent):",
|
|
80
|
-
"1. NOVELTY: Does the lesson add information not already present in the source asset?",
|
|
81
|
-
"2. NON-REDUNDANCY: Is this lesson meaningfully different from what the source already says?",
|
|
82
|
-
"",
|
|
83
|
-
"Source asset content:",
|
|
84
|
-
"```",
|
|
85
|
-
sourceContent.slice(0, 2000),
|
|
86
|
-
"```",
|
|
87
|
-
];
|
|
88
|
-
if (similarLessons && similarLessons.length > 0) {
|
|
89
|
-
lines.push("");
|
|
90
|
-
lines.push("Existing similar lessons (top-3 by similarity). Rate lower if the proposed lesson is substantially similar to any of these:");
|
|
91
|
-
for (const sl of similarLessons) {
|
|
92
|
-
lines.push(`\nExisting lesson ref: ${sl.ref}`);
|
|
93
|
-
lines.push("```");
|
|
94
|
-
lines.push(sl.content.slice(0, 500));
|
|
95
|
-
lines.push("```");
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
lines.push("");
|
|
99
|
-
lines.push("Proposed lesson content:");
|
|
100
|
-
lines.push("```");
|
|
101
|
-
lines.push(lessonContent.slice(0, 1000));
|
|
102
|
-
lines.push("```");
|
|
103
|
-
lines.push("");
|
|
104
|
-
lines.push('Return ONLY valid JSON, no prose: {"scores": {"novelty": <1-5 integer>, "nonRedundancy": <1-5 integer>}, "reason": "<one sentence>"}');
|
|
105
|
-
return lines.join("\n");
|
|
106
|
-
}
|
|
107
|
-
function boundedDocument(content, maxChars = 6000) {
|
|
108
|
-
if (content.length <= maxChars)
|
|
109
|
-
return content;
|
|
110
|
-
const half = Math.floor((maxChars - 80) / 2);
|
|
111
|
-
return `${content.slice(0, half)}\n\n[... middle omitted for bounded judge context ...]\n\n${content.slice(-half)}`;
|
|
112
|
-
}
|
|
113
|
-
function buildChangedRegion(sourceContent, candidateContent) {
|
|
114
|
-
const source = sourceContent.split("\n");
|
|
115
|
-
const candidate = candidateContent.split("\n");
|
|
116
|
-
let prefix = 0;
|
|
117
|
-
while (prefix < source.length && prefix < candidate.length && source[prefix] === candidate[prefix])
|
|
118
|
-
prefix++;
|
|
119
|
-
let suffix = 0;
|
|
120
|
-
while (suffix < source.length - prefix &&
|
|
121
|
-
suffix < candidate.length - prefix &&
|
|
122
|
-
source[source.length - 1 - suffix] === candidate[candidate.length - 1 - suffix]) {
|
|
123
|
-
suffix++;
|
|
124
|
-
}
|
|
125
|
-
const removed = source.slice(prefix, source.length - suffix).join("\n");
|
|
126
|
-
const added = candidate.slice(prefix, candidate.length - suffix).join("\n");
|
|
127
|
-
return boundedDocument(`Removed or replaced:\n${removed || "(none)"}\n\nAdded or replacement:\n${added || "(none)"}`);
|
|
128
|
-
}
|
|
129
|
-
/** Build quality criteria for revising an existing asset in place. */
|
|
130
|
-
export function buildReflectJudgePrompt(candidateContent, sourceContent, feedback) {
|
|
131
|
-
return [
|
|
132
|
-
"You are evaluating a proposed revision to an existing akm asset.",
|
|
133
|
-
"",
|
|
134
|
-
"Score this revision on each criterion from 1 (poor) to 5 (excellent):",
|
|
135
|
-
"1. FEEDBACK ALIGNMENT: Does the revision address the supplied feedback or improve retrieval and clarity?",
|
|
136
|
-
"2. PRESERVATION: Does it retain the source's concrete facts, code, commands, examples, and structure without truncation?",
|
|
137
|
-
"3. QUALITY: Is the revision coherent, actionable, complete, and free of unsupported claims?",
|
|
138
|
-
"",
|
|
139
|
-
"Overlap with the source is expected and must not lower the score by itself; this is an in-place revision, not a new lesson.",
|
|
140
|
-
"",
|
|
141
|
-
"Feedback:",
|
|
142
|
-
"```",
|
|
143
|
-
(feedback.length > 0 ? feedback.join("\n") : "No explicit feedback supplied.").slice(0, 1000),
|
|
144
|
-
"```",
|
|
145
|
-
"",
|
|
146
|
-
"Source asset content:",
|
|
147
|
-
"```",
|
|
148
|
-
boundedDocument(sourceContent),
|
|
149
|
-
"```",
|
|
150
|
-
"",
|
|
151
|
-
"Proposed revision:",
|
|
152
|
-
"```",
|
|
153
|
-
boundedDocument(candidateContent),
|
|
154
|
-
"```",
|
|
155
|
-
"",
|
|
156
|
-
"Changed region:",
|
|
157
|
-
"```",
|
|
158
|
-
buildChangedRegion(sourceContent, candidateContent),
|
|
159
|
-
"```",
|
|
160
|
-
"",
|
|
161
|
-
'Return ONLY valid JSON, no prose: {"scores": {"feedbackAlignment": <1-5 integer>, "preservation": <1-5 integer>, "quality": <1-5 integer>}, "reason": "<one sentence>"}',
|
|
162
|
-
].join("\n");
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Criterion keys `buildJudgePrompt` asks the lesson judge to score.
|
|
166
|
-
* R16: ACTIONABILITY dropped (splinter measured AUC 0.46 against accept/reject
|
|
167
|
-
* outcomes — no signal — and averaging it pulled scores toward the review band).
|
|
168
|
-
*/
|
|
169
|
-
const LESSON_JUDGE_CRITERIA_KEYS = ["novelty", "nonRedundancy"];
|
|
170
|
-
/** Criterion keys `buildReflectJudgePrompt` asks the reflect judge to score. */
|
|
171
|
-
const REFLECT_JUDGE_CRITERIA_KEYS = ["feedbackAlignment", "preservation", "quality"];
|
|
172
|
-
/**
|
|
173
|
-
* R16 / r2-2 / JUDGE2: parse the judge's JSON response, accepting either the
|
|
174
|
-
* current per-criterion shape (`{"scores": {...}, "reason"}`, averaged in
|
|
175
|
-
* code) or the old averaged-float shape (`{"score": 1-5, "reason"}`) a model
|
|
176
|
-
* may still return. `expectedCriteriaKeys` names the criteria this judge's
|
|
177
|
-
* prompt asked for; only those keys are read, validated, and averaged — a
|
|
178
|
-
* `scores` object missing any of them is a parse failure (a truncated or
|
|
179
|
-
* partial response can't auto-pass on whatever keys happened to arrive), and
|
|
180
|
-
* any OTHER key present (e.g. a model spelling a key differently, or echoing
|
|
181
|
-
* a criterion the prompt didn't ask for) is silently ignored rather than
|
|
182
|
-
* changing the score or failing the parse. Each expected criterion (or the
|
|
183
|
-
* bare score) must be a finite number in 1..5; anything else — an
|
|
184
|
-
* out-of-range or non-finite value, a non-string `reason` — is a parse
|
|
185
|
-
* failure so the caller routes to review exactly as before.
|
|
186
|
-
*/
|
|
187
|
-
function parseJudgeResponse(raw, expectedCriteriaKeys) {
|
|
188
|
-
const parsed = parseEmbeddedJsonResponse(raw);
|
|
189
|
-
if (!parsed || typeof parsed.reason !== "string")
|
|
190
|
-
return undefined;
|
|
191
|
-
const reason = parsed.reason;
|
|
192
|
-
if (parsed.scores !== undefined) {
|
|
193
|
-
if (typeof parsed.scores !== "object" || parsed.scores === null || Array.isArray(parsed.scores))
|
|
194
|
-
return undefined;
|
|
195
|
-
const scores = parsed.scores;
|
|
196
|
-
const criteria = {};
|
|
197
|
-
let sum = 0;
|
|
198
|
-
for (const key of expectedCriteriaKeys) {
|
|
199
|
-
const value = scores[key];
|
|
200
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 1 || value > 5)
|
|
201
|
-
return undefined;
|
|
202
|
-
criteria[key] = value;
|
|
203
|
-
sum += value;
|
|
204
|
-
}
|
|
205
|
-
const score = sum / expectedCriteriaKeys.length;
|
|
206
|
-
return { score, reason, criteria };
|
|
207
|
-
}
|
|
208
|
-
if (typeof parsed.score === "number" && Number.isFinite(parsed.score) && parsed.score >= 1 && parsed.score <= 5) {
|
|
209
|
-
return { score: parsed.score, reason };
|
|
210
|
-
}
|
|
211
|
-
return undefined;
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* JUDGE2: strict JSON Schema for a judge response, sent through the same
|
|
215
|
-
* `supportsJsonSchema`-gated `request.responseSchema` path
|
|
216
|
-
* `src/llm/graph-extract.ts` (`GRAPH_EXTRACTION_JSON_SCHEMA`) uses — a
|
|
217
|
-
* provider that doesn't opt in (`runner.connection.supportsJsonSchema`) sees
|
|
218
|
-
* no change. Built from `expectedCriteriaKeys` so each judge's schema matches
|
|
219
|
-
* exactly the criteria its own prompt asks for; `additionalProperties: false`
|
|
220
|
-
* at both levels means a model that spells a key differently is rejected by
|
|
221
|
-
* a schema-enforcing provider rather than silently producing a parse failure.
|
|
222
|
-
*/
|
|
223
|
-
function buildJudgeResponseSchema(expectedCriteriaKeys) {
|
|
224
|
-
const properties = {};
|
|
225
|
-
for (const key of expectedCriteriaKeys) {
|
|
226
|
-
properties[key] = { type: "integer", minimum: 1, maximum: 5 };
|
|
227
|
-
}
|
|
228
|
-
return {
|
|
229
|
-
type: "object",
|
|
230
|
-
required: ["scores", "reason"],
|
|
231
|
-
additionalProperties: false,
|
|
232
|
-
properties: {
|
|
233
|
-
scores: {
|
|
234
|
-
type: "object",
|
|
235
|
-
required: [...expectedCriteriaKeys],
|
|
236
|
-
additionalProperties: false,
|
|
237
|
-
properties,
|
|
238
|
-
},
|
|
239
|
-
reason: { type: "string" },
|
|
240
|
-
},
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
async function runQualityJudge(feature, config, prompt, expectedCriteriaKeys, chat, options = {}) {
|
|
244
|
-
const resolvedDefault = !options.runnerSelectionFrozen && !options.llmRunner
|
|
245
|
-
? resolveImproveLlmExecution({ config, processName: `${feature}-judge` })
|
|
246
|
-
: null;
|
|
247
|
-
if (resolvedDefault)
|
|
248
|
-
options.onNotices?.(resolvedDefault.notices);
|
|
249
|
-
const runner = options.llmRunner ?? resolvedDefault?.runner;
|
|
250
|
-
if (!runner) {
|
|
251
|
-
return { pass: false, score: -1, reason: "no LLM configured — cannot judge, failing closed" };
|
|
252
|
-
}
|
|
253
|
-
try {
|
|
254
|
-
// UNGATED at the seam (no akmConfig): the quality gates' enablement is
|
|
255
|
-
// resolved by the caller before this function runs, and a transport throw
|
|
256
|
-
// propagates into the fail-closed catch below. `feature` labels the call.
|
|
257
|
-
const raw = await callStructured({
|
|
258
|
-
feature,
|
|
259
|
-
runner,
|
|
260
|
-
...(options.lease ? { lease: options.lease } : {}),
|
|
261
|
-
messages: [
|
|
262
|
-
{ role: "system", content: "Return only valid JSON. No prose." },
|
|
263
|
-
{ role: "user", content: prompt },
|
|
264
|
-
],
|
|
265
|
-
request: {
|
|
266
|
-
enableThinking: false,
|
|
267
|
-
// R13: the judge must not inherit the generation runner's temperature
|
|
268
|
-
// (measured: 10/16 verdict flips at 0.3, 0/16 at 0). Pinned regardless
|
|
269
|
-
// of what `engines.<name>.temperature` the runner resolves.
|
|
270
|
-
temperature: 0,
|
|
271
|
-
// JUDGE2: bounds the response to exactly this judge's criteria on
|
|
272
|
-
// providers that opt into structured output; a no-op otherwise.
|
|
273
|
-
responseSchema: buildJudgeResponseSchema(expectedCriteriaKeys),
|
|
274
|
-
...(Object.hasOwn(options, "timeoutMs") ? { timeoutMs: options.timeoutMs } : {}),
|
|
275
|
-
...(options.signal ? { signal: options.signal } : {}),
|
|
276
|
-
...(chat ? { chat } : {}),
|
|
277
|
-
},
|
|
278
|
-
parse: (rawResponse) => rawResponse ?? "",
|
|
279
|
-
// Unreachable on the ungated path (errors propagate); fail closed anyway.
|
|
280
|
-
onError: () => "",
|
|
281
|
-
fallback: "",
|
|
282
|
-
...(options.onNotices ? { onNotices: options.onNotices } : {}),
|
|
283
|
-
});
|
|
284
|
-
const parsed = parseJudgeResponse(raw, expectedCriteriaKeys);
|
|
285
|
-
if (!parsed) {
|
|
286
|
-
return { pass: false, score: -1, reason: "judge parse failed — routed to review", reviewNeeded: true };
|
|
287
|
-
}
|
|
288
|
-
// D-5 / #388: Three-band system (MT-Bench arXiv:2306.05685 — ~±0.5 judge variance).
|
|
289
|
-
// >= 3.5: auto-queue as pending (pass: true)
|
|
290
|
-
// 2.5–3.5: review-needed band — uncertain, escalate to human (reviewNeeded: true)
|
|
291
|
-
// < 2.5: auto-reject (pass: false)
|
|
292
|
-
const { score, reason, criteria } = parsed;
|
|
293
|
-
if (score >= 3.5)
|
|
294
|
-
return { pass: true, score, reason, ...(criteria ? { criteria } : {}) };
|
|
295
|
-
if (score >= 2.5)
|
|
296
|
-
return { pass: false, score, reason, reviewNeeded: true, ...(criteria ? { criteria } : {}) };
|
|
297
|
-
return { pass: false, score, reason, ...(criteria ? { criteria } : {}) };
|
|
298
|
-
}
|
|
299
|
-
catch (error) {
|
|
300
|
-
// Invalid symbolic credentials are configuration failures, not a negative
|
|
301
|
-
// content verdict. Provider/runtime failures retain the fail-closed result.
|
|
302
|
-
if (error instanceof ConfigError)
|
|
303
|
-
throw error;
|
|
304
|
-
return { pass: false, score: -1, reason: "judge timeout/error — routed to review", reviewNeeded: true };
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Run the LLM-as-judge quality gate on a proposal's content.
|
|
309
|
-
*
|
|
310
|
-
* Exported so reflect.ts can apply the same gate to reflect proposals (R-5 / #374).
|
|
311
|
-
* The selected strategy's distill/reflect quality-gate setting is resolved by
|
|
312
|
-
* the caller before this function runs.
|
|
313
|
-
*
|
|
314
|
-
* Fail-CLOSED (07 P0-2): returns `pass: false` (score -1) on timeout, parse
|
|
315
|
-
* failure, or missing LLM. Minted content that cannot be judged is rejected,
|
|
316
|
-
* not passed through — an unverifiable judge must never wave content into the
|
|
317
|
-
* stash. The rejection is `quality_rejected`, not `review_needed`.
|
|
318
|
-
*/
|
|
319
|
-
export async function runLessonQualityJudge(config, lessonContent, sourceContent, chat, options = {}) {
|
|
320
|
-
return runQualityJudge("lesson_quality_gate", config, buildJudgePrompt(lessonContent, sourceContent, options.similarLessons), LESSON_JUDGE_CRITERIA_KEYS, chat, options);
|
|
321
|
-
}
|
|
322
|
-
/** Judge an in-place reflect revision without applying new-lesson novelty criteria. */
|
|
323
|
-
export async function runReflectQualityJudge(config, candidateContent, sourceContent, feedback, chat, options = {}) {
|
|
324
|
-
return runQualityJudge("proposal_quality_gate", config, buildReflectJudgePrompt(candidateContent, sourceContent, feedback), REFLECT_JUDGE_CRITERIA_KEYS, chat, options);
|
|
325
|
-
}
|
|
326
|
-
// ── Quality-rejection helper ─────────────────────────────────────────────────
|
|
327
|
-
/**
|
|
328
|
-
* Write a rejected lesson to `$STATE/improve/distill-rejected/<stash>/`
|
|
329
|
-
* (itlackey/akm#890), persist it as a real `proposals` row, append a
|
|
330
|
-
* `distill_invoked` quality-rejected event, and return the `quality_rejected`
|
|
331
|
-
* envelope.
|
|
332
|
-
*
|
|
333
|
-
* R10: the proposal row is minted through the same `createProposal`
|
|
334
|
-
* (`emitProposal`) path every other distill proposal takes, so `source:
|
|
335
|
-
* "distill"` fingerprint/backoff bookkeeping (proposal/repository.ts
|
|
336
|
-
* `checkFingerprintAndBackoff`) and the Reflexion "previously rejected"
|
|
337
|
-
* context (distill.ts's `buildDistillMessages`, reflect.ts's
|
|
338
|
-
* `readRejectedProposals`) can see it — before this, a quality rejection
|
|
339
|
-
* left only an event and a `$STATE`-side file nothing read, so the same ref
|
|
340
|
-
* was re-selected and re-rejected on every run. `review_needed` stays
|
|
341
|
-
* `pending` for a human to triage in the normal queue (matching what
|
|
342
|
-
* promote-memory.ts's comment always claimed) and is stamped with a
|
|
343
|
-
* `quality-gate` gate decision so the triage drain's `classifyPendingProposals`
|
|
344
|
-
* (proposal/drain.ts) leaves it pending instead of deferring it to the
|
|
345
|
-
* judgment tier, which could auto-accept it with no human in the loop;
|
|
346
|
-
* `quality_rejected` is minted pending, then immediately archived to
|
|
347
|
-
* `rejected` with the judge's reason.
|
|
348
|
-
* A fingerprint/backoff guard hit here (rare pre-R9; the pre-generation
|
|
349
|
-
* guard is item R9) just means no new row — the envelope + event below are
|
|
350
|
-
* written either way.
|
|
351
|
-
*
|
|
352
|
-
* @param stash - Root stash directory.
|
|
353
|
-
* @param inputRef - The original input ref (for the event).
|
|
354
|
-
* @param proposalRef - The proposed lesson/knowledge ref.
|
|
355
|
-
* @param content - The raw content that failed the quality gate.
|
|
356
|
-
* @param score - Quality score from the judge.
|
|
357
|
-
* @param reason - Human-readable rejection reason.
|
|
358
|
-
* @param extraMeta - Optional additional metadata for the event.
|
|
359
|
-
* @param eventsCtx - Events context so the emit takes appendEvent's fast path (R25).
|
|
360
|
-
* @param proposalOpts - Test seam / attribution passthrough for the minted proposal row.
|
|
361
|
-
*/
|
|
362
|
-
export function writeQualityRejection(stash, inputRef, proposalRef, content, score, reason, extraMeta = {}, eligibilitySource, eventsCtx, proposalOpts = {}) {
|
|
363
|
-
// D-5 / #388: reviewNeeded flag selects "review_needed" vs "quality_rejected" outcome.
|
|
364
|
-
const outcome = extraMeta.reviewNeeded ? "review_needed" : "quality_rejected";
|
|
365
|
-
// r2-1: the mint-time canonical validator inside createProposal (via
|
|
366
|
-
// emitProposal) throws UsageError for structurally-invalid content (e.g. a
|
|
367
|
-
// lessons/ ref missing description/when_to_use). The proposal row here is
|
|
368
|
-
// bookkeeping for backoff/Reflexion, never the authoritative record of the
|
|
369
|
-
// rejection, so a validator throw degrades to "no row minted" — the same
|
|
370
|
-
// bucket as the fingerprint/backoff skip below, not a caller-visible error.
|
|
371
|
-
// r3-1: the archiveProposal call below is guarded the same way, for the
|
|
372
|
-
// same reason.
|
|
373
|
-
let mintedProposal;
|
|
374
|
-
try {
|
|
375
|
-
mintedProposal = emitProposal({ stashDir: stash, ...(proposalOpts.proposalsCtx ? { proposalsCtx: proposalOpts.proposalsCtx } : {}) }, {
|
|
376
|
-
ref: proposalRef,
|
|
377
|
-
source: "distill",
|
|
378
|
-
...(proposalOpts.sourceRun !== undefined ? { sourceRun: proposalOpts.sourceRun } : {}),
|
|
379
|
-
...(proposalOpts.modelId !== undefined ? { modelId: proposalOpts.modelId } : {}),
|
|
380
|
-
payload: { content },
|
|
381
|
-
...(eligibilitySource ? { eligibilitySource } : {}),
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
catch {
|
|
385
|
-
mintedProposal = undefined;
|
|
386
|
-
}
|
|
387
|
-
let proposal;
|
|
388
|
-
if (mintedProposal && !isProposalSkipped(mintedProposal)) {
|
|
389
|
-
if (outcome === "quality_rejected") {
|
|
390
|
-
try {
|
|
391
|
-
proposal = archiveProposal(stash, mintedProposal.id, "rejected", reason, proposalOpts.proposalsCtx);
|
|
392
|
-
}
|
|
393
|
-
catch (error) {
|
|
394
|
-
warn(`[akm] writeQualityRejection: failed to archive proposal ${mintedProposal.id} as rejected: ${error instanceof Error ? error.message : String(error)}`);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
else {
|
|
398
|
-
proposal = mintedProposal;
|
|
399
|
-
// REVIEW: stamp the mint so the triage drain's `classifyPendingProposals`
|
|
400
|
-
// skips it instead of deferring it to the judgment tier, which could
|
|
401
|
-
// auto-accept it under `applyMode: promote` with no human ever seeing
|
|
402
|
-
// the review-band content the gate explicitly refused to auto-queue.
|
|
403
|
-
// Best-effort like the mint/archive tolerance above: a stamp failure
|
|
404
|
-
// warns and continues rather than blocking the rejection envelope.
|
|
405
|
-
try {
|
|
406
|
-
proposal =
|
|
407
|
-
recordGateDecision(stash, mintedProposal.id, { outcome: "deferred", reason: "quality-review", gate: "quality-gate" }, proposalOpts.proposalsCtx) ?? proposal;
|
|
408
|
-
}
|
|
409
|
-
catch (error) {
|
|
410
|
-
warn(`[akm] writeQualityRejection: failed to stamp gate decision for ${mintedProposal.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
const rejectDir = getDistillRejectedDir(stash);
|
|
415
|
-
fs.mkdirSync(rejectDir, { recursive: true });
|
|
416
|
-
const ts = timestampForFilename();
|
|
417
|
-
const rejectPath = path.join(rejectDir, `${ts}-${proposalRef.replace(/[:/\\]/g, "-")}.md`);
|
|
418
|
-
// R16: surface the judge's per-criterion scores in the envelope frontmatter
|
|
419
|
-
// when the caller supplied them (a judge-based rejection), same as the event.
|
|
420
|
-
const criteria = extraMeta.criteria && typeof extraMeta.criteria === "object" && !Array.isArray(extraMeta.criteria)
|
|
421
|
-
? extraMeta.criteria
|
|
422
|
-
: undefined;
|
|
423
|
-
const criteriaFrontmatter = criteria
|
|
424
|
-
? `criteria:\n${Object.entries(criteria)
|
|
425
|
-
.map(([key, value]) => ` ${key}: ${value}`)
|
|
426
|
-
.join("\n")}\n`
|
|
427
|
-
: "";
|
|
428
|
-
fs.writeFileSync(rejectPath, `---\nscore: ${score}\nreason: ${reason}\noutcome: ${outcome}\n${criteriaFrontmatter}---\n\n${content}`, "utf8");
|
|
429
|
-
// #652 / itlackey/akm#890: journal it even though it now lands under
|
|
430
|
-
// `$STATE`, outside the stash's git repo — `result.writtenPaths` reports
|
|
431
|
-
// every path a run touched, in or out of the stash (describeRunWrittenPaths
|
|
432
|
-
// in improve.ts falls back to the absolute path for anything outside the
|
|
433
|
-
// stash root), and the auto-sync commit's own containment check
|
|
434
|
-
// (resolveSyncPathSet's `relativeWrittenPath`) already drops anything
|
|
435
|
-
// outside `repoDir` from what gets staged — recording it here cannot cause
|
|
436
|
-
// it to be committed.
|
|
437
|
-
recordWrittenPath(rejectPath);
|
|
438
|
-
appendEvent({
|
|
439
|
-
eventType: "distill_invoked",
|
|
440
|
-
ref: inputRef,
|
|
441
|
-
metadata: {
|
|
442
|
-
outcome,
|
|
443
|
-
proposalRef,
|
|
444
|
-
score,
|
|
445
|
-
reason,
|
|
446
|
-
...extraMeta,
|
|
447
|
-
// Attribution tagging: stamp the eligibility lane so distill_invoked can be
|
|
448
|
-
// sliced by lane downstream. See EligibilitySource.
|
|
449
|
-
...(eligibilitySource ? { eligibilitySource } : {}),
|
|
450
|
-
},
|
|
451
|
-
}, eventsCtx);
|
|
452
|
-
return {
|
|
453
|
-
schemaVersion: 1,
|
|
454
|
-
ok: true,
|
|
455
|
-
outcome,
|
|
456
|
-
inputRef,
|
|
457
|
-
proposalRef,
|
|
458
|
-
score,
|
|
459
|
-
reason,
|
|
460
|
-
...(proposal ? { proposalId: proposal.id, proposal } : {}),
|
|
461
|
-
...extraMeta,
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
* G4 — content-score a distilled OUTPUT (lesson/knowledge proposal body) and
|
|
466
|
-
* persist it to state.db :: asset_salience with `encoding_source: "content"`.
|
|
467
|
-
*
|
|
468
|
-
* Lessons are refused as distill INPUTS (`DISTILL_REFUSED_INPUT_TYPES`), so
|
|
469
|
-
* this creation-time write is their only chance to earn a real content-derived
|
|
470
|
-
* encoding score instead of sitting on the type-weight stub forever. Best-effort:
|
|
471
|
-
* never blocks or fails the proposal flow.
|
|
472
|
-
*/
|
|
473
|
-
export function persistOutputEncodingSalience(ref, body, existingRefVocabulary,
|
|
474
|
-
// Operator opt-out (improve.salience.outcomeWeightEnabled: false) must apply
|
|
475
|
-
// here too, or distill-written rank_score rows would use WS-2 weights while
|
|
476
|
-
// preparation uses parity weights — inconsistent salience semantics.
|
|
477
|
-
outcomeWeightEnabled) {
|
|
478
|
-
try {
|
|
479
|
-
const parsedRef = parseRefInput(ref);
|
|
480
|
-
const salienceResult = scoreEncodingSalience({
|
|
481
|
-
body,
|
|
482
|
-
type: parsedRef.type,
|
|
483
|
-
existingRefVocabulary,
|
|
484
|
-
revisionCount: 0, // a freshly distilled output IS a first encounter
|
|
485
|
-
});
|
|
486
|
-
withStateDb((stateDb) => {
|
|
487
|
-
const vector = computeSalience({
|
|
488
|
-
ref,
|
|
489
|
-
type: parsedRef.type,
|
|
490
|
-
retrievalFreq: 0,
|
|
491
|
-
encodingSalience: salienceResult.score,
|
|
492
|
-
outcomeWeightEnabled,
|
|
493
|
-
});
|
|
494
|
-
upsertAssetSalience(stateDb, ref, vector);
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
catch {
|
|
498
|
-
// Best-effort — scoring must never block proposal creation.
|
|
499
|
-
}
|
|
500
|
-
}
|