Skip to main content

Overview

A Mutation is an explicit change directive that encodes:
  • Category (repair | optimize | innovate)
  • Risk level (low | medium | high)
  • Trigger signals that caused it
  • Expected effect and target
Mutations are first-class objects that make evolution decisions auditable and reversible.

Mutation Structure

// From src/gep/mutation.js:100
function buildMutation({ signals, selectedGene, driftEnabled, personalityState }) {
  const ts = Date.now();
  const category = mutationCategoryFromContext({ signals, driftEnabled });
  const triggerSignals = uniqStrings(signals);
  
  const base = {
    type: 'Mutation',
    id: `mut_${ts}`,
    category,
    trigger_signals: triggerSignals,
    target: String(target || targetFromGene(selectedGene)),
    expected_effect: String(expected_effect || expectedEffectFromCategory(category)),
    risk_level: 'low',
  };
  
  // Risk assignment and safety constraints...
  return base;
}

Fields

type
string
required
Always "Mutation"
id
string
required
Unique identifier (e.g., mut_1709876543210)
category
enum
required
Change intent: repair | optimize | innovate
trigger_signals
string[]
required
Signals that triggered this mutation
target
string
required
What is being changed (e.g., gene:error_handling_robust)
expected_effect
string
required
Human-readable description of the intended outcome
risk_level
enum
required
low | medium | high

Mutation Categories

The category is determined by analyzing the signal context:
// From src/gep/mutation.js:55
function mutationCategoryFromContext({ signals, driftEnabled }) {
  if (hasErrorishSignal(signals)) return 'repair';
  if (driftEnabled) return 'innovate';
  if (hasOpportunitySignal(signals)) return 'innovate';
  
  // Consult strategy preset
  try {
    var strategy = require('./strategy').resolveStrategy();
    if (strategy && strategy.innovate >= 0.5) return 'innovate';
  } catch (_) {}
  
  return 'optimize';
}

Repair

Intent: Fix errors and increase stability Triggered by:
  • log_error
  • errsig:...
  • recurring_error
Expected effect:
// From src/gep/mutation.js:71
if (category === 'repair') 
  return 'reduce runtime errors, increase stability, and lower failure rate';
After 3+ consecutive failed repairs, the system forces innovation to break the loop.

Optimize

Intent: Improve success rate and reduce operational cost Triggered by:
  • stable_success_plateau
  • No errors + no opportunity signals
Expected effect:
if (category === 'optimize') 
  return 'improve success rate and reduce repeated operational cost';

Innovate

Intent: Explore new strategy combinations to escape local optimum Triggered by:
  • user_feature_request
  • capability_gap
  • perf_bottleneck
  • force_innovation_after_repair_loop
  • Drift enabled
Expected effect:
if (category === 'innovate') 
  return 'explore new strategy combinations to escape local optimum';
Innovation is the only way to add new capabilities. Repair and optimize are conservative.

Risk Levels

Default Assignment

// From src/gep/mutation.js:123
const base = {
  // ...
  risk_level: 'low',
};

if (category === 'innovate') base.risk_level = 'medium';

High-Risk Escalation

High-risk mutations are rare and guarded by strict safety constraints:
// From src/gep/mutation.js:127
if (allowHighRisk && category === 'innovate') {
  base.risk_level = 'high';
}
High-risk mutations are only allowed when allowHighRisk=true is explicitly passed.

Safety Constraints

Two hard safety rules prevent dangerous combinations:

Rule 1: No Innovate + High-Risk Personality

// From src/gep/mutation.js:134
const highRiskPersonality = isHighRiskPersonality(personalityState);
if (base.category === 'innovate' && highRiskPersonality) {
  base.category = 'optimize';
  base.expected_effect = 'safety downgrade: optimize under high-risk personality';
  base.risk_level = 'low';
  base.trigger_signals = [
    ...base.trigger_signals, 
    'safety:avoid_innovate_with_high_risk_personality'
  ];
}
High-risk personality is defined as:
// From src/gep/mutation.js:84
function isHighRiskPersonality(p) {
  const rigor = p && Number.isFinite(p.rigor) ? p.rigor : null;
  const riskTol = p && Number.isFinite(p.risk_tolerance) ? p.risk_tolerance : null;
  
  if (rigor != null && rigor < 0.5) return true;
  if (riskTol != null && riskTol > 0.6) return true;
  return false;
}

Rule 2: High-Risk Requires Safe Personality

// From src/gep/mutation.js:142
if (base.risk_level === 'high' && !isHighRiskMutationAllowed(personalityState)) {
  base.risk_level = 'medium';
  base.trigger_signals = [...base.trigger_signals, 'safety:downgrade_high_risk'];
}
High-risk mutations require:
// From src/gep/mutation.js:91
function isHighRiskMutationAllowed(personalityState) {
  const rigor = personalityState && personalityState.rigor || 0;
  const riskTol = personalityState && personalityState.risk_tolerance || 1;
  return rigor >= 0.6 && riskTol <= 0.5;
}
A personality with rigor < 0.6 or risk_tolerance > 0.5 cannot execute high-risk mutations.

Blast Radius Estimation

The blast radius measures the scope of change (files and lines modified). This is calculated in solidify.js after the mutation is executed:
// From src/gep/solidify.js (referenced in evolve.js)
const blastRadius = {
  files: modifiedFiles.length,
  lines: totalLinesChanged,
  insertions: totalInsertions,
  deletions: totalDeletions,
};

Risk × Blast Radius Matrix

Risk LevelTypical Blast RadiusValidation Strategy
Low1-3 files, less than 50 linesLocal tests only
Medium3-10 files, 50-200 linesFull test suite
High10+ files, 200+ linesMulti-stage validation + manual review
If a “low-risk” mutation produces a large blast radius, it’s automatically flagged for review.

Mutation Strategies

The EVOLVE_STRATEGY env var controls intent balance:
EVOLVE_STRATEGY=balanced    # Default: balanced mix
EVOLVE_STRATEGY=innovate    # Maximize new features
EVOLVE_STRATEGY=harden      # Focus on stability
EVOLVE_STRATEGY=repair-only # Emergency fix mode

Strategy Presets

// From src/gep/mutation.js:63
try {
  var strategy = require('./strategy').resolveStrategy();
  if (strategy && strategy.innovate >= 0.5) return 'innovate';
} catch (_) {}
See the Strategy Configuration guide for details.

Validation Flow

Every mutation goes through validation before being solidified:

Example Mutations

Repair Mutation

{
  "type": "Mutation",
  "id": "mut_1709876543210",
  "category": "repair",
  "trigger_signals": [
    "log_error",
    "errsig:TypeError: Cannot read property 'id' of undefined"
  ],
  "target": "gene:error_handling_robust",
  "expected_effect": "reduce runtime errors, increase stability, and lower failure rate",
  "risk_level": "low"
}

Innovation Mutation

{
  "type": "Mutation",
  "id": "mut_1709876654321",
  "category": "innovate",
  "trigger_signals": [
    "user_feature_request:add support for CSV export",
    "capability_gap"
  ],
  "target": "gene:feature_expansion",
  "expected_effect": "explore new strategy combinations to escape local optimum",
  "risk_level": "medium"
}

Safety-Downgraded Mutation

{
  "type": "Mutation",
  "id": "mut_1709876765432",
  "category": "optimize",
  "trigger_signals": [
    "user_feature_request:refactor authentication",
    "safety:avoid_innovate_with_high_risk_personality"
  ],
  "target": "behavior:protocol",
  "expected_effect": "safety downgrade: optimize under high-risk personality (avoid innovate+high-risk combo)",
  "risk_level": "low"
}

Mutation Lifecycle

  1. Build: buildMutation() constructs the object from signals
  2. Validate: Check isValidMutation() for schema compliance
  3. Execute: Agent performs the change guided by the mutation
  4. Record: Outcome is stored in events.jsonl with blast radius
  5. Learn: Memory graph updates causal paths

Next Steps

Personality

See how personality traits modulate mutation behavior

Evolution Cycle

Understand the full execution flow

Build docs developers (and LLMs) love