OverviewFilesCommitsIssuesDocsReleasesPeers

basal-agent commits / 23e7acd

basal-agent: coupling.c — wiring instead of walls; real, selected, not enough
Tests the one axis the 14-experiment arc never varied: whether the boundary that privatizes catalysis has to be a CONTAINER at all. Every prior attempt (space, cis-acting, cohesion, metabolic integration) put the chemistry in a bag and the parasites ended up in the bag too. Levin's individuals are gap-junctional COUPLING patterns, not walls — so this supplies wiring and no container. Same chemistry as ribozyme.c. Each unit owns 4 junctions and controls their conductance; catalysis flows BOTH ways scaled by each end's phi; received flow sets that unit's PRIVATE fidelity. Heritable trait k = how much a unit reallocates conductance toward junctions that delivered (k=0 = public good, k=1 = full reciprocity). No containers, space, assortment or group selection; global Wright-Fisher. Supplied: the option to condition (the rung34.c standard). Must emerge: parasite exclusion — no rule wires catalysts to catalysts, and a unit sees only its own inflow, never anyone's type. 10 seeds: k=0 public good 5.99 -> 4.69 +- 0.06 k=1 reciprocity 5.99 -> 5.36 +- 0.04 (+0.67, many sd) k free to evolve 5.99 -> 5.07 +- 0.03, k climbed 0.10 -> 0.449 k=1 SHUFFLED control 5.99 -> 4.67 +- 0.05 (= k=0) Reciprocity is real; the shuffled control rules out "concentrating conductance" as the explanation; and conditioning is selected for un-forced. But phi FALLS in every arm — wiring slows the tragedy, it does not reverse it. NULL, no crossing. Diagnosis: wiring is rebuilt from scratch each generation, so reciprocity never accumulates. Gap junctions PERSIST, and that persistence is what makes a coupling pattern an individual. Next increment = inherited partners, flagged as supplying more structure and needing its own shuffled control. Not run here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
23e7acdce4029d4eb7133769609542d149ebfe3f
by plankatron <fleeky@gmail.com> · 2026-07-31T20:18:42.000Z

Changed files (3) +307 -0

.gitignore +1 -0
……@@ -37,3 +37,4 @@ belief_field_agent
3737agent_learn
3838ribophi
3939rung34phi
40coupling
coupling.c +240 -0
……@@ -0,0 +1,240 @@
1/* coupling.c — can a WIRING rule privatize a public good, with NO container anywhere?
2 *
3 * THE QUESTION. Across 14 experiments the arc's wall was always the same: catalysis is a public
4 * good, parasites free-ride, and the ONLY thing that ever rescued it was a SUPPLIED compartment
5 * (ribozyme.c ignites at compartment size 4-8, fails well-mixed). Every attempt to make the
6 * boundary emerge for free failed -- spatial locality (bridges.c arm A), cis-acting (arm B),
7 * cohesion from complementarity (coemerge.c), metabolic/energetic/coded integration
8 * (integrated.c). All of those are CONTAINERS: put the chemistry in a bag, and the parasites end
9 * up in the bag too.
10 *
11 * The untested axis is whether the boundary has to be a container AT ALL. In Levin's systems what
12 * makes a pile of cells one individual is not a wall but gap-junctional COUPLING -- the individual
13 * is a wiring pattern, and you can move the boundary by changing the wiring without touching a
14 * membrane. So: can a set of molecules become one individual purely by whom they exchange with?
15 *
16 * WHAT IS SUPPLIED vs WHAT MUST EMERGE (the razor -- issue #6, "never encode the answer"):
17 * SUPPLIED: the OPTION to condition. Each unit carries a heritable trait k in [0,1] = how much it
18 * reallocates its own junction conductances toward partners that send flow back. k=0 is the OLD
19 * PUBLIC GOOD (give to everyone regardless). k=1 is full reciprocity. This is the same standard
20 * rung34.c met: we supply the law-space, selection decides. NOTHING rewards high k directly.
21 * MUST EMERGE: exclusion of parasites. There is NO rule anywhere that says "catalysts only wire to
22 * catalysts". A parasite can form junctions freely and free-ride. A unit cannot see anyone's
23 * type -- it observes only how much flow arrived down each of its own junctions.
24 * ABSENT ENTIRELY: containers, compartments, space, assortment, group selection. Replication is
25 * global Wright-Fisher over the whole population.
26 *
27 * MECHANISM. Unit i owns LINKS junctions; it controls the conductance w of each. Catalysis flows
28 * BOTH WAYS through a junction, scaled by each end's fold score phi: i sends (phi_i/PHIMAX)*w and
29 * receives (phi_j/PHIMAX)*w. So cutting a junction to a freeloader costs i almost nothing -- the
30 * freeloader was not sending anything back. That asymmetry is the whole hypothesis. Received flow
31 * sets a unit's PRIVATE copying fidelity, so fidelity stops being a public good and becomes a
32 * property of who you are wired to.
33 *
34 * Constants F0/F1/BETA/L/PHIMAX/TOTAL/GEN and phi()/replicate() are IDENTICAL to ribozyme.c so the
35 * result is directly comparable to a known failure: ribozyme well-mixed goes 5.99 -> 5.50.
36 * (Note replicate() flips each bit with probability f, so f->1 yields the COMPLEMENT; phi is
37 * complement-invariant, so high f does preserve fold score. Copied verbatim, not "fixed".)
38 *
39 * PRE-REGISTERED (written before the first run):
40 * P1 k frozen at 0 (unconditional giving) -> phi FALLS. Reproduces the public-goods tragedy.
41 * P2 k frozen at 1 (full reciprocity) -> phi RISES with no container. This is the real test.
42 * P3 k free to evolve -> k climbs from its low start AND phi rises.
43 * P4 CONTROL, the one that can kill P2/P3: a SHUFFLED arm where each unit's conductance updates
44 * are applied to a random permutation of its junctions -- same arithmetic, same budget, same
45 * concentration of w, but decoupled from who actually sent flow. If phi rises here too, then
46 * the effect is about concentrating conductance, NOT about reciprocity, and P2/P3 mean nothing.
47 *
48 * Honest note: if this works it is reciprocity / partner choice, which social evolution knows well
49 * (cf. Levin S., Nat Ecol Evol 2019, cited as ref 74 by the Phi_r paper). The claim would not be a
50 * new mechanism; it would be that the boundary can be a WIRING RULE rather than a WALL.
51 * Any prediction may fail. A null is a result. Do not tune to force a positive.
52 *
53 * build: cc -O2 -Wall -std=c11 -o coupling coupling.c -lm
54 */
55#include <math.h>
56#include <stdio.h>
57#include <stdint.h>
58
59/* ---------- identical to ribozyme.c ---------- */
60#define L 24
61#define PHIMAX (L/2)
62#define TOTAL 4800
63#define GEN 200
64#define F0 0.85
65#define F1 0.999
66#define BETA 2.0
67
68/* ---------- coupling-specific ---------- */
69#define LINKS 4
70#define TROUND 8
71#define MUTK 0.03
72#define RSCALE 1.0
73
74static unsigned long long RNG;
75static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; }
76static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); }
77static double randn(void){ double u=urand(),v=urand(); if(u<1e-300)u=1e-300; return sqrt(-2*log(u))*cos(6.283185307*v); }
78
79static int phi(uint32_t s){ int c=0; for(int i=0;i<PHIMAX;i++){ int a=(s>>i)&1, b=(s>>(L-1-i))&1; if(a!=b) c++; } return c; }
80static uint32_t replicate(uint32_t t,double f){ uint32_t c=0; for(int i=0;i<L;i++){ int b=(t>>i)&1; int nb=(urand()<f)?(1-b):b; if(nb) c|=(1u<<i);} return c; }
81
82static uint32_t seq[TOTAL], nseq[TOTAL];
83static double kk[TOTAL], nkk[TOTAL];
84static int lnk[TOTAL][LINKS];
85static double ww[TOTAL][LINKS], inflow[TOTAL][LINKS];
86static double recv[TOTAL], fid[TOTAL], cumw[TOTAL];
87static int phic[TOTAL];
88
89/* mode: 0 = k frozen at kfix; 1 = k evolvable. shuffled: apply conductance updates to a permuted
90 set of the unit's own junctions (same arithmetic, decoupled from who actually sent flow). */
91static double run(int evolve_k,double kfix,int shuffled,double *k_end,double *f_end,double *phi_start)
92{
93 for(int i=0;i<TOTAL;i++){
94 uint32_t s=0; for(int b=0;b<L;b++) if(urand()<0.5) s|=(1u<<b);
95 seq[i]=s; kk[i]= evolve_k? 0.10 : kfix; /* evolvable arm starts LOW, like rung34 */
96 }
97 { double sp=0; for(int i=0;i<TOTAL;i++) sp+=phi(seq[i]); *phi_start=sp/TOTAL; }
98
99 for(int g=0;g<GEN;g++){
100 for(int i=0;i<TOTAL;i++) phic[i]=phi(seq[i]);
101
102 /* fresh random wiring each generation: no persistent social structure is supplied */
103 for(int i=0;i<TOTAL;i++){
104 for(int l=0;l<LINKS;l++){
105 int j; do { j=(int)(xs()%TOTAL); } while(j==i);
106 lnk[i][l]=j; ww[i][l]=1.0/LINKS;
107 }
108 }
109 for(int i=0;i<TOTAL;i++) recv[i]=0.0;
110
111 for(int r=0;r<TROUND;r++){
112 for(int i=0;i<TOTAL;i++) for(int l=0;l<LINKS;l++) inflow[i][l]=0.0;
113 /* bidirectional flow through each junction, scaled by each end's phi */
114 for(int i=0;i<TOTAL;i++){
115 double gi=(double)phic[i]/PHIMAX;
116 for(int l=0;l<LINKS;l++){
117 int j=lnk[i][l]; double c=ww[i][l];
118 double i2j = gi*c;
119 double j2i = ((double)phic[j]/PHIMAX)*c;
120 recv[j]+=i2j; recv[i]+=j2i;
121 inflow[i][l]=j2i; /* what i observes: flow down its own junction l */
122 }
123 }
124 /* conductance update: reallocate toward junctions that delivered, in proportion to k */
125 for(int i=0;i<TOTAL;i++){
126 double tot=0; for(int l=0;l<LINKS;l++) tot+=inflow[i][l];
127 if(tot<=0) continue;
128 double k=kk[i];
129 double share[LINKS];
130 for(int l=0;l<LINKS;l++) share[l]=inflow[i][l]/tot;
131 if(shuffled){ /* P4: same update, wrong addresses */
132 for(int l=LINKS-1;l>0;l--){ int m=(int)(xs()%(unsigned long long)(l+1)); double t=share[l]; share[l]=share[m]; share[m]=t; }
133 }
134 double s=0;
135 for(int l=0;l<LINKS;l++){ ww[i][l]=(1.0-k)*ww[i][l]+k*share[l]; s+=ww[i][l]; }
136 if(s>0) for(int l=0;l<LINKS;l++) ww[i][l]/=s; /* fixed giving budget */
137 }
138 }
139
140 /* private fidelity from received flow */
141 for(int i=0;i<TOTAL;i++){
142 double R=recv[i]/TROUND/RSCALE; if(R<0)R=0; if(R>1)R=1;
143 fid[i]=F0+(F1-F0)*R;
144 }
145
146 /* global Wright-Fisher. NO compartments, NO group selection. Parasites replicate faster. */
147 double tot=0;
148 for(int i=0;i<TOTAL;i++){ tot+=1.0+BETA*(1.0-(double)phic[i]/PHIMAX); cumw[i]=tot; }
149 for(int i=0;i<TOTAL;i++){
150 double r=urand()*tot; int lo=0,hi=TOTAL-1;
151 while(lo<hi){ int mid=(lo+hi)/2; if(cumw[mid]<r) lo=mid+1; else hi=mid; }
152 nseq[i]=replicate(seq[lo],fid[lo]);
153 double k2 = evolve_k ? kk[lo]+MUTK*randn() : kk[lo];
154 if(k2<0)k2=0;
155 if(k2>1)k2=1;
156 nkk[i]=k2;
157 }
158 for(int i=0;i<TOTAL;i++){ seq[i]=nseq[i]; kk[i]=nkk[i]; }
159 }
160
161 double sp=0,sk=0,sf=0;
162 for(int i=0;i<TOTAL;i++){ sp+=phi(seq[i]); sk+=kk[i]; sf+=fid[i]; }
163 *k_end=sk/TOTAL; *f_end=sf/TOTAL;
164 return sp/TOTAL;
165}
166
167int main(void)
168{
169 unsigned long long seeds[10];
170 seeds[0]=0x9e3779b97f4a7c15ULL; seeds[1]=0xd1b54a32d192ed03ULL; seeds[2]=0x2545f4914f6cdd1dULL;
171 for(int i=3;i<10;i++) seeds[i]=0x9e3779b97f4a7c15ULL ^ (0x100000001b3ULL*(unsigned long long)(i+1));
172 int NS=10;
173
174 printf("=== COUPLING: can a wiring rule privatize catalysis with NO container? ===\n");
175 printf(" Same chemistry as ribozyme.c (phi = hairpin fold, parasites %.0fx faster, f0=%.2f f1=%.3f).\n",1+BETA,F0,F1);
176 printf(" NO compartments, NO space, NO group selection. Global Wright-Fisher over %d units.\n",TOTAL);
177 printf(" Each unit owns %d junctions; catalysis flows BOTH ways; trait k = how much it\n",LINKS);
178 printf(" reallocates conductance toward junctions that delivered. %d exchange rounds/gen.\n",TROUND);
179 printf(" REFERENCE: ribozyme.c well-mixed (no compartments) went 5.99 -> 5.50, parasites won.\n\n");
180
181 printf(" arm | mean phi (start->end of %2d) | k end | fidelity end\n",PHIMAX);
182 printf(" ---------------------------------+-----------------------------+-------+-------------\n");
183
184 double base_s=0,base_e=0;
185 struct { const char*name; int ev; double kf; int sh; } arms[]={
186 {"k=0 frozen (public good) ", 0, 0.0, 0},
187 {"k=1 frozen (full reciprocity) ", 0, 1.0, 0},
188 {"k free to evolve (start 0.10) ", 1, 0.0, 0},
189 {"k=1 SHUFFLED (control) ", 0, 1.0, 1},
190 };
191 int NA=(int)(sizeof(arms)/sizeof(arms[0]));
192 double endphi[8], startphi[8], endk[8];
193 for(int a=0;a<NA;a++){
194 double S=0,E=0,K=0,F=0; double ev[16];
195 for(int s=0;s<NS;s++){
196 double ke,fe,ps; RNG=seeds[s];
197 double e=run(arms[a].ev,arms[a].kf,arms[a].sh,&ke,&fe,&ps);
198 ev[s]=e; E+=e; S+=ps; K+=ke; F+=fe;
199 }
200 S/=NS;E/=NS;K/=NS;F/=NS;
201 double sd=0; for(int s=0;s<NS;s++) sd+=(ev[s]-E)*(ev[s]-E); sd=sqrt(sd/(NS-1));
202 endphi[a]=E; startphi[a]=S; endk[a]=K;
203 if(a==0){ base_s=S; base_e=E; }
204 printf(" %s | %.2f -> %5.2f +- %.2f | %.3f | %.4f\n",arms[a].name,S,E,sd,K,F);
205 }
206 printf("\n");
207
208 int pub_fell = endphi[0] < startphi[0]-0.3;
209 int recip_rose = endphi[1] > startphi[1]+0.5;
210 int evo_rose = endphi[2] > startphi[2]+0.5;
211 int k_climbed = endk[2] > 0.30;
212 int shuf_rose = endphi[3] > startphi[3]+0.5;
213
214 printf(" P1 public good (k=0) : phi %s (%.2f -> %.2f)\n", pub_fell?"FELL — tragedy reproduced":"did NOT fall", base_s, base_e);
215 printf(" P2 reciprocity (k=1) : phi %s (%.2f -> %.2f)\n", recip_rose?"ROSE":"did NOT rise", startphi[1], endphi[1]);
216 printf(" P3 k evolvable : phi %s (%.2f -> %.2f), k %s (0.10 -> %.3f)\n",
217 evo_rose?"ROSE":"did NOT rise", startphi[2], endphi[2], k_climbed?"CLIMBED":"did not climb", endk[2]);
218 printf(" P4 shuffled control : phi %s (%.2f -> %.2f)\n", shuf_rose?"ROSE — CONFOUND":"did NOT rise (good)", startphi[3], endphi[3]);
219 printf("\n");
220
221 if(recip_rose && pub_fell && !shuf_rose)
222 printf(" => COUPLING PRIVATIZES THE PUBLIC GOOD WITH NO CONTAINER. Cutting a junction to a\n"
223 " freeloader costs nothing because it was sending nothing back, so conditional\n"
224 " conductance starves parasites of fidelity while catalysts fund each other. The\n"
225 " shuffled control did NOT rise, so this is reciprocity and not merely concentrating\n"
226 " conductance. %s\n",
227 evo_rose&&k_climbed ? "AND k evolved up on its own — the wiring rule is itself selected."
228 : "NOTE: k did NOT evolve up on its own, so conditioning works but is not self-installing.");
229 else if(recip_rose && shuf_rose)
230 printf(" => CONFOUNDED. phi rose in the shuffled control too, so the effect is about\n"
231 " concentrating conductance onto few partners, NOT about reciprocity. Do not claim\n"
232 " a coupling result from this.\n");
233 else if(!recip_rose)
234 printf(" => HONEST NULL. Wiring did not privatize catalysis here: parasites harvest enough\n"
235 " before conductances sort, or catalysts never find each other in a random network.\n"
236 " Containers remain the only thing in the arc that privatizes. Accept the null.\n");
237 else
238 printf(" => Mixed/ambiguous — report the numbers as-is, claim nothing.\n");
239 return 0;
240}
coupling.md +66 -0
……@@ -0,0 +1,66 @@
1# `coupling.c` — wiring instead of walls: real, selected, and not enough
2
3**Question.** Across 14 experiments the wall was always the same: catalysis is a public good,
4parasites free-ride, and the only thing that ever rescued it was a **supplied compartment**. Every
5attempt to make a boundary emerge for free failed — space, cis-acting, cohesion, metabolic
6integration. All of those are **containers**: put the chemistry in a bag, the parasites end up in
7the bag too.
8
9Untested axis: does the boundary have to be a container at all? In Levin's systems what makes a pile
10of cells one individual is not a wall but **gap-junctional coupling** — the individual is a wiring
11pattern, movable by changing wiring without touching a membrane.
12
13**Design.** Same chemistry as `ribozyme.c` (φ = hairpin fold, parasites 3× faster, F0=0.85,
14F1=0.999, 4800 units, 200 gens). Each unit owns 4 junctions and controls their conductance;
15catalysis flows **both ways**, scaled by each end's φ. Received flow sets that unit's **private**
16copying fidelity. Heritable trait **k** ∈ [0,1] = how much a unit reallocates conductance toward
17junctions that delivered. **k=0 is the old public good; k=1 is full reciprocity.**
18
19Supplied: the *option* to condition (the `rung34.c` standard). Must emerge: parasite exclusion —
20no rule says catalysts wire to catalysts, and a unit cannot see anyone's type, only its own inflow.
21Absent entirely: containers, space, assortment, group selection. Global Wright-Fisher.
22
23## Results (10 seeds)
24
25| arm | mean φ (start → end of 12) | k end | fidelity end |
26|---|---|---|---|
27| k=0 frozen (public good) | 5.99 → **4.69 ± 0.06** | 0.000 | 0.9630 |
28| k=1 frozen (full reciprocity) | 5.99 → **5.36 ± 0.04** | 1.000 | 0.9741 |
29| k free to evolve (start 0.10) | 5.99 → **5.07 ± 0.03** | **0.449** | 0.9718 |
30| k=1 **SHUFFLED** (control) | 5.99 → **4.67 ± 0.05** | 1.000 | 0.9625 |
31
32Three findings, in order of confidence:
33
341. **Reciprocity is real.** k=1 beats k=0 by **+0.67 φ**, many sd apart.
352. **It is not an artifact of concentrating conductance.** The shuffled control — same arithmetic,
36 same budget, same concentration of w, but applied to a random permutation of the unit's own
37 junctions — lands at **4.67, indistinguishable from k=0**. So the gain comes from *whom* the
38 conductance points at, i.e. genuinely from reciprocity.
393. **Conditioning is selected for, un-forced.** k climbs 0.10 → **0.449** with nothing rewarding it
40 directly, and the evolvable arm sits at 5.07, between the k=0 and k=1 arms — exactly where a
41 population at k≈0.45 should sit.
42
43**And it is still a null.** φ falls in every arm. Wiring slows the tragedy; it does not reverse it.
44No crossing.
45
46## Diagnosis
47
48The likely cause is a design decision I made in the name of supplying nothing: **the wiring is
49rebuilt from scratch every generation.** Reciprocity gets 8 exchange rounds to sort, then the whole
50network is randomised. But in Levin's systems gap junctions **persist** — and that persistence is
51precisely what makes a coupling pattern an *individual* rather than a transient interaction. The
52model may have discarded the essential ingredient while trying to avoid supplying structure.
53
54The principled next increment is **persistent junctions**: offspring inherit their parent's
55partners, so a catalyst-rich subnetwork can consolidate across generations.
56
57⚠️ Honest caveat on that increment: inheriting partners is *not* a container (parasites inherit
58partners too, nothing forbids them coupling), but it does supply more structure than this run did,
59and it edges toward lineage-level clustering. It must be flagged as such, not slipped in — and it
60needs its own shuffled control.
61
62## Comparison note
63
64Do **not** read these against `ribozyme.c`'s well-mixed 5.50. That arm sets fidelity from the *pool
65mean* φ, so everyone receives the same fairly high fidelity; here fidelity is private and
66wiring-dependent. The correct internal baseline is the k=0 arm (4.69).