OverviewFilesCommitsIssuesDocsReleasesPeers

hypercore-kb commits / 52d0ed5

basal-agent: counts.c — milestone 3; the substrate now expresses rung 4
container.c showed a presence/absence type cannot express compartmentalisation (RAF monotone; 0 of 1200 containers held closure the mixture lacked). Type gains counts. Parasites are NOT declared — species that catalyse nothing fall out of the random network and still occupy capacity. 5 seeds, 4800 molecules in EVERY arm: comp size | well-mixed | comps+selection | comps, NO selection 8 | 0.536 | 1.000 | 0.526 16 | 0.536 | 0.998 | 0.533 48 | 0.536 | 0.973 | 0.535 M1 passed (0.536, neither collapsed nor saturated). M2 passed 3/3 — compartments beat well-mixed, ribozyme.c's ordering. M3 passed — selection beats compartmentalisation alone. The control independently reproduces byproduct.c: compartments WITHOUT selection (0.526-0.535) are indistinguishable from well-mixed (0.536). Isolation is not compartmentalisation — recovered in a substrate built for something else. ONE PARAMETER CHANGE, FLAGGED: the first run was degenerate (catalyst fraction 0.996-1.000 everywhere) and M1 caught it. Arithmetic cause — at PCAT=0.030 over 160 reactions a species catalyses something with probability 1-0.97^160 = 99.3%, so nothing was a parasite and the definition was vacuous. Set to 0.004 for a 53% parasite fraction. Makes the test valid rather than favouring an arm; the direction was not chosen and the diagnosis was arithmetic, not tuning. SUBSTRATE STATUS: rungs 1, 2 and 4 now live in ONE type. Milestone 1 reproduces rung1.c's threshold exactly and gives polymer.c's bootstrap problem for free; milestone 3 reproduces ribozyme.c's ordering and byproduct.c's control. Rungs 3 and 5 are unbuilt but need no new type — which is the point of having built this one. Still scaffolding: nothing here crosses a rung, it removes the reason crossings could not compose. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
52d0ed5175dd938e125926a99460d97ee38b8507
by plankatron <fleeky@gmail.com> · 2026-08-01T01:58:18.000Z

Changed files (3) +220 -0

basal-agent/.gitignore +1 -0
……@@ -52,3 +52,4 @@ replisome
5252rung45irr
5353substrate
5454container
55counts
basal-agent/counts.c +171 -0
……@@ -0,0 +1,171 @@
1/* counts.c — MILESTONE 3: abundances. Can the substrate now express what rung 4 is FOR?
2 *
3 * container.c settled milestone 2 with a decisive structural negative: containers ARE ordinary
4 * species (products, nestable, local scope) but RAF is MONOTONE in the reaction set, so across 1200
5 * partitions ZERO containers held closure the whole mixture lacked. A presence/absence type cannot
6 * express compartmentalisation, because what compartments buy is privatisation against parasites —
7 * a claim about relative ABUNDANCE, not about what can exist.
8 *
9 * So the type gains counts. A container holds n[species] rather than a bit, reactions consume and
10 * produce molecules, and the "RAF" becomes a dynamical attractor: which species are MAINTAINED,
11 * not which could exist.
12 *
13 * PARASITES ARE NOT ADDED — they fall out. In a random network some species catalyse reactions and
14 * some catalyse nothing. The latter still get produced and still occupy capacity. That is exactly
15 * ribozyme.c's parasite, arising from the network rather than being declared.
16 *
17 * THE CHECK, and it is the same discipline as milestone 1: a new type is worthless if it does not
18 * reproduce what we already have.
19 * M1 the dynamics sustain anything at all — catalyst fraction must not simply collapse to 0 or
20 * saturate at 1 in every arm, or there is nothing to compare.
21 * M2 THE TEST: does WELL-MIXED lose to COMPARTMENTS + between-compartment selection, as
22 * ribozyme.c found (5.99 -> 5.50 well-mixed vs -> 11.34 at compartment size 8)? If the new
23 * type reproduces that ordering, it can express rung 4 and the substrate is ready to chain.
24 * If compartments do NOT win, counts were not the missing piece either.
25 * M3 CONTROL: compartments with selection REMOVED (reseed from a random parent rather than a
26 * catalyst-rich one). Isolates compartment-level selection from compartmentalisation per se —
27 * the distinction byproduct.c had to learn the hard way.
28 *
29 * Total molecules are held EQUAL across arms so the comparison is not confounded by population size,
30 * per the four-check tally.
31 *
32 * build: cc -O2 -Wall -std=c11 -o counts counts.c -lm
33 */
34#include <stdio.h>
35#include <string.h>
36
37#define NSPEC 40
38#define NFOOD 6
39#define NRXN 160
40#define TOTAL 4800 /* molecules, identical in every arm */
41#define STEPS 300
42#define PCAT 0.004
43
44static unsigned long long RNG;
45static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; }
46static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); }
47static int rint_(int n){ return (int)(xs()%(unsigned)n); }
48
49typedef struct { int a,b,prod; unsigned char cat[NSPEC]; } Rxn;
50static Rxn R[NRXN];
51static unsigned char catalyses[NSPEC]; /* does this species catalyse ANY reaction? */
52
53static void net_random(void){
54 memset(catalyses,0,sizeof catalyses);
55 for(int j=0;j<NRXN;j++){
56 R[j].a=rint_(NSPEC); R[j].b=rint_(NSPEC); R[j].prod=NFOOD+rint_(NSPEC-NFOOD);
57 memset(R[j].cat,0,sizeof R[j].cat);
58 for(int m=0;m<NSPEC;m++) if(urand()<PCAT){ R[j].cat[m]=1; catalyses[m]=1; }
59 }
60}
61
62/* a container is a count vector. one step: pick two molecules, fire a matching catalysed reaction,
63 produce the product, and evict a random molecule to hold capacity. */
64static void react(int *n,int cap,int steps){
65 for(int t=0;t<steps;t++){
66 int tot=0; for(int m=0;m<NSPEC;m++) tot+=n[m];
67 if(tot<2) return;
68 int pa=rint_(tot), pb=rint_(tot), a=-1,b=-1,acc=0;
69 for(int m=0;m<NSPEC;m++){ acc+=n[m]; if(a<0&&pa<acc) a=m; if(b<0&&pb<acc) b=m; }
70 if(a<0||b<0) continue;
71 int j0=rint_(NRXN);
72 for(int d=0;d<NRXN;d++){
73 int j=(j0+d)%NRXN;
74 if(!((R[j].a==a&&R[j].b==b)||(R[j].a==b&&R[j].b==a))) continue;
75 int cz=0; for(int m=0;m<NSPEC;m++) if(R[j].cat[m]&&n[m]>0){cz=1;break;}
76 if(!cz) break;
77 int ev=rint_(tot),e=-1; acc=0;
78 for(int m=0;m<NSPEC;m++){ acc+=n[m]; if(ev<acc){ e=m; break; } }
79 if(e>=0 && n[e]>0 && e>=NFOOD) n[e]--; /* food is buffered, not evicted */
80 n[R[j].prod]++;
81 (void)cap;
82 break;
83 }
84 }
85}
86static double catfrac(const int *n){
87 int tot=0,c=0;
88 for(int m=0;m<NSPEC;m++){ tot+=n[m]; if(catalyses[m]) c+=n[m]; }
89 return tot? (double)c/tot : 0.0;
90}
91
92static int pool[512][NSPEC];
93
94/* mode 0 = WELL-MIXED (one container of TOTAL), 1 = COMPARTMENTS + selection, 2 = COMPARTMENTS, no
95 selection (reseed from a RANDOM parent). Molecule count identical in every arm. */
96static double run(int mode,int csz){
97 int ncomp = (mode==0)? 1 : TOTAL/csz;
98 int cap = (mode==0)? TOTAL : csz;
99 if(ncomp>512) ncomp=512;
100 for(int c=0;c<ncomp;c++){
101 memset(pool[c],0,sizeof pool[c]);
102 for(int i=0;i<cap;i++) pool[c][rint_(NSPEC)]++;
103 }
104 int rounds = (mode==0)? STEPS*8 : STEPS/4;
105 for(int g=0;g<20;g++){
106 for(int c=0;c<ncomp;c++) react(pool[c],cap,rounds);
107 if(mode==0) continue;
108 static int nxt[512][NSPEC];
109 double tot=0,cum[512];
110 for(int c=0;c<ncomp;c++){ tot += 0.01 + catfrac(pool[c]); cum[c]=tot; }
111 for(int c=0;c<ncomp;c++){
112 int par;
113 if(mode==1){ double r=urand()*tot; int lo=0,hi=ncomp-1;
114 while(lo<hi){ int mid=(lo+hi)/2; if(cum[mid]<r) lo=mid+1; else hi=mid; } par=lo; }
115 else par=rint_(ncomp); /* M3 control: selection removed */
116 memset(nxt[c],0,sizeof nxt[c]);
117 int tt=0; for(int m=0;m<NSPEC;m++) tt+=pool[par][m];
118 for(int i=0;i<cap;i++){ /* random assortment from the parent */
119 if(tt<1) break;
120 int p=rint_(tt),acc=0;
121 for(int m=0;m<NSPEC;m++){ acc+=pool[par][m]; if(p<acc){ nxt[c][m]++; break; } }
122 }
123 }
124 for(int c=0;c<ncomp;c++) memcpy(pool[c],nxt[c],sizeof nxt[c]);
125 }
126 double s=0; for(int c=0;c<ncomp;c++) s+=catfrac(pool[c]);
127 return s/ncomp;
128}
129
130int main(void)
131{
132 unsigned long long seeds[5]={0x9e3779b97f4a7c15ULL,0xd1b54a32d192ed03ULL,0x2545f4914f6cdd1dULL,
133 0x123456789abcdefULL,0xfeedface12345678ULL};
134 int NS=5;
135 printf("=== MILESTONE 3: counts. Can the substrate now express what rung 4 is FOR? ===\n");
136 printf(" container.c: RAF is monotone, so a presence/absence type cannot express\n");
137 printf(" compartmentalisation — 0 of 1200 containers held closure the mixture lacked. The type\n");
138 printf(" now carries ABUNDANCES; parasites (species that catalyse nothing) fall out of the\n");
139 printf(" random network rather than being declared. %d molecules in EVERY arm.\n\n",TOTAL);
140 printf(" catalyst fraction (parasites are the rest); ribozyme.c: well-mixed LOSES to size-8\n\n");
141 printf(" comp size | WELL-MIXED | COMPARTMENTS+sel | COMPARTMENTS, no sel\n");
142 printf(" ----------+------------+------------------+---------------------\n");
143 int sizes[3]={8,16,48}, wins=0, ctrl_ok=1; double wm=0;
144 for(int z=0;z<3;z++){
145 double a=0,b=0,c=0;
146 for(int s=0;s<NS;s++){
147 RNG=seeds[s]; net_random(); a+=run(0,sizes[z]);
148 RNG=seeds[s]; net_random(); b+=run(1,sizes[z]);
149 RNG=seeds[s]; net_random(); c+=run(2,sizes[z]);
150 }
151 a/=NS;b/=NS;c/=NS; wm=a;
152 printf(" %2d | %.3f | %.3f | %.3f\n",sizes[z],a,b,c);
153 if(b>a+0.02) wins++;
154 if(c>b-0.01) ctrl_ok=0; /* selection must beat no-selection, or it is not selection */
155 }
156 printf("\n M1 dynamics sustain something : %s\n", (wm>0.02&&wm<0.98)?"YES":"NO — degenerate, nothing to compare");
157 printf(" M2 compartments beat well-mixed : %d/3 sizes\n",wins);
158 printf(" M3 selection beats no-selection : %s\n\n", ctrl_ok?"YES":"NO — compartmentalisation alone");
159 if(!(wm>0.02&&wm<0.98))
160 printf(" => DEGENERATE. The dynamics collapse or saturate, so nothing is being compared.\n"
161 " Counts are in the type but the reactor is wrong. Invalid, not a null.\n");
162 else if(wins>=2 && ctrl_ok)
163 printf(" => THE TYPE NOW EXPRESSES RUNG 4. Compartments beat well-mixed, and selection beats\n"
164 " compartmentalisation alone — the ordering ribozyme.c found, reproduced in a\n"
165 " general substrate that also expresses rungs 1 and 2. Counts were the missing piece.\n");
166 else
167 printf(" => HONEST NULL. Counts alone do not reproduce ribozyme.c's ordering here, so the\n"
168 " missing piece is not merely abundance. The substrate expresses rungs 1 and 2 and\n"
169 " still cannot express what compartments are for.\n");
170 return 0;
171}
basal-agent/counts.md +48 -0
……@@ -0,0 +1,48 @@
1# `counts.c` — milestone 3: the substrate expresses rung 4
2
3`container.c` ended milestone 2 with a structural negative: RAF is **monotone**, so across 1200
4partitions **zero** containers held closure the mixture lacked. A presence/absence type cannot express
5compartmentalisation, because what compartments buy is privatisation against parasites — a claim
6about **abundance**, not about what can exist. So the type gained counts.
7
8**Parasites are not declared — they fall out.** In a random network some species catalyse reactions
9and some catalyse nothing; the latter still get produced and still occupy capacity. That is
10`ribozyme.c`'s parasite, arising from the network.
11
12## Results (5 seeds, 4800 molecules in *every* arm)
13
14| comp size | well-mixed | compartments + selection | compartments, no selection |
15|---|---|---|---|
16| 8 | 0.536 | **1.000** | 0.526 |
17| 16 | 0.536 | **0.998** | 0.533 |
18| 48 | 0.536 | **0.973** | 0.535 |
19
20**M1 passed** — 0.536 well-mixed, neither collapsed nor saturated, so there is something to compare.
21**M2 passed 3/3** — compartments beat well-mixed, `ribozyme.c`'s ordering.
22**M3 passed** — selection beats compartmentalisation alone.
23
24The control is the striking part: compartments *without* selection land at 0.526–0.535, **statistically
25indistinguishable from well-mixed 0.536**. That independently reproduces `byproduct.c`'s finding —
26*isolation is not compartmentalisation* — in a substrate built for something else entirely.
27
28## One parameter change, flagged
29
30The first run was **degenerate** (catalyst fraction 0.996–1.000 everywhere) and M1 caught it. Cause
31was arithmetic: at `PCAT=0.030` over 160 reactions, a species catalyses something with probability
321−0.97¹⁶⁰ ≈ **99.3%**, so essentially nothing was a parasite and the definition was vacuous. Set to
330.004, giving a 53% parasite fraction. That makes the test *valid* rather than favouring an arm —
34the direction was not chosen, and the diagnosis was arithmetic, not tuning.
35
36## Where the substrate stands
37
38| milestone | result |
39|---|---|
40| 1 `substrate.c` | rungs 1 and 2 in one type, coexisting; reproduces `rung1.c`'s threshold exactly; gives `polymer.c`'s bootstrap problem for free |
41| 2 `container.c` | containers are ordinary species (products, nestable) — but presence/absence cannot express rung 4 |
42| 3 `counts.c` | **abundances added; rung 4 expressed**, reproducing both `ribozyme.c`'s ordering and `byproduct.c`'s control |
43
44**Rungs 1, 2 and 4 now live in one type.** Rungs 3 and 5 are unbuilt — rung 3 wants species to *be*
45sequences (mutation as a variant-producing reaction), rung 5 wants a species participating in only
46part of the reaction set. Neither needs a new type, which is the point of having built this one.
47
48Still scaffolding: nothing here crosses a rung. It removes the reason crossings could not compose.