@evomap/evolver-core 2.0.0-beta.2 → 2.0.0-beta.22
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/assets/gep/genes.jsonl +5 -5
- package/dist/algo/bans.d.ts +10 -1
- package/dist/algo/bans.js +56 -6
- package/dist/algo/candidateAssembly.d.ts +25 -2
- package/dist/algo/candidateAssembly.js +171 -26
- package/dist/algo/capabilityCandidates.js +10 -0
- package/dist/algo/conversationSniffer.js +25 -8
- package/dist/algo/cycleEngine.d.ts +63 -5
- package/dist/algo/cycleEngine.js +320 -42
- package/dist/algo/cycleFailureClassifier.d.ts +1 -1
- package/dist/algo/evolutionEvent.d.ts +26 -0
- package/dist/algo/evolutionEvent.js +32 -0
- package/dist/algo/exploration.d.ts +7 -0
- package/dist/algo/exploration.js +16 -3
- package/dist/algo/geneHealth.d.ts +36 -3
- package/dist/algo/geneHealth.js +47 -4
- package/dist/algo/geneIntake.d.ts +46 -1
- package/dist/algo/geneIntake.js +121 -10
- package/dist/algo/geneSelection.d.ts +126 -6
- package/dist/algo/geneSelection.js +479 -36
- package/dist/algo/index.d.ts +6 -1
- package/dist/algo/index.js +6 -1
- package/dist/algo/kautoProjection.d.ts +41 -0
- package/dist/algo/kautoProjection.js +95 -0
- package/dist/algo/kautoValidator.d.ts +68 -0
- package/dist/algo/kautoValidator.js +256 -0
- package/dist/algo/memoryGraph.d.ts +62 -0
- package/dist/algo/memoryGraph.js +86 -0
- package/dist/algo/orchestrator.d.ts +17 -1
- package/dist/algo/orchestrator.js +30 -4
- package/dist/algo/publishEligibility.d.ts +34 -0
- package/dist/algo/publishEligibility.js +52 -0
- package/dist/algo/solidify.d.ts +11 -2
- package/dist/algo/solidify.js +37 -7
- package/dist/algo/ucb1.d.ts +53 -0
- package/dist/algo/ucb1.js +156 -0
- package/dist/assetrepair/hubRejection.d.ts +12 -0
- package/dist/assetrepair/hubRejection.js +109 -0
- package/dist/assetrepair/index.d.ts +2 -0
- package/dist/assetrepair/index.js +2 -0
- package/dist/assetrepair/repair.d.ts +33 -0
- package/dist/assetrepair/repair.js +155 -0
- package/dist/assetstore/assetSidecarRecords.d.ts +28 -0
- package/dist/assetstore/assetSidecarRecords.js +384 -0
- package/dist/assetstore/assetSidecarRecovery.d.ts +48 -0
- package/dist/assetstore/assetSidecarRecovery.js +288 -0
- package/dist/assetstore/assetStoreHealth.d.ts +81 -0
- package/dist/assetstore/assetStoreHealth.js +319 -0
- package/dist/assetstore/assetStoreLayout.d.ts +2 -0
- package/dist/assetstore/assetStoreLayout.js +6 -0
- package/dist/assetstore/assetStoreStorage.d.ts +42 -0
- package/dist/assetstore/assetStoreStorage.js +336 -0
- package/dist/assetstore/assetSyncLedger.d.ts +91 -1
- package/dist/assetstore/assetSyncLedger.js +718 -59
- package/dist/assetstore/foreignJsonlSource.d.ts +48 -0
- package/dist/assetstore/foreignJsonlSource.js +150 -0
- package/dist/assetstore/index.d.ts +5 -0
- package/dist/assetstore/index.js +5 -0
- package/dist/assetstore/learningHistory.js +3 -3
- package/dist/assetstore/localAssetStoreSnapshot.d.ts +51 -0
- package/dist/assetstore/localAssetStoreSnapshot.js +329 -0
- package/dist/assetstore/localJsonl.d.ts +12 -1
- package/dist/assetstore/localJsonl.js +251 -42
- package/dist/assetstore/provenance.d.ts +93 -4
- package/dist/assetstore/provenance.js +368 -84
- package/dist/assetstore/provider.d.ts +63 -0
- package/dist/assetstore/provider.js +97 -6
- package/dist/assetstore/reviewFilter.d.ts +19 -1
- package/dist/assetstore/reviewFilter.js +39 -1
- package/dist/assetstore/reviewLedger.d.ts +8 -2
- package/dist/assetstore/reviewLedger.js +71 -45
- package/dist/assetstore/unionReadStore.d.ts +25 -0
- package/dist/assetstore/unionReadStore.js +119 -0
- package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
- package/dist/benchmark/antiGeneBenchmark.js +4 -3
- package/dist/benchmark/antiGeneRollout.d.ts +2 -0
- package/dist/benchmark/antiGeneRollout.js +4 -3
- package/dist/benchmark/index.d.ts +3 -1
- package/dist/benchmark/index.js +3 -1
- package/dist/benchmark/selectionFlatAbstention.d.ts +152 -0
- package/dist/benchmark/selectionFlatAbstention.js +481 -0
- package/dist/benchmark/triggerShift.d.ts +62 -0
- package/dist/benchmark/triggerShift.js +106 -0
- package/dist/bootstrap/envFingerprint.d.ts +9 -0
- package/dist/bootstrap/envFingerprint.js +5 -0
- package/dist/bootstrap/index.d.ts +3 -1
- package/dist/bootstrap/index.js +3 -1
- package/dist/bootstrap/lifecycleBootstrap.d.ts +111 -0
- package/dist/bootstrap/lifecycleBootstrap.js +433 -0
- package/dist/bootstrap/v1EnvCompat.d.ts +113 -0
- package/dist/bootstrap/v1EnvCompat.js +303 -0
- package/dist/events/eventArchive.d.ts +2 -0
- package/dist/events/eventArchive.js +13 -3
- package/dist/events/eventSchema.d.ts +7 -7
- package/dist/events/eventStore.d.ts +2 -0
- package/dist/events/eventStore.js +5 -1
- package/dist/events/ingest.d.ts +2 -1
- package/dist/events/ingest.js +15 -0
- package/dist/events/paths.d.ts +12 -10
- package/dist/events/paths.js +24 -20
- package/dist/events/public.d.ts +2 -2
- package/dist/events/public.js +2 -2
- package/dist/events/reports.d.ts +2 -0
- package/dist/events/reports.js +4 -0
- package/dist/exec/autoExec.d.ts +68 -4
- package/dist/exec/autoExec.js +392 -33
- package/dist/exec/autonomousCycle.d.ts +31 -4
- package/dist/exec/autonomousCycle.js +71 -13
- package/dist/exec/claudeBridge.d.ts +80 -15
- package/dist/exec/claudeBridge.js +845 -76
- package/dist/exec/executionBinding.d.ts +414 -0
- package/dist/exec/executionBinding.js +588 -0
- package/dist/exec/index.d.ts +1 -0
- package/dist/exec/index.js +1 -0
- package/dist/exec/openPrRegistry.d.ts +8 -2
- package/dist/exec/openPrRegistry.js +32 -22
- package/dist/exec/prompt.js +14 -1
- package/dist/exec/proofOfWork.d.ts +1 -1
- package/dist/exec/proofOfWork.js +2 -2
- package/dist/exec/runnerRegistry.d.ts +153 -36
- package/dist/exec/runnerRegistry.js +848 -65
- package/dist/exec/selfPr.js +1 -7
- package/dist/feedback/envelope.d.ts +61 -0
- package/dist/feedback/envelope.js +168 -0
- package/dist/feedback/index.d.ts +1 -0
- package/dist/feedback/index.js +1 -0
- package/dist/hooks/hooks.js +1 -0
- package/dist/hub/assetCallLog.d.ts +35 -1
- package/dist/hub/assetCallLog.js +124 -1
- package/dist/hub/bindings.d.ts +8 -1
- package/dist/hub/bindings.js +29 -8
- package/dist/hub/capability.d.ts +130 -4
- package/dist/hub/conversationDistiller.d.ts +19 -0
- package/dist/hub/conversationDistiller.js +115 -37
- package/dist/hub/fake.d.ts +3 -2
- package/dist/hub/fake.js +2 -1
- package/dist/hub/index.d.ts +1 -0
- package/dist/hub/index.js +1 -0
- package/dist/hub/questionGenerator.d.ts +5 -1
- package/dist/hub/questionGenerator.js +8 -6
- package/dist/hub/recipeCompose.d.ts +27 -0
- package/dist/hub/recipeCompose.js +90 -0
- package/dist/hub/sanitize.js +122 -7
- package/dist/index.d.ts +6 -1
- package/dist/index.js +7 -1
- package/dist/issueReporter/index.d.ts +156 -0
- package/dist/issueReporter/index.js +1688 -0
- package/dist/mailbox/dispatch.d.ts +1 -1
- package/dist/mailbox/dispatch.js +22 -6
- package/dist/mailbox/envelope.d.ts +7 -1
- package/dist/mailbox/envelope.js +9 -2
- package/dist/mailbox/ipcServer.d.ts +12 -2
- package/dist/mailbox/ipcServer.js +183 -13
- package/dist/mailbox/store.d.ts +89 -3
- package/dist/mailbox/store.js +895 -41
- package/dist/modelCompatibility.d.ts +164 -0
- package/dist/modelCompatibility.js +309 -0
- package/dist/observers/valueDigestObserver.d.ts +9 -0
- package/dist/observers/valueDigestObserver.js +35 -2
- package/dist/ops/cleanup.js +1 -1
- package/dist/ops/evolutionGraphProjection.d.ts +20 -0
- package/dist/ops/evolutionGraphProjection.js +315 -0
- package/dist/ops/index.d.ts +2 -1
- package/dist/ops/index.js +2 -1
- package/dist/ops/savingsCore.js +1 -2
- package/dist/ops/selfUpdate.d.ts +18 -1
- package/dist/ops/selfUpdate.js +88 -23
- package/dist/ops/valueOutreach.d.ts +3 -1
- package/dist/ops/valueOutreach.js +5 -1
- package/dist/personality/schema.d.ts +24 -24
- package/dist/schema/evolutionGraph.d.ts +784 -0
- package/dist/schema/evolutionGraph.js +187 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/proofOfWork.d.ts +125 -6
- package/dist/schema/proofOfWork.js +102 -4
- package/dist/schema/signal.d.ts +3 -3
- package/dist/schema/signal.js +1 -1
- package/dist/shadow/shadowHub.js +1 -0
- package/dist/signals/curriculum.d.ts +55 -0
- package/dist/signals/curriculum.js +202 -0
- package/dist/signals/cycleHistoryFromEvents.js +17 -8
- package/dist/signals/expand.d.ts +15 -1
- package/dist/signals/expand.js +169 -1
- package/dist/signals/extractor.d.ts +2 -2
- package/dist/signals/extractor.js +31 -6
- package/dist/signals/index.d.ts +4 -1
- package/dist/signals/index.js +4 -1
- package/dist/signals/metaSignals.d.ts +4 -0
- package/dist/signals/metaSignals.js +42 -0
- package/dist/signals/scopeVocabulary.d.ts +75 -0
- package/dist/signals/scopeVocabulary.js +91 -0
- package/dist/signals/signalGate.js +1 -1
- package/dist/signals/taskDomain.d.ts +22 -0
- package/dist/signals/taskDomain.js +43 -0
- package/dist/strategy/constraintAblation.d.ts +64 -0
- package/dist/strategy/constraintAblation.js +2820 -0
- package/dist/strategy/constraintAblationPredicates.d.ts +31 -0
- package/dist/strategy/constraintAblationPredicates.js +339 -0
- package/dist/strategy/index.d.ts +2 -1
- package/dist/strategy/index.js +2 -1
- package/dist/trace/index.d.ts +3 -1
- package/dist/trace/index.js +3 -1
- package/dist/trace/learningTrace.d.ts +216 -0
- package/dist/trace/learningTrace.js +298 -0
- package/dist/trace/proxyTurns.d.ts +31 -0
- package/dist/trace/proxyTurns.js +137 -0
- package/dist/trace/trajectory.d.ts +8 -0
- package/dist/trace/trajectory.js +14 -2
- package/dist/util/fetchPort.d.ts +1 -0
- package/dist/util/fetchPort.js +11 -0
- package/dist/util/fileLock.d.ts +113 -7
- package/dist/util/fileLock.js +1035 -80
- package/dist/util/index.d.ts +3 -1
- package/dist/util/index.js +2 -1
- package/dist/verify/index.d.ts +2 -1
- package/dist/verify/index.js +1 -1
- package/dist/verify/sandboxRunner.d.ts +30 -0
- package/dist/verify/sandboxRunner.js +370 -27
- package/dist/verify/sandboxedValidation.d.ts +16 -2
- package/dist/verify/sandboxedValidation.js +200 -22
- package/dist/verify/validation.d.ts +35 -4
- package/dist/verify/validation.js +164 -16
- package/dist/wire/geneHints.d.ts +88 -16
- package/dist/wire/geneHints.js +124 -15
- package/dist/wire/index.d.ts +8 -3
- package/dist/wire/index.js +2 -2
- package/dist/wire/schemaGate.d.ts +21 -0
- package/dist/wire/schemaGate.js +119 -10
- package/dist/workflow/dsl.d.ts +24 -3
- package/dist/workflow/dsl.js +4 -0
- package/dist/workflow/engine.d.ts +5 -1
- package/dist/workflow/engine.js +3 -0
- package/dist/workflow/index.d.ts +3 -1
- package/dist/workflow/index.js +3 -1
- package/dist/workflow/runtime.d.ts +110 -0
- package/dist/workflow/runtime.js +1298 -0
- package/dist/workflow/stateStore.d.ts +172 -0
- package/dist/workflow/stateStore.js +1044 -0
- package/package.json +12 -4
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SelectionPolicy, Ucb1History } from './ucb1.js';
|
|
1
2
|
export type PlateauSeverity = 'suggested' | 'required';
|
|
2
3
|
export interface PlateauState {
|
|
3
4
|
active: boolean;
|
|
@@ -6,12 +7,16 @@ export interface PlateauState {
|
|
|
6
7
|
}
|
|
7
8
|
/** Exploration control fed into selection. Absent → pure deterministic top-score selection. */
|
|
8
9
|
export interface ExplorationInput {
|
|
10
|
+
/** Selection policy requested by the composition layer. Default preserves legacy engine-health + drift. */
|
|
11
|
+
policy?: SelectionPolicy;
|
|
9
12
|
/** Force drift on even without a plateau (e.g. an explicit explore policy). */
|
|
10
13
|
driftEnabled?: boolean;
|
|
11
14
|
/** Plateau detected upstream; an active plateau forces drift intensity up. */
|
|
12
15
|
plateau?: PlateauState;
|
|
13
16
|
/** Total attempts across the candidate pool (drives the maturity decay of the drift offset). */
|
|
14
17
|
totalAttempts?: number;
|
|
18
|
+
/** Event-log-derived state for UCB1. Undefined means fail-safe to legacy drift. */
|
|
19
|
+
ucb1History?: Ucb1History;
|
|
15
20
|
}
|
|
16
21
|
/**
|
|
17
22
|
* Adaptive drift intensity (ported v1): 1/sqrt(Ne) + an offset that decays from 0.3 → 0.02 as the pool
|
|
@@ -25,6 +30,8 @@ export interface DriftDecision {
|
|
|
25
30
|
index: number;
|
|
26
31
|
intensity: number;
|
|
27
32
|
}
|
|
33
|
+
/** Deterministic top-N window shared by legacy random drift and UCB1. */
|
|
34
|
+
export declare function explorationWindowSize(eligibleCount: number, exp: ExplorationInput | undefined): number;
|
|
28
35
|
/**
|
|
29
36
|
* Pick which ranked candidate to take among `eligibleCount` above-floor candidates.
|
|
30
37
|
* No exploration → deterministic top (index 0). With exploration → compute intensity (an active plateau
|
package/dist/algo/exploration.js
CHANGED
|
@@ -15,8 +15,9 @@ const PLATEAU_FORCE = 10;
|
|
|
15
15
|
export function computeDriftIntensity(ne, totalAttempts = 0) {
|
|
16
16
|
if (!Number.isFinite(ne) || ne <= 1)
|
|
17
17
|
return 0.7;
|
|
18
|
+
const attempts = Number.isFinite(totalAttempts) ? Math.max(0, totalAttempts) : 0;
|
|
18
19
|
const maturityThreshold = ne * MATURITY_ATTEMPTS_PER_GENE;
|
|
19
|
-
const maturity = maturityThreshold > 0 ? Math.min(1,
|
|
20
|
+
const maturity = maturityThreshold > 0 ? Math.min(1, attempts / maturityThreshold) : 0;
|
|
20
21
|
const offset = DRIFT_OFFSET_MAX - (DRIFT_OFFSET_MAX - DRIFT_OFFSET_MIN) * maturity;
|
|
21
22
|
return Math.min(1, 1 / Math.sqrt(ne) + offset);
|
|
22
23
|
}
|
|
@@ -34,6 +35,18 @@ export function detectPlateau(recentOutcomes) {
|
|
|
34
35
|
return { active: true, severity: 'suggested', count };
|
|
35
36
|
return { active: false, severity: 'suggested', count };
|
|
36
37
|
}
|
|
38
|
+
function explorationActive(exp) {
|
|
39
|
+
return Boolean(exp && (exp.driftEnabled || exp.plateau?.active));
|
|
40
|
+
}
|
|
41
|
+
/** Deterministic top-N window shared by legacy random drift and UCB1. */
|
|
42
|
+
export function explorationWindowSize(eligibleCount, exp) {
|
|
43
|
+
if (!explorationActive(exp) || eligibleCount <= 1)
|
|
44
|
+
return Math.min(1, Math.max(0, eligibleCount));
|
|
45
|
+
let intensity = computeDriftIntensity(eligibleCount, exp.totalAttempts ?? 0);
|
|
46
|
+
if (exp.plateau?.active)
|
|
47
|
+
intensity = Math.max(intensity, exp.plateau.severity === 'required' ? 1.0 : 0.7);
|
|
48
|
+
return Math.min(eligibleCount, Math.max(2, Math.ceil(eligibleCount * intensity)));
|
|
49
|
+
}
|
|
37
50
|
/**
|
|
38
51
|
* Pick which ranked candidate to take among `eligibleCount` above-floor candidates.
|
|
39
52
|
* No exploration → deterministic top (index 0). With exploration → compute intensity (an active plateau
|
|
@@ -41,7 +54,7 @@ export function detectPlateau(recentOutcomes) {
|
|
|
41
54
|
* with intensity). rng() is called at most twice; pass a seeded rng for deterministic tests.
|
|
42
55
|
*/
|
|
43
56
|
export function driftSelect(eligibleCount, exp, rng) {
|
|
44
|
-
if (!
|
|
57
|
+
if (!explorationActive(exp) || eligibleCount <= 1) {
|
|
45
58
|
return { driftMode: 'deterministic', index: 0, intensity: 0 };
|
|
46
59
|
}
|
|
47
60
|
let intensity = computeDriftIntensity(eligibleCount, exp.totalAttempts ?? 0);
|
|
@@ -49,7 +62,7 @@ export function driftSelect(eligibleCount, exp, rng) {
|
|
|
49
62
|
intensity = Math.max(intensity, exp.plateau.severity === 'required' ? 1.0 : 0.7);
|
|
50
63
|
if (rng() >= intensity)
|
|
51
64
|
return { driftMode: 'deterministic', index: 0, intensity };
|
|
52
|
-
const topN =
|
|
65
|
+
const topN = explorationWindowSize(eligibleCount, exp);
|
|
53
66
|
const index = Math.min(topN - 1, Math.max(0, Math.floor(rng() * topN)));
|
|
54
67
|
return { driftMode: exp.plateau?.active ? 'plateau_drift' : 'drift', index, intensity };
|
|
55
68
|
}
|
|
@@ -12,13 +12,46 @@ export interface GeneHealthWeights {
|
|
|
12
12
|
reuse: number;
|
|
13
13
|
antiPattern: number;
|
|
14
14
|
}
|
|
15
|
-
export declare const HEALTH_WEIGHTS_VERSION = "gh-
|
|
15
|
+
export declare const HEALTH_WEIGHTS_VERSION = "gh-2";
|
|
16
16
|
export declare const DEFAULT_HEALTH_WEIGHTS: GeneHealthWeights;
|
|
17
17
|
/**
|
|
18
|
-
* gene 健康分 = w1
|
|
18
|
+
* gene 健康分 = successRate·(w1 + w2·reuse归一) − w3·antiPattern密度.
|
|
19
19
|
* 输入 = M3-6 聚合视图(不内联 learning_history) + anti_patterns 数 + 复用计数.
|
|
20
20
|
*/
|
|
21
21
|
export declare function geneHealthScore(view: GeneLearningView, opts?: {
|
|
22
22
|
reuseCount?: number;
|
|
23
23
|
antiPatternCount?: number;
|
|
24
|
-
}, w?: GeneHealthWeights): GeneHealth;
|
|
24
|
+
}, w?: GeneHealthWeights): GeneHealth;
|
|
25
|
+
/**
|
|
26
|
+
* Whether a gene has any DECISIVE evidence behind its health score.
|
|
27
|
+
*
|
|
28
|
+
* `aggregateLearningHistory` divides successes by `success + failed`, excluding inert runs from both
|
|
29
|
+
* sides, so a gene whose capsules are all inert — or which has never run — yields `successRate = 0` and
|
|
30
|
+
* therefore `score = 0`. That zero means "nothing is known", not "known to be bad", and the two must not
|
|
31
|
+
* render the same: showing 0% for an unproven gene is the same class of lie as showing a self-reported
|
|
32
|
+
* 98%. A surface reporting a score must check this first and say "not assessed" when it is false.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isGeneHealthAssessable(view: Pick<GeneLearningView, 'success' | 'failed'>): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* The best score {@link geneHealthScore} can return under `w`: a gene with a perfect success rate, reuse
|
|
37
|
+
* saturated, and no anti-patterns. Derived from the weights rather than hard-coded, so retuning them
|
|
38
|
+
* cannot silently leave the display scale calibrated to the old ceiling.
|
|
39
|
+
*/
|
|
40
|
+
export declare function geneHealthScoreCeiling(w?: GeneHealthWeights): number;
|
|
41
|
+
/**
|
|
42
|
+
* Map a raw health score onto [0, 1] for DISPLAY only.
|
|
43
|
+
*
|
|
44
|
+
* `geneHealthScore` is not a 0–1 quantity: under the default weights it tops out at 0.7 and floors at
|
|
45
|
+
* -0.4 (the anti-pattern penalty). Rendering the raw number as a percentage would report a flawless gene
|
|
46
|
+
* as 70%, so any surface showing a percentage has to rescale — and doing that at each surface is how two
|
|
47
|
+
* surfaces end up disagreeing.
|
|
48
|
+
*
|
|
49
|
+
* Negative scores clamp to 0 rather than mapping the full [-ceiling_penalty, ceiling] range onto [0, 1]:
|
|
50
|
+
* a linear map would place "no evidence at all" (raw 0) near the middle of the bar, which reads as a
|
|
51
|
+
* passing grade for a gene that has proven nothing. The penalty is not lost, it is just not separately
|
|
52
|
+
* legible below zero — callers that need it read `GeneHealth.score` / `antiPatternPenalty` directly.
|
|
53
|
+
*
|
|
54
|
+
* Never feed this back into selection: ranking consumes the raw score, and clamping there would make
|
|
55
|
+
* every penalized gene tie at 0.
|
|
56
|
+
*/
|
|
57
|
+
export declare function normalizeGeneHealthScore(score: number, w?: GeneHealthWeights): number;
|
package/dist/algo/geneHealth.js
CHANGED
|
@@ -1,16 +1,59 @@
|
|
|
1
|
-
export const HEALTH_WEIGHTS_VERSION = 'gh-
|
|
2
|
-
export const DEFAULT_HEALTH_WEIGHTS = { successRate: 0.6, reuse: 0.
|
|
1
|
+
export const HEALTH_WEIGHTS_VERSION = 'gh-2';
|
|
2
|
+
export const DEFAULT_HEALTH_WEIGHTS = { successRate: 0.6, reuse: 0.1, antiPattern: 0.4 };
|
|
3
3
|
/** reuseCount 归一(对数压缩, 复用越多分越高但边际递减). */
|
|
4
4
|
function reuseScore(count) {
|
|
5
5
|
return count <= 0 ? 0 : Math.min(1, Math.log10(count + 1) / 2); // 100 次≈封顶
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* gene 健康分 = w1
|
|
8
|
+
* gene 健康分 = successRate·(w1 + w2·reuse归一) − w3·antiPattern密度.
|
|
9
9
|
* 输入 = M3-6 聚合视图(不内联 learning_history) + anti_patterns 数 + 复用计数.
|
|
10
10
|
*/
|
|
11
11
|
export function geneHealthScore(view, opts = {}, w = DEFAULT_HEALTH_WEIGHTS) {
|
|
12
12
|
const reuseCount = opts.reuseCount ?? view.total;
|
|
13
13
|
const antiPatternPenalty = Math.min(1, (opts.antiPatternCount ?? 0) / 5); // 5+ anti-pattern 封顶惩罚
|
|
14
|
-
const
|
|
14
|
+
const confidenceAdjustedSuccess = view.successRate * (w.successRate + w.reuse * reuseScore(reuseCount));
|
|
15
|
+
const score = confidenceAdjustedSuccess - w.antiPattern * antiPatternPenalty;
|
|
15
16
|
return { geneId: view.geneId, successRate: view.successRate, reuseCount, antiPatternPenalty, score };
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Whether a gene has any DECISIVE evidence behind its health score.
|
|
20
|
+
*
|
|
21
|
+
* `aggregateLearningHistory` divides successes by `success + failed`, excluding inert runs from both
|
|
22
|
+
* sides, so a gene whose capsules are all inert — or which has never run — yields `successRate = 0` and
|
|
23
|
+
* therefore `score = 0`. That zero means "nothing is known", not "known to be bad", and the two must not
|
|
24
|
+
* render the same: showing 0% for an unproven gene is the same class of lie as showing a self-reported
|
|
25
|
+
* 98%. A surface reporting a score must check this first and say "not assessed" when it is false.
|
|
26
|
+
*/
|
|
27
|
+
export function isGeneHealthAssessable(view) {
|
|
28
|
+
return view.success + view.failed >= 1;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The best score {@link geneHealthScore} can return under `w`: a gene with a perfect success rate, reuse
|
|
32
|
+
* saturated, and no anti-patterns. Derived from the weights rather than hard-coded, so retuning them
|
|
33
|
+
* cannot silently leave the display scale calibrated to the old ceiling.
|
|
34
|
+
*/
|
|
35
|
+
export function geneHealthScoreCeiling(w = DEFAULT_HEALTH_WEIGHTS) {
|
|
36
|
+
return w.successRate + w.reuse;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Map a raw health score onto [0, 1] for DISPLAY only.
|
|
40
|
+
*
|
|
41
|
+
* `geneHealthScore` is not a 0–1 quantity: under the default weights it tops out at 0.7 and floors at
|
|
42
|
+
* -0.4 (the anti-pattern penalty). Rendering the raw number as a percentage would report a flawless gene
|
|
43
|
+
* as 70%, so any surface showing a percentage has to rescale — and doing that at each surface is how two
|
|
44
|
+
* surfaces end up disagreeing.
|
|
45
|
+
*
|
|
46
|
+
* Negative scores clamp to 0 rather than mapping the full [-ceiling_penalty, ceiling] range onto [0, 1]:
|
|
47
|
+
* a linear map would place "no evidence at all" (raw 0) near the middle of the bar, which reads as a
|
|
48
|
+
* passing grade for a gene that has proven nothing. The penalty is not lost, it is just not separately
|
|
49
|
+
* legible below zero — callers that need it read `GeneHealth.score` / `antiPatternPenalty` directly.
|
|
50
|
+
*
|
|
51
|
+
* Never feed this back into selection: ranking consumes the raw score, and clamping there would make
|
|
52
|
+
* every penalized gene tie at 0.
|
|
53
|
+
*/
|
|
54
|
+
export function normalizeGeneHealthScore(score, w = DEFAULT_HEALTH_WEIGHTS) {
|
|
55
|
+
const ceiling = geneHealthScoreCeiling(w);
|
|
56
|
+
if (!Number.isFinite(score) || ceiling <= 0)
|
|
57
|
+
return 0;
|
|
58
|
+
return Math.min(1, Math.max(0, score / ceiling));
|
|
16
59
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Gene, type GenerationSource } from '../wire/index.js';
|
|
1
|
+
import { type EnvClass, type Gene, type GeneClaim, type GeneRuntimeProfile, type GeneScope, type GeneVerifierProfile, type GenerationSource } from '../wire/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* True when a gene id is in the `gene_distilled_` namespace. NB this prefix is now a NAMESPACE marker, NOT a
|
|
4
4
|
* provenance tag: v1 used it to mean "skill-derived" (auto-evolved genes were `gene_auto_`), but v2's intakeGene
|
|
@@ -26,9 +26,27 @@ export interface GeneCandidate {
|
|
|
26
26
|
forbidden_paths?: readonly string[];
|
|
27
27
|
};
|
|
28
28
|
validation?: readonly string[];
|
|
29
|
+
/**
|
|
30
|
+
* Runtime profile: which LLM produced this gene. This is the \(K_{auto}\) runtime coordinate, and it was the
|
|
31
|
+
* binding constraint on automatic-governance eligibility in production (32.9% populated vs 99%+ for the
|
|
32
|
+
* retrieval coordinates, bench/thesis/result-kauto-coverage.json) — because intake never populated it, so it
|
|
33
|
+
* only appeared when some other writer happened to set it. Intake now fills it from the SAME producer the
|
|
34
|
+
* environment fingerprint already uses (detectModelName), which resolves an explicit EVOLVER_MODEL_NAME or a
|
|
35
|
+
* host CLI's model env var. Callers may pass it explicitly to override detection.
|
|
36
|
+
*
|
|
37
|
+
* The literal 'unknown' is what detectModelName returns when nothing is discoverable, and it is deliberately
|
|
38
|
+
* NOT written: an undetectable runtime is not a machine-decidable coordinate, and recording 'unknown' would
|
|
39
|
+
* inflate K_auto coverage with rows that cannot actually be governed by runtime. Absent therefore keeps its
|
|
40
|
+
* existing meaning (not recorded), and a present value always names a real runtime.
|
|
41
|
+
*/
|
|
42
|
+
model_name?: string;
|
|
29
43
|
routing_hint?: unknown;
|
|
30
44
|
tool_policy?: unknown;
|
|
31
45
|
generation_meta?: unknown;
|
|
46
|
+
claims?: unknown;
|
|
47
|
+
scope?: unknown;
|
|
48
|
+
runtime_profile?: unknown;
|
|
49
|
+
verifier_profile?: unknown;
|
|
32
50
|
}
|
|
33
51
|
/** Minimal shape of an existing gene needed for dedup. */
|
|
34
52
|
export interface ExistingGeneRef {
|
|
@@ -40,6 +58,33 @@ export interface GeneIntakeResult {
|
|
|
40
58
|
gene?: Gene;
|
|
41
59
|
errors: string[];
|
|
42
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Map free-text retrieval signals into the closed constraint language so scope containment is decidable.
|
|
63
|
+
* Already-namespaced terms and version intervals pass through; bare tokens become `capability:<token>`.
|
|
64
|
+
* Hard facets (`required:…`) keep the marker around the namespaced term.
|
|
65
|
+
*/
|
|
66
|
+
export declare function namespaceScopeSignals(signals: readonly string[]): string[];
|
|
67
|
+
/** Detect a coarse env_class for runtime_profile from process env (CI → ci, else local). */
|
|
68
|
+
export declare function detectEnvClass(env?: NodeJS.ProcessEnv): EnvClass;
|
|
69
|
+
/**
|
|
70
|
+
* Honest defaults for K_auto coordinates the producer did not state. Never invents a coordinate from
|
|
71
|
+
* nothing: each default is grounded in fields the gene already carries (signals, model, validation).
|
|
72
|
+
*/
|
|
73
|
+
export declare function deriveDefaultKautoCoordinates(input: {
|
|
74
|
+
signals: readonly string[];
|
|
75
|
+
modelName?: string;
|
|
76
|
+
validation: readonly string[];
|
|
77
|
+
claims?: GeneClaim[] | null;
|
|
78
|
+
scope?: GeneScope | null;
|
|
79
|
+
runtime_profile?: GeneRuntimeProfile | null;
|
|
80
|
+
verifier_profile?: GeneVerifierProfile | null;
|
|
81
|
+
env?: NodeJS.ProcessEnv;
|
|
82
|
+
}): {
|
|
83
|
+
claims: GeneClaim[] | null;
|
|
84
|
+
scope: GeneScope | null;
|
|
85
|
+
runtime_profile: GeneRuntimeProfile | null;
|
|
86
|
+
verifier_profile: GeneVerifierProfile | null;
|
|
87
|
+
};
|
|
43
88
|
/**
|
|
44
89
|
* Validate + normalize a distilled/proposed gene for pool insertion. On success returns the canonical Gene
|
|
45
90
|
* (defaults filled, asset_id computed); otherwise the structural / dedup / schema errors.
|
package/dist/algo/geneIntake.js
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
// signals fully overlap an existing one (dedup, so the pool does not grow redundant). The gene's CONTENT
|
|
6
6
|
// is generated upstream (the agent runtime / a distillation prompt — generative, out of core scope); this
|
|
7
7
|
// slice is the structural gate. Pairs with capabilityCandidates (which proposes what to distill).
|
|
8
|
-
import {
|
|
8
|
+
import { detectModelName } from '../bootstrap/envFingerprint.js';
|
|
9
|
+
import { computeAssetId, validateWire, SCHEMA_VERSION, normalizeRoutingHint, normalizeToolPolicy, normalizeGenerationMeta, normalizeClaims, normalizeGeneScope, normalizeRuntimeProfile, normalizeVerifierProfile, stripGeneHints, ENV_CLASSES, } from '../wire/index.js';
|
|
9
10
|
const VALID_CATEGORIES = ['repair', 'optimize', 'innovate', 'explore'];
|
|
10
11
|
const DEFAULT_FORBIDDEN_PATHS = ['.git', 'node_modules'];
|
|
11
12
|
const DEFAULT_MAX_FILES = 12;
|
|
12
13
|
/** Id prefix every distilled (skill-derived) gene carries. Recognised via {@link isDistilledGeneId}. */
|
|
13
14
|
const DISTILLED_ID_PREFIX = 'gene_distilled_';
|
|
15
|
+
const LEGACY_CONVERSATION_ID_PREFIX = 'gene_conversation_';
|
|
14
16
|
/**
|
|
15
17
|
* True when a gene id is in the `gene_distilled_` namespace. NB this prefix is now a NAMESPACE marker, NOT a
|
|
16
18
|
* provenance tag: v1 used it to mean "skill-derived" (auto-evolved genes were `gene_auto_`), but v2's intakeGene
|
|
@@ -51,7 +53,84 @@ function fnv1a(s) {
|
|
|
51
53
|
}
|
|
52
54
|
return (h >>> 0).toString(16).padStart(8, '0');
|
|
53
55
|
}
|
|
56
|
+
const nonEmptyModel = (v) => {
|
|
57
|
+
const t = (v ?? '').trim();
|
|
58
|
+
return t.length > 0 ? t.slice(0, 100) : undefined;
|
|
59
|
+
};
|
|
54
60
|
const clean = (xs) => (xs ?? []).map((s) => String(s).trim()).filter((s) => s.length > 0);
|
|
61
|
+
/** Already-namespaced closed-constraint scope terms (kautoValidator.SCOPE_TERM prefixes). */
|
|
62
|
+
const NAMESPACED_SCOPE = /^(?:repo|lineage|pkg|lang|framework|capability|tool|model|time|env):[A-Za-z0-9._@/:-]+$/;
|
|
63
|
+
const VERSION_INTERVAL_SCOPE = /^[A-Za-z0-9._-]+@(?:[><=^~]{1,2})?\d[\w.*-]*(?:\s*-\s*\d[\w.*-]*)?$/;
|
|
64
|
+
const PLACEHOLDER_VERIFIER = /^(?:node|python3?|ruby|deno|bun|go|java|npm|pnpm|yarn)\s+(?:--?v(?:ersion)?|-V)\s*$/i;
|
|
65
|
+
const TRIVIAL_VERIFIER = /^(?:true|:|echo\b.*|exit\s+0)\s*$/i;
|
|
66
|
+
/**
|
|
67
|
+
* Map free-text retrieval signals into the closed constraint language so scope containment is decidable.
|
|
68
|
+
* Already-namespaced terms and version intervals pass through; bare tokens become `capability:<token>`.
|
|
69
|
+
* Hard facets (`required:…`) keep the marker around the namespaced term.
|
|
70
|
+
*/
|
|
71
|
+
export function namespaceScopeSignals(signals) {
|
|
72
|
+
const out = [];
|
|
73
|
+
for (const raw of signals) {
|
|
74
|
+
const t = String(raw ?? '').trim();
|
|
75
|
+
if (!t)
|
|
76
|
+
continue;
|
|
77
|
+
const required = t.startsWith('required:');
|
|
78
|
+
const bare = required ? t.slice('required:'.length).trim() : t;
|
|
79
|
+
if (!bare)
|
|
80
|
+
continue;
|
|
81
|
+
const namespaced = (NAMESPACED_SCOPE.test(bare) || VERSION_INTERVAL_SCOPE.test(bare))
|
|
82
|
+
? bare
|
|
83
|
+
: `capability:${bare.replace(/[^A-Za-z0-9._@/-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 80)}`;
|
|
84
|
+
if (!namespaced || namespaced === 'capability:')
|
|
85
|
+
continue;
|
|
86
|
+
out.push(required ? `required:${namespaced}` : namespaced);
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
/** Detect a coarse env_class for runtime_profile from process env (CI → ci, else local). */
|
|
91
|
+
export function detectEnvClass(env = process.env) {
|
|
92
|
+
const truthy = (v) => {
|
|
93
|
+
const t = (v ?? '').trim().toLowerCase();
|
|
94
|
+
return t !== '' && t !== '0' && t !== 'false' && t !== 'no';
|
|
95
|
+
};
|
|
96
|
+
if (truthy(env['CI']) || truthy(env['GITHUB_ACTIONS']) || truthy(env['GITLAB_CI'])
|
|
97
|
+
|| truthy(env['BUILDKITE']) || truthy(env['CIRCLECI']) || truthy(env['TRAVIS'])) {
|
|
98
|
+
return 'ci';
|
|
99
|
+
}
|
|
100
|
+
if (truthy(env['EVOLVER_ENV_CLASS'])) {
|
|
101
|
+
const v = String(env['EVOLVER_ENV_CLASS']).trim().toLowerCase();
|
|
102
|
+
if (ENV_CLASSES.includes(v))
|
|
103
|
+
return v;
|
|
104
|
+
}
|
|
105
|
+
return 'local';
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Honest defaults for K_auto coordinates the producer did not state. Never invents a coordinate from
|
|
109
|
+
* nothing: each default is grounded in fields the gene already carries (signals, model, validation).
|
|
110
|
+
*/
|
|
111
|
+
export function deriveDefaultKautoCoordinates(input) {
|
|
112
|
+
const claims = input.claims ?? (input.signals.length > 0
|
|
113
|
+
? [{ predicate: 'output_contract', kind: 'behavioral' }]
|
|
114
|
+
: null);
|
|
115
|
+
const scope = input.scope ?? (() => {
|
|
116
|
+
const namespaced = namespaceScopeSignals(input.signals);
|
|
117
|
+
return namespaced.length > 0 ? { signals: namespaced } : null;
|
|
118
|
+
})();
|
|
119
|
+
const runtime_profile = input.runtime_profile ?? (input.modelName
|
|
120
|
+
? { runtime: input.modelName, env_class: detectEnvClass(input.env) }
|
|
121
|
+
: null);
|
|
122
|
+
const verifier_profile = input.verifier_profile ?? (() => {
|
|
123
|
+
const cmds = input.validation.map((c) => String(c).trim()).filter(Boolean);
|
|
124
|
+
if (cmds.length === 0)
|
|
125
|
+
return null;
|
|
126
|
+
const substantive = cmds.find((c) => !PLACEHOLDER_VERIFIER.test(c) && !TRIVIAL_VERIFIER.test(c));
|
|
127
|
+
// Light distill validation deliberately keeps `node --version` for sandbox safety; the gene still
|
|
128
|
+
// passed through evolver's sandboxed validation gate, which is a real verifier identity (not a
|
|
129
|
+
// shell placeholder). Prefer a substantive command when present; else name the gate.
|
|
130
|
+
return { verifier: substantive ?? 'evolver-sandboxed-validation', decision: 'pass' };
|
|
131
|
+
})();
|
|
132
|
+
return { claims, scope, runtime_profile, verifier_profile };
|
|
133
|
+
}
|
|
55
134
|
/** Returns the id of an existing gene whose signals are a superset of `signals` (i.e. the candidate is redundant), else null. */
|
|
56
135
|
function fullyOverlaps(signals, existing) {
|
|
57
136
|
const newSet = signals.map((s) => s.toLowerCase());
|
|
@@ -84,14 +163,42 @@ export function intakeGene(candidate, existing = []) {
|
|
|
84
163
|
if (errors.length > 0)
|
|
85
164
|
return { ok: false, errors };
|
|
86
165
|
const category = VALID_CATEGORIES.includes(candidate.category) ? candidate.category : 'optimize';
|
|
87
|
-
|
|
88
|
-
// v2-delta EvoX hints (v1 PR #93): normalized so a candidate carrying them lands canonical, dropped to
|
|
166
|
+
// First-class EvoX hints (v1 PR #93): normalized so a candidate carrying them lands canonical, not dropped, and
|
|
89
167
|
// absent when malformed/empty. The router / tool-gate reads absent === "no opinion".
|
|
90
168
|
const routingHint = normalizeRoutingHint(candidate.routing_hint);
|
|
91
169
|
const toolPolicy = normalizeToolPolicy(candidate.tool_policy);
|
|
92
|
-
//
|
|
170
|
+
// Local provenance + quality metadata (v1 #302): normalized so a candidate carrying it lands canonical,
|
|
93
171
|
// dropped to absent when malformed/no-recognized-source.
|
|
94
172
|
const generationMeta = normalizeGenerationMeta(candidate.generation_meta);
|
|
173
|
+
// 只有调用方明确证明记录来自蒸馏时,才保留 intake 之前的会话命名空间。
|
|
174
|
+
// 这样既兼容重试和下游逻辑 ID 查询,也不允许任意调用方 ID 绕过 intake 的命名空间所有权规则。
|
|
175
|
+
const preservesLegacyConversationId = generationMeta?.source === 'distilled'
|
|
176
|
+
&& typeof candidate.id === 'string'
|
|
177
|
+
&& candidate.id.startsWith(LEGACY_CONVERSATION_ID_PREFIX);
|
|
178
|
+
const id = candidate.id && (candidate.id.startsWith(DISTILLED_ID_PREFIX) || preservesLegacyConversationId)
|
|
179
|
+
? candidate.id : `${DISTILLED_ID_PREFIX}${fnv1a(signals.join('|'))}`;
|
|
180
|
+
// K_auto runtime coordinate. Explicit caller value wins; otherwise detect from the environment using the same
|
|
181
|
+
// producer the env fingerprint uses. 'unknown' means undetectable, so it is dropped rather than recorded (see
|
|
182
|
+
// GeneCandidate.model_name) — absent keeps meaning "not recorded", never "runtime is literally unknown".
|
|
183
|
+
const detectedModel = nonEmptyModel(candidate.model_name) ?? nonEmptyModel(detectModelName());
|
|
184
|
+
const modelName = detectedModel === 'unknown' ? undefined : detectedModel;
|
|
185
|
+
// First-class K_auto projection-key coordinates. Producer-supplied values win when they normalize; otherwise
|
|
186
|
+
// derive honest defaults grounded in signals/model/validation so forward intake can clear strict K_auto
|
|
187
|
+
// without fabricating coordinates from nothing. Still ride along in asset_id and strip before validateWire.
|
|
188
|
+
const validation = candidate.validation ? [...candidate.validation] : [];
|
|
189
|
+
const derived = deriveDefaultKautoCoordinates({
|
|
190
|
+
signals,
|
|
191
|
+
...(modelName ? { modelName } : {}),
|
|
192
|
+
validation,
|
|
193
|
+
claims: normalizeClaims(candidate.claims),
|
|
194
|
+
scope: normalizeGeneScope(candidate.scope),
|
|
195
|
+
runtime_profile: normalizeRuntimeProfile(candidate.runtime_profile),
|
|
196
|
+
verifier_profile: normalizeVerifierProfile(candidate.verifier_profile),
|
|
197
|
+
});
|
|
198
|
+
const claims = derived.claims;
|
|
199
|
+
const scope = derived.scope;
|
|
200
|
+
const runtimeProfile = derived.runtime_profile;
|
|
201
|
+
const verifierProfile = derived.verifier_profile;
|
|
95
202
|
const gene = {
|
|
96
203
|
type: 'Gene',
|
|
97
204
|
schema_version: SCHEMA_VERSION,
|
|
@@ -103,12 +210,17 @@ export function intakeGene(candidate, existing = []) {
|
|
|
103
210
|
max_files: candidate.constraints?.max_files ?? DEFAULT_MAX_FILES,
|
|
104
211
|
forbidden_paths: [...(candidate.constraints?.forbidden_paths ?? DEFAULT_FORBIDDEN_PATHS)],
|
|
105
212
|
},
|
|
106
|
-
validation
|
|
213
|
+
validation,
|
|
107
214
|
summary: candidate.summary ?? `Strategy for: ${signals.slice(0, 3).join(', ')}`,
|
|
215
|
+
...(modelName ? { model_name: modelName } : {}),
|
|
108
216
|
...(candidate.preconditions ? { preconditions: [...candidate.preconditions] } : {}),
|
|
109
217
|
...(routingHint ? { routing_hint: routingHint } : {}),
|
|
110
218
|
...(toolPolicy ? { tool_policy: toolPolicy } : {}),
|
|
111
219
|
...(generationMeta ? { generation_meta: generationMeta } : {}),
|
|
220
|
+
...(claims ? { claims } : {}),
|
|
221
|
+
...(scope ? { scope } : {}),
|
|
222
|
+
...(runtimeProfile ? { runtime_profile: runtimeProfile } : {}),
|
|
223
|
+
...(verifierProfile ? { verifier_profile: verifierProfile } : {}),
|
|
112
224
|
asset_id: '',
|
|
113
225
|
};
|
|
114
226
|
// asset_id folds in the hints + generation_meta (intake's own canonical shape — gep-sdk canonicalize hashes every
|
|
@@ -116,11 +228,10 @@ export function intakeGene(candidate, existing = []) {
|
|
|
116
228
|
// routing_hint/tool_policy:null plus empty epigenetic_marks/learning_history/anti_patterns/preconditions that
|
|
117
229
|
// v2 intake omits, so the canonical shapes differ. Self-consistent here; not a cross-impl parity guarantee.
|
|
118
230
|
gene.asset_id = computeAssetId(gene) ?? '';
|
|
119
|
-
// Structural gate validates the gep-sdk-known
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
// (the publish/egress path is sanitize-only). Same v2-delta contract Capsule's proof_of_work had pre-1.11.0.
|
|
231
|
+
// Structural gate validates the gep-sdk-known Gene shape. gep-sdk 1.13.0 made routing_hint/tool_policy plus the
|
|
232
|
+
// K_auto coordinates first-class, so stripGeneHints removes only local annotations (generation_meta/model_name)
|
|
233
|
+
// before the check. That keeps SDK constraints active for every first-class field while preserving local-only
|
|
234
|
+
// metadata in asset_id and in the returned gene.
|
|
124
235
|
const v = validateWire(stripGeneHints(gene));
|
|
125
236
|
if (!v.ok)
|
|
126
237
|
return { ok: false, errors: v.errors };
|
|
@@ -5,6 +5,8 @@ import type { GeneLearningView } from '../assetstore/learningHistory.js';
|
|
|
5
5
|
import type { AssetRecord } from '../assetstore/provider.js';
|
|
6
6
|
import { type ExplorationInput } from './exploration.js';
|
|
7
7
|
import type { GenerationSource } from '../wire/index.js';
|
|
8
|
+
import type { MemoryGraphGeneEvidence } from './memoryGraph.js';
|
|
9
|
+
import { UCB1_REWARD_POLICY_VERSION, UCB1_SELECTION_POLICY_VERSION, type SelectionPolicy, type Ucb1Choice, type Ucb1FallbackReason } from './ucb1.js';
|
|
8
10
|
/** 一个候选 gene 的选择期素材. */
|
|
9
11
|
export interface GeneCandidateInput {
|
|
10
12
|
geneId: string;
|
|
@@ -35,6 +37,8 @@ export interface GeneCandidateInput {
|
|
|
35
37
|
* set the hard gates already produced, so a high confidence can never resurrect a gene that was excluded.
|
|
36
38
|
*/
|
|
37
39
|
confidence?: number;
|
|
40
|
+
/** Scoped local MemoryGraph outcome signal in [-1,1]. Data-only and never executable prompt content. */
|
|
41
|
+
memoryBoost?: number;
|
|
38
42
|
/**
|
|
39
43
|
* Cross-runtime reuse sentiment in [-1, 1] for this gene (#268 phase 1): the net of self-reported reuse
|
|
40
44
|
* SUCCESSes vs negatives (failed/mismatched/stale/unsafe), computed upstream from reuse-outcome events
|
|
@@ -44,17 +48,35 @@ export interface GeneCandidateInput {
|
|
|
44
48
|
* effect, so the factor is dormant until a caller injects the signal (default-off).
|
|
45
49
|
*/
|
|
46
50
|
reuseAdjust?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Soft preference for genes whose five K_auto coordinates are machine-decidable (decideKauto.inKauto).
|
|
53
|
+
* Assembly stamps this when the source record clears the strict predicate. SOFT only: it re-orders near-ties
|
|
54
|
+
* among already-admitted candidates and can NEVER resurrect a gene excluded by trust/review/ban. Absent/false
|
|
55
|
+
* → 0 contribution, so the historical catalogue (strict membership 0%) is not zero-scored.
|
|
56
|
+
*/
|
|
57
|
+
kautoMember?: boolean;
|
|
47
58
|
/**
|
|
48
59
|
* Authoritative provenance tag from Gene.generation_meta.source. The legacy `gene_distilled_` prefix remains a
|
|
49
60
|
* fallback only for old candidates that do not carry this field.
|
|
50
61
|
*/
|
|
51
62
|
generationSource?: GenerationSource;
|
|
63
|
+
/**
|
|
64
|
+
* Assembly-owned UCB1 eligibility. Only trusted approved/legacy-local candidates may set true. Injected callers
|
|
65
|
+
* must not self-assert this bit; candidateAssembly overwrites Hub candidates to false.
|
|
66
|
+
*/
|
|
67
|
+
explorationEligible?: boolean;
|
|
52
68
|
}
|
|
53
69
|
export interface SelectionInput {
|
|
54
70
|
signals: readonly string[];
|
|
55
71
|
candidates: readonly GeneCandidateInput[];
|
|
72
|
+
/** Trust-filtered library corpus captured before relevance admission. Omit for direct strategy callers. */
|
|
73
|
+
semanticCorpus?: readonly GeneCandidateInput[];
|
|
74
|
+
/** Emergency rollback: restore the pre-IDF semantic scorer and skip profile construction. */
|
|
75
|
+
disableSemanticIdf?: boolean;
|
|
56
76
|
/** 低于此分则不选(→ 走 innovate 新基因), 默认 0. */
|
|
57
77
|
floor?: number;
|
|
78
|
+
/** Relevance guard rollout. Omit for legacy selector behavior in direct/core callers. */
|
|
79
|
+
selectionGuard?: SelectionGuardMode;
|
|
58
80
|
/**
|
|
59
81
|
* Explicit gene requested by GEP / an external runtime. This is a hard selection only within the already
|
|
60
82
|
* assembled candidate/fallback pools: it cannot resurrect a gene filtered by trust/review/ban upstream, and it is
|
|
@@ -67,8 +89,9 @@ export interface SelectionInput {
|
|
|
67
89
|
/**
|
|
68
90
|
* Distilled-gene fallback pool (ported from v1 #97): broadly-applicable distilled genes that do NOT match the
|
|
69
91
|
* live signals, supplied by the assembly layer (already trust/review/ban-filtered) so they never compete in the
|
|
70
|
-
* normal scored set. Used ONLY
|
|
71
|
-
* through to a blind innovate, selection reuses a known
|
|
92
|
+
* normal scored set. Used ONLY after normal selection has no reusable positive choice (the legacy non-positive
|
|
93
|
+
* pool or an enforced no-match guard): instead of falling through to a blind innovate, selection reuses a known
|
|
94
|
+
* distilled strategy. Epigenetically-suppressed entries
|
|
72
95
|
* (epigeneticPenalty > 0) are skipped — v2's event-log-derived epigeneticPenalty is the analog of v1's asset-mark
|
|
73
96
|
* hard suppression (a related band, not the identical predicate).
|
|
74
97
|
*/
|
|
@@ -78,11 +101,15 @@ export interface SelectionInput {
|
|
|
78
101
|
* for prompt rendering only; they never enter scoring, fallback, or forced selection.
|
|
79
102
|
*/
|
|
80
103
|
antiWarnings?: readonly AntiWarning[];
|
|
104
|
+
/** Structured, scoped outcome evidence selected upstream. Contains no raw memory text or instructions. */
|
|
105
|
+
memoryEvidence?: readonly MemoryGraphGeneEvidence[];
|
|
81
106
|
}
|
|
82
107
|
export interface ScoredCandidate {
|
|
83
108
|
geneId: string;
|
|
84
109
|
assetId?: string;
|
|
85
110
|
score: number;
|
|
111
|
+
/** Internal expanded match in [0,1]; omitted from root-event candidate payloads. */
|
|
112
|
+
matchScore?: number;
|
|
86
113
|
reasons: string[];
|
|
87
114
|
health?: GeneHealth;
|
|
88
115
|
}
|
|
@@ -105,6 +132,40 @@ export interface GeneDecision {
|
|
|
105
132
|
antiWarnings?: AntiWarning[];
|
|
106
133
|
weightsVersion: string;
|
|
107
134
|
strategyName: string;
|
|
135
|
+
/** Human-readable explanation for the winning candidate. */
|
|
136
|
+
selectedReason?: string;
|
|
137
|
+
/** Bounded structured outcome evidence for prompt enrichment. */
|
|
138
|
+
memoryEvidence?: MemoryGraphGeneEvidence[];
|
|
139
|
+
/** Deterministic identity of the bounded IDF profile used for this decision. */
|
|
140
|
+
semanticProfileVersion?: string;
|
|
141
|
+
/** Number of trusted semantic documents represented by the profile. */
|
|
142
|
+
semanticDocumentCount?: number;
|
|
143
|
+
/** Compact policy trace; omitted for the default engine-health behavior. */
|
|
144
|
+
selectionPolicy?: SelectionPolicyTrace;
|
|
145
|
+
/** Versioned relevance guard trace; omitted only for explicit legacy rollback. */
|
|
146
|
+
selectionGuard?: SelectionGuardTrace;
|
|
147
|
+
}
|
|
148
|
+
export interface SelectionPolicyTrace {
|
|
149
|
+
requested: Exclude<SelectionPolicy, 'engine-health'>;
|
|
150
|
+
effective: 'engine-health' | 'ucb1';
|
|
151
|
+
selectionPolicyVersion: typeof UCB1_SELECTION_POLICY_VERSION;
|
|
152
|
+
rewardPolicyVersion: typeof UCB1_REWARD_POLICY_VERSION;
|
|
153
|
+
arm?: Ucb1Choice;
|
|
154
|
+
shadowArmId?: string;
|
|
155
|
+
shadowDisagrees?: boolean;
|
|
156
|
+
fallbackReason?: Ucb1FallbackReason;
|
|
157
|
+
}
|
|
158
|
+
export type SelectionGuardMode = 'legacy' | 'shadow' | 'enforce';
|
|
159
|
+
export declare const SELECTION_GUARD_VERSION = "relevance-guard-v1";
|
|
160
|
+
export type SelectionGuardReason = 'no_match' | 'plateau_flat_match';
|
|
161
|
+
export type SelectionGuardStatus = 'allowed' | 'shadow' | 'forced' | 'ucb1' | 'fallback' | 'innovate';
|
|
162
|
+
export interface SelectionGuardTrace {
|
|
163
|
+
mode: Exclude<SelectionGuardMode, 'legacy'>;
|
|
164
|
+
version: typeof SELECTION_GUARD_VERSION;
|
|
165
|
+
status: SelectionGuardStatus;
|
|
166
|
+
reason?: SelectionGuardReason;
|
|
167
|
+
maxMatch?: number;
|
|
168
|
+
matchSpread?: number;
|
|
108
169
|
}
|
|
109
170
|
/**
|
|
110
171
|
* Weight of the preferred-gene confidence factor (fourth factor, positive cross-cycle learning). Kept small so
|
|
@@ -118,12 +179,70 @@ export declare const CONFIDENCE_WEIGHT = 0.15;
|
|
|
118
179
|
* ±REUSE_WEIGHT and can never dominate health/signal-match.
|
|
119
180
|
*/
|
|
120
181
|
export declare const REUSE_WEIGHT = 0.1;
|
|
182
|
+
/** Weight of scoped local MemoryGraph outcome evidence. */
|
|
183
|
+
export declare const MEMORY_GRAPH_WEIGHT = 0.12;
|
|
184
|
+
/** Bounded weight for a canonical task-domain signal match (#628). */
|
|
185
|
+
export declare const TASK_DOMAIN_WEIGHT = 0.08;
|
|
186
|
+
/** signals_match is weak domain evidence; its maximum score contribution is 0.08 * 0.5 = 0.04. */
|
|
187
|
+
export declare const TASK_DOMAIN_SIGNAL_EVIDENCE = 0.5;
|
|
188
|
+
/**
|
|
189
|
+
* Soft boost for strict K_auto members. Smaller than CONFIDENCE_WEIGHT: membership is a writer-side property,
|
|
190
|
+
* not verified cycle history, so it only breaks near-ties between already-eligible candidates.
|
|
191
|
+
*/
|
|
192
|
+
export declare const KAUTO_WEIGHT = 0.05;
|
|
121
193
|
/**
|
|
122
194
|
* Version of the full engine-health weight vector (health 0.6 + signal-match 0.4 − epigenetic penalty
|
|
123
|
-
* + CONFIDENCE_WEIGHT × confidence + REUSE_WEIGHT × reuse-sentiment
|
|
124
|
-
* weight snapshots track the change. Composed from the
|
|
195
|
+
* + CONFIDENCE_WEIGHT × confidence + REUSE_WEIGHT × reuse-sentiment + KAUTO_WEIGHT × kauto-member).
|
|
196
|
+
* Bumped whenever a factor is added so golden weight snapshots track the change. Composed from the
|
|
197
|
+
* health-weights version so a change to either layer shows.
|
|
125
198
|
*/
|
|
126
|
-
export declare const
|
|
199
|
+
export declare const LEGACY_SELECTION_WEIGHTS_VERSION = "sel-6-domain(gh-2,conf=0.15,memory=0.12,reuse=0.1,domain=0.08)";
|
|
200
|
+
export declare const SELECTION_WEIGHTS_VERSION = "sel-7-idf-domain(gh-2,conf=0.15,memory=0.12,reuse=0.1,domain=0.08)";
|
|
201
|
+
export interface KautoAblationPoolResult {
|
|
202
|
+
lambda: number;
|
|
203
|
+
ranking: Array<{
|
|
204
|
+
rank: number;
|
|
205
|
+
geneId: string;
|
|
206
|
+
assetId?: string;
|
|
207
|
+
score: number;
|
|
208
|
+
scoreBase: number;
|
|
209
|
+
kautoContribution: number;
|
|
210
|
+
kautoMember: boolean;
|
|
211
|
+
}>;
|
|
212
|
+
selectedGeneId: string | null;
|
|
213
|
+
selectedAssetId?: string;
|
|
214
|
+
scoreBaseMin: number;
|
|
215
|
+
scoreBaseMax: number;
|
|
216
|
+
scoreBaseMean: number;
|
|
217
|
+
}
|
|
218
|
+
export interface KautoAblationCompare {
|
|
219
|
+
lambdas: readonly number[];
|
|
220
|
+
pools: KautoAblationPoolResult[];
|
|
221
|
+
/** Pairs (baseline λ=0 vs each λ>0) where any gene's rank changed. */
|
|
222
|
+
rankChangesByLambda: Record<string, number>;
|
|
223
|
+
/** Pairs where the selected (top) gene changed vs λ=0. */
|
|
224
|
+
selectedChangesByLambda: Record<string, boolean>;
|
|
225
|
+
/** Pairs where the top-k set changed vs λ=0. */
|
|
226
|
+
topKChangesByLambda: Record<string, number>;
|
|
227
|
+
topK: number;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Offline λ ablation over an already-admitted candidate pool.
|
|
231
|
+
* Does not run hard gates / force / distilled fallback — those stay outside the soft preference.
|
|
232
|
+
* Pure ranking sensitivity for score_T2 = score_base + λ · 1[k_a ∈ K_auto].
|
|
233
|
+
*/
|
|
234
|
+
export declare function ablateKautoLambda(input: Pick<SelectionInput, 'signals' | 'candidates' | 'semanticCorpus' | 'disableSemanticIdf'>, lambdas?: readonly number[], opts?: {
|
|
235
|
+
topK?: number;
|
|
236
|
+
floor?: number;
|
|
237
|
+
}): KautoAblationCompare;
|
|
238
|
+
interface SelectionGuardAssessment {
|
|
239
|
+
wouldAbstain: boolean;
|
|
240
|
+
reason?: SelectionGuardReason;
|
|
241
|
+
maxMatch?: number;
|
|
242
|
+
matchSpread?: number;
|
|
243
|
+
}
|
|
244
|
+
/** Refs #626: identify selections whose relevance is absent or cannot discriminate during a plateau. */
|
|
245
|
+
export declare function assessSelectionGuard(scored: readonly ScoredCandidate[], plateauActive: boolean): SelectionGuardAssessment;
|
|
127
246
|
/** 实现1: engine 健康分主导(health 0.6 + 信号匹配 0.4). */
|
|
128
247
|
export declare const engineHealthSelection: Strategy<SelectionInput, GeneDecision>;
|
|
129
248
|
/** 实现2: 纯信号匹配采样(忽略 health, 对照基线 — 经验主义要可对比). */
|
|
@@ -131,4 +250,5 @@ export declare const signalMatchSelection: Strategy<SelectionInput, GeneDecision
|
|
|
131
250
|
/** 实现3: agent 主导(注入决策回调; engine 只给候选+分, agent 拍板, D26 agent 一等公民). */
|
|
132
251
|
export declare function agentLedSelection(pick: (scored: ScoredCandidate[], input: SelectionInput) => string | null): Strategy<SelectionInput, GeneDecision>;
|
|
133
252
|
/** 选 gene StrategyPoint: 默认 engine-health, 备选 signal-match(+ 可注册 agent-led). */
|
|
134
|
-
export declare function makeGeneSelectionPoint(): StrategyPoint<SelectionInput, GeneDecision>;
|
|
253
|
+
export declare function makeGeneSelectionPoint(): StrategyPoint<SelectionInput, GeneDecision>;
|
|
254
|
+
export {};
|