OverviewFilesCommitsIssuesDocsReleasesPeers

hypercore-kb commits / fa8b4de

basal-agent: fluctuate.c — the scrambled control kills the fluctuation result
threecarrier.c's fourth attempt reported reading ON raising working fraction 0.294 -> 0.478 under a fluctuating target set. Scored on function instead of template abundance, with the reading knockout reduced to one variable and run against a SCRAMBLED control, it does not survive. Faithful reading does not beat a scrambled read in either world (-0.174 fresh, -0.069 recur; 1/24 and 5/24 seeds), so the ON-vs-OFF gain is the conversion of a template into a catalyst, not the information it carries. genome.c's result again. P3 confirms fluctuation genuinely costs function (+0.921); P4 — memory pays where the world repeats — is not supported, RECUR is null too. All four tests of the test pass, so this is a result, not a void. Known gap, recorded in fluctuate.md: run() computes R->redund and R->gapfill — the numbers that would decide whether the scrambled win is the diversity effect genome.md named — and main() never stores or prints them. Written 2026-08-01, left unrun when the machine lost power; run 2026-08-04. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fa8b4de635db427776b576ca262b3637fc6bdda7
by plankatron <fleeky@gmail.com> · 2026-08-05T02:19:00.000Z

Changed files (2) +499 -0

basal-agent/fluctuate.c +417 -0
……@@ -0,0 +1,417 @@
1/* fluctuate.c — does MEMORY pay when the world CHANGES? Scored on FUNCTION, against a SCRAMBLED
2 * control, with the reading knockout reduced to ONE variable.
3 *
4 * WHERE THIS COMES FROM. threecarrier.c's fourth attempt reported that under a fluctuating target
5 * set, turning reading ON raised the working fraction 0.294 -> 0.478 and function 1.27 -> 1.47.
6 * That number is NOT usable as it stands, for two reasons found by reading its source:
7 *
8 * (1) WRONG METRIC. Its pre-registered M1/M2 scored TEMPLATE ABUNDANCE. Reading converts a template
9 * replication event into a catalyst, so the reading-OFF arm holds MORE templates (0.023 vs
10 * 0.012) precisely because they are useless there. Template count measures templates NOT BEING
11 * USED. genome.md records this identical mistake; it has now been made three times.
12 *
13 * (2) THE KNOCKOUT MOVED TWO VARIABLES. threecarrier.c:238-239 reads
14 * if(ko!=2 && nc>0 && urand()<0.5){ ch.role=CAT; ch.type=p.type; }
15 * else if(urand()>f) ch.type=rint_(NTYPE); // copy error
16 * An if/else. With reading ON a read child SKIPS the copy-error branch; with reading OFF every
17 * template replication takes it. So "reading off" also raises template mutation load. That is
18 * the one-knob-two-variables fault the 2026-07-31 post-mortem counted four separate times.
19 *
20 * WHAT THIS FILE CHANGES, AND NOTHING ELSE. Chemistry, sizes, rates, seeding and between-compartment
21 * selection are IDENTICAL to threecarrier.c so the numbers stay comparable:
22 * - copy error now applies to EVERY template replication, independent of reading. Reading is a
23 * separate, subsequent event. The knockout is one variable.
24 * - scored on FUNCTION and WORKING FRACTION, time-averaged over the second half of the run
25 * (many switch cycles, not one phase-dependent snapshot). Template fraction is still reported,
26 * and is explicitly NOT a criterion.
27 * - 24 seeds, not 5, with the paired per-seed difference and its spread reported.
28 *
29 * THE CONTROL, WHICH IS THE POINT. genome.c ran this same question and looked positive until the
30 * SCRAMBLED control inverted it: reading that produces a catalyst of a RANDOM type BEAT faithful
31 * reading at every mutation rate, because the gain was the mechanism turning non-folders into
32 * folders, and the information contributed nothing. threecarrier.c never ran that control. Comparing
33 * read-ON against read-OFF cannot separate the information from the conversion, because reading also
34 * adds a catalyst, which raises nc, which raises both growth (GROW*nc) and fidelity (nc>0 => FHI).
35 * So the headline comparison here is FAITHFUL vs SCRAMBLED, not ON vs OFF.
36 *
37 * genome.md also named the missing ingredient and designed the fix deliberately left unrun: "a
38 * genome is only worth having when a SPECIFIC configuration beats a random one". threecarrier.c
39 * supplied that (NTARG specific types out of NTYPE) but never ran the control it was designed for.
40 * This does.
41 *
42 * AND THE PREDICTION THAT MAKES A NULL INFORMATIVE. Under a FRESH random redraw, a stored type is a
43 * target again with probability NTARG/NTYPE = 0.25 -- exactly the odds a scrambled read gets by
44 * dice. So a fresh-redraw world offers memory no edge in principle, and worse: right after a switch
45 * the template pool is enriched for the OLD targets, which is worse than random. If memory pays
46 * anywhere it is in a world that REPEATS. So the fluctuating condition is run twice:
47 * FRESH -- targets redrawn at random every switch (threecarrier.c's condition)
48 * RECUR -- cycled among NENV fixed target sets, so a type not needed now IS needed again
49 * Both are pre-registered before running, so a null on FRESH plus a positive on RECUR is a stated
50 * prediction confirmed, not a story told afterwards.
51 *
52 * SUPPLIED vs MUST EMERGE:
53 * SUPPLIED: the three carriers seeded complete and correct, the reading physics, between-compartment
54 * selection on current function, and the environment's switching schedule.
55 * MUST EMERGE: any advantage of holding information. NOTHING rewards templates directly -- they
56 * fold nothing and cost a slot. Parasites are not seeded; they arise by mutation and replicate
57 * BETA faster, so the tragedy is live in every arm.
58 *
59 * PRE-REGISTERED:
60 * P1 THE PRIMARY TEST: under fluctuation, FAITHFUL reading beats SCRAMBLED reading on function.
61 * One variable: the type the read catalyst gets. If this fails, the information is doing
62 * nothing and any ON-vs-OFF gain is the conversion, exactly as in genome.c.
63 * P2 reading of any kind beats no reading. REPORTED BUT CONFOUNDED by construction (conversion +
64 * information + the nc it feeds). It is not evidence for memory and is not read as such.
65 * P3 fluctuation actually costs function relative to static. If it does not, nothing was survived.
66 * P4 THE STATED ALTERNATIVE: if P1 is null under FRESH but holds under RECUR, then memory pays only
67 * when the world repeats itself -- a condition on the ENVIRONMENT, not on the chemistry.
68 *
69 * TESTS OF THE TEST (any failure voids the arm it belongs to; a void result is reported as void):
70 * G1 reads actually happen -- nonzero in every reading arm, exactly zero in every OFF arm.
71 * G2 templates actually exist. If the template fraction is ~0 there is no third carrier and nothing
72 * was tested. This is what voided threecarrier.c's second and third attempts.
73 * G3 the environment actually changes -- switches occur and consecutive target sets differ.
74 * G4 the arms differ at all.
75 *
76 * Do not tune to force a positive. A null with G1-G4 passing is a real result: it says memory cannot
77 * pay under instantaneous selection even when the world moves, which is the fifth 1->2 constraint
78 * stated more strongly than the post-mortem could state it.
79 *
80 * build: cc -O2 -Wall -Wextra -std=c11 -o fluctuate fluctuate.c -lm
81 */
82#include <math.h>
83#include <stdio.h>
84#include <string.h>
85
86#define NCOMP 600
87#define CAP 16
88#define GEN 400
89#define BURN 200 /* measurement window is generations BURN..GEN-1 */
90#define NTYPE 16
91#define NTARG 4
92#define NENV 3 /* RECUR: this many fixed target sets, cycled */
93#define SWEVERY 15
94#define BETA 2.0 /* parasite replication advantage */
95#define MUT 0.02
96#define FLO 0.85 /* template copy fidelity with no catalyst present */
97#define FHI 0.995 /* ... with one (the replicase coupling) */
98#define GROW 0.55
99#define DEATH 0.15
100#define PREAD 0.5 /* per-replication chance a template is read */
101#define NSEED 24
102
103enum { CAT=0, TEM=1, PAR=2 };
104enum { ENV_STATIC=0, ENV_FRESH=1, ENV_RECUR=2 };
105enum { READ_OFF=0, READ_FAITHFUL=1, READ_SCRAMBLED=2 };
106
107static unsigned long long RNG;
108static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; }
109static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); }
110static int rint_(int n){ return (int)(xs()%(unsigned)n); }
111
112typedef struct { unsigned char role, type; } Unit;
113static Unit cell[NCOMP][CAP], nxt[NCOMP][CAP];
114static int sz[NCOMP], nsz[NCOMP];
115static double mat[NCOMP], nmat[NCOMP];
116
117static int TARGET[NTYPE];
118static int ENVSET[NENV][NTYPE];
119
120typedef struct {
121 double func, work, tfrac, parfrac; /* time-averaged over the measurement window */
122 double early, late; /* function just after / just before a switch */
123 double reads; /* read events per compartment per generation */
124 double redund, gapfill; /* fraction of reads that were redundant / filled a gap */
125 double switches, overlap; /* did the environment actually change? */
126} Res;
127
128static void counts(int c,int *nc,int *nt,int *np){
129 *nc=*nt=*np=0;
130 for(int k=0;k<sz[c];k++){
131 if(cell[c][k].role==CAT) (*nc)++;
132 else if(cell[c][k].role==TEM) (*nt)++;
133 else (*np)++;
134 }
135}
136/* function = how many of the SPECIFIC target types are present among catalysts. Identical to
137 threecarrier.c. Nothing rewards templates; they fold nothing and still cost a slot. */
138static int func_of(int c){
139 int seen[NTYPE]; memset(seen,0,sizeof seen);
140 for(int k=0;k<sz[c];k++) if(cell[c][k].role==CAT) seen[cell[c][k].type]=1;
141 int f=0; for(int t=0;t<NTYPE;t++) if(seen[t]&&TARGET[t]) f++;
142 return f;
143}
144static void drawset(int *set){
145 for(int t=0;t<NTYPE;t++) set[t]=0;
146 for(int got=0;got<NTARG;){ int t=rint_(NTYPE); if(!set[t]){ set[t]=1; got++; } }
147}
148static int overlap_of(const int *a,const int *b){
149 int o=0; for(int t=0;t<NTYPE;t++) if(a[t]&&b[t]) o++; return o;
150}
151
152static void run(int envmode,int readmode,Res *R)
153{
154 int prev[NTYPE]; int envi=0;
155 double nsw=0, novl=0, reads=0, redund=0, gapfill=0;
156 double fsum=0, wsum=0, tsum=0, psum=0; long nmeas=0;
157 double phase_f[SWEVERY]; long phase_n[SWEVERY];
158 memset(phase_f,0,sizeof phase_f); memset(phase_n,0,sizeof phase_n);
159
160 if(envmode==ENV_RECUR){
161 for(int e=0;e<NENV;e++) drawset(ENVSET[e]);
162 memcpy(TARGET,ENVSET[0],sizeof TARGET);
163 } else drawset(TARGET);
164
165 /* SEEDED COMPLETE AND CORRECT: catalysts and templates covering the target set. Identical to
166 threecarrier.c -- nothing here has to bootstrap; the question is only whether it holds. */
167 for(int c=0;c<NCOMP;c++){
168 sz[c]=CAP; mat[c]=0;
169 for(int k=0;k<CAP;k++){
170 int tg=-1,seen=0;
171 for(int t=0;t<NTYPE&&tg<0;t++) if(TARGET[t]){ if(seen==(k/2)%NTARG) tg=t; seen++; }
172 cell[c][k].role = (k%2)?TEM:CAT;
173 cell[c][k].type = (unsigned char)(tg<0?0:tg);
174 }
175 }
176
177 int lastsw=0;
178 for(int g=0;g<GEN;g++){
179 if(envmode!=ENV_STATIC && g>0 && g%SWEVERY==0){
180 memcpy(prev,TARGET,sizeof prev);
181 if(envmode==ENV_FRESH) drawset(TARGET);
182 else { envi=(envi+1)%NENV; memcpy(TARGET,ENVSET[envi],sizeof TARGET); }
183 nsw++; novl += overlap_of(prev,TARGET); lastsw=g;
184 }
185 for(int c=0;c<NCOMP;c++){
186 int nc,nt,np; counts(c,&nc,&nt,&np);
187 mat[c] += GROW*nc; /* metabolism -> boundary */
188 double f = (nc>0)? FHI : FLO; /* catalyst -> template fidelity */
189 double tot=0,cum[CAP];
190 for(int k=0;k<sz[c];k++){ tot += (cell[c][k].role==PAR)? 1.0+BETA : 1.0; cum[k]=tot; }
191 /* which catalyst types this compartment ALREADY has, fixed at the start of the generation
192 so both arms are scored against the same reference. Used only to characterize WHY an
193 arm wins -- it feeds no dynamics. */
194 int present[NTYPE]; memset(present,0,sizeof present);
195 for(int k=0;k<sz[c];k++) if(cell[c][k].role==CAT) present[cell[c][k].type]=1;
196 int newn=0;
197 for(int k=0;k<sz[c];k++) if(urand()>=DEATH) nxt[c][newn++]=cell[c][k];
198 while(mat[c]>=1.0 && newn<CAP && sz[c]>0){
199 double r=urand()*tot; int lo=0,hi=sz[c]-1;
200 while(lo<hi){ int mid=(lo+hi)/2; if(cum[mid]<r) lo=mid+1; else hi=mid; }
201 Unit p=cell[c][lo], ch=p;
202 if(p.role==TEM){
203 /* THE FIX. Copy error applies to EVERY template replication, independent of
204 reading; reading is a separate, subsequent event. In threecarrier.c these were
205 an if/else, so the reading knockout also changed mutation load. Both RNG draws
206 are taken unconditionally so the arms stay on the same stream as long as
207 possible -- the read modes then differ in exactly one thing: the type the
208 produced catalyst gets. */
209 if(urand()>f) ch.type=(unsigned char)rint_(NTYPE); /* copy error */
210 double rread = urand();
211 unsigned char rtype = (unsigned char)rint_(NTYPE);
212 if(readmode!=READ_OFF && nc>0 && rread<PREAD){
213 ch.role=CAT; /* template -> function */
214 if(readmode==READ_SCRAMBLED) ch.type=rtype; /* the control: no information */
215 reads++;
216 /* did this read add anything? A read that reproduces a type the compartment
217 already has changes no function; one that supplies a MISSING target type
218 raises it by one. This is the measurement that decides whether a scrambled
219 win is the diversity effect genome.md named. */
220 if(present[ch.type]) redund++;
221 else if(TARGET[ch.type]) gapfill++;
222 }
223 }
224 if(urand()<MUT){ ch.role=(unsigned char)rint_(3); ch.type=(unsigned char)rint_(NTYPE); }
225 nxt[c][newn++]=ch; mat[c]-=1.0;
226 }
227 nsz[c]=newn; nmat[c]=mat[c];
228 }
229 for(int c=0;c<NCOMP;c++){ sz[c]=nsz[c]; mat[c]=nmat[c]; for(int k=0;k<sz[c];k++) cell[c][k]=nxt[c][k]; }
230 /* between-compartment: reproduce in proportion to CURRENT function. Identical to
231 threecarrier.c, and it is the instantaneous selection the deferred-benefit obstacle is
232 about -- deliberately left in place, since removing it would answer a different question. */
233 {
234 double tot=0,cum[NCOMP];
235 for(int c=0;c<NCOMP;c++){ tot += 0.02 + func_of(c); cum[c]=tot; }
236 for(int c=0;c<NCOMP;c++){
237 double r=urand()*tot; int lo=0,hi=NCOMP-1;
238 while(lo<hi){ int mid=(lo+hi)/2; if(cum[mid]<r) lo=mid+1; else hi=mid; }
239 int m = sz[lo]<CAP? sz[lo] : CAP;
240 nsz[c]=m; nmat[c]=mat[lo]*0.5;
241 for(int k=0;k<m;k++) nxt[c][k]=cell[lo][rint_(sz[lo]>0?sz[lo]:1)];
242 }
243 for(int c=0;c<NCOMP;c++){ sz[c]=nsz[c]; mat[c]=nmat[c]; for(int k=0;k<sz[c];k++) cell[c][k]=nxt[c][k]; }
244 }
245 if(g>=BURN){
246 int ok=0,tp=0,tt=0,tu=0; double fs=0;
247 for(int c=0;c<NCOMP;c++){
248 int nc,nt,np; counts(c,&nc,&nt,&np);
249 int fc=func_of(c);
250 if(fc>=2) ok++;
251 fs+=fc; tp+=np; tt+=nt; tu+=sz[c];
252 }
253 double mf=fs/NCOMP;
254 fsum+=mf; wsum+=(double)ok/NCOMP;
255 tsum += tu? (double)tt/tu : 0; psum += tu? (double)tp/tu : 0;
256 nmeas++;
257 if(envmode!=ENV_STATIC){ int ph=g-lastsw; if(ph<SWEVERY){ phase_f[ph]+=mf; phase_n[ph]++; } }
258 }
259 }
260 R->func=fsum/nmeas; R->work=wsum/nmeas; R->tfrac=tsum/nmeas; R->parfrac=psum/nmeas;
261 R->reads = reads/((double)NCOMP*GEN);
262 R->redund = reads? redund/reads : 0;
263 R->gapfill = reads? gapfill/reads : 0;
264 R->switches=nsw; R->overlap = nsw? novl/nsw : 0;
265 /* where memory should pay if it pays anywhere: the generations right after a switch, versus
266 right before the next one. */
267 double e=0,l=0; long en=0,ln=0;
268 for(int ph=0;ph<5;ph++){ e+=phase_f[ph]; en+=phase_n[ph]; }
269 for(int ph=SWEVERY-5;ph<SWEVERY;ph++){ l+=phase_f[ph]; ln+=phase_n[ph]; }
270 R->early = en? e/en : 0; R->late = ln? l/ln : 0;
271}
272
273typedef struct { const char *nm; int env, rd; } Arm;
274
275static void stats(const double *v,int n,double *mu,double *sd){
276 double s=0; for(int i=0;i<n;i++) s+=v[i]; *mu=s/n;
277 double q=0; for(int i=0;i<n;i++){ double d=v[i]-*mu; q+=d*d; }
278 *sd = n>1? sqrt(q/(n-1)) : 0;
279}
280/* paired difference a-b across seeds: mean, standard error, and how many seeds favour a */
281static void paired(const double *a,const double *b,int n,double *mu,double *sem,int *win){
282 double d[NSEED]; *win=0;
283 for(int i=0;i<n;i++){ d[i]=a[i]-b[i]; if(d[i]>0) (*win)++; }
284 double sd; stats(d,n,mu,&sd); *sem = n>1? sd/sqrt((double)n) : 0;
285}
286
287int main(void)
288{
289 Arm arms[7]={
290 {"STATIC faithful",ENV_STATIC, READ_FAITHFUL },
291 {"FRESH faithful",ENV_FRESH, READ_FAITHFUL },
292 {"FRESH scrambled",ENV_FRESH, READ_SCRAMBLED},
293 {"FRESH off",ENV_FRESH, READ_OFF },
294 {"RECUR faithful",ENV_RECUR, READ_FAITHFUL },
295 {"RECUR scrambled",ENV_RECUR, READ_SCRAMBLED},
296 {"RECUR off",ENV_RECUR, READ_OFF }};
297 enum { A_STAT=0, A_FF, A_FS, A_FO, A_RF, A_RS, A_RO };
298
299 static double F[7][NSEED], W[7][NSEED], T[7][NSEED], P[7][NSEED];
300 static double EA[7][NSEED], LA[7][NSEED], RD[7][NSEED], OV[7][NSEED];
301
302 printf("=== fluctuate.c — does memory pay when the world changes? ===\n");
303 printf(" Scored on FUNCTION, not template abundance (the metric that voided threecarrier.c's\n");
304 printf(" fourth attempt). Reading knockout reduced to ONE variable. %d seeds.\n", NSEED);
305 printf(" THE HEADLINE IS FAITHFUL vs SCRAMBLED: reading also converts a template into a catalyst,\n");
306 printf(" which raises nc and so raises growth AND fidelity. Only the scrambled control holds that\n");
307 printf(" constant and isolates the information. genome.c's positive died to this control.\n\n");
308 printf(" %d of %d types needed at a time; environment switches every %d generations;\n", NTARG,NTYPE,SWEVERY);
309 printf(" FRESH redraws at random, RECUR cycles %d fixed sets. Measured over generations %d-%d.\n\n",
310 NENV,BURN,GEN-1);
311
312 for(int k=0;k<7;k++){
313 for(int s=0;s<NSEED;s++){
314 Res R;
315 RNG = 0x9e3779b97f4a7c15ULL ^ (0x100000001b3ULL*(unsigned long long)(s+1));
316 for(int w=0;w<8;w++) xs(); /* warm the stream */
317 run(arms[k].env,arms[k].rd,&R);
318 F[k][s]=R.func; W[k][s]=R.work; T[k][s]=R.tfrac; P[k][s]=R.parfrac;
319 EA[k][s]=R.early; LA[k][s]=R.late; RD[k][s]=R.reads; OV[k][s]=R.overlap;
320 }
321 }
322
323 printf(" arm | function (max %d) | working | reads/c/g | templates | parasites\n",NTARG);
324 printf(" -------------------+-------------------+-----------+-----------+-----------+----------\n");
325 double fmu[7],fsd[7],wmu[7],wsd[7],tmu[7],tsd[7],pmu[7],psd[7],rmu[7],rsd[7];
326 for(int k=0;k<7;k++){
327 stats(F[k],NSEED,&fmu[k],&fsd[k]); stats(W[k],NSEED,&wmu[k],&wsd[k]);
328 stats(T[k],NSEED,&tmu[k],&tsd[k]); stats(P[k],NSEED,&pmu[k],&psd[k]);
329 stats(RD[k],NSEED,&rmu[k],&rsd[k]);
330 printf(" %s | %.3f +- %.3f | %.3f | %.3f | %.3f | %.3f\n",
331 arms[k].nm,fmu[k],fsd[k],wmu[k],rmu[k],tmu[k],pmu[k]);
332 }
333 printf(" (template fraction is REPORTED, and is deliberately NOT a criterion — see header)\n\n");
334
335 /* ---- tests of the test ---- */
336 double omu,osd; stats(OV[A_FF],NSEED,&omu,&osd);
337 double omu2,osd2; stats(OV[A_RF],NSEED,&omu2,&osd2);
338 int g1 = (rmu[A_FF]>0 && rmu[A_FS]>0 && rmu[A_RF]>0 && rmu[A_RS]>0
339 && rmu[A_FO]==0 && rmu[A_RO]==0);
340 int g2 = (tmu[A_FF]>0.002 && tmu[A_RF]>0.002);
341 int g3 = (omu < NTARG - 0.05) && (omu2 < NTARG - 0.05);
342 printf(" G1 reads happen in reading arms, never in OFF arms : %s (%.3f/%.3f on, %.3f/%.3f off)\n",
343 g1?"PASS":"FAIL", rmu[A_FF],rmu[A_RF],rmu[A_FO],rmu[A_RO]);
344 printf(" G2 templates actually exist (else no third carrier): %s (%.4f fresh, %.4f recur)\n",
345 g2?"PASS":"FAIL", tmu[A_FF],tmu[A_RF]);
346 printf(" G3 the environment actually changes : %s (overlap %.2f fresh, %.2f recur, of %d)\n",
347 g3?"PASS":"FAIL", omu,omu2,NTARG);
348
349 double d,se; int win;
350 paired(F[A_FF],F[A_FS],NSEED,&d,&se,&win);
351 double d_p1f=d, se_p1f=se; int w_p1f=win;
352 paired(F[A_RF],F[A_RS],NSEED,&d,&se,&win);
353 double d_p1r=d, se_p1r=se; int w_p1r=win;
354 paired(F[A_FF],F[A_FO],NSEED,&d,&se,&win);
355 double d_p2f=d, se_p2f=se;
356 paired(F[A_RF],F[A_RO],NSEED,&d,&se,&win);
357 double d_p2r=d, se_p2r=se;
358 paired(F[A_STAT],F[A_FF],NSEED,&d,&se,&win);
359 double d_p3=d, se_p3=se;
360
361 int g4 = fabs(d_p1f)>2*se_p1f || fabs(d_p1r)>2*se_p1r || fabs(d_p2f)>2*se_p2f || fabs(d_p3)>2*se_p3;
362 printf(" G4 the arms differ at all : %s\n\n", g4?"PASS":"FAIL");
363
364 if(!(g1&&g2&&g3&&g4)){
365 printf(" => VOID. A test of the test failed, so nothing below is a result. Fix the test, not\n"
366 " the hypothesis.\n");
367 return 0;
368 }
369
370 int p1f = d_p1f > 2*se_p1f;
371 int p1r = d_p1r > 2*se_p1r;
372 printf(" P1 FRESH: faithful beats scrambled : %s %+.3f +- %.3f (%d/%d seeds)\n",
373 p1f?"YES":"no", d_p1f, se_p1f, w_p1f, NSEED);
374 printf(" P1 RECUR: faithful beats scrambled : %s %+.3f +- %.3f (%d/%d seeds)\n",
375 p1r?"YES":"no", d_p1r, se_p1r, w_p1r, NSEED);
376 printf(" P2 reading beats no reading (CONFOUNDED — conversion, not memory):\n");
377 printf(" FRESH %+.3f +- %.3f RECUR %+.3f +- %.3f\n", d_p2f,se_p2f,d_p2r,se_p2r);
378 printf(" P3 fluctuation costs function : %s static-minus-fresh %+.3f +- %.3f\n",
379 (d_p3>2*se_p3)?"YES":"no", d_p3, se_p3);
380 printf(" post-switch -> pre-switch function (where memory should pay if anywhere):\n");
381 {
382 double ea,es,la,ls;
383 stats(EA[A_FF],NSEED,&ea,&es); stats(LA[A_FF],NSEED,&la,&ls);
384 double ea2,es2,la2,ls2;
385 stats(EA[A_FS],NSEED,&ea2,&es2); stats(LA[A_FS],NSEED,&la2,&ls2);
386 double ea3,es3,la3,ls3;
387 stats(EA[A_RF],NSEED,&ea3,&es3); stats(LA[A_RF],NSEED,&la3,&ls3);
388 double ea4,es4,la4,ls4;
389 stats(EA[A_RS],NSEED,&ea4,&es4); stats(LA[A_RS],NSEED,&la4,&ls4);
390 printf(" FRESH faithful %.3f -> %.3f | scrambled %.3f -> %.3f\n", ea,la,ea2,la2);
391 printf(" RECUR faithful %.3f -> %.3f | scrambled %.3f -> %.3f\n", ea3,la3,ea4,la4);
392 }
393 printf("\n");
394
395 if(p1f && p1r)
396 printf(" => THE INFORMATION IS DOING WORK, IN BOTH WORLDS. Faithful reading beats a scrambled\n"
397 " read that converts identically, so it is the type carried by the template and not\n"
398 " the conversion. This is the control genome.c died to, passed.\n");
399 else if(!p1f && p1r)
400 printf(" => MEMORY PAYS ONLY WHEN THE WORLD REPEATS. P4 as pre-registered: a fresh random\n"
401 " redraw gives a stored type the same %.2f odds a dice roll gets, so there is nothing\n"
402 " to be faithful to; a recurring world makes a specific past configuration worth more\n"
403 " than a random one, and faithful reading separates from its control. The condition is\n"
404 " on the ENVIRONMENT, not the chemistry.\n", (double)NTARG/NTYPE);
405 else if(p1f && !p1r)
406 printf(" => BACKWARDS AND UNEXPLAINED. Faithful wins under a random redraw but not under a\n"
407 " repeating world, which inverts the stated prediction. Do not narrate this;\n"
408 " characterize it before claiming anything.\n");
409 else
410 printf(" => HONEST NULL, AND IT IS genome.c's RESULT AGAIN. Faithful reading does not beat a\n"
411 " scrambled read in either world (%+.3f fresh, %+.3f recur), so whatever ON-vs-OFF\n"
412 " gain exists is the CONVERSION of a template into a catalyst, not the information it\n"
413 " carries. threecarrier.c's 0.294 -> 0.478 is therefore not evidence for memory.\n"
414 " Memory still cannot pay under instantaneous selection, and a moving world does not\n"
415 " rescue it.\n", d_p1f, d_p1r);
416 return 0;
417}
basal-agent/fluctuate.md +82 -0
……@@ -0,0 +1,82 @@
1# `fluctuate.c` — does memory pay when the world changes?
2
3The clean re-run of `threecarrier.c`'s fluctuation result, scored on the right variable and
4against the control that killed `genome.c`.
5
6## Where it comes from
7
8`threecarrier.c`'s fourth attempt reported that under a fluctuating target set, turning reading
9ON raised the working fraction 0.294 → 0.478 and function 1.27 → 1.47. Reading its source found
10two faults that made the number unusable:
11
121. **Wrong metric.** The pre-registered M1/M2 scored template *abundance*. Reading consumes a
13 template to make a catalyst, so the reading-OFF arm holds more templates precisely because
14 they are useless there. Abundance measures templates **not being used**. Third time in the
15 session for this mistake; `genome.md` already records it.
162. **The knockout moved two variables.** `threecarrier.c:238-239` made copy-error and reading an
17 `if/else`, so a read child skipped the copy-error branch — "reading off" also raised template
18 mutation load.
19
20## What changed, and nothing else
21
22Chemistry, sizes, rates, seeding and between-compartment selection are identical, so the numbers
23stay comparable. Copy error now applies to every template replication independent of reading;
24scoring is on function and working fraction time-averaged over the second half; 24 seeds instead
25of 5; and the headline comparison is **FAITHFUL vs SCRAMBLED**, not ON vs OFF — because reading
26also converts a template into a catalyst, which raises `nc`, which raises both growth and
27fidelity. Only the scrambled control holds that constant and isolates the information.
28
29Run twice: **FRESH** (targets redrawn at random each switch, threecarrier's condition) and
30**RECUR** (cycled among 3 fixed sets, so a type not needed now *is* needed again).
31
32## Result
33
34| arm | function (max 4) | working | reads/c/g | templates | parasites |
35|---|---|---|---|---|---|
36| STATIC faithful | 2.375 ± 0.028 | 0.934 | 0.020 | 0.007 | 0.014 |
37| FRESH faithful | 1.455 ± 0.071 | 0.461 | 0.032 | 0.020 | 0.020 |
38| FRESH **scrambled** | **1.629** ± 0.045 | 0.566 | 0.066 | 0.047 | 0.016 |
39| FRESH off | 1.390 ± 0.074 | 0.404 | 0.000 | 0.012 | 0.019 |
40| RECUR faithful | 1.616 ± 0.183 | 0.577 | 0.029 | 0.015 | 0.018 |
41| RECUR **scrambled** | **1.684** ± 0.132 | 0.612 | 0.051 | 0.035 | 0.016 |
42| RECUR off | 1.603 ± 0.192 | 0.565 | 0.000 | 0.009 | 0.018 |
43
44All four tests of the test **PASS** — reads happen only in reading arms, templates exist, the
45environment actually changes (overlap 1.02/1.07 of 4), the arms differ.
46
47| pre-registered | | |
48|---|---|---|
49| P1 FRESH faithful > scrambled | **no** | −0.174 ± 0.019 (1/24 seeds) |
50| P1 RECUR faithful > scrambled | **no** | −0.069 ± 0.017 (5/24 seeds) |
51| P2 reading > no reading (confounded) | — | +0.065 ± 0.017 FRESH, +0.012 ± 0.008 RECUR |
52| P3 fluctuation costs function | **yes** | +0.921 ± 0.017 |
53
54## Reading
55
56**`genome.c`'s result again.** Faithful reading does not beat a scrambled read in either world,
57so whatever ON-vs-OFF gain exists is the **conversion** of a template into a catalyst, not the
58information the template carries. `threecarrier.c`'s 0.294 → 0.478 is therefore **not evidence
59for memory**. A moving world does not rescue it, and P4 — memory pays where the world repeats —
60is not supported either: RECUR is null too.
61
62**It is stronger than a null.** Faithful is significantly *worse* than scrambled in both worlds,
63favoured by 1/24 and 5/24 seeds. Scrambled also does roughly twice the reads (0.066 vs 0.032/c/g)
64and carries ~2× the templates. That points at the diversity effect `genome.md` named: a random
65type is more often a type the compartment lacks.
66
67## What it is not, and the gap
68
69This does not show memory is impossible — it shows it cannot pay **under instantaneous
70selection**, which is the fifth 1→2 constraint stated more strongly than the 2026-07-31
71post-mortem could state it. Between-compartment selection scores current function every
72generation and was deliberately left in place; removing it answers a different question.
73
74**The measurement that would settle the scrambled win was computed and discarded.** `run()` fills
75`R->redund` and `R->gapfill` — the fraction of reads that reproduce a type already present versus
76supply a missing target — exactly the numbers designed to test the diversity explanation. `main()`
77never stores or prints them. That is the first thing to fix before drawing the mechanism.
78
79---
80
81*Written 2026-08-01, interrupted by a power loss ~45 min later and left unrun (the binary on disk
82predated the last edit). Compiled clean and run 2026-08-04; 20 s, 24 seeds, 7 arms.*