Physicsru commited on
Commit
8de8d01
Β·
verified Β·
1 Parent(s): 4b3638d

README: TL;DR with pairwise contrasts (fixed nested code fences)

Browse files
Files changed (1) hide show
  1. README.md +88 -90
README.md CHANGED
@@ -12,52 +12,55 @@ language:
12
 
13
  # Compositional-generalization checkpoints (recall-then-assemble, Qwen3-4B-Base)
14
 
15
- Research checkpoints for interpretability work on **why a model does or does not compose skills it has
16
- only ever seen in isolation**. Every checkpoint below is one cell of a controlled study in which cells
17
- differ from each other in exactly one training variable. All weights are stored as saved by the trainer
18
- (`model.safetensors`, fp32, ~16 GB each; architecture `qwen3`, 4B parameters). Each subfolder is a
19
- complete Hugging Face model directory (config, tokenizer, chat template).
 
20
 
21
  ```python
22
  from transformers import AutoModelForCausalLM, AutoTokenizer
23
  import torch
24
- repo = "Physicsru/compgen-checkpoints"
25
- sub = "sft-eco-s1" # any folder name from the table below
26
  tok = AutoTokenizer.from_pretrained(repo, subfolder=sub)
27
  model = AutoModelForCausalLM.from_pretrained(repo, subfolder=sub, torch_dtype=torch.float32)
28
  ```
29
 
30
- ## The task in one paragraph
31
-
32
- A library of 25 string operators with opaque names `func_0` … `func_24` (e.g. `func_3` = sort the
33
- characters, `func_24` = a backtracking palindrome transform with an unused `depth` parameter). The model
34
- first learns every operator **as an atomic skill** (closed-book: given `def main_solution(x): return
35
- func_3(x)` and an input, recall the body of `func_3` and write a program). Then it is trained on
36
- **compositions** (`func_5(func_3(func_1(x, 2)), 'ab')`) built **only from the 13 train operators**. The
37
- 12 **held-out operators** are never composed in any training data. The test question is whether the
38
- model can compose the held-out operators anyway. The answer format is *recall-then-assemble* (RA):
39
 
40
- ```
41
- Recall func_3: Sort the characters in the string.
42
- ```python
43
- def func_3(s): ...
44
- ```
45
- Recall func_1: Repeat the string s exactly n times.
46
- ```python
47
- def func_1(s, n): ...
48
- ```
49
- Assemble:
50
- ```python
51
- <all recalled definitions> + def main_solution(x): return func_3(func_1(x, 2))
52
- ```
53
- ```
 
 
 
54
 
55
- Metrics used in the tables: **held-out d4 / d8** = program accuracy on held-out-operator programs of
56
- expression depth 4 / 8 (256 programs per depth, `eval/heldout_trees_d1-8.parquet`); **serial d8 / d12 /
57
- d20** = accuracy on pure nesting chains f1(f2(…fd(x))) over held-out operators
58
- (`eval/heldout_chains_d1-20.parquet`); **one-parameter rate** = fraction of `Recall func_24` blocks whose
59
- signature drops the second parameter (`def func_24(s):`), the single failure mode that separates good and
60
- bad RL outcomes.
 
 
 
 
 
 
 
 
61
 
62
  ## Lineage
63
 
@@ -67,59 +70,56 @@ Qwen3-4B-Base
67
  └─ stage 1.5 "closed-book": 20k depth-1 atomic tasks over all 25 ops + 12k depth-2..4 TRAIN-op
68
  compositions, prose + one code block (no RA format) β†’ stage15b-init
69
  β”œβ”€ RA bootstrap SFT cells (2 epochs, batch 128, LR 2e-5, seed 1) β†’ sft-*
70
- β”‚ all cells share the SAME 10,000 atomic tasks (400 per op, all 25 ops)
71
- β”‚ and differ in (a) how atomic tasks are packed into answers and (b) which
72
- β”‚ composition rows are added
73
  └─ (from sft-eco-s1) GRPO, KL 0.01 to the init, 100 steps β†’ rl-*
74
  ```
75
 
76
  ## Checkpoints
77
 
78
- | folder | init | atomic side (10k single-op tasks) | composition side | RL pool | steps | held-out numbers | status |
79
- |---|---|---|---|---|---|---|---|
80
- | `stage15b-init` | stage 1 | 20k closed-book depth-1 rows, prose + one code block | 12k depth-2..4 train-op comps (same format) | β€” | 500 | d4 / d8 = 0.03 / 0.00 (no RA format yet) | pending |
81
- | `sft-d1-s1` | stage15b-init | **single-task**: one op per answer | **none** | β€” | 152 | 0.00 / 0.00 | uploaded |
82
- | `sft-v1-s1` | stage15b-init | single-task | 15,979 mixed-structure train-op comps, depth 2-4 | β€” | 400 | 0.53Β±0.15 / 0.09Β±0.05 (3 seeds; this seed 0.75 / 0.15) | uploaded |
83
- | `sft-c1-s1` | stage15b-init | **co-occurrence groups**: 1-4 independent single-op tasks in one answer (all ops) | **none** | β€” | 58 | 0.66Β±0.14 / 0.08Β±0.04 | uploaded |
84
- | `sft-eco-s1` ("E-co") | stage15b-init | co-occurrence groups | the same 15,979 comps | β€” | 308 | 0.97Β±0.02 / 0.73Β±0.15 (this seed 0.98 / 0.83); serial d20 0.50 | uploaded |
85
- | `sft-c4-s1` | stage15b-init | co-occurrence groups | 12,452 mixed comps, **depth 2 only** | β€” | 252 | 0.70Β±0.03 / 0.12Β±0.05 | pending |
86
- | `sft-c4b-s1` | stage15b-init | co-occurrence groups | 12,436 mixed comps, **depth 2-4** (same count as c4) | β€” | 252 | 0.90Β±0.04 / 0.62Β±0.13 | pending |
87
- | `sft-matched-isolated-s1` | stage15b-init | per step: 48 atomic tasks as 48 single-task rows | per step: 76 comps (same stream as grouped) | β€” | 400 | 0.65Β±0.08 / 0.16Β±0.02 (3 paired seeds) | pending |
88
- | `sft-matched-grouped-s1` | stage15b-init | per step: the SAME 48 atomic tasks packed into 20 grouped rows | the same 76 comps | β€” | 400 | 0.93Β±0.03 / 0.47Β±0.04 | pending |
89
- | `rl-r1a-step100` | sft-eco-s1 | β€” | β€” | 1:1 mix of train-op serial chains d10-20 and all-op multi-task atomic prompts (widths 1-12) | 100 | serial d8/d12/d20 0.85 / 0.63 / 0.61; func_24 one-parameter 226/903 = 25% | uploaded |
90
- | `rl-r1b-step100` | sft-eco-s1 | β€” | β€” | same pool, different seed | 100 | 0.94 / 0.97 / 0.89; one-parameter 9/903 = 1% | pending |
91
- | `rl-mda-step5` | sft-eco-s1 | β€” | β€” | **mixed-depth pool**: chains + prompts holding one deep train-op chain task followed by 1-2 long-literal atomic tasks over all ops | 5 | 0.95 / 0.92 / 0.82; one-parameter 57/903 = 6% | pending |
92
- | `rl-mda-step50` | sft-eco-s1 | β€” | β€” | same run | 50 | 0.91 / 0.63 / 0.57; one-parameter 396/903 = **44%** | pending |
93
- | `rl-mda-step100` | sft-eco-s1 | β€” | β€” | same run | 100 | 0.97 / 0.97 / 0.93; one-parameter 3/903 = 0.3% | pending |
94
- | `rl-mdb-step100` | sft-eco-s1 | β€” | β€” | mixed-depth pool, second replicate | 100 | 0.99 / 0.98 / 0.95; one-parameter 33/903 = 3.7% | uploaded |
95
-
96
- "mixed-structure comps" = train-op compositions whose expression trees mix unary nesting, binary
97
- operators and literals (the benchmark's native generator); "co-occurrence groups" put several
98
- *independent* atomic tasks into one prompt/answer so that each definition is recalled next to others
99
- (no data flow between them). Held-out operators appear in every cell only as depth-1 atomic tasks.
100
-
101
- ## What each pair isolates
102
-
103
- | pair | the one difference | effect (held-out d4 / d8 unless stated) | what to look for |
104
- |---|---|---|---|
105
- | `sft-v1-s1` vs `sft-eco-s1` | atomic tasks single-task vs in co-occurrence groups (same comps; E-co has fewer rows, 308 vs 400 steps) | 0.53 / 0.09 → 0.97 / 0.73 | the headline effect: name→definition binding under multi-definition load. v1's failures are *chimeras* (a held-out name written with a train operator's body; 1,102 of 1,175 wrong bodies). Decomposed inference (each helper recalled in its own forward pass, then assembled mechanically) scores 1.00 for v1, so the whole gap is retrieval under load, not missing knowledge. |
106
- | `sft-matched-isolated-s1` vs `sft-matched-grouped-s1` | identical task stream, identical 400 steps, per-token loss; only the packing differs | 0.65 / 0.16 β†’ 0.93 / 0.47 | the same effect with every confound removed (row count, steps, task order). The gap opens from step 100. |
107
- | `sft-d1-s1` vs `sft-v1-s1` | composition demos added (no co-occurrence) | 0.00 β†’ 0.53 | what the demos install when atomics are single-task: d1 never produces a multi-helper program at all (format never seen with k β‰₯ 2). |
108
- | `sft-c1-s1` vs `sft-eco-s1` | composition demos added (with co-occurrence) | 0.66 / 0.08 β†’ 0.97 / 0.73 | with co-occurrence the model composes without any demo at mid depth; the demos buy depth (d8). |
109
- | 2Γ—2: `sft-d1-s1`, `sft-v1-s1`, `sft-c1-s1`, `sft-eco-s1` | co-occurrence Γ— composition demos | 0.00 / 0.53 / 0.66 / 0.97 (d4) | interaction: co-occurrence is worth more than demos, and the two are super-additive at depth. |
110
- | `sft-c4-s1` vs `sft-c4b-s1` | comp depth range 2 vs 2-4 at the same row count | 0.70 / 0.12 β†’ 0.90 / 0.62 | depth diversity of demos (not volume: 2k vs 12k depth-2 demos are equal, 0.77 vs 0.70). |
111
- | `stage15b-init` vs any `sft-*` | the RA format itself | 0.03 β†’ … | what "recall then assemble" adds on top of the closed-book atomic knowledge. |
112
- | `sft-eco-s1` vs `rl-mdb-step100` | RL (GRPO on train-op chains + atomic prompts; held-out ops never composed) | serial d20 0.50 β†’ 0.95 | what RL on *train-op* chains changes for *held-out* chains: deep serial execution improves for every operator. KL 0.01 keeps weights close to the init, so weight-difference analyses are meaningful. |
113
- | `rl-r1a-step100` vs `rl-r1b-step100` | seed only (same pool, same init) | d20 0.61 vs 0.89; func_24 one-parameter 25% vs 1% | the bistable outcome: one held-out operator (`func_24`, whose dropped parameter is semantically inert) either keeps or loses its second parameter when its call is nested among other library calls. Everything else is β‰₯ 0.95 in both. |
114
- | `rl-mda-step5` β†’ `step50` β†’ `step100` | same run, time only | one-parameter 6% β†’ 44% β†’ 0.3%; d20 0.82 β†’ 0.57 β†’ 0.93 | the drift switching on and off inside one run: weights change little between 50 and 100, one operator's signature flips. Compare `func_24` with its train twin `func_23` (same structure, never fails). |
115
- | `sft-eco-s1` vs `rl-r1a-step100` | RL, drifted outcome | d20 0.50 → 0.61 with the func_24 drift | the failure is latent in the SFT init (E-co writes `func_24(s)` in 0 / 5 / 18% of blocks at name→argument distance <40 / 40-150 / 150+ chars) and RL amplifies it in some seeds. |
116
-
117
- Things established about the failure mode that may help target an analysis: the drift tracks the number of
118
- *other library calls' argument tails* standing between the operator's name and its own argument in the
119
- skeleton (r1a, d β‰₯ 10: 0 tails 1%, one 15%, two 34%); builtin-method tails, long literals, definition
120
- load and a preceding chain in the same prompt do not trigger it (probe families 1b, 1d, 1f, 1g in `eval/`,
121
- which are teacher-forced prefixes usable as fixed inputs across checkpoints); the RL reward never sees the
122
- error in a legal (held-out-free) context, so RL acts through rewarded correct samples.
123
 
124
  ## Evaluation inputs (`eval/`)
125
 
@@ -134,13 +134,11 @@ error in a legal (held-out-free) context, so RL acts through rewarded correct sa
134
  | `probe_1f.parquet` | 2,048 | builtin-method argument tails in front of the op's own argument |
135
  | `probe_1g.parquet` | 1,280 | long literal (8-200 chars) as the op's first argument |
136
 
137
- Rows are in the verl code-execution format: `prompt` (chat messages), `reward_model.ground_truth`
138
- (JSON with `ref_code`, `ref_input`, `ref_output`), `extra_info` (depth, k = distinct ops, probe
139
- condition). Greedy decoding, 3,072 new tokens, was used for every number above.
140
 
141
  ## Provenance
142
 
143
- Every number here is traceable in the project ledger `verl/analysis/RESULTS_PROVENANCE.md` (sections MAIN
144
  RESULT, C1–C5 CAUSAL TABLE, MATCHED SFT, DEEP CHAINS, Mixed-depth arm RESULT, PROBES) to a job id, a
145
- sweep directory and a CI/classification report; 3-seed bands are mean Β± sd over trainer seeds 1 / 7 / 123.
146
- Checkpoints marked *pending* in the table are not yet uploaded (storage-quota decision pending).
 
12
 
13
  # Compositional-generalization checkpoints (recall-then-assemble, Qwen3-4B-Base)
14
 
15
+ ## TL;DR
16
+
17
+ 15 checkpoints of Qwen3-4B-Base from **one controlled study of whether a model can compose skills it has
18
+ only ever seen in isolation**. Every checkpoint is one cell of that study; cells differ in exactly one
19
+ training variable, so pairs of folders isolate one effect each. One subfolder = one complete HF model
20
+ directory (fp32 `model.safetensors` β‰ˆ 16 GB, tokenizer, chat template).
21
 
22
  ```python
23
  from transformers import AutoModelForCausalLM, AutoTokenizer
24
  import torch
25
+ repo, sub = "Physicsru/compgen-checkpoints", "sft-eco-s1" # any folder from the table below
 
26
  tok = AutoTokenizer.from_pretrained(repo, subfolder=sub)
27
  model = AutoModelForCausalLM.from_pretrained(repo, subfolder=sub, torch_dtype=torch.float32)
28
  ```
29
 
30
+ **Which two folders compare what** (held-out compositional accuracy at depth 4 / depth 8 unless stated):
 
 
 
 
 
 
 
 
31
 
32
+ | contrast | without | with | effect |
33
+ |---|---|---|---|
34
+ | **Co-occurrence atomic data** (several independent single-skill tasks in one prompt/answer, width 2-4) β€” cleanest version: identical task stream and steps | `sft-matched-isolated-s1` | `sft-matched-grouped-s1` | 0.65 / 0.16 β†’ 0.93 / 0.47 |
35
+ | **Co-occurrence atomic data** β€” the paper's two models (same compositions; E-co has fewer rows) | `sft-v1-s1` | `sft-eco-s1` | 0.53 / 0.09 β†’ 0.97 / 0.73 |
36
+ | **Composition demos (depth 2-4, train skills only)**, atomics single-task | `sft-d1-s1` | `sft-v1-s1` | 0.00 / 0.00 β†’ 0.53 / 0.09 |
37
+ | **Composition demos**, atomics in co-occurrence groups | `sft-c1-s1` | `sft-eco-s1` | 0.66 / 0.08 β†’ 0.97 / 0.73 |
38
+ | **Depth of the demos** (depth-2 only vs depth 2-4, same row count) | `sft-c4-s1` | `sft-c4b-s1` | 0.70 / 0.12 β†’ 0.90 / 0.62 |
39
+ | **RL** (GRPO on train-skill chains + atomic prompts; held-out skills never composed) β€” good outcome | `sft-eco-s1` | `rl-mdb-step100` | held-out chains d20 0.50 β†’ 0.95 |
40
+ | **RL** β€” drifted outcome (one held-out skill loses a parameter) | `sft-eco-s1` | `rl-r1a-step100` | d20 0.50 β†’ 0.61; `func_24` arity error 25% |
41
+ | **Seed only** (same RL pool, same init) | `rl-r1a-step100` | `rl-r1b-step100` | d20 0.61 vs 0.89; arity error 25% vs 1% |
42
+ | **Same RL run over time** (drift switches on, then off) | `rl-mda-step5` β†’ `rl-mda-step50` | β†’ `rl-mda-step100` | arity error 6% β†’ 44% β†’ 0.3%; d20 0.82 β†’ 0.57 β†’ 0.93 |
43
+ | **The recall-then-assemble format itself** | `stage15b-init` | any `sft-*` | 0.03 / 0.00 β†’ … |
44
+
45
+ The four SFT cells `sft-d1-s1`, `sft-v1-s1`, `sft-c1-s1`, `sft-eco-s1` form a 2Γ—2 (co-occurrence no/yes Γ—
46
+ demos no/yes); all SFT cells start from `stage15b-init`; all RL runs start from `sft-eco-s1`.
47
+
48
+ ## The task
49
 
50
+ A library of 25 string operators with opaque names `func_0` … `func_24` (e.g. `func_3` = sort the
51
+ characters; `func_24` = a backtracking palindrome transform with a semantically unused `depth` parameter).
52
+ The model first learns every operator **as an atomic skill** (closed-book: given `def main_solution(x):
53
+ return func_3(x)` and an input, recall the body of `func_3` and write a program). It is then trained on
54
+ **compositions** (`func_5(func_3(func_1(x, 2)), 'ab')`) built **only from the 13 train operators**; the 12
55
+ **held-out operators** are never composed in any training data. The test asks the model to compose the
56
+ held-out operators. The answer format is *recall-then-assemble* (RA): one `Recall func_N: <gloss>` block
57
+ with the definition per operator, then one `Assemble:` block with all definitions plus `main_solution`.
58
+
59
+ Metrics: **held-out d4 / d8** = program accuracy on held-out-operator programs of expression depth 4 / 8
60
+ (256 per depth, `eval/heldout_trees_d1-8.parquet`); **chains d20** = pure nesting chains f1(f2(…f20(x)))
61
+ over held-out operators (`eval/heldout_chains_d1-20.parquet`); **arity error** = fraction of `Recall
62
+ func_24` blocks that drop the second parameter (`def func_24(s):`), the single failure that separates good
63
+ and bad RL outcomes. Greedy decoding, 3,072 new tokens.
64
 
65
  ## Lineage
66
 
 
70
  └─ stage 1.5 "closed-book": 20k depth-1 atomic tasks over all 25 ops + 12k depth-2..4 TRAIN-op
71
  compositions, prose + one code block (no RA format) β†’ stage15b-init
72
  β”œβ”€ RA bootstrap SFT cells (2 epochs, batch 128, LR 2e-5, seed 1) β†’ sft-*
73
+ β”‚ all cells share the SAME 10,000 atomic tasks (400 per op, all 25 ops) and differ in
74
+ β”‚ (a) how atomic tasks are packed into answers and (b) which composition rows are added
 
75
  └─ (from sft-eco-s1) GRPO, KL 0.01 to the init, 100 steps β†’ rl-*
76
  ```
77
 
78
  ## Checkpoints
79
 
80
+ | folder | init | atomic side (10k single-op tasks) | composition side | RL pool | steps | held-out numbers |
81
+ |---|---|---|---|---|---|---|
82
+ | `stage15b-init` | stage 1 | 20k closed-book depth-1 rows, prose + one code block | 12k depth-2..4 train-op comps (same format) | β€” | 500 | d4 / d8 = 0.03 / 0.00 (no RA format yet) |
83
+ | `sft-d1-s1` | stage15b-init | **single-task**: one op per answer | **none** | β€” | 152 | 0.00 / 0.00 |
84
+ | `sft-v1-s1` | stage15b-init | single-task | 15,979 mixed-structure train-op comps, depth 2-4 | β€” | 400 | 0.53Β±0.15 / 0.09Β±0.05 (3 seeds; this seed 0.75 / 0.15) |
85
+ | `sft-c1-s1` | stage15b-init | **co-occurrence groups**: 1-4 independent single-op tasks in one answer (all ops) | **none** | β€” | 58 | 0.66Β±0.14 / 0.08Β±0.04 |
86
+ | `sft-eco-s1` ("E-co") | stage15b-init | co-occurrence groups | the same 15,979 comps | β€” | 308 | 0.97Β±0.02 / 0.73Β±0.15 (this seed 0.98 / 0.83); chains d20 0.50 |
87
+ | `sft-c4-s1` | stage15b-init | co-occurrence groups | 12,452 mixed comps, **depth 2 only** | β€” | 252 | 0.70Β±0.03 / 0.12Β±0.05 |
88
+ | `sft-c4b-s1` | stage15b-init | co-occurrence groups | 12,436 mixed comps, **depth 2-4** (same count as c4) | β€” | 252 | 0.90Β±0.04 / 0.62Β±0.13 |
89
+ | `sft-matched-isolated-s1` | stage15b-init | per step: 48 atomic tasks as 48 single-task rows | per step: 76 comps (same stream as grouped) | β€” | 400 | 0.65Β±0.08 / 0.16Β±0.02 (3 paired seeds) |
90
+ | `sft-matched-grouped-s1` | stage15b-init | per step: the SAME 48 atomic tasks packed into 20 grouped rows | the same 76 comps | β€” | 400 | 0.93Β±0.03 / 0.47Β±0.04 |
91
+ | `rl-r1a-step100` | sft-eco-s1 | β€” | β€” | 1:1 mix of train-op serial chains d10-20 and all-op multi-task atomic prompts (widths 1-12) | 100 | chains d8/d12/d20 0.85 / 0.63 / 0.61; arity error 226/903 = 25% |
92
+ | `rl-r1b-step100` | sft-eco-s1 | β€” | β€” | same pool, different seed | 100 | 0.94 / 0.97 / 0.89; 9/903 = 1% |
93
+ | `rl-mda-step5` | sft-eco-s1 | β€” | β€” | **mixed-depth pool**: chains + prompts holding one deep train-op chain task followed by 1-2 long-literal atomic tasks over all ops | 5 | 0.95 / 0.92 / 0.82; 57/903 = 6% |
94
+ | `rl-mda-step50` | sft-eco-s1 | β€” | β€” | same run | 50 | 0.91 / 0.63 / 0.57; 396/903 = **44%** |
95
+ | `rl-mda-step100` | sft-eco-s1 | β€” | β€” | same run | 100 | 0.97 / 0.97 / 0.93; 3/903 = 0.3% |
96
+ | `rl-mdb-step100` | sft-eco-s1 | β€” | β€” | mixed-depth pool, second replicate | 100 | 0.99 / 0.98 / 0.95; 33/903 = 3.7% |
97
+
98
+ "Mixed-structure comps" = train-op compositions whose expression trees mix unary nesting, binary operators
99
+ and literals (the benchmark's native generator). "Co-occurrence groups" put several *independent* atomic
100
+ tasks into one prompt/answer so each definition is recalled next to others (no data flow between them).
101
+ Held-out operators appear in every cell only as depth-1 atomic tasks. All steps: batch 128; SFT 2 epochs.
102
+
103
+ ## What each contrast shows (for choosing an analysis)
104
+
105
+ - **Co-occurrence** (`isolated` vs `grouped`, `v1` vs `eco`): the failure of the "without" model is a
106
+ *chimera* β€” a held-out name written with a train operator's body (1,102 of 1,175 wrong bodies in v1).
107
+ Decomposed inference (each helper recalled in its own forward pass, then assembled mechanically) scores
108
+ 1.00 for v1, so the whole gap is name→definition retrieval under multi-definition load, not missing
109
+ knowledge. In the matched pair the gap opens from step 100.
110
+ - **Composition demos** (`d1` vs `v1`, `c1` vs `eco`): without co-occurrence the demos are what makes any
111
+ multi-helper program possible (d1 never writes one); with co-occurrence the model already composes at
112
+ mid depth without a single demo (c1 0.66) and the demos buy depth (d8 0.08 β†’ 0.73). Demo *diversity*
113
+ matters (c4 vs c4b), demo *volume* does not (2k vs 12k depth-2 demos: 0.77 vs 0.70).
114
+ - **RL** (`eco` vs `mdb` / `r1a`, `r1a` vs `r1b`, `mda` over time): RL on train-operator chains lifts deep
115
+ serial execution for every operator (d20 0.50 β†’ 0.9+), but in some seeds one held-out operator
116
+ (`func_24`, whose dropped parameter is semantically inert) loses its second parameter when its call is
117
+ nested among other library calls. The drift is latent in the SFT init (E-co writes `func_24(s)` in
118
+ 0 / 5 / 18% of blocks at name→argument distance <40 / 40-150 / 150+ chars), tracks the number of other
119
+ library calls' argument tails between the name and the own argument, is not triggered by builtin-method
120
+ tails, long literals, definition load or a preceding chain (probe families 1b/1d/1f/1g in `eval/`), and
121
+ reverses inside one run (`mda` 44% β†’ 0.3%). KL 0.01 keeps RL weights close to `sft-eco-s1`, so
122
+ weight-difference analyses between `eco` and any `rl-*` folder, or between `mda` steps, are meaningful.
 
 
123
 
124
  ## Evaluation inputs (`eval/`)
125
 
 
134
  | `probe_1f.parquet` | 2,048 | builtin-method argument tails in front of the op's own argument |
135
  | `probe_1g.parquet` | 1,280 | long literal (8-200 chars) as the op's first argument |
136
 
137
+ Rows are in the verl code-execution format: `prompt` (chat messages), `reward_model.ground_truth` (JSON
138
+ with `ref_code`, `ref_input`, `ref_output`), `extra_info` (depth, k = distinct ops, probe condition).
 
139
 
140
  ## Provenance
141
 
142
+ Every number is traceable in the project ledger `verl/analysis/RESULTS_PROVENANCE.md` (sections MAIN
143
  RESULT, C1–C5 CAUSAL TABLE, MATCHED SFT, DEEP CHAINS, Mixed-depth arm RESULT, PROBES) to a job id, a
144
+ sweep directory and a CI / classification report; 3-seed bands are mean Β± sd over trainer seeds 1 / 7 / 123.