← Back to Blog

Compete in the Arena: Optimizing Fitness

Advanced tutorial: submit your gene to the Arena, analyze F(g) and V(g) scores, iteratively improve performance, and climb the rankings.

Compete in the Arena: Optimizing Fitness

The Arena is where genes prove their worth. Every gene submitted to the Arena receives a fitness score (F(g)) and a safety score (V(g)) — two metrics that determine its rank, survival, and your developer reputation.

In this tutorial, you'll submit a gene, understand its scores, iteratively improve it, and watch it climb the rankings.

Prerequisites

Step 1: Submit to the Arena

Let's submit a gene. If you don't have one, create a quick JSON formatter:

mkdir -p genes/json-fmt && cat > genes/json-fmt/index.ts << 'EOF'
export async function express(input: { code: string; indent?: number }) {
  const indent = input.indent ?? 2;
  try {
    const parsed = JSON.parse(input.code);
    return { formatted: JSON.stringify(parsed, null, indent), valid: true };
  } catch {
    return { formatted: input.code, valid: false };
  }
}
EOF

rotifer wrap json-fmt --domain code.format
rotifer compile json-fmt

Now submit:

rotifer arena submit json-fmt
Testing 'json-fmt' before submission...
✓ All tests passed

Submitting to Arena...
✓ Gene 'json-fmt' submitted

Rank:     #2 in code.format
V(g):     0.9100
Fidelity: Native

Step 2: Understand the Scores

F(g) — Fitness Score

F(g) is multiplicative, not a weighted sum. Since v0.5.5 the model has been:

F(g) = S_r · ln(1 + C_util) · (1 + R_rob) · L · Cost
Symbol What it measures How it is obtained
S_r success rate across sandbox runs measured — zero here zeros the whole score
C_util coverage / utilization defaults to 0.5 when not measured
R_rob robustness under adversarial input defaults to 0.5 when not measured
L latency efficiency, 1 / (1 + avg_ms / scale)faster is nearer 1 measured
Cost resource efficiency, 1 / (1 + avg_cost / scale)cheaper is nearer 1 measured

Five factors, multiplied, with no cap. L and Cost are efficiency scores, not the costs themselves: the faster and cheaper a gene runs, the nearer they sit to 1 and the higher the score; the slower and costlier, the nearer to 0 and the more the score is pulled down.

Fidelity is not a bonus term inside the formula — it is a discount applied afterwards: F(g) = base × discount, with Native 1.0, Hybrid 0.85, Wrapped 0.7.

Two of the five inputs are still placeholders, and the reference scale inside L and Cost is provisional and still being calibrated. That is why a submission today is filed as an estimate rather than a ranked score — and why the sample output in this post does not pin down absolute figures. What to read is how the terms move each other, not any one number. Read them as a reproducible execution record; the ordering they will eventually produce is not settled yet.

V(g) — Safety Score

The safety validation is a hard gate with a separate 0.0–1.0 score:

V(g) is Test_Pass_Rate / Security_Leak_Risk. The leak risk comes from a static pattern scan over the gene's source — line-level rules, not an AST analysis:

Rule Detects Severity
S-01 Dynamic code execution (eval, new Function) CRITICAL
S-02 System command execution (child_process, exec, spawn) CRITICAL
S-03 Code obfuscation (base64 decode then execute) CRITICAL
S-04 Suspicious external communication HIGH
S-05 Environment variable access HIGH
S-06 Persistent outbound connection HIGH
S-07 File system operations MEDIUM

Admission Gate

The protocol sets a threshold on each score:

V(g) is a hard gate: fail it and the gene is rejected with diagnostic feedback.

The F(g) gate does not block submission for now. The reason is in the section above: two of its inputs are placeholders and the reference scale in its efficiency terms is provisional — gating admission on a score the same run files as "estimated, not ranked" measures the scale, not the gene. The CLI still prints F(g) and flags it when it falls below τ, but it will not reject on it. The gate returns once the reference scale is calibrated.

Step 3: Read What the Submission Actually Reports

Submitting again prints the full record, not just the headline score:

rotifer arena submit json-fmt
✓ Gene 'json-fmt' submitted to Arena
  Domain: code.format
  Fidelity: Native
  V(g): 0.9100
  Success Rate: 90.0%
  Latency Score: 0.9881
  Admission: PASSED
  Execution: Sandbox verified (20 runs)
  Recorded as: estimated

Three things are worth reading carefully.

Success Rate: 90.0% is the lever. S_r sits in the numerator of F(g), and it is the one factor whose zero collapses the whole score. Two of the other inputs — C_util and R_rob — are still fixed placeholders, so they contribute the same amount to every gene in the Arena and cannot be optimized against.

Recorded as: estimated is not decoration. Until those placeholders are measured, submissions are filed as estimates: the execution happened and is recorded, but the number does not yet rank.

V(g) is a separate axis, not part of F(g). A gene can be perfectly safe and useless, or fast and rejected. They gate independently at F(g) >= 0.3 and V(g) >= 0.7.

So the question this tutorial can answer today is a narrow one: why did 2 of 20 runs fail, and what does fixing them do to the score?

Step 4: Raise the Success Rate

A run counts as a failure when express() throws, times out, or returns output that violates the declared outputSchema. For the JSON formatter, the failures are malformed input the naive implementation gives up on:

export async function express(input: { code: string; indent?: number }) {
  const indent = input.indent ?? 2;
  const code = (input.code ?? '').trim();

  if (!code) {
    return { formatted: '', valid: false };
  }

  try {
    const parsed = JSON.parse(code);
    return { formatted: JSON.stringify(parsed, null, indent), valid: true };
  } catch {
    // Salvage the common case: trailing commas
    try {
      const cleaned = code.replace(/,\s*([\]}])/g, '$1');
      const parsed = JSON.parse(cleaned);
      return { formatted: JSON.stringify(parsed, null, indent), valid: true };
    } catch {
      return { formatted: code, valid: false };
    }
  }
}

Note what the fallback does not do: it never throws and never returns a partial object. Returning { formatted, valid: false } for genuinely broken input is a successful run reporting a negative result — that is a different thing from a crash, and the Arena scores it differently.

Recompile and resubmit:

rotifer compile json-fmt
rotifer arena submit json-fmt
  Success Rate: 100.0%

S_r moved from 0.90 to 1.00 and F(g) moved with it, proportionally — S_r is a direct multiplier, so a ten percent gain in success rate is a ten percent gain in the score. That is the multiplicative structure doing exactly what it says.

Step 5: Check the Safety Axis Separately

V(g) comes from a static pattern scan over your source. Run it on its own before you submit:

rotifer vg json-fmt

The scan is line-level regex matching against the S-01 to S-07 rules above. That makes it fast and it makes it blunt: a string containing the word eval in a comment can trip S-01. Read the finding, don't just chase the grade — the point of V(g) is that a consumer can see what your gene reaches for before installing it.

Step 6: Watch the Rankings

Monitor your gene's position in real-time:

rotifer arena watch code.format
Watching code.format rankings...

[14:32:01] json-fmt ↑ #2 → #1 (F: 0.820.86)
[14:32:04] No changes
[14:32:07] No changes

Press Ctrl+C to stop

Step 7: Go Global with Cloud Arena

Local Arena is great for testing. To compete globally:

rotifer login
rotifer arena submit json-fmt --cloud
✓ Submitted to Cloud Arena
Rank: #8 globally in code.format

View global rankings:

rotifer arena list --cloud -d code.format

Step 8: Check Your Reputation

Every Arena submission affects your developer reputation:

rotifer reputation --mine
Developer Reputation:
  Arena Score:    0.82  (based on gene rankings)
  Usage Score:    0.45  (based on install counts)
  Stability:     0.91  (based on gene consistency)

  Overall:       0.73

Reputation is a composite of your genes' Arena performance, how often others use them, and their reliability over time.

The Optimization Loop

The cycle is the point, even while the scoring model is still being sharpened:

  1. Submit → get the execution record, not just a number
  2. Diagnose → find the runs that failed and why
  3. Improve → targeted code changes
  4. Resubmit → verify S_r moved
  5. Watch → monitor competitive position

This is selection pressure in its earliest form: the Arena measures, and your gene adapts to what it measures. What it measures well today is whether the gene does what it declared it would.

Tips for High Fitness


Deep Dive: See the Gene Standard specification for the complete fitness model, and the Arena CLI Reference for all command options.