Skip to main content

Pilot-2: served format, habit episodes

Weekend run on the rig, 2026-11-07/08. Pilot-2 kept the base model and the held-out set, and fixed what pilot-1 got wrong.

What changed from pilot-1​

Pilot-1Pilot-2
Training formatthinking off, one-line system promptthinking on with a thought before every action; the exact lean pi wire format (D-FT-8, D-FT-9)
Agent harness at evalpi default (7,338-token prefix)lean pi profile (~910 tokens)
Datatrajectories from other harnesses (55% with stale paths), per-turn samples3,011 habit-simulated episodes with real tool output: solve, repair chains, examples (Training data)
Samplesone per assistant turnone per episode, with loss on every assistant turn
LoRAtop 16 blocks, rank 16, 1 epochall blocks, rank 32, 2 epochs

Training​

  • The first attempt diverged.
    • Settings: learning rate 1e-4, LoRA scale 20.
    • Train loss jumped from 0.31 to 10.2 at step 80, as warmup ended. Validation went from 0.59 to 6.76.
  • The re-run trained cleanly.
    • Settings: learning rate 2e-5, LoRA scale 10, warmup 100.
    • It took ~21 h for 2,368 steps.
Step0200100012002368
Val loss0.5920.1910.1760.1690.175
  • Served with the base model's sampling defaults (temperature 1, top_k 64, top_p 0.95).

Held-out A/B (lean profile, agent mode)​

Each arm had a 5-hour wall-clock cap; A and C hit it before finishing all 24 benchmarks. The base + slim-prompt arm (A2) did not run before the weekend window closed.

ArmModelPromptPassCoreStretchFailuresMedian output tokens per pass
Abase 12Bfull teaching prompt6/13 (46%)6/100/33 compile, 3 timeout, 1 runtime9,869
Bpilot-22.4 KB slim prompt4/24 (17%)3/121/1216 compile, 3 logic, 1 runtime3,097
Cpilot-2none4/19 (21%)2/92/1011 compile, 2 logic, 1 runtime, 1 timeout2,185

On the 10 benchmarks all three arms reached, A passed 5, B passed 1 and C passed 2.

The kill criterion (B ≥ A) fails.

What it shows​

  • The agent protocol is fixed. Pilot-1 failed every agent run on protocol: no file written, tool calls lost in the thinking channel. Pilot-2 has zero protocol misses. Every failure is a real program that does not compile or prints the wrong output.

  • Concise only when it succeeds. On its passes the fine-tune used about a third of base's output tokens. Per run it is the other way round, because failing runs loop:

    ArmMedian output tokens per runMedian turnsRuns ≥ 50 turnsFinal error is a parse error
    A (base)9,7284.50/101/10
    B (ft + slim)17,16857.513/2414/24
    C (ft, no prompt)12,05529.58/189/18

    A's 3 other rows hit pi's 1-hour hard timeout with no output.

Diagnosis (2026-11-09)​

The banked rows (final code, final error, tool histogram, turns) are enough to see what went wrong:

  • The fine-tune's syntax is wrong. Two thirds of its failures end in a parse error, and the errors are borrowed syntax:

    • as casts and -> match arms;
    • bare assignment without let;
    • ; in expression-bodied functions, and ? inside interpolation;
    • a missing {.

    Base's failures are type and effect errors in programs that parse.

  • It loops instead of looking things up. Typical failing runs are 40–80 write → check cycles that rewrite the whole file and never converge (merge_sort: 408 turns). It almost never reads docs or examples once an error appears.

  • The training data did not cover this. Of 1,671 repair episodes:

    • 618 fix undefined variable and 202 fix exhaustiveness;
    • 26 fix a parse error;
    • no episode shows the "two failed fixes, so look it up" move. The 241 episodes with an ailang docs or ailang examples search lookup all do it before the first write.

    The repair chains came from staleness pairs: programs that once compiled and later broke on checker changes. That source cannot produce the syntax mistakes a model makes on its own.

So the result is not a ceiling. The model learned the shape of the loop, but the data never showed it its own kinds of mistakes, or the habit of looking up after a failed fix.

Open questions for pilot-3​

These are not yet decided.

  • On-policy repair data (best supported by the diagnosis). Generate episodes from the fine-tune's own failures:

    1. Run pilot-2 on the training benchmarks only, never the held-out 24.
    2. Keep its real parse and type errors.
    3. Repair each one with the existing iterative stale_fix.py loop, verified against the expected output.
    4. Render the repairs as episodes. After a second failed fix, the episode does a lookup: ailang docs, ailang examples search, or ailang prompt for the syntax.

    Separately, cap or penalise turn counts over ~20 in the episode mix.

  • Fine-tune + the full teaching prompt. A fine-tune that carries the habits, given the prompt for language knowledge, might beat base while staying concise. This arm was never run.

  • More language data. The 2,733 verified repo programs and the eval passes were unused as agent episodes. Adding them would widen the language the model has seen beyond the 57 benchmarks.

  • Self-distillation. Base 12B's own verified thinking would give richer reasoning than the fact-based thoughts.

  • A2 and complete arms. Every arm should finish all 24 benchmarks; the time caps cut A and C short.