@evomap/evolver-core 2.0.0-beta.9 → 2.0.0

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 (142) hide show
  1. package/dist/algo/candidateAssembly.d.ts +7 -2
  2. package/dist/algo/candidateAssembly.js +81 -13
  3. package/dist/algo/capabilityCandidates.js +10 -0
  4. package/dist/algo/cycleEngine.d.ts +23 -2
  5. package/dist/algo/cycleEngine.js +236 -36
  6. package/dist/algo/exploration.d.ts +7 -0
  7. package/dist/algo/exploration.js +16 -3
  8. package/dist/algo/geneHealth.d.ts +2 -2
  9. package/dist/algo/geneHealth.js +5 -4
  10. package/dist/algo/geneSelection.d.ts +63 -5
  11. package/dist/algo/geneSelection.js +330 -30
  12. package/dist/algo/index.d.ts +2 -0
  13. package/dist/algo/index.js +2 -0
  14. package/dist/algo/orchestrator.d.ts +8 -1
  15. package/dist/algo/orchestrator.js +15 -3
  16. package/dist/algo/publishEligibility.d.ts +34 -0
  17. package/dist/algo/publishEligibility.js +52 -0
  18. package/dist/algo/ucb1.d.ts +53 -0
  19. package/dist/algo/ucb1.js +156 -0
  20. package/dist/assetstore/assetSidecarRecords.d.ts +7 -2
  21. package/dist/assetstore/assetSidecarRecords.js +238 -0
  22. package/dist/assetstore/assetSidecarRecovery.js +2 -2
  23. package/dist/assetstore/assetStoreHealth.d.ts +6 -0
  24. package/dist/assetstore/assetStoreHealth.js +56 -14
  25. package/dist/assetstore/assetStoreStorage.d.ts +1 -1
  26. package/dist/assetstore/assetStoreStorage.js +27 -9
  27. package/dist/assetstore/assetSyncLedger.d.ts +86 -0
  28. package/dist/assetstore/assetSyncLedger.js +683 -4
  29. package/dist/assetstore/index.d.ts +1 -0
  30. package/dist/assetstore/index.js +1 -0
  31. package/dist/assetstore/localAssetStoreSnapshot.d.ts +51 -0
  32. package/dist/assetstore/localAssetStoreSnapshot.js +329 -0
  33. package/dist/assetstore/localJsonl.d.ts +4 -2
  34. package/dist/assetstore/localJsonl.js +89 -9
  35. package/dist/assetstore/provenance.d.ts +80 -4
  36. package/dist/assetstore/provenance.js +313 -5
  37. package/dist/assetstore/provider.d.ts +58 -1
  38. package/dist/assetstore/provider.js +97 -6
  39. package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
  40. package/dist/benchmark/antiGeneBenchmark.js +4 -3
  41. package/dist/benchmark/antiGeneRollout.d.ts +2 -0
  42. package/dist/benchmark/antiGeneRollout.js +4 -3
  43. package/dist/benchmark/index.d.ts +2 -1
  44. package/dist/benchmark/index.js +2 -1
  45. package/dist/benchmark/selectionFlatAbstention.d.ts +152 -0
  46. package/dist/benchmark/selectionFlatAbstention.js +481 -0
  47. package/dist/bootstrap/envFingerprint.d.ts +9 -0
  48. package/dist/bootstrap/envFingerprint.js +5 -0
  49. package/dist/bootstrap/index.d.ts +2 -1
  50. package/dist/bootstrap/index.js +2 -1
  51. package/dist/bootstrap/v1EnvCompat.d.ts +111 -0
  52. package/dist/bootstrap/v1EnvCompat.js +280 -0
  53. package/dist/events/eventArchive.d.ts +2 -0
  54. package/dist/events/eventArchive.js +13 -3
  55. package/dist/events/eventSchema.d.ts +7 -7
  56. package/dist/events/eventStore.d.ts +2 -0
  57. package/dist/events/eventStore.js +5 -1
  58. package/dist/events/ingest.d.ts +1 -0
  59. package/dist/events/ingest.js +1 -0
  60. package/dist/events/paths.d.ts +3 -1
  61. package/dist/events/paths.js +4 -0
  62. package/dist/events/public.d.ts +2 -2
  63. package/dist/events/public.js +2 -2
  64. package/dist/events/reports.d.ts +2 -0
  65. package/dist/events/reports.js +4 -0
  66. package/dist/exec/autoExec.d.ts +43 -2
  67. package/dist/exec/autoExec.js +76 -9
  68. package/dist/exec/autonomousCycle.d.ts +22 -4
  69. package/dist/exec/autonomousCycle.js +64 -13
  70. package/dist/exec/claudeBridge.d.ts +32 -7
  71. package/dist/exec/claudeBridge.js +281 -29
  72. package/dist/exec/prompt.js +5 -1
  73. package/dist/exec/runnerRegistry.d.ts +68 -26
  74. package/dist/exec/runnerRegistry.js +307 -72
  75. package/dist/exec/selfPr.js +1 -7
  76. package/dist/feedback/envelope.d.ts +61 -0
  77. package/dist/feedback/envelope.js +168 -0
  78. package/dist/feedback/index.d.ts +1 -0
  79. package/dist/feedback/index.js +1 -0
  80. package/dist/hooks/hooks.js +1 -0
  81. package/dist/hub/assetCallLog.d.ts +35 -1
  82. package/dist/hub/assetCallLog.js +124 -1
  83. package/dist/hub/bindings.d.ts +8 -1
  84. package/dist/hub/bindings.js +17 -6
  85. package/dist/hub/capability.d.ts +90 -3
  86. package/dist/hub/fake.d.ts +2 -2
  87. package/dist/hub/fake.js +1 -1
  88. package/dist/hub/questionGenerator.d.ts +5 -1
  89. package/dist/hub/questionGenerator.js +8 -6
  90. package/dist/index.d.ts +3 -1
  91. package/dist/index.js +4 -1
  92. package/dist/mailbox/dispatch.d.ts +1 -1
  93. package/dist/mailbox/dispatch.js +22 -6
  94. package/dist/mailbox/envelope.d.ts +7 -1
  95. package/dist/mailbox/envelope.js +9 -2
  96. package/dist/mailbox/ipcServer.d.ts +10 -2
  97. package/dist/mailbox/ipcServer.js +163 -13
  98. package/dist/mailbox/store.d.ts +89 -3
  99. package/dist/mailbox/store.js +895 -41
  100. package/dist/ops/evolutionGraphProjection.d.ts +20 -0
  101. package/dist/ops/evolutionGraphProjection.js +315 -0
  102. package/dist/ops/index.d.ts +2 -1
  103. package/dist/ops/index.js +2 -1
  104. package/dist/ops/selfUpdate.d.ts +8 -0
  105. package/dist/ops/selfUpdate.js +24 -8
  106. package/dist/personality/schema.d.ts +16 -16
  107. package/dist/schema/evolutionGraph.d.ts +784 -0
  108. package/dist/schema/evolutionGraph.js +187 -0
  109. package/dist/schema/index.d.ts +1 -0
  110. package/dist/schema/index.js +1 -0
  111. package/dist/schema/signal.d.ts +3 -3
  112. package/dist/schema/signal.js +1 -1
  113. package/dist/signals/curriculum.d.ts +55 -0
  114. package/dist/signals/curriculum.js +202 -0
  115. package/dist/signals/cycleHistoryFromEvents.js +17 -8
  116. package/dist/signals/expand.d.ts +15 -1
  117. package/dist/signals/expand.js +169 -1
  118. package/dist/signals/extractor.d.ts +2 -2
  119. package/dist/signals/extractor.js +31 -6
  120. package/dist/signals/index.d.ts +3 -1
  121. package/dist/signals/index.js +3 -1
  122. package/dist/signals/metaSignals.d.ts +4 -0
  123. package/dist/signals/metaSignals.js +42 -0
  124. package/dist/signals/signalGate.js +1 -1
  125. package/dist/signals/taskDomain.d.ts +22 -0
  126. package/dist/signals/taskDomain.js +43 -0
  127. package/dist/strategy/constraintAblation.js +115 -369
  128. package/dist/strategy/constraintAblationPredicates.d.ts +31 -0
  129. package/dist/strategy/constraintAblationPredicates.js +339 -0
  130. package/dist/trace/index.d.ts +3 -1
  131. package/dist/trace/index.js +3 -1
  132. package/dist/trace/learningTrace.d.ts +209 -0
  133. package/dist/trace/learningTrace.js +276 -0
  134. package/dist/trace/proxyTurns.d.ts +31 -0
  135. package/dist/trace/proxyTurns.js +137 -0
  136. package/dist/verify/sandboxRunner.d.ts +28 -0
  137. package/dist/verify/sandboxRunner.js +218 -19
  138. package/dist/verify/sandboxedValidation.d.ts +9 -0
  139. package/dist/verify/sandboxedValidation.js +113 -13
  140. package/dist/verify/validation.d.ts +11 -1
  141. package/dist/verify/validation.js +31 -0
  142. package/package.json +5 -2
@@ -5,6 +5,8 @@ import type { ReviewLedger } from '../assetstore/reviewLedger.js';
5
5
  import type { AntiWarning, GeneCandidateInput } from './geneSelection.js';
6
6
  export interface AssembleOptions {
7
7
  limit?: number;
8
+ /** Build the bounded trusted pre-admission corpus used by semantic IDF. Default true. */
9
+ includeSemanticCorpus?: boolean;
8
10
  provenance?: ProvenanceStore;
9
11
  includeUntrusted?: boolean;
10
12
  review?: ReviewLedger;
@@ -39,10 +41,13 @@ export interface SelectionPool {
39
41
  /**
40
42
  * Distilled genes that passed the trust/review/ban gates but do NOT match the live signals. Surfaced
41
43
  * separately (NOT in `candidates`, so they never compete in normal scoring) for the v1 #97 fallback: when no
42
- * candidate clears the floor, selection reuses one of these broadly-applicable distilled strategies instead of
43
- * falling through to a blind innovate. Kept lightweight (no learning-history aggregation) — picked first-match.
44
+ * normal selection has no reusable positive choice, selection reuses one of these broadly-applicable distilled
45
+ * strategies instead of falling through to a blind innovate. Kept lightweight (no learning-history aggregation)
46
+ * — picked first-match.
44
47
  */
45
48
  distilledFallback: GeneCandidateInput[];
49
+ /** Trust-filtered library documents captured before live-signal relevance admission. */
50
+ semanticCorpus: GeneCandidateInput[];
46
51
  /**
47
52
  * Matched AntiGene guardrails for the live signals. This list is advisory-only and is kept out of candidates and
48
53
  * distilledFallback so negative memory cannot be selected as a strategy.
@@ -1,8 +1,10 @@
1
1
  import { aggregateLearningHistory } from '../assetstore/learningHistory.js';
2
2
  import { reuseSentiment } from '../ops/reuseOutcomes.js';
3
- import { tagOverlapScore } from '../signals/expand.js';
3
+ import { expandSignals, geneTags, tagOverlapScore, } from '../signals/expand.js';
4
+ import { withoutTaskDomainSignals } from '../signals/taskDomain.js';
4
5
  import { bannedGenesFromFailures } from './bans.js';
5
6
  import { geneGenerationSource } from './geneIntake.js';
7
+ const SEMANTIC_CORPUS_LIMIT = 1_000;
6
8
  function asStrings(v) {
7
9
  return Array.isArray(v) ? v.filter((x) => typeof x === 'string') : [];
8
10
  }
@@ -59,6 +61,8 @@ function combinedReuseSentiment(map, ...ids) {
59
61
  }
60
62
  /** Genes banned by repeated signal-matched failures (>=2 failed capsules covering the signals). */
61
63
  async function computeBans(store, signals, limit) {
64
+ if (signals.length === 0)
65
+ return new Set();
62
66
  const caps = await store.search({ kind: 'Capsule', signalsAny: [...signals], limit });
63
67
  const failures = caps
64
68
  .filter((c) => c['outcome']?.status === 'failed')
@@ -68,6 +72,24 @@ async function computeBans(store, signals, limit) {
68
72
  }));
69
73
  return bannedGenesFromFailures(failures, signals);
70
74
  }
75
+ const GENERIC_NAMESPACE_TAGS = new Set(['action', 'area', 'problem', 'risk', 'signal']);
76
+ // Generic namespace tags and inferred action/signal subtypes are too broad to admit a candidate by themselves.
77
+ function hasSelectionAdmissionEvidence(liveSignals, gene) {
78
+ const tags = new Set(geneTags(gene));
79
+ const triggerTags = new Set(expandSignals(gene.signalsMatch ?? []));
80
+ const categoryActionTag = gene.category ? `action:${gene.category.toLowerCase()}` : undefined;
81
+ if (liveSignals.some((signal) => ((triggerTags.has(signal) || signal === categoryActionTag)
82
+ && !GENERIC_NAMESPACE_TAGS.has(signal)))) {
83
+ return true;
84
+ }
85
+ const liveTags = expandSignals(liveSignals);
86
+ if (liveTags.some((tag) => (tags.has(tag)
87
+ && (tag.startsWith('problem:')
88
+ || tag.startsWith('area:')
89
+ || tag.startsWith('risk:')))))
90
+ return true;
91
+ return liveTags.some((tag) => tag.startsWith('signal:') && triggerTags.has(tag));
92
+ }
71
93
  /**
72
94
  * Assemble the full selection pool from the store for the given signals: the relevant scored candidates AND the
73
95
  * distilled-gene fallback pool, in a single pass over the gene list (one store.list + one ban computation). A gene
@@ -77,18 +99,33 @@ async function computeBans(store, signals, limit) {
77
99
  */
78
100
  export async function assembleSelectionPool(store, signals, opts = {}) {
79
101
  const limit = opts.limit ?? 500;
80
- const genes = await store.list('Gene', limit);
81
- const banned = await computeBans(store, signals, limit);
82
- const sigSet = new Set(signals);
102
+ const includeSemanticCorpus = opts.includeSemanticCorpus !== false;
103
+ const scanLimit = includeSemanticCorpus ? Math.max(limit, SEMANTIC_CORPUS_LIMIT) : limit;
104
+ const genes = await store.list('Gene', scanLimit);
105
+ const matchingSignals = withoutTaskDomainSignals(signals);
106
+ const banned = await computeBans(store, matchingSignals, limit);
107
+ const sigSet = new Set(matchingSignals);
83
108
  const provenance = opts.provenance?.snapshot();
84
109
  const review = opts.review?.snapshot();
85
110
  const out = [];
86
111
  const distilledFallback = [];
112
+ const semanticCorpus = [];
113
+ const semanticIdentities = new Set();
114
+ const addSemanticCandidate = (candidate) => {
115
+ if (!includeSemanticCorpus || semanticCorpus.length >= SEMANTIC_CORPUS_LIMIT)
116
+ return;
117
+ const identity = candidate.assetId ?? candidate.geneId;
118
+ if (semanticIdentities.has(identity))
119
+ return;
120
+ semanticIdentities.add(identity);
121
+ semanticCorpus.push(candidate);
122
+ };
87
123
  const antiWarnings = [];
88
- for (const g of genes) {
124
+ for (const [geneIndex, g] of genes.entries()) {
125
+ const provenanceRecord = provenance?.get(String(g.asset_id));
89
126
  // Trust-first (#30): untrusted (e.g. hub-ingested) genes are excluded from the candidate pool by default;
90
127
  // they enter only with includeUntrusted or after an explicit promotion. Provenance is keyed by asset_id.
91
- if (opts.provenance && !opts.includeUntrusted && provenance?.get(String(g.asset_id))?.trusted === false)
128
+ if (opts.provenance && !opts.includeUntrusted && provenanceRecord?.trusted === false)
92
129
  continue;
93
130
  // Review-first (#89/#91): auto-distilled drafts land quarantined until a human approves; rejected drafts stay
94
131
  // out too. No record → eligible (cycle/migrate genes). Symmetric to the provenance trust-first filter above.
@@ -103,10 +140,26 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
103
140
  if (isBannedCandidate(banned, geneId, assetId))
104
141
  continue; // repeated signal-matched failures → not a candidate (nor a fallback)
105
142
  const signalsMatch = asStrings(g['signals_match']);
143
+ const matchingSignalsForGene = withoutTaskDomainSignals(signalsMatch);
106
144
  const category = typeof g['category'] === 'string' ? String(g['category']) : undefined;
107
145
  const summary = typeof g['summary'] === 'string' ? String(g['summary']) : undefined;
108
- const literal = signalsMatch.some((m) => sigSet.has(m));
109
- const relevant = literal || tagOverlapScore(signals, { signalsMatch, geneId, category, summary }) > 0;
146
+ const literal = matchingSignalsForGene.some((m) => sigSet.has(m));
147
+ const tagInput = { signalsMatch: matchingSignalsForGene, geneId, category, summary };
148
+ // Experimental probation and explicitly untrusted records may be selectable by opt-in, but never shape global
149
+ // document frequency. Only trusted, approved/legacy-local records enter the pre-admission semantic corpus.
150
+ if (provenanceRecord?.trusted !== false && (reviewRecord === undefined || reviewRecord.state === 'approved')) {
151
+ addSemanticCandidate({
152
+ geneId,
153
+ assetId,
154
+ signalsMatch,
155
+ view: emptyLearningView(geneId),
156
+ ...(category ? { category } : {}),
157
+ ...(summary ? { summary } : {}),
158
+ });
159
+ }
160
+ if (geneIndex >= limit)
161
+ continue;
162
+ const relevant = literal || hasSelectionAdmissionEvidence(matchingSignals, tagInput);
110
163
  if (!relevant) {
111
164
  // #97: a trusted, approved, non-banned distilled (or evolved) gene that doesn't match the live signals is not
112
165
  // a normal candidate, but it IS eligible as a last-resort fallback (selection uses it only when nothing clears
@@ -129,6 +182,8 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
129
182
  continue;
130
183
  }
131
184
  const view = await aggregateLearningHistory(store, geneId);
185
+ const explorationEligible = provenanceRecord?.trusted !== false
186
+ && (reviewRecord === undefined || reviewRecord.state === 'approved');
132
187
  // #268 Bugbot: reuse events key by assetId, which may be the content asset_id (sha256:…) OR the logical id —
133
188
  // candidates key by the logical geneId. Look the sentiment up by BOTH so the soft re-order actually matches
134
189
  // regardless of which form the reuse-result carried (recall's resolveGene accepts both for the same reason).
@@ -144,25 +199,34 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
144
199
  ...(category ? { category } : {}),
145
200
  ...(summary ? { summary } : {}),
146
201
  ...(reuseAdjustVal !== undefined ? { reuseAdjust: reuseAdjustVal } : {}),
202
+ explorationEligible,
147
203
  });
148
204
  }
149
205
  // #110: merge hub reuse candidates into the same pool, trust-first — local (trusted) genes win on a
150
206
  // geneId collision, and a hub candidate banned by repeated signal-matched failures stays out too.
151
207
  if (opts.hubCandidates && opts.hubCandidates.length > 0) {
152
208
  const localIds = new Set(out.map((c) => c.geneId));
209
+ const localAssetIds = new Set(out.map((c) => c.assetId).filter((id) => id !== undefined));
153
210
  for (const h of opts.hubCandidates) {
154
211
  if (!passesInjectedCandidateGates(h, opts, provenance, review))
155
212
  continue;
156
213
  if (localIds.has(h.geneId))
157
214
  continue; // a trusted local gene already covers this id
215
+ if (h.assetId && localAssetIds.has(h.assetId))
216
+ continue; // the same content identity is already local/trusted
158
217
  if (isBannedCandidate(banned, h.geneId, h.assetId))
159
218
  continue;
160
219
  // Stamp the reuse sentiment onto a hub candidate too (only when it didn't carry one), matched by its geneId
161
220
  // OR its asset_id — symmetric with local genes, so a map keyed like reuse events (often sha256:…) still hits
162
221
  // (#268 Bugbot). A hub candidate that exposes neither matching id is simply left unstamped.
163
222
  const hubAdj = h.reuseAdjust === undefined ? combinedReuseSentiment(opts.reuseCounts, h.geneId, h.assetId) : undefined;
164
- out.push(hubAdj !== undefined ? { ...h, reuseAdjust: hubAdj } : h);
223
+ // A transient Hub candidate must never self-assert active-bandit cold-start eligibility. It still competes
224
+ // under the existing base score and legacy drift; UCB1 fails safe for a mixed window.
225
+ const guarded = { ...h, explorationEligible: false };
226
+ out.push(hubAdj !== undefined ? { ...guarded, reuseAdjust: hubAdj } : guarded);
165
227
  localIds.add(h.geneId);
228
+ if (h.assetId)
229
+ localAssetIds.add(h.assetId);
166
230
  }
167
231
  }
168
232
  for (const a of await store.list('AntiGene', limit)) {
@@ -177,8 +241,10 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
177
241
  continue;
178
242
  const antiGeneId = stringField(a['id']) ?? String(a.asset_id);
179
243
  const summary = stringField(a['summary']);
180
- const relevant = trigger.some((m) => sigSet.has(m))
181
- || tagOverlapScore(signals, { signalsMatch: trigger, geneId: antiGeneId, summary }) > 0;
244
+ const matchingTrigger = withoutTaskDomainSignals(trigger);
245
+ // This is a safety inclusion gate: ubiquitous evidence must still emit warnings.
246
+ const relevant = matchingTrigger.some((m) => sigSet.has(m))
247
+ || tagOverlapScore(matchingSignals, { signalsMatch: matchingTrigger, geneId: antiGeneId, summary }) > 0;
182
248
  if (!relevant)
183
249
  continue;
184
250
  const severity = severityOf(a['severity']);
@@ -193,7 +259,7 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
193
259
  ...(rationale ? { rationale } : {}),
194
260
  });
195
261
  }
196
- return { candidates: out, distilledFallback, antiWarnings };
262
+ return { candidates: out, distilledFallback, semanticCorpus, antiWarnings };
197
263
  }
198
264
  /**
199
265
  * Assemble selection candidates from the store for the given signals (the relevant scored set only).
@@ -201,5 +267,7 @@ export async function assembleSelectionPool(store, signals, opts = {}) {
201
267
  * distilled-gene fallback pool.
202
268
  */
203
269
  export async function assembleCandidates(store, signals, opts = {}) {
204
- return (await assembleSelectionPool(store, signals, opts)).candidates;
270
+ // This compatibility wrapper discards semanticCorpus, so preserve its legacy I/O bound instead of scanning
271
+ // 1,000 records for data the caller cannot consume.
272
+ return (await assembleSelectionPool(store, signals, { ...opts, includeSemanticCorpus: false })).candidates;
205
273
  }
@@ -20,6 +20,16 @@ const SIGNAL_CANDIDATES = [
20
20
  { signal: 'capability_gap', title: 'Fill capability gap' },
21
21
  { signal: 'stable_success_plateau', title: 'Explore new strategies during stability plateau' },
22
22
  { signal: 'external_opportunity', title: 'Evaluate external A2A asset for local adoption' },
23
+ // Harness context-budget family (v1 context-compression gene family port). v2 ships no seed-gene catalog, so
24
+ // the reusable strategies arrive as ADVISORY candidates the runtime may distill into genes — one per bloat
25
+ // source, because a single "shorten the prompt" proposal loses the distinction that decides what is safe to
26
+ // drop (an always-on tool schema is lazy-loadable; an approval gate is not).
27
+ { signal: 'prompt_budget_measurement', title: 'Measure the prompt budget per source before compressing context' },
28
+ { signal: 'context_explosion', title: 'Attribute a context-window overflow to its largest prompt source' },
29
+ { signal: 'tool_schema_bloat', title: 'Load exact tool/MCP schemas from the runtime loader instead of always-on prompt text' },
30
+ { signal: 'skill_list_bloat', title: 'Compress skill and agent-type descriptions into selectable route cards' },
31
+ { signal: 'transcript_context_bloat', title: 'Compress a pasted transcript into a session handoff packet' },
32
+ { signal: 'memory_index_budget', title: 'Keep the memory index lean and rely on relevance recall for detail' },
23
33
  ];
24
34
  /** Highest → lowest priority problem class used to pick a failure cluster's grouping key (ported v1). */
25
35
  const PROBLEM_PRIORITY = ['problem:performance', 'problem:protocol', 'problem:reliability', 'problem:stagnation', 'problem:capability'];
@@ -4,13 +4,14 @@ import type { GepCategory, Mutation, Capsule, EvolutionEvent } from '../wire/ind
4
4
  import type { AssetStoreProvider } from '../assetstore/provider.js';
5
5
  import type { StrategyPoint } from '../strategy/strategyPoint.js';
6
6
  import { type CycleStage } from '../cycle/stateMachine.js';
7
- import { type GeneDecision, type SelectionInput, type GeneCandidateInput, type AntiWarning } from './geneSelection.js';
7
+ import { type GeneDecision, type SelectionInput, type GeneCandidateInput, type AntiWarning, type SelectionGuardMode } from './geneSelection.js';
8
8
  import { type EnvFingerprint } from '../bootstrap/envFingerprint.js';
9
9
  import type { PersonalityStore } from '../personality/store.js';
10
10
  import { type ResolutionStatus } from './solidify.js';
11
11
  import type { ProofOfWork } from '../schema/proofOfWork.js';
12
12
  import { type ClassifyRecentEvent } from './cycleFailureClassifier.js';
13
13
  import type { MemoryGraphGeneEvidence } from './memoryGraph.js';
14
+ import { type SelectionPolicy } from './ucb1.js';
14
15
  export interface TriggerEval {
15
16
  trigger: boolean;
16
17
  reasons: string[];
@@ -66,6 +67,8 @@ export interface CycleEngineDeps {
66
67
  rng?: () => number;
67
68
  /** Injected environment fingerprint (deterministic tests). Defaults to capturing the real runtime env. */
68
69
  envFingerprint?: () => EnvFingerprint;
70
+ /** Latest external capability gaps. Composition owns persistence/wire details; core reads one bounded snapshot. */
71
+ capabilityGaps?: () => readonly string[];
69
72
  /** 触发评估(常注入 TriggerEngine.evaluate 的包装; 缺省=直接触发). */
70
73
  trigger?: (p: ProblemPattern, now: number) => Promise<TriggerEval> | TriggerEval;
71
74
  /** 可进化人格(可选). 注入后, 每轮:
@@ -82,10 +85,20 @@ export interface CycleInput {
82
85
  cycleId: string;
83
86
  problem: ProblemPattern;
84
87
  signals: readonly string[];
88
+ /** Curriculum targets already prepared before candidate assembly. Omit for direct runCycle callers. */
89
+ curriculumSignals?: readonly string[];
85
90
  category: GepCategory;
86
91
  /** Optional explicit strategy preset name; when set, it wins over history-derived meta-signal auto-detection. */
87
92
  strategyName?: string;
88
93
  candidates: readonly GeneCandidateInput[];
94
+ /** Trust-filtered library corpus captured before relevance admission for stable semantic IDF. */
95
+ semanticCorpus?: readonly GeneCandidateInput[];
96
+ /** Emergency rollback: use the pre-IDF semantic scorer for this cycle. */
97
+ disableSemanticIdf?: boolean;
98
+ /** Experimental plateau selection policy. Default preserves engine-health + legacy random drift. */
99
+ selectionPolicy?: SelectionPolicy;
100
+ /** Versioned relevance-guard rollout. Omit for legacy direct-call behavior. */
101
+ selectionGuard?: SelectionGuardMode;
89
102
  selectionFloor?: number;
90
103
  /**
91
104
  * Explicit GEP/runtime-selected gene. Forwarded after candidate assembly and local hard filters, so it cannot
@@ -102,7 +115,7 @@ export interface CycleInput {
102
115
  /**
103
116
  * Distilled-gene fallback pool (ported from v1 #97): broadly-applicable distilled genes that do NOT match the
104
117
  * live signals, assembled (trust/review/ban-filtered) upstream. Forwarded to selection, which uses one only as a
105
- * last resort when no candidate clears the floor — reusing a known distilled strategy instead of a blind innovate.
118
+ * last resort when normal selection has no reusable positive choice — reusing a known distilled strategy instead of a blind innovate.
106
119
  */
107
120
  distilledFallback?: readonly GeneCandidateInput[];
108
121
  /** Advisory-only AntiGene warnings matched upstream for this cycle's base signals. */
@@ -150,5 +163,13 @@ export interface CycleResult {
150
163
  export declare class CycleEngine {
151
164
  private readonly deps;
152
165
  constructor(deps: CycleEngineDeps);
166
+ /**
167
+ * Add V1-compatible curriculum targets from V2's replayable event history. Public so the orchestrator can run
168
+ * it before candidate assembly; runCycle calls it again for direct callers. Set merging makes that idempotent.
169
+ */
170
+ prepareCurriculumSignals(signals: readonly string[]): {
171
+ signals: string[];
172
+ curriculumSignals: string[];
173
+ };
153
174
  runCycle(input: CycleInput): Promise<CycleResult>;
154
175
  }