Tree A: the Ledger: work log
Append-only and chronological. Each entry records what was done, why, any surprises, and what comes next, in enough detail for a stranger to pick up mid-stride.
2026-09-30: planning
Wrote plan.md, summary.md, direction-questions.md and both todo files from the research survey (../../Review.md, ../../research-plan.md). Next: see todo-agent.md.
2026-09-30: Experiment 0.1 built and running
Wrote exp01_sorting.py (stdlib, --selftest, ~400 lines). The rules follow the authors' repo, cloned for the purpose, where it differs from the paper's prose (direction-questions.md Q6). Their DG formula was in the repo and is now ported (Q1 settled). The script has incremental counters for adjacent descents, total inversions and bubble's own rule; two schedulers; movable and immovable frozen cells; and chimera runs with two label-only controls and a run-mean statistic (Q7).
Three surprises. The first reading of the insertion rule stalled under frozen cells; the authors' code skips frozen cells in the prefix check. Bubble picks a side at random, so "no swap this round" is an unreliable stop signal: a run with one remaining inversion stopped early ~1.5% of the time until the stop condition became "no bubble cell wants to move". In the smoke run (n=32, 10 seeds), Kendall DG was 0.000 for every bubble and insertion variant at every frozen count, as P2 predicts. Adjacent-metric DG was large, and present at zero frozen cells. The paper's own formula gave 0.39 for cell-view bubble at zero frozen (they report 0.24 at n=100) and rose with immovable frozen cells.
Started n=64 and n=100 runs, 100 seeds each, in the background; output goes to results/exp01-n64 and results/exp01-n100. Next: evaluate P1 to P5 from the CSVs; write the summary table here; draft the 0.1 write-up.
2026-09-30: Experiment 0.1 results (n=64 and n=100, 100 seeds each)
Full tables are in results/exp01-n64/grid.csv, results/exp01-n100/grid.csv and the chimera.csv files. The rows below are at n=100, roundrobin scheduler, immovable frozen cells. dg_paper is the authors' own formula ported verbatim; dg_ken is delayed gratification scored on total inversions.
| algo, variant | frozen | swaps | final inv | dg_adj | dg_ken | dg_paper [95% CI] | paper reports |
|---|---|---|---|---|---|---|---|
| bubble, classical | 0 | 2506 | 0 | 6.27 | 0.000 | 0.079 [0.077, 0.081] | not given |
| bubble, cell-view | 0 | 2506 | 0 | 6.47 | 0.000 | 0.218 [0.215, 0.221] | 0.24 |
| bubble, cell-view | 1 | 1676 | 830 | 4.32 | 0.000 | 0.259 [0.252, 0.266] | 0.29 |
| bubble, cell-view | 2 | 1198 | 1309 | 3.06 | 0.000 | 0.301 [0.292, 0.312] | 0.32 |
| bubble, cell-view | 3 | 943 | 1564 | 2.39 | 0.000 | 0.342 [0.326, 0.357] | 0.37 |
| insertion, cell-view | 0 | 2506 | 0 | 0.46 | 0.000 | 1.057 [1.035, 1.081] | 1.10 |
| insertion, cell-view | 3 | 943 | 1564 | 0.38 | 0.000 | 1.161 [1.129, 1.199] | 1.19 |
| selection, cell-view | 0 | 1522 | 0 | 0.13 | 0.000 | 5.75 [4.80, 7.10] | no trend |
With the random-permutation scheduler, bubble cell-view dg_paper was 0.388, 0.422, 0.467 and 0.499 for 0 to 3 frozen cells.
Chimera (n=100, roundrobin), mean same-label-neighbour fraction over the run:
| pair | chimera | control: all run first | control: all run second |
|---|---|---|---|
| bubble+insertion | 0.319 [0.312, 0.327] | 0.244 [0.239, 0.248] | 0.242 [0.233, 0.250] |
| bubble+selection | 0.334 [0.326, 0.342] | 0.244 | 0.248 [0.243, 0.254] |
| insertion+selection | 0.373 [0.364, 0.381] | 0.242 | 0.248 |
Predictions:
- P1 held. DG under the adjacent-pair metric was present at zero frozen cells in all six variants, and the paper's own formula reproduced their reported numbers within 10% (0.218 vs 0.24; 1.057 vs 1.10).
- P2 held. DG on total inversions was 0.000 for every bubble and insertion variant at every frozen count, under both schedulers and at both sizes. Selection cell-view reached 0.001 at most. Each adjacent out-of-order swap removes exactly one inversion, so the "backing up" exists only in the adjacent-pair count.
- P3 held for the paper's formula under immovable frozen cells, with a monotone rise and a slope matching theirs. Under our formula the direction reversed, because frozen cells cut the number of swaps. The trend belongs to the statistic, and the system does not produce it.
- P4 partial. Chimeras clustered above both label-only controls, with separated CIs, for all three pairs. That includes bubble+insertion, whose total swap counts are identical, so swap-count efficiency is not the driver. Rate per round is the remaining candidate (bubble moves many cells per round, insertion one). The next test is a rate-matched chimera.
- P5 failed for the paper's formula on bubble: 0.218 (round robin) vs 0.388 (random order). The scheduler alone shifted it by 78%, more than the whole frozen-cell effect. Insertion was scheduler-invariant, since one cell moves at a time. The original code left scheduling to Python threads.
Classical top-down bubble sort scored 0.079 on the authors' formula with no frozen cells, so the statistic is non-zero for a textbook algorithm nobody calls agential. Classical and cell-view insertion were identical at every setting; when only one cell can move, "cell view" is a relabelling.
Reading: the headline competency (delayed gratification) is a metric artefact in the sense pre-registered in P2, and its reported dependence on barriers comes from the DG formula. The clustering effect is real against a label-only control. A mechanical explanation is available for it and has not been tested yet. Nothing here needed a scheduler-free explanation, and one headline number moved by 78% with the scheduler.
One surprise: our immovable-frozen condition matched the paper's series, although their published code implements only the movable kind. Either the paper's runs used a different branch, or the movable/immovable distinction matters less than the formula. To ask (outreach Q2, Q3).
Next: rate-matched chimera (bubble vs bubble-with-move-probability-p); write-up under 2,000 words; then Experiment 0.3.
2026-09-30: Experiment 0.3, ledger calibration: run, and gate A2 reached
Wrote and ran exp03_ledger.py (stdlib, --selftest, 3 s). Ring of 12, ten-step budget, 0 to 2 barriers, 6,216 reachable states. Eight systems, two competencies, three effort terms and four rules, all as pre-registered in plan.md this morning. Full table in results/exp03/ledger.csv. All quantities in bits.
| system | p_success | C_beh | E_code | E_params | E_train | R1 | R2 | R3 |
|---|---|---|---|---|---|---|---|---|
| random | 0.384 | 2 | 0 | 0 | 0 | 2 | -30 | 2 |
| solver, program | 1.000 | 8866 | 3352 | 0 | 0 | +5514 | +5514 | +5514 |
| solver, table | 1.000 | 8866 | 624 | 4104 | 0 | +4138 | +8210 | +4138 |
| greedy, correct | 0.917 | 6980 | 1264 | 0 | 0 | +5716 | +5716 | +5716 |
| greedy, buggy | 0.903 | 5994 | 880 | 0 | 0 | +5114 | +5114 | +5114 |
| Q, trained (100k episodes) | 0.996 | 5749 | 4344 | 7112 | 432193 | -5713 | -430826 | -437906 |
| Q, untrained | 0.378 | 7 | 1320 | 13136 | 0 | -14456 | -1352 | -14456 |
| reservoir, untrained | 0.178 | 0 | 672 | 13112 | 0 | -13784 | -704 | -13784 |
R4 (leave-one-out fit) was dominated by the trained Q outlier (+163,893) and told us nothing, as expected. Buggy scored below correct under every rule.
The pre-registered pass criterion is |residual| below 10% of the largest E in the set. That E is the trained Q's 432k-bit training signal, so the threshold is 43k. Read literally, R1 passed on all five zero-systems, and R2, R3 and R4 failed on the trained Q. Scaled to the quantity under test instead (10% of the largest C_beh, 887 bits), nothing passed. This morning's literal threshold was misspecified. Its tolerance, 43,219 bits, is almost five times the largest competency in the set (8,866 bits), so it absorbs every residual. (Corrected 2026-10-30; this entry first said "four times".) Both readings are reported, and the decision is the operator's (direction-questions.md Q8).
Whatever the threshold:
- The lookup table had a positive residual (+4,138) under the artefact rule. Because the task is structured, the table compresses, and its compressed size (4,104 bits) is below the behaviour bits it carries (8,866). Behaviour bits and description bits are different currencies, even for the system that pays for everything explicitly. The pre-registered "table = 0" failed under every rule.
- The program solver's residual (+5,514) is the task's compressibility relative to the programmer's knowledge. No rule prices design, and none can without circularity. Levin's minimal systems (bubble sort) fall into this case.
- The trained Q's residual was -5.7k under the artefact rule and -431k under the procedure rule. The training signal costs far more bits than the behaviour it buys, which is sample efficiency and no free lunch. The term is coherent, and it is the form the ledger takes for trained systems.
- The two untrained systems were negative under the artefact rule, since their parameters cost bits and buy nothing. Under the procedure rule they were near zero, because a seed is cheap. Which is right depends on whether random parameters count as effort. The calibration cannot settle that; the two rules encode the two answers.
Reading: no single accounting puts designed and trained systems on one scale. For designed systems the residual is task compressibility minus code length, a fact about the task and the programmer. For trained systems it is behaviour bits minus training-signal bits, a fact about sample efficiency. Levin's "delta between effort in and competency out" names two incommensurable quantities. The one that applies to his minimal systems is the one that cannot be priced.
No surprises relative to plan.md's expectations, and that is itself the result. The only unpredicted number was the table's positive residual, which makes the conclusion sharper.
Next: operator decision on gate A2 (Q8). Recommendation in Q8. If Tree A stops: 0.1 write-up still goes out (the sorting deflation stands on its own); the harness moves to Tree B's folder; the trained-system ledger (R2 form) moves to spine/01 as a per-checkpoint measure.
2026-09-30: write-up drafted
Drafted writeup.md. It covers 0.1 and 0.3 together, with provenance (commit ids, file hashes), both readings of the 0.3 threshold, the strongest competency reading of each result, limitations, and reproduction commands. Next: rate-matched chimera (the one control the write-up still owes); then the write-up is complete pending Q8.
2026-09-30: Experiment 0.1b, rate-matched chimera: the clustering mechanism
Wrote exp04_rate_chimera.py. It imports exp01_sorting, which gained an optional per-cell move probability; the default path is unchanged and the 0.1 self-test still passes. All cells run bubble, and label-B cells attempt a move with probability p. n = 100, 100 seeds, round robin. Pre-registered in plan.md before any code.
| p | mean same-label-neighbour fraction [95% CI] | peak |
|---|---|---|
| 1.0 | 0.244 [0.240, 0.249] | 0.379 |
| 0.75 | 0.246 [0.242, 0.251] | 0.383 |
| 0.5 | 0.255 [0.250, 0.259] | 0.395 |
| 0.25 | 0.276 [0.271, 0.282] | 0.414 |
| 0.1 | 0.294 [0.288, 0.300] | 0.434 |
| 0.02 (post hoc) | 0.316 [0.309, 0.322] | 0.457 |
| 0.01 (post hoc) | 0.320 [0.313, 0.326] | 0.469 |
For reference, from 0.1: label-only control 0.244 [0.239, 0.248]; bubble+insertion chimera 0.319 [0.312, 0.327].
- P4a held. At p = 1 the chimera equalled the control exactly (0.244).
- P4b held. The fraction rose monotonically as p fell, and every step from p = 0.5 down was CI-separated from p = 1.
- P4c was not reached inside the pre-registered set (0.294 at p = 0.1 against 0.319). Two exploratory values followed, labelled post hoc. p = 0.02 gave 0.316 and p = 0.01 gave 0.320, both within CI of the bubble+insertion chimera. Insertion moves one cell per round at n = 100, so its per-cell rate relative to bubble is of that order.
Reading: clustering by algotype is a rate effect. Two populations of identical cells that differ only in how often they take a turn cluster as much as two populations running different algorithms. The rules do not need to differ. Handing half the cells a slower clock reproduces the paper's Figure 14C. That completes the 0.1 deflation. Results are in results/exp04/ and results/exp04-exploratory/.
No surprises. The one gap (P4c) closed with the post hoc values, which are reported as post hoc.
Next: writeup.md updated (done below). Tree A now has nothing pending except the operator decision on Q8.
2026-09-30: prose pass for authors
Rewrote writeup.md in a plain register against the extended machine-tells list now in style.md (sources: Wikipedia's Signs of AI writing, the humanizer skill's pattern list, getspike's account of the causes). Facts and numbers unchanged. The hashes in section 2 now match the current scripts. The same pass covered PREMISE.md, Review.md, research-directions.md, research-plan.md and the spine summaries. The Levin email in outreach/ now carries the 0.1 result paragraph; it can go once the operator settles the sender line. Next: operator decisions (Q8; sender line). No experiment pending on this tree.
2026-09-30: Experiment 0.1c, the authors' own code, run unmodified
Wrote exp05_authors_code.py. It drives the cell classes from the authors' repository (vendored under vendor/cell_research, commit 1fd2bd59 of 2024-10-30, unmodified) with their thread-per-cell scheduling, their frozen-cell mechanism, their per-swap snapshots and their delayed-gratification function copied verbatim. Only tkinter and numpy were removed from the driver, and none of our code touches the dynamics. n = 100. Bubble ran 100 experiments per frozen count, insertion and selection 30. Their analysis takes the mean. The median and an outlier count are added because the mean turned out to rest on a few runs.
| algo | frozen | mean of their DG [95% CI] | median | p25 to p75 | runs above 1 | max | DG on total inversions | final inversions |
|---|---|---|---|---|---|---|---|---|
| bubble | 0 | 0.196 [0.191, 0.200] | 0.195 | 0.182 to 0.209 | 0 of 100 | 0.24 | 0.000 | 0 |
| bubble | 1 | 3.38 [0.95, 6.61] | 0.195 | 0.186 to 0.206 | 4 of 100 | 83.4 | 0.000 | 34 |
| bubble | 2 | 3.45 [0.92, 6.82] | 0.196 | 0.185 to 0.213 | 4 of 100 | 86.7 | 0.000 | 96 |
| bubble | 3 | 3.81 [1.49, 7.44] | 0.202 | 0.185 to 0.214 | 5 of 100 | 81.7 | 0.000 | 174 |
| insertion | 0 | 1.075 [1.039, 1.114] | 1.067 | 1.000 to 1.167 | 22 of 30 | 1.34 | 0.000 | 0 |
| insertion | 3 | 2.12 [0.56, 5.20] | 0.584 | 0.469 to 0.690 | 3 of 30 | 46.0 | 0.000 | 708 |
| selection | 0 | 3.79 [3.40, 4.23] | 3.78 | 2.88 to 4.65 | 30 of 30 | 6.21 | 0.000 | 0 |
For the same conditions the paper reports bubble 0.24, 0.29, 0.32, 0.37; insertion 1.10 and 1.19; selection "no trend".
Reading:
- The authors' own simulation, scored with their own function, gave 0.196 for bubble at zero frozen cells (paper 0.24; our round-robin reimplementation 0.218) and 1.075 for insertion (paper 1.10; ours 1.057). The reimplementation is faithful.
- On their code the barrier trend does not exist at the median: 0.195, 0.195, 0.196, 0.202. The mean rises only because four or five runs in a hundred produce values near 80. Their formula divides each recovery by the size of the dip before it, so a one-descent dip followed by a long recovery gives a ratio in the tens. The reported series (0.24 to 0.37) matches neither the medians nor the means of their published code. For insertion the median fell with three frozen cells (1.067 to 0.584), where the paper reports a rise.
- Delayed gratification on total inversions was 0.000 in every one of the 490 runs. (Corrected 2026-10-30 from 460; the result files hold 4 × 100 bubble runs and 3 × 30 insertion and selection runs.) Their code, like ours, never moves the array backward on the quantity the sort reduces.
- This answers the puzzle from the earlier entry, where our immovable condition matched their series better than their movable code did. Their code does not reproduce their series under either reading, so the match was coincidence. To ask which code produced Table 2 (outreach Q2, Q3).
Files: results/exp05/*_runs.json (per run), *_summary.csv, the three logs. Script sha256 (first 16 hex): exp05_authors_code.py 310ca3c513ceed5b; bubble_summary.csv 5e102eaa69798b33. The run took about 75 minutes on two cores, most of it Python threads spinning on the lock.
Next: nothing on this tree. The write-up (section 3.7) and the email carry this; the tree is closed.
2026-10-30: write-up sent to the authors
Sent the email in outreach/levin-email-draft.md to
Michael Levin, with a link to the public copy of the write-up, marked as
a draft awaiting his response. Waiting to hear back. The draft's notes
say to copy the lab's general enquiries address if there is no reply in
two weeks.
Next: wait for Levin's reply; fold any correction into the write-up and log it here.