@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.
Files changed (240) hide show
  1. package/assets/gep/genes.jsonl +5 -5
  2. package/dist/algo/bans.d.ts +10 -1
  3. package/dist/algo/bans.js +56 -6
  4. package/dist/algo/candidateAssembly.d.ts +25 -2
  5. package/dist/algo/candidateAssembly.js +171 -26
  6. package/dist/algo/capabilityCandidates.js +10 -0
  7. package/dist/algo/conversationSniffer.js +25 -8
  8. package/dist/algo/cycleEngine.d.ts +63 -5
  9. package/dist/algo/cycleEngine.js +320 -42
  10. package/dist/algo/cycleFailureClassifier.d.ts +1 -1
  11. package/dist/algo/evolutionEvent.d.ts +26 -0
  12. package/dist/algo/evolutionEvent.js +32 -0
  13. package/dist/algo/exploration.d.ts +7 -0
  14. package/dist/algo/exploration.js +16 -3
  15. package/dist/algo/geneHealth.d.ts +36 -3
  16. package/dist/algo/geneHealth.js +47 -4
  17. package/dist/algo/geneIntake.d.ts +46 -1
  18. package/dist/algo/geneIntake.js +121 -10
  19. package/dist/algo/geneSelection.d.ts +126 -6
  20. package/dist/algo/geneSelection.js +479 -36
  21. package/dist/algo/index.d.ts +6 -1
  22. package/dist/algo/index.js +6 -1
  23. package/dist/algo/kautoProjection.d.ts +41 -0
  24. package/dist/algo/kautoProjection.js +95 -0
  25. package/dist/algo/kautoValidator.d.ts +68 -0
  26. package/dist/algo/kautoValidator.js +256 -0
  27. package/dist/algo/memoryGraph.d.ts +62 -0
  28. package/dist/algo/memoryGraph.js +86 -0
  29. package/dist/algo/orchestrator.d.ts +17 -1
  30. package/dist/algo/orchestrator.js +30 -4
  31. package/dist/algo/publishEligibility.d.ts +34 -0
  32. package/dist/algo/publishEligibility.js +52 -0
  33. package/dist/algo/solidify.d.ts +11 -2
  34. package/dist/algo/solidify.js +37 -7
  35. package/dist/algo/ucb1.d.ts +53 -0
  36. package/dist/algo/ucb1.js +156 -0
  37. package/dist/assetrepair/hubRejection.d.ts +12 -0
  38. package/dist/assetrepair/hubRejection.js +109 -0
  39. package/dist/assetrepair/index.d.ts +2 -0
  40. package/dist/assetrepair/index.js +2 -0
  41. package/dist/assetrepair/repair.d.ts +33 -0
  42. package/dist/assetrepair/repair.js +155 -0
  43. package/dist/assetstore/assetSidecarRecords.d.ts +28 -0
  44. package/dist/assetstore/assetSidecarRecords.js +384 -0
  45. package/dist/assetstore/assetSidecarRecovery.d.ts +48 -0
  46. package/dist/assetstore/assetSidecarRecovery.js +288 -0
  47. package/dist/assetstore/assetStoreHealth.d.ts +81 -0
  48. package/dist/assetstore/assetStoreHealth.js +319 -0
  49. package/dist/assetstore/assetStoreLayout.d.ts +2 -0
  50. package/dist/assetstore/assetStoreLayout.js +6 -0
  51. package/dist/assetstore/assetStoreStorage.d.ts +42 -0
  52. package/dist/assetstore/assetStoreStorage.js +336 -0
  53. package/dist/assetstore/assetSyncLedger.d.ts +91 -1
  54. package/dist/assetstore/assetSyncLedger.js +718 -59
  55. package/dist/assetstore/foreignJsonlSource.d.ts +48 -0
  56. package/dist/assetstore/foreignJsonlSource.js +150 -0
  57. package/dist/assetstore/index.d.ts +5 -0
  58. package/dist/assetstore/index.js +5 -0
  59. package/dist/assetstore/learningHistory.js +3 -3
  60. package/dist/assetstore/localAssetStoreSnapshot.d.ts +51 -0
  61. package/dist/assetstore/localAssetStoreSnapshot.js +329 -0
  62. package/dist/assetstore/localJsonl.d.ts +12 -1
  63. package/dist/assetstore/localJsonl.js +251 -42
  64. package/dist/assetstore/provenance.d.ts +93 -4
  65. package/dist/assetstore/provenance.js +368 -84
  66. package/dist/assetstore/provider.d.ts +63 -0
  67. package/dist/assetstore/provider.js +97 -6
  68. package/dist/assetstore/reviewFilter.d.ts +19 -1
  69. package/dist/assetstore/reviewFilter.js +39 -1
  70. package/dist/assetstore/reviewLedger.d.ts +8 -2
  71. package/dist/assetstore/reviewLedger.js +71 -45
  72. package/dist/assetstore/unionReadStore.d.ts +25 -0
  73. package/dist/assetstore/unionReadStore.js +119 -0
  74. package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
  75. package/dist/benchmark/antiGeneBenchmark.js +4 -3
  76. package/dist/benchmark/antiGeneRollout.d.ts +2 -0
  77. package/dist/benchmark/antiGeneRollout.js +4 -3
  78. package/dist/benchmark/index.d.ts +3 -1
  79. package/dist/benchmark/index.js +3 -1
  80. package/dist/benchmark/selectionFlatAbstention.d.ts +152 -0
  81. package/dist/benchmark/selectionFlatAbstention.js +481 -0
  82. package/dist/benchmark/triggerShift.d.ts +62 -0
  83. package/dist/benchmark/triggerShift.js +106 -0
  84. package/dist/bootstrap/envFingerprint.d.ts +9 -0
  85. package/dist/bootstrap/envFingerprint.js +5 -0
  86. package/dist/bootstrap/index.d.ts +3 -1
  87. package/dist/bootstrap/index.js +3 -1
  88. package/dist/bootstrap/lifecycleBootstrap.d.ts +111 -0
  89. package/dist/bootstrap/lifecycleBootstrap.js +433 -0
  90. package/dist/bootstrap/v1EnvCompat.d.ts +113 -0
  91. package/dist/bootstrap/v1EnvCompat.js +303 -0
  92. package/dist/events/eventArchive.d.ts +2 -0
  93. package/dist/events/eventArchive.js +13 -3
  94. package/dist/events/eventSchema.d.ts +7 -7
  95. package/dist/events/eventStore.d.ts +2 -0
  96. package/dist/events/eventStore.js +5 -1
  97. package/dist/events/ingest.d.ts +2 -1
  98. package/dist/events/ingest.js +15 -0
  99. package/dist/events/paths.d.ts +12 -10
  100. package/dist/events/paths.js +24 -20
  101. package/dist/events/public.d.ts +2 -2
  102. package/dist/events/public.js +2 -2
  103. package/dist/events/reports.d.ts +2 -0
  104. package/dist/events/reports.js +4 -0
  105. package/dist/exec/autoExec.d.ts +68 -4
  106. package/dist/exec/autoExec.js +392 -33
  107. package/dist/exec/autonomousCycle.d.ts +31 -4
  108. package/dist/exec/autonomousCycle.js +71 -13
  109. package/dist/exec/claudeBridge.d.ts +80 -15
  110. package/dist/exec/claudeBridge.js +845 -76
  111. package/dist/exec/executionBinding.d.ts +414 -0
  112. package/dist/exec/executionBinding.js +588 -0
  113. package/dist/exec/index.d.ts +1 -0
  114. package/dist/exec/index.js +1 -0
  115. package/dist/exec/openPrRegistry.d.ts +8 -2
  116. package/dist/exec/openPrRegistry.js +32 -22
  117. package/dist/exec/prompt.js +14 -1
  118. package/dist/exec/proofOfWork.d.ts +1 -1
  119. package/dist/exec/proofOfWork.js +2 -2
  120. package/dist/exec/runnerRegistry.d.ts +153 -36
  121. package/dist/exec/runnerRegistry.js +848 -65
  122. package/dist/exec/selfPr.js +1 -7
  123. package/dist/feedback/envelope.d.ts +61 -0
  124. package/dist/feedback/envelope.js +168 -0
  125. package/dist/feedback/index.d.ts +1 -0
  126. package/dist/feedback/index.js +1 -0
  127. package/dist/hooks/hooks.js +1 -0
  128. package/dist/hub/assetCallLog.d.ts +35 -1
  129. package/dist/hub/assetCallLog.js +124 -1
  130. package/dist/hub/bindings.d.ts +8 -1
  131. package/dist/hub/bindings.js +29 -8
  132. package/dist/hub/capability.d.ts +130 -4
  133. package/dist/hub/conversationDistiller.d.ts +19 -0
  134. package/dist/hub/conversationDistiller.js +115 -37
  135. package/dist/hub/fake.d.ts +3 -2
  136. package/dist/hub/fake.js +2 -1
  137. package/dist/hub/index.d.ts +1 -0
  138. package/dist/hub/index.js +1 -0
  139. package/dist/hub/questionGenerator.d.ts +5 -1
  140. package/dist/hub/questionGenerator.js +8 -6
  141. package/dist/hub/recipeCompose.d.ts +27 -0
  142. package/dist/hub/recipeCompose.js +90 -0
  143. package/dist/hub/sanitize.js +122 -7
  144. package/dist/index.d.ts +6 -1
  145. package/dist/index.js +7 -1
  146. package/dist/issueReporter/index.d.ts +156 -0
  147. package/dist/issueReporter/index.js +1688 -0
  148. package/dist/mailbox/dispatch.d.ts +1 -1
  149. package/dist/mailbox/dispatch.js +22 -6
  150. package/dist/mailbox/envelope.d.ts +7 -1
  151. package/dist/mailbox/envelope.js +9 -2
  152. package/dist/mailbox/ipcServer.d.ts +12 -2
  153. package/dist/mailbox/ipcServer.js +183 -13
  154. package/dist/mailbox/store.d.ts +89 -3
  155. package/dist/mailbox/store.js +895 -41
  156. package/dist/modelCompatibility.d.ts +164 -0
  157. package/dist/modelCompatibility.js +309 -0
  158. package/dist/observers/valueDigestObserver.d.ts +9 -0
  159. package/dist/observers/valueDigestObserver.js +35 -2
  160. package/dist/ops/cleanup.js +1 -1
  161. package/dist/ops/evolutionGraphProjection.d.ts +20 -0
  162. package/dist/ops/evolutionGraphProjection.js +315 -0
  163. package/dist/ops/index.d.ts +2 -1
  164. package/dist/ops/index.js +2 -1
  165. package/dist/ops/savingsCore.js +1 -2
  166. package/dist/ops/selfUpdate.d.ts +18 -1
  167. package/dist/ops/selfUpdate.js +88 -23
  168. package/dist/ops/valueOutreach.d.ts +3 -1
  169. package/dist/ops/valueOutreach.js +5 -1
  170. package/dist/personality/schema.d.ts +24 -24
  171. package/dist/schema/evolutionGraph.d.ts +784 -0
  172. package/dist/schema/evolutionGraph.js +187 -0
  173. package/dist/schema/index.d.ts +1 -0
  174. package/dist/schema/index.js +1 -0
  175. package/dist/schema/proofOfWork.d.ts +125 -6
  176. package/dist/schema/proofOfWork.js +102 -4
  177. package/dist/schema/signal.d.ts +3 -3
  178. package/dist/schema/signal.js +1 -1
  179. package/dist/shadow/shadowHub.js +1 -0
  180. package/dist/signals/curriculum.d.ts +55 -0
  181. package/dist/signals/curriculum.js +202 -0
  182. package/dist/signals/cycleHistoryFromEvents.js +17 -8
  183. package/dist/signals/expand.d.ts +15 -1
  184. package/dist/signals/expand.js +169 -1
  185. package/dist/signals/extractor.d.ts +2 -2
  186. package/dist/signals/extractor.js +31 -6
  187. package/dist/signals/index.d.ts +4 -1
  188. package/dist/signals/index.js +4 -1
  189. package/dist/signals/metaSignals.d.ts +4 -0
  190. package/dist/signals/metaSignals.js +42 -0
  191. package/dist/signals/scopeVocabulary.d.ts +75 -0
  192. package/dist/signals/scopeVocabulary.js +91 -0
  193. package/dist/signals/signalGate.js +1 -1
  194. package/dist/signals/taskDomain.d.ts +22 -0
  195. package/dist/signals/taskDomain.js +43 -0
  196. package/dist/strategy/constraintAblation.d.ts +64 -0
  197. package/dist/strategy/constraintAblation.js +2820 -0
  198. package/dist/strategy/constraintAblationPredicates.d.ts +31 -0
  199. package/dist/strategy/constraintAblationPredicates.js +339 -0
  200. package/dist/strategy/index.d.ts +2 -1
  201. package/dist/strategy/index.js +2 -1
  202. package/dist/trace/index.d.ts +3 -1
  203. package/dist/trace/index.js +3 -1
  204. package/dist/trace/learningTrace.d.ts +216 -0
  205. package/dist/trace/learningTrace.js +298 -0
  206. package/dist/trace/proxyTurns.d.ts +31 -0
  207. package/dist/trace/proxyTurns.js +137 -0
  208. package/dist/trace/trajectory.d.ts +8 -0
  209. package/dist/trace/trajectory.js +14 -2
  210. package/dist/util/fetchPort.d.ts +1 -0
  211. package/dist/util/fetchPort.js +11 -0
  212. package/dist/util/fileLock.d.ts +113 -7
  213. package/dist/util/fileLock.js +1035 -80
  214. package/dist/util/index.d.ts +3 -1
  215. package/dist/util/index.js +2 -1
  216. package/dist/verify/index.d.ts +2 -1
  217. package/dist/verify/index.js +1 -1
  218. package/dist/verify/sandboxRunner.d.ts +30 -0
  219. package/dist/verify/sandboxRunner.js +370 -27
  220. package/dist/verify/sandboxedValidation.d.ts +16 -2
  221. package/dist/verify/sandboxedValidation.js +200 -22
  222. package/dist/verify/validation.d.ts +35 -4
  223. package/dist/verify/validation.js +164 -16
  224. package/dist/wire/geneHints.d.ts +88 -16
  225. package/dist/wire/geneHints.js +124 -15
  226. package/dist/wire/index.d.ts +8 -3
  227. package/dist/wire/index.js +2 -2
  228. package/dist/wire/schemaGate.d.ts +21 -0
  229. package/dist/wire/schemaGate.js +119 -10
  230. package/dist/workflow/dsl.d.ts +24 -3
  231. package/dist/workflow/dsl.js +4 -0
  232. package/dist/workflow/engine.d.ts +5 -1
  233. package/dist/workflow/engine.js +3 -0
  234. package/dist/workflow/index.d.ts +3 -1
  235. package/dist/workflow/index.js +3 -1
  236. package/dist/workflow/runtime.d.ts +110 -0
  237. package/dist/workflow/runtime.js +1298 -0
  238. package/dist/workflow/stateStore.d.ts +172 -0
  239. package/dist/workflow/stateStore.js +1044 -0
  240. 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
@@ -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, totalAttempts / maturityThreshold) : 0;
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 (!exp || (!exp.driftEnabled && !exp.plateau?.active) || eligibleCount <= 1) {
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 = Math.min(eligibleCount, Math.max(2, Math.ceil(eligibleCount * intensity)));
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-1";
15
+ export declare const HEALTH_WEIGHTS_VERSION = "gh-2";
16
16
  export declare const DEFAULT_HEALTH_WEIGHTS: GeneHealthWeights;
17
17
  /**
18
- * gene 健康分 = w1·successRate + w2·reuse归一 − w3·antiPattern密度.
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;
@@ -1,16 +1,59 @@
1
- export const HEALTH_WEIGHTS_VERSION = 'gh-1';
2
- export const DEFAULT_HEALTH_WEIGHTS = { successRate: 0.6, reuse: 0.3, antiPattern: 0.4 };
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·successRate + w2·reuse归一 − w3·antiPattern密度.
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 score = w.successRate * view.successRate + w.reuse * reuseScore(reuseCount) - w.antiPattern * antiPatternPenalty;
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.
@@ -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 { computeAssetId, validateWire, SCHEMA_VERSION, normalizeRoutingHint, normalizeToolPolicy, normalizeGenerationMeta, stripGeneHints, } from '../wire/index.js';
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
- const id = candidate.id && candidate.id.startsWith(DISTILLED_ID_PREFIX) ? candidate.id : `${DISTILLED_ID_PREFIX}${fnv1a(signals.join('|'))}`;
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
- // v2-delta provenance + quality metadata (v1 #302): normalized so a candidate carrying it lands canonical,
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: candidate.validation ? [...candidate.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 CORE. routing_hint / tool_policy / generation_meta are v2-delta
120
- // (pending a gene-schema bump), so strip them before the check — else additionalProperties:false rejects the
121
- // gene at intake. The full hinted gene stays schema-invalid until the SDK catches up — surfaced by the advisory
122
- // validateWire preview (evolver_gep_build) and enforced by the hub on receipt, NOT by a local egress gate
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 as a last resort when no candidate clears the floor: instead of falling straight
71
- * through to a blind innovate, selection reuses a known distilled strategy. Epigenetically-suppressed entries
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). Bumped whenever a factor is added so golden
124
- * weight snapshots track the change. Composed from the health-weights version so a change to either layer shows.
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 SELECTION_WEIGHTS_VERSION = "sel-3(gh-1,conf=0.15,reuse=0.1)";
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 {};