Ten skills, one model, one pass
We taught our Learner 1.0 model ten unrelated skills one after another, one training example per update, thousands of examples per skill, with no replay and no label telling it where one skill ended and the next began. Every acquired skill is retained through all the sequential teaches and the base eval holds constant showing no loss of base capabilities.
1. The question and what was measured
When supervised skills are taught in sequence to one model with a fixed number of trainable parameters, does teaching the later ones erase the earlier ones? The measurement is the count of exactly correct answers on a fixed 225-row held-out panel for every skill, taken at the checkpoint right after that skill's own teach and again after every later teach.
Final panel scores after the tenth teach, in the taught order: SCAN 222, Meridian 84, Adyghe G2P 146, Oriel 9, COGS 225, Sable 198, PCFG SET 172, Tessel 188, Juniper 120, Bracken 161, each of 225. Against each skill's own-end score the changes are 0, +1, −1, −3, 0, 0, −2, 0, +2, 0. The one skill that moved by more than two rows, Oriel, was also the one the model never learned well: 12 of 225 at its own teach.
Acquisition varied widely by skill, from 12 to 225 of 225 at own-end. That spread is part of the result. The retention claim is about the skills that were acquired, and it is a claim about this stream, this order and this budget, not about an unlimited horizon.
2. Setup
Model. Learner 1.0, with 1.14 billion trainable parameters, fixed before the first skill and never grown. Everything else about the learning mechanism is proprietary and is not described here.
Objective. Cross-entropy on the answer tokens only, including the native end-of-sequence token, so the model is also trained to stop.
Data order. Ten skills in a fixed order (SCAN, Meridian, Adyghe G2P, Oriel, COGS, Sable, PCFG SET, Tessel, Juniper, Bracken), each as a contiguous block of rows. One pass: no row is presented twice. No rows from an earlier skill are replayed during a later one.
Batch and accumulation. Batch size one, no gradient accumulation: every update is a single example. Gradient clipping at 1.0. Each teach resumed from the checkpoint the previous accepted teach ended on.
What the learner sees. Only the example text: the prompt and the answer. No skill label, boundary marker or teach index is given to it. The colored bands in the figures are the experiment design, not an input.
Checkpoints and monitoring. A full resumable checkpoint at the end of every skill (and at quarter points within it). During training, a held-out loss was measured every 25 updates on eight fixed panel rows per monitored skill; this monitor is separate from the final evaluation and is reported as a curve, not a score.
Generation and scoring. Greedy decoding with a per-skill token cap set from the longest target in the skill; a row is correct only if the whole answer matches the frozen target under that skill's scorer (section 5).
Compute. Training ran on 1 H200. The ten teaches were not one uninterrupted job (section 10).
3. What one sample is
A sample is one prompt and one target answer. The model reads the prompt, is trained on every token of the answer including the end-of-sequence token, and the resulting gradient is applied as one update. Then the next sample. Here is the first training row of the fourth skill, exactly as stored:
Apply the oriel packet codec procedure to the input. Return only a JSON list of integers, without explanation.
Input: {"payload":[9,3,2,13,6,13,12,12]}
Answer:Target (all 21 integers are supervised, plus the end-of-sequence token):
[15,13,8,14,12,8,10,7,7,2,8,15,13,3,2,8,1,5,1,5,9]
Counting. Two counts appear in this article. Updates is the number of single-example updates the final checkpoint was trained with, 63,282. Supervised tokens are the answer tokens the loss was computed on, including end-of-sequence. Examples differ in length, so the tables report both.
The training data. Every training row of all ten skills, in the taught order, is in the replication repository: ten_skills/data/train. The held-out panels are in ten_skills/data/evals. The files are there to be read and re-scored; the repository does not run this training.
4. The ten skills
Four are public datasets (SCAN, Adyghe grapheme-to-phoneme, COGS, PCFG SET) and six are procedures written for this experiment so that the base model could not know them in advance (Meridian, Oriel, Sable, Tessel, Juniper, Bracken). For the written procedures the prompt states only the input and the output format; the rules below were never shown to the learner. Each card shows one real training row and one or two real held-out rows with the model's actual answer at the end of that skill's teach and after all ten teaches. Examples are chosen for length and structure, not for success; each skill with a wrong final answer shows one.
1. SCAN: compositional command-to-action translation (public dataset)
A navigation command in a small controlled language (walk, run, jump, look, turn left/right, around, opposite, twice, thrice, and, after) is translated into the exact sequence of primitive actions. Training rows come from the public SCAN length-split training file; the fixed panel rows come from the released retention bank, which has zero training-group overlap by the release manifest. Scored as an exact match of the whole action sequence.
A real training row (scan/train/16767:ce_v2)
Request: Translate this command into actions: run around left twice after walk right thrice Response:
Target:
I_TURN_RIGHT I_WALK I_TURN_RIGHT I_WALK I_TURN_RIGHT I_WALK I_TURN_LEFT I_RUN I_TURN_LEFT I_RUN I_TURN_LEFT I_RUN I_TURN_LEFT I_RUN I_TURN_LEFT I_RUN I_TURN_LEFT I_RUN I_TURN_LEFT I_RUN I_TURN_LEFT I_RUN
A held-out question (scan/dev/9952:ce_v2)
Request: Translate this command into actions: walk thrice and look around right Response:
Target:
I_WALK I_WALK I_WALK I_TURN_RIGHT I_LOOK I_TURN_RIGHT I_LOOK I_TURN_RIGHT I_LOOK I_TURN_RIGHT I_LOOK
Answer at the end of its own teach and after all ten teaches (identical): correct
I_WALK I_WALK I_WALK I_TURN_RIGHT I_LOOK I_TURN_RIGHT I_LOOK I_TURN_RIGHT I_LOOK I_TURN_RIGHT I_LOOK
A held-out question the model got wrong (scan/dev/15105:ce_v2)
Request: Translate this command into actions: turn around left thrice after turn opposite left thrice Response:
Target:
I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT
Answer at the end of its own teach and after all ten teaches (identical): wrong
I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT I_TURN_LEFT
2. Meridian: stateful financial-event accounting (new procedure)
Process a list of events in order from balance 0 and reserve 0. A deposit first pays off reserve debt, then credits the remainder to balance. A purchase costs its amount plus a fee of 3; if the balance covers it, debit and count it accepted, otherwise raise the reserve by 2 and count it rejected without paying. A refund credits the amount minus 1 (minimum zero). Return balance, reserve, accepted and rejected. The prompt gives only the input and output format; the rules are never shown to the learner.
A real training row (meridian_settlement:candidate_train:01569)
Apply the meridian settlement procedure to the input. Return only a JSON object with integer fields balance, reserve, accepted, rejected, without explanation.
Input: {"events":[["refund",19],["purchase",18],["deposit",6],["deposit",18],["purchase",27],["purchase",25],["refund",9]]}
Answer:Target:
{"accepted":1,"balance":18,"rejected":2,"reserve":2}
A held-out question (meridian_settlement:retention:00454)
Apply the meridian settlement procedure to the input. Return only a JSON object with integer fields balance, reserve, accepted, rejected, without explanation.
Input: {"events":[["purchase",29],["deposit",37],["purchase",25],["purchase",24],["refund",21]]}
Answer:Target:
{"accepted":1,"balance":27,"rejected":2,"reserve":2}Answer at the end of its own teach and after all ten teaches (identical): correct
{"accepted":1,"balance":27,"rejected":2,"reserve":2}
A held-out question the model got wrong (meridian_settlement:retention:00195)
Apply the meridian settlement procedure to the input. Return only a JSON object with integer fields balance, reserve, accepted, rejected, without explanation.
Input: {"events":[["refund",12],["deposit",4],["refund",19],["refund",31],["refund",38],["deposit",5],["deposit",3],["deposit",22],["deposit",30]]}
Answer:Target:
{"accepted":0,"balance":160,"rejected":0,"reserve":0}Answer at the end of its own teach and after all ten teaches (identical): wrong
{"accepted":0,"balance":159,"rejected":0,"reserve":0}
3. Adyghe grapheme-to-phoneme (public dataset)
Transcribe a written Adyghe word into IPA under the SIGMORPHON 2020 convention. Adyghe is a Northwest Caucasian language with a large consonant inventory and long orthographic words, so a single wrong segment fails the row.
A real training row (g2p_ady:train:3071)
Transcribe this Adyghe word into IPA using the SIGMORPHON 2020 grapheme-to-phoneme convention. Return only the transcription, with spaces between phoneme tokens. Word: чъыгшъхьацыз Answer:
Target:
t͡ʃ ə ɣ ʂ ħ aː t͡ʃ ə z
A held-out question (g2p_ady:test:255)
Transcribe this Adyghe word into IPA using the SIGMORPHON 2020 grapheme-to-phoneme convention. Return only the transcription, with spaces between phoneme tokens. Word: мэузын Answer:
Target:
m a w z ə n
Answer at the end of its own teach and after all ten teaches (identical): correct
m a w z ə n
A held-out question the model got wrong (g2p_ady:test:281)
Transcribe this Adyghe word into IPA using the SIGMORPHON 2020 grapheme-to-phoneme convention. Return only the transcription, with spaces between phoneme tokens. Word: ожъубанэхьэмлыу Answer:
Target:
w a ʐʷ b aː n a ħ a m l ə w
Answer at the end of its own teach and after all ten teaches (identical): wrong
w a ʐʷ b aː n a ħ a m ɮ ə w
4. Oriel: binary protocol encoding with escaping and a checksum (new procedure)
Encode a list of payload values 0 to 15. Start with a header [11, number of values]. For each value x emit two nibbles, (x+5) mod 16 and (3x+1) mod 16. Append a checksum: the sum of (position+1) times payload[position], modulo 16. Then escape every nibble equal to 11 or 15 as the pair [15, nibble XOR 6] without escaping the escape nibbles again. Return the final integer list. A row is correct only when the complete list is exactly right.
A real training row (oriel_packet_codec:candidate_train:02363)
Apply the oriel packet codec procedure to the input. Return only a JSON list of integers, without explanation.
Input: {"payload":[9,3,2,13,6,13,12,12]}
Answer:Target:
[15,13,8,14,12,8,10,7,7,2,8,15,13,3,2,8,1,5,1,5,9]
A held-out question (oriel_packet_codec:retention:00442)
Apply the oriel packet codec procedure to the input. Return only a JSON list of integers, without explanation.
Input: {"payload":[1,10,3,1,5,4,4]}
Answer:Target:
[15,13,7,6,4,15,9,15,9,8,10,6,4,10,0,9,13,9,13,15,9]
Answer at the end of its own teach and after all ten teaches (identical): correct
[15,13,7,6,4,15,9,15,9,8,10,6,4,10,0,9,13,9,13,15,9]
A held-out question the model got wrong (oriel_packet_codec:retention:00115)
Apply the oriel packet codec procedure to the input. Return only a JSON list of integers, without explanation.
Input: {"payload":[10,10,12,6,1,2,10,14,0]}
Answer:Target:
[15,13,9,15,9,15,9,15,9,15,9,1,5,15,13,3,6,4,7,7,15,9,15,9,3,15,13,5,1,1]
Answer at the end of its own teach and after all ten teaches (identical): wrong
[15,13,9,15,9,15,9,15,9,15,13,3,15,13,3,6,4,7,7,15,9,15,9,3,15,13,5,1,15,13]
5. COGS: sentence to logical form (public dataset)
Translate an English sentence into its COGS logical form. The training rows are in-distribution rows of the public corpus; the fixed panel is drawn from the released retention bank with zero training-group overlap. Not the official generalization split; this run measured in-distribution acquisition and retention.
A real training row (cogs_semantics:train:02979)
Translate the sentence into its COGS logical form. Return only the logical form, without explanation. Sentence: A melon was improved by a moose . Answer:
Target:
melon ( x _ 1 ) AND improve . theme ( x _ 3 , x _ 1 ) AND improve . agent ( x _ 3 , x _ 6 ) AND moose ( x _ 6 )
A held-out question (cogs_semantics:dev:00690)
Translate the sentence into its COGS logical form. Return only the logical form, without explanation. Sentence: A cake was given to the giraffe . Answer:
Target:
* giraffe ( x _ 6 ) ; cake ( x _ 1 ) AND give . theme ( x _ 3 , x _ 1 ) AND give . recipient ( x _ 3 , x _ 6 )
Answer at the end of its own teach and after all ten teaches (identical): correct
* giraffe ( x _ 6 ) ; cake ( x _ 1 ) AND give . theme ( x _ 3 , x _ 1 ) AND give . recipient ( x _ 3 , x _ 6 )
No held-out row was wrong at the final checkpoint (225 of 225).
6. Sable: a finite-state transaction protocol (new procedure)
Start IDLE with pending, completed and errors at 0. BEGIN in IDLE opens a transaction, elsewhere it is an error. ADD(n) in OPEN adds n to pending, elsewhere an error. COMMIT in OPEN with pending at least 5 moves pending into completed and returns to IDLE; any other COMMIT is an error and leaves the state unchanged. CANCEL in OPEN clears pending and returns to IDLE, elsewhere an error. Return state, pending, completed, errors.
A real training row (sable_workflow:candidate_train:01135)
Apply the sable workflow procedure to the input. Return only a JSON object with state (IDLE or OPEN), pending, completed, errors (integers), without explanation.
Input: {"events":[["ADD",3],["BEGIN"],["BEGIN"],["BEGIN"],["ADD",4],["CANCEL"],["CANCEL"]]}
Answer:Target:
{"completed":0,"errors":4,"pending":0,"state":"IDLE"}
A held-out question (sable_workflow:retention:00447)
Apply the sable workflow procedure to the input. Return only a JSON object with state (IDLE or OPEN), pending, completed, errors (integers), without explanation.
Input: {"events":[["ADD",1],["BEGIN"],["COMMIT"],["ADD",4],["CANCEL"],["CANCEL"]]}
Answer:Target:
{"completed":0,"errors":3,"pending":0,"state":"IDLE"}Answer at the end of its own teach and after all ten teaches (identical): correct
{"completed":0,"errors":3,"pending":0,"state":"IDLE"}
A held-out question the model got wrong (sable_workflow:retention:00398)
Apply the sable workflow procedure to the input. Return only a JSON object with state (IDLE or OPEN), pending, completed, errors (integers), without explanation.
Input: {"events":[["BEGIN"],["ADD",5],["COMMIT"],["COMMIT"],["ADD",4],["ADD",5],["ADD",5],["BEGIN"],["COMMIT"]]}
Answer:Target:
{"completed":5,"errors":5,"pending":0,"state":"OPEN"}Answer at the end of its own teach and after all ten teaches (identical): wrong
{"completed":19,"errors":2,"pending":0,"state":"IDLE"}
7. PCFG SET: evaluate a compositional string expression (public dataset)
Evaluate an expression built from string-manipulation functions over symbol sequences and return the resulting space-separated symbol sequence. Answers can run to several hundred tokens; the two rows in the whole experiment that hit the generation cap are both from this skill.
A real training row (pcfg_set:train:77047)
Evaluate this PCFG SET expression. Return only the resulting space-separated symbol sequence, with no explanation. Expression: prepend remove_first prepend M19 O17 Z6 B5 Z6 , shift I10 A1 , B18 D6 C7 , Q9 O16 X12 C2 V1 Answer:
Target:
Q9 O16 X12 C2 V1 B18 D6 C7
A held-out question (pcfg_set:test:5768)
Evaluate this PCFG SET expression. Return only the resulting space-separated symbol sequence, with no explanation. Expression: prepend remove_second X15 X20 K18 , remove_first echo echo K18 O14 C20 E11 E5 , F18 E10 K19 L12 , T11 J18 K19 Answer:
Target:
T11 J18 K19 X15 X20 K18
Answer at the end of its own teach and after all ten teaches (identical): correct
T11 J18 K19 X15 X20 K18
A held-out question the model got wrong (pcfg_set:test:6939)
Evaluate this PCFG SET expression. Return only the resulting space-separated symbol sequence, with no explanation. Expression: repeat swap_first_last echo repeat remove_first shift reverse copy shift shift S11 G6 O17 , echo repeat prepend M7 X12 E1 S16 , shift swap_first_last reverse D3 B14 H19 Answer:
Target:
S16 H19 D3 M7 X12 E1 S16 B14 H19 D3 M7 X12 E1 S16 S16 B14 H19 D3 M7 X12 E1 S16 B14 H19 D3 M7 X12 E1 S16 S16 B14 S16 H19 D3 M7 X12 E1 S16 B14 H19 D3 M7 X12 E1 S16 S16 B14 H19 D3 M7 X12 E1 S16 B14 H19 D3 M7 X12 E1 S16 S16 B14
Answer at the end of its own teach: wrong
H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1
Answer after all ten teaches: wrong
H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X14 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1 S16 H19 B14 D3 M7 X12 E1
8. Tessel: constrained lot allocation with rollback (new procedure)
Order inventory lots by expiry ascending, then lot id. A lot is eligible only when its expiry is at least delivery day plus 3 and it is cold. Allocate demand from eligible lots in that order; charge 4 per opened lot plus 2 per unit. If demand cannot be filled completely, cancel every allocation and charge 0. Return the ordered allocations, the charge and the unfilled amount.
A real training row (tessel_lot_allocation:candidate_train:01608)
Apply the tessel lot allocation procedure to the input. Return only a JSON object with allocations (ordered [lot_id,units] pairs), charge (integer), unfilled (integer), without explanation.
Input: {"delivery_day":4,"demand":22,"lots":[{"cold":true,"expiry":13,"id":"L0","units":12},{"cold":false,"expiry":3,"id":"L1","units":6},{"cold":true,"expiry":15,"id":"L2","units":12},{"cold":true,"expiry":10,"id":"L3","units":4},{"cold":false,"expiry":12,"id":"L4","units":12},{"cold":true,"expiry":25,"id":"L5","units":6},{"cold":true,"expiry":1,"id":"L6","units":7},{"cold":true,"expiry":10,"id":"L7","units":10},{"cold":true,"expiry":25,"id":"L8","units":12}]}
Answer:Target:
{"allocations":[["L3",4],["L7",10],["L0",8]],"charge":56,"unfilled":0}
A held-out question (tessel_lot_allocation:retention:00246)
Apply the tessel lot allocation procedure to the input. Return only a JSON object with allocations (ordered [lot_id,units] pairs), charge (integer), unfilled (integer), without explanation.
Input: {"delivery_day":9,"demand":20,"lots":[{"cold":false,"expiry":7,"id":"L0","units":8},{"cold":true,"expiry":3,"id":"L1","units":9},{"cold":true,"expiry":21,"id":"L2","units":7},{"cold":true,"expiry":12,"id":"L3","units":8},{"cold":true,"expiry":8,"id":"L4","units":7},{"cold":true,"expiry":3,"id":"L5","units":11},{"cold":true,"expiry":2,"id":"L6","units":12}]}
Answer:Target:
{"allocations":[],"charge":0,"unfilled":20}Answer at the end of its own teach and after all ten teaches (identical): correct
{"allocations":[],"charge":0,"unfilled":20}
A held-out question the model got wrong (tessel_lot_allocation:retention:00057)
Apply the tessel lot allocation procedure to the input. Return only a JSON object with allocations (ordered [lot_id,units] pairs), charge (integer), unfilled (integer), without explanation.
Input: {"delivery_day":3,"demand":34,"lots":[{"cold":false,"expiry":24,"id":"L0","units":8},{"cold":true,"expiry":21,"id":"L1","units":2},{"cold":true,"expiry":23,"id":"L2","units":9},{"cold":true,"expiry":22,"id":"L3","units":7},{"cold":true,"expiry":1,"id":"L4","units":4},{"cold":true,"expiry":23,"id":"L5","units":9},{"cold":true,"expiry":7,"id":"L6","units":3},{"cold":true,"expiry":9,"id":"L7","units":10}]}
Answer:Target:
{"allocations":[["L6",3],["L7",10],["L1",2],["L3",7],["L2",9],["L5",3]],"charge":92,"unfilled":0}Answer at the end of its own teach and after all ten teaches (identical): wrong
{"allocations":[],"charge":0,"unfilled":34}
9. Juniper: non-preemptive priority scheduling (new procedure)
Each job has a release time, a duration and a priority. From clock 0, among released unscheduled jobs choose the highest priority, tie-break by shorter duration then id; if none is released, advance to the next release. Run jobs without preemption with a 2-unit cooldown after each. Return ordered [job, start, end] triples.
A real training row (juniper_dispatch:candidate_train:01932)
Apply the juniper dispatch procedure to the input. Return only a JSON list of [job_id,start,end] triples in execution order, without explanation.
Input: {"jobs":[{"duration":1,"id":"J0","priority":3,"release":11},{"duration":5,"id":"J1","priority":4,"release":12},{"duration":7,"id":"J2","priority":1,"release":12},{"duration":5,"id":"J3","priority":3,"release":8},{"duration":4,"id":"J4","priority":3,"release":11},{"duration":1,"id":"J5","priority":2,"release":14},{"duration":4,"id":"J6","priority":3,"release":0},{"duration":5,"id":"J7","priority":2,"release":8}]}
Answer:Target:
[["J6",0,4],["J3",8,13],["J1",15,20],["J0",22,23],["J4",25,29],["J5",31,32],["J7",34,39],["J2",41,48]]
A held-out question (juniper_dispatch:retention:00036)
Apply the juniper dispatch procedure to the input. Return only a JSON list of [job_id,start,end] triples in execution order, without explanation.
Input: {"jobs":[{"duration":2,"id":"J0","priority":4,"release":4},{"duration":6,"id":"J1","priority":4,"release":14},{"duration":5,"id":"J2","priority":3,"release":4},{"duration":1,"id":"J3","priority":2,"release":2},{"duration":4,"id":"J4","priority":4,"release":7},{"duration":4,"id":"J5","priority":3,"release":4},{"duration":3,"id":"J6","priority":1,"release":1}]}
Answer:Target:
[["J6",1,4],["J0",6,8],["J4",10,14],["J1",16,22],["J5",24,28],["J2",30,35],["J3",37,38]]
Answer at the end of its own teach: wrong
[["J6",1,4],["J0",6,8],["J4",10,14],["J1",16,22],["J2",24,29],["J5",31,35],["J3",37,38]]
Answer after all ten teaches: correct
[["J6",1,4],["J0",6,8],["J4",10,14],["J1",16,22],["J5",24,28],["J2",30,35],["J3",37,38]]
A held-out question the model got wrong (juniper_dispatch:retention:00110)
Apply the juniper dispatch procedure to the input. Return only a JSON list of [job_id,start,end] triples in execution order, without explanation.
Input: {"jobs":[{"duration":2,"id":"J0","priority":3,"release":6},{"duration":2,"id":"J1","priority":1,"release":5},{"duration":4,"id":"J2","priority":1,"release":14},{"duration":7,"id":"J3","priority":1,"release":14},{"duration":4,"id":"J4","priority":1,"release":11},{"duration":7,"id":"J5","priority":4,"release":4},{"duration":4,"id":"J6","priority":4,"release":6},{"duration":7,"id":"J7","priority":1,"release":8},{"duration":6,"id":"J8","priority":4,"release":5}]}
Answer:Target:
[["J5",4,11],["J6",13,17],["J8",19,25],["J0",27,29],["J1",31,33],["J2",35,39],["J4",41,45],["J3",47,54],["J7",56,63]]
Answer at the end of its own teach and after all ten teaches (identical): wrong
[["J5",4,11],["J6",13,17],["J8",19,25],["J0",27,29],["J1",31,33],["J4",35,39],["J2",41,45],["J7",47,54],["J3",56,63]]
10. Bracken: half-open interval set arithmetic (new procedure)
Take the union of the open half-open intervals, subtract the union of the closed ones, merge touching intervals and return the sorted maximal remaining intervals as [start, end] integer pairs.
A real training row (bracken_intervals:candidate_train:02810)
Apply the bracken intervals procedure. Return only a JSON array of [start,end] integer pairs, without explanation.
Input: {"closed":[[1,2],[-8,0],[32,36],[40,49]],"open":[[-2,3],[-10,-1],[30,40],[18,20]]}
Answer:Target:
[[-10,-8],[0,1],[2,3],[18,20],[30,32],[36,40]]
A held-out question (bracken_intervals:retention:00103)
Apply the bracken intervals procedure. Return only a JSON array of [start,end] integer pairs, without explanation.
Input: {"closed":[[9,11],[-9,-4],[-1,7],[21,23]],"open":[[23,24],[32,38],[9,11]]}
Answer:Target:
[[23,24],[32,38]]
Answer at the end of its own teach and after all ten teaches (identical): correct
[[23,24],[32,38]]
A held-out question the model got wrong (bracken_intervals:retention:00075)
Apply the bracken intervals procedure. Return only a JSON array of [start,end] integer pairs, without explanation.
Input: {"closed":[[37,38],[-8,-4],[20,23]],"open":[[-9,-1],[24,25],[36,45],[-6,0]]}
Answer:Target:
[[-9,-8],[-4,0],[24,25],[36,37],[38,45]]
Answer at the end of its own teach and after all ten teaches (identical): wrong
[[-9,-8],[-4,-1],[24,25],[36,37],[38,45]]
5. Evaluation
Panels. Each skill has a fixed panel of 225 held-out rows. No panel prompt appears among the training prompts of its skill, and no training prompt appears twice within a skill; both are exact-match checks that the repository's scoring command repeats. Eight rows of each panel were also used for the loss monitor during training, so the panels are held out from training but were observed while it ran. The SCAN and COGS panels are samples of those datasets and are not their published generalization splits. For the written procedures the inputs are random instances of the same fixed procedure; a held-out row is a new input, not a new kind of task, and the panels do not test transfer beyond that.
Identity. An answer counts for a checkpoint only if it was generated from that checkpoint's manifest, with the fixed prompt, the skill's cap and the frozen scorer, and it stopped on end-of-sequence or the cap. When the same row was answered twice under the same identity, the first terminal record is used. Across the 2,250 final answers there are 2 cap hits (both PCFG SET, scored wrong) and 0 conflicting duplicates.
Scorers. Five skill-specific scorers, frozen before the run: exact action-sequence match (SCAN), exact logical form (COGS), exact IPA segment sequence (Adyghe), exact symbol sequence (PCFG SET), and typed-JSON comparison for the six procedures (the answer is parsed as JSON and compared with the oracle value; malformed JSON is wrong). No answer repair.
Monitor versus final. The held-out loss curves in the figures come from eight fixed panel rows per skill measured every 25 updates during training; the scores in the tables come from the full 225-row panels generated after training at each checkpoint. The two are different measurements of the same held-out rows and are never mixed.
Pairing. Retention is a paired comparison: for a given skill, the same 225 rows are scored at its own-end checkpoint and at each later checkpoint, so every change is a row that flipped, and every flipped row can be inspected in the evidence explorer.
6. Results
Every checkpoint, every skill
| checkpoint | SCAN | Meridian | Adyghe G2P | Oriel | COGS | Sable | PCFG SET | Tessel | Juniper | Bracken |
|---|---|---|---|---|---|---|---|---|---|---|
| after 1: SCAN | 222 | |||||||||
| after 2: Meridian | 222 | 83 | ||||||||
| after 3: Adyghe G2P | 222 | 84 | 147 | |||||||
| after 4: Oriel | 222 | 82 | 146 | 12 | ||||||
| after 5: COGS | 222 | 81 | 146 | 14 | 225 | |||||
| after 6: Sable | 222 | 81 | 146 | 15 | 225 | 198 | ||||
| after 7: PCFG SET | 222 | 82 | 146 | 16 | 225 | 197 | 174 | |||
| after 8: Tessel | 222 | 83 | 146 | 14 | 225 | 198 | 173 | 188 | ||
| after 9: Juniper | 222 | 84 | 147 | 15 | 225 | 198 | 174 | 187 | 118 | |
| after 10: Bracken | 222 | 84 | 146 | 9 | 225 | 198 | 172 | 188 | 120 | 161 |
Read down a column. SCAN is 222 at all ten checkpoints. Meridian moves between 81 and 84. Adyghe G2P between 146 and 147. COGS stays at 225. Sable is 198 at every checkpoint but one, where it is 197. PCFG SET 172 to 174, Tessel 187 to 188, Juniper 118 to 120. Oriel is the exception: 12, 14, 15, 16, 14, 15, then 9.
Own-end versus final
| skill | own-end | final | change | own-end % | final % |
|---|---|---|---|---|---|
| 1. SCAN | 222 | 222 | +0 | 98.7% | 98.7% |
| 2. Meridian | 83 | 84 | +1 | 36.9% | 37.3% |
| 3. Adyghe G2P | 147 | 146 | -1 | 65.3% | 64.9% |
| 4. Oriel | 12 | 9 | -3 | 5.3% | 4.0% |
| 5. COGS | 225 | 225 | +0 | 100.0% | 100.0% |
| 6. Sable | 198 | 198 | +0 | 88.0% | 88.0% |
| 7. PCFG SET | 174 | 172 | -2 | 77.3% | 76.4% |
| 8. Tessel | 188 | 188 | +0 | 83.6% | 83.6% |
| 9. Juniper | 118 | 120 | +2 | 52.4% | 53.3% |
| 10. Bracken | 161 | 161 | +0 | 71.6% | 71.6% |
| all ten (of 2,250) | 1,528 | 1,525 | -3 | 67.9% | 67.8% |
Summed over all 2,250 rows the model answered 1,528 correctly at own-end and 1,525 at the end, a net change of -3 rows. Excluding Oriel, the nine acquired skills sum to 1,516 at own-end and 1,516 at the end. Both denominators are stated.
Retention as loss
Acquisition per skill
Training dose
| skill | updates | presented tokens | supervised tokens (incl. EOS) | cumulative updates |
|---|---|---|---|---|
| 1. SCAN | 9,850 | 499,982 | 297,232 | 9,850 |
| 2. Meridian | 3,557 | 349,925 | 68,159 | 13,407 |
| 3. Adyghe G2P | 3,600 | 232,037 | 42,122 | 17,007 |
| 4. Oriel | 3,568 | 349,908 | 179,890 | 20,575 |
| 5. COGS | 21,309 | 1,799,981 | 1,099,479 | 41,884 |
| 6. Sable | 3,911 | 349,982 | 73,150 | 45,795 |
| 7. PCFG SET | 7,871 | 699,825 | 195,151 | 53,666 |
| 8. Tessel | 2,835 | 600,000 | 73,159 | 56,501 |
| 9. Juniper | 3,025 | 699,873 | 209,278 | 59,526 |
| 10. Bracken | 3,756 | 340,150 | 57,751 | 63,282 |
| total | 63,282 | 5,921,663 | 2,295,371 |
These totals are the examples the final checkpoint was trained on. Tokens are counted with the base model's tokenizer.
7. Oriel: what the changed answers look like
Oriel is the skill that moved: 12 of 225 at its own teach, 15 after Juniper, 9 after Bracken. The last step lost seven rows and gained one, a net loss of six (2.67 percentage points of the panel, 40% of the 15 it had). A second bounded generation on the same checkpoint reproduced the 9 exactly.
The lost rows share one pattern. Re-scoring each component of each answer with the frozen scorer shows that on all seven the header, the transformed payload, the escaping and the decoded length are still correct after Bracken; only the checksum value changed. The gained row is the mirror image: only its checksum was wrong before. Across all 225 rows the checksum was right on 15 before and 11 after, while the other components stayed within one or two rows. Another 37 rows wrong at both checkpoints also changed, so the answers moved, not the scoring.
The checksum is the final integer of the packet (written as an escape pair when it equals 11 or 15, so the raw list can change length while the decoded length does not). A wrong checksum invalidates the packet, so this is a real decline, localized to the last value of a skill the model never learned well. The monitored held-out loss moved only from 0.0586 to 0.0605 nats: a one-value change flips an exact grade while barely moving the mean token loss.
| row | payload | target | after teach 9 | after teach 10 |
|---|---|---|---|---|
| 00008 | [12, 1, 7, 9, 2, 9, 12] | [15,13,7,1,5,6,4,12,6,14,12,7,7,14,12,1,5,15,13] | [15,13,7,1,5,6,4,12,6,14,12,7,7,14,12,1,5,15,13] correct | [15,13,7,1,5,6,4,12,6,14,12,7,7,14,12,1,5,15,9] wrong |
| 00130 | [12, 10, 10, 9, 7, 8, 10] | [15,13,7,1,5,15,9,15,9,15,9,15,9,14,12,12,6,13,9,15,9,15,9,15,13] | [15,13,7,1,5,15,9,15,9,15,9,15,9,14,12,12,6,13,9,15,9,15,9,15,13] correct | [15,13,7,1,5,15,9,15,9,15,9,15,9,14,12,12,6,13,9,15,9,15,9,1] wrong |
In the first row the escaped checksum pair 15,13 (which decodes to 11) became 15,9 (which decodes to 15). In the second the pair became the single value 1: the decoded list is the same length, and only the checksum value differs. All seven lost rows and the gained row, with both complete predictions, are in the table below (each row id opens that row in the evidence explorer) and in plots/data/derived/oriel_flipped_rows.json; the per-row component analysis for all 225 rows is in the evidence explorer.
All eight rows that changed grade
| row | payload | target | after teach 9 | after teach 10 |
|---|---|---|---|---|
| 00008 | [12, 1, 7, 9, 2, 9, 12] | [15,13,7,1,5,6,4,12,6,14,12,7,7,14,12,1,5,15,13] | [15,13,7,1,5,6,4,12,6,14,12,7,7,14,12,1,5,15,13] correct | [15,13,7,1,5,6,4,12,6,14,12,7,7,14,12,1,5,15,9] wrong |
| 00021 | [0, 6, 1, 11, 7, 12, 3, 12] | [15,13,8,5,1,15,13,3,6,4,0,2,12,6,1,5,8,10,1,5,15,13] | [15,13,8,5,1,15,13,3,6,4,0,2,12,6,1,5,8,10,1,5,15,13] correct | [15,13,8,5,1,15,13,3,6,4,0,2,12,6,1,5,8,10,1,5,15,9] wrong |
| 00130 | [12, 10, 10, 9, 7, 8, 10] | [15,13,7,1,5,15,9,15,9,15,9,15,9,14,12,12,6,13,9,15,9,15,9,15,13] | [15,13,7,1,5,15,9,15,9,15,9,15,9,14,12,12,6,13,9,15,9,15,9,15,13] correct | [15,13,7,1,5,15,9,15,9,15,9,15,9,14,12,12,6,13,9,15,9,15,9,1] wrong |
| 00265 | [1, 8, 12, 0, 14, 0] | [15,13,6,6,4,13,9,1,5,5,1,3,15,13,5,1,15,13] | [15,13,6,6,4,13,9,1,5,5,1,3,15,13,5,1,15,13] correct | [15,13,6,6,4,13,9,1,5,5,1,3,15,13,5,1,15,9] wrong |
| 00321 | [12, 10, 15, 8, 15, 7, 7, 2, 8] | [15,13,9,1,5,15,9,15,9,4,14,13,9,4,14,12,6,12,6,7,7,13,9,15,13] | [15,13,9,1,5,15,9,15,9,4,14,13,9,4,14,12,6,12,6,7,7,13,9,15,13] correct | [15,13,9,1,5,15,9,15,9,4,14,13,9,4,14,12,6,12,6,7,7,13,9,1] wrong |
| 00420 | [11, 15, 10, 1, 2, 4, 12] | [15,13,7,0,2,4,14,15,9,15,9,6,4,7,7,9,13,1,5,1] | [15,13,7,0,2,4,14,15,9,15,9,6,4,7,7,9,13,1,5,1] correct | [15,13,7,0,2,4,14,15,9,15,9,6,4,7,7,9,13,1,5,14] wrong |
| 00485 | [6, 8, 11, 6, 9, 11, 7, 10] | [15,13,8,15,13,3,13,9,0,2,15,13,3,14,12,0,2,12,6,15,9,15,9,15,9] | [15,13,8,15,13,3,13,9,0,2,15,13,3,14,12,0,2,12,6,15,9,15,9,15,9] correct | [15,13,8,15,13,3,13,9,0,2,15,13,3,14,12,0,2,12,6,15,9,15,9,15,13] wrong |
| 00496 | [14, 8, 9, 1, 6, 7, 5, 6, 1] | [15,13,9,3,15,13,13,9,14,12,6,4,15,13,3,12,6,10,0,15,13,3,6,4,1] | [15,13,9,3,15,13,13,9,14,12,6,4,15,13,3,12,6,10,0,15,13,3,6,4,15,13] wrong | [15,13,9,3,15,13,13,9,14,12,6,4,15,13,3,12,6,10,0,15,13,3,6,4,1] correct |
8. Base capability
The base does not move materially on the measured benchmarks. Across the ten-skill stream, the full base-capability battery remains near its starting level, and the endpoint probes remain stable.
Two measurements. A 498-item sentinel (ARC 128, HellaSwag 128, MMLU 114, WinoGrande 128; likelihood choice among the options) was run at all eleven checkpoints; it stayed between 348 and 353 correct throughout. The full likelihood battery of 16,481 items (MMLU 14,042 over 57 subjects, ARC-Challenge 1,172, WinoGrande 1,267; 5-shot, lm-eval 0.4.12 port, seed 0) was run at teaches 0, 5 and 10. The battery is likelihood-scored only; no free-generation benchmark was run for this experiment.
| battery | after teach 0 | after teach 5 | after teach 10 |
|---|---|---|---|
| MMLU, macro over 57 subjects | 0.8634 | 0.8631 | 0.8654 |
| MMLU, micro | 0.8625 | 0.8621 | 0.8636 |
| ARC-Challenge (acc / normalized) | 0.7056 / 0.7415 | 0.7022 / 0.7398 | 0.7099 / 0.7466 |
| WinoGrande | 0.7948 | 0.7924 | 0.7885 |
The largest movement is WinoGrande, from 0.7948 to 0.7885 (0.63 points down over ten teaches); ARC-Challenge goes from 0.7056 to 0.7099 and the MMLU macro average from 0.8634 to 0.8654. These are deterministic likelihood scores, each measured once per checkpoint. The sentinel per checkpoint:
| after teach | correct of 498 | normalized | ARC | HellaSwag | MMLU | WinoGrande |
|---|---|---|---|---|---|---|
| 0 | 350 | 372 | 78/128 | 79/128 | 97/114 | 96/128 |
| 1 | 350 | 373 | 79/128 | 78/128 | 97/114 | 96/128 |
| 2 | 348 | 371 | 78/128 | 78/128 | 96/114 | 96/128 |
| 3 | 348 | 372 | 78/128 | 78/128 | 96/114 | 96/128 |
| 4 | 350 | 374 | 79/128 | 79/128 | 96/114 | 96/128 |
| 5 | 350 | 372 | 79/128 | 78/128 | 96/114 | 97/128 |
| 6 | 349 | 371 | 79/128 | 78/128 | 96/114 | 96/128 |
| 7 | 350 | 376 | 78/128 | 78/128 | 97/114 | 97/128 |
| 8 | 352 | 375 | 81/128 | 78/128 | 96/114 | 97/128 |
| 9 | 353 | 376 | 81/128 | 78/128 | 98/114 | 96/128 |
| 10 | 351 | 374 | 81/128 | 78/128 | 97/114 | 95/128 |
9. Interpretation, and how to check it
Acquisition varied by skill, from complete (COGS 225, SCAN 222) to weak (Oriel 9 to 16) at the dose each received, and the dose was set in advance without pilots. Retention on the acquired skills was within two rows of own-end on every one of them after up to 53,432 further updates on other skills, with no replay and no label. The base does not move materially on the measured benchmarks (section 8). The one decline, Oriel, is real, reproducible and localized to the checksum of a skill that was never learned well.
What this does not show: transfer beyond new inputs of the same procedure, behavior past ten skills or past this budget, or that the same holds for other orders. Independent replication has not happened yet; the released data, scorers and answers exist so that it can.
To check the numbers: every training row, panel row, scorer and stored answer is in the replication repository (ten_skills/), including the 2,250 final and 2,250 own-end answers with their grades. The evidence explorer lets you filter every held-out answer by skill and result. Figures regenerate from the released data with one command (plots/build.py).
Run the experiment through the API. Use the supplied client, training data and evaluation driver to teach the ten skills sequentially and score their held-out answers. Start with a small end-to-end example, or run the full training schedule. See the API replication guide for access, setup, commands and estimated costs.
10. Provenance
The result is the evaluated accepted sequence of eleven checkpoints: the base model and the checkpoint after each of the ten teaches. It was not one uninterrupted job. Training stopped and resumed from saved checkpoints between teaches and once within a teach, each time restoring the full training state. Every accepted checkpoint is identified by its digest in the repository's lineage file, and every answer file names the checkpoint it was generated from.