What one task actually is

Every task is a known composition of primitives — the structure — instantiated with concrete parameters and data — the surface.

We generate the tasks, so we know the structure. The model is never told it. There is no docstring. It sees input/output pairs and must induce the rule, then write transform(xs).

Holds fixed
Varies
Tests

What the model sees


      

That is the whole prompt. No docstring, no list of primitives, no hint that there are two steps.

The hidden structure

? → ?

Try it first. Look at the pairs on the left and say the rule out loud. That guess is exactly the induction problem the model is handed.

One demo, pushed through the composition

input
after step 1
after step 2

demo

How verification works



    
candidate program sandboxed executor all 8 cases must match

Exact match, element by element. No LLM judge, no partial credit. The model sees the 4 demos; the executor also runs 4 hidden tests it was never shown. Fail one case and the task is unsolved.

Held-out set What it measures Base
HO-surfaceSame structures as training, unseen surface. Specialisation: did it learn the transformation, or memorise these particular lists?0.100
HO-compositionNovel compositions of the same primitives; templates never trained on. Systematic generalisation — the one the whole project cared about.0.083
FORGET probeMBPP+, ordinary unrelated Python problems, never trained on. What the update destroyed.0.847
The 12-primitive vocabulary — each maps list[int] → list[int]

The generator draws every structure from this vocabulary. The model is not shown this list either.

Honesty note.

Scale note.