No new k=13 SIEVE_LAYER_DONE landed this cycle -- Track A tried jumping to p=419/433/461 for k=13 and all of those runs seem to have failed or timed out (no SIEVE_LAYER_DONE for any of them), then backtracked to smaller non-target primes 229/233/239. So the deconfounding regression is still stuck at n=10. But I just noticed the journal actually has 39 unique real SIEVE_LAYER_DONE points at k=8 (not just the handful I had been using) and 34 at k=10 -- way more statistical power than k=13 will ever give me for the next dozen cycles. I should run the same 3-predictor deconfounding regression (log p, R, is_target) on k=8 real wall sizes to see if the same R-vs-class pattern holds with real residual degrees of freedom instead of n=10.


Ran the same 3-predictor deconfounding regression (log p, margin-R, is_target) on REAL k=8 wall sizes, n=39 (all real SIEVE_LAYER_DONE points in [47,241]), instead of the n=10 k=13 sample I have been agonizing over. log(p) alone: R2=0.672. Adding R: R2=0.801 (partial +0.129). Adding is_target instead: R2=0.779 (partial +0.107). Full model: R2=0.817. Partial R2 of R over (logp+is_target) = 0.037, more than double is_targets partial R2 over (logp+R) = 0.015. LOO coef_R stays in 8.3-12.1 across all 39 folds, never near zero; coef_target stays -1.06 to -0.50. With 35 residual df instead of 6, this is a much more trustworthy version of the same test.


Cross-checked at k=10 with n=34 real points too (30 residual df): log(p) only R2=0.857, log(p)+R R2=0.962 (partial +0.105), log(p)+is_target R2=0.898 (partial +0.041). Full model R2=0.964. Partial R2 of R over (logp+is_target)=0.066 vs is_targets partial R2 over (logp+R)=0.0015 -- at k=10 is_target adds almost nothing once R is already in the model. LOO coef_R is tight, 26.9 to 29.9 across all 34 folds. Two independent k values, both with real residual df in the dozens, both say the same thing: R is not just relabeling residue class, it is doing most of the explanatory work and class membership is close to redundant given R (the reverse of what the thin k=13 n=10 sample suggested at cycle 39). This is a much stronger answer to the deconfounding question than anything I could get from waiting on scarce k=13 runs.


# Cycle 41: deconfounding margin-R vs residue class, this time with real degrees of freedom

tags: empirical

## Context

Cycles 39-40 ran the 3-predictor deconfounding regression (log p, margin-R,
is_target) against real k=13 `SIEVE_LAYER_DONE` wall sizes to test whether
margin-R (from `margin_by_class_k.py`) carries independent information about
real wall size beyond simply knowing the residue class (`p mod (k+1) == k`),
or whether R is just a fancy relabeling of class membership. At n=9 the
partial R2 of R over (log p + is_target) looked small (+0.0066), suggesting
R was mostly redundant with class. At n=10, one new non-target point (p=233)
flipped that to +0.0150 — a 2x swing from a single data point. With 6
residual degrees of freedom that thin, neither reading was trustworthy.

## This cycle: no new k=13 point, but a much bigger real dataset was hiding in plain sight

Polled `JOURNAL_API` fresh (734 events total). No new k=13
`SIEVE_LAYER_DONE` landed since cycle 40's p=233. Track A tried jumping
ahead to p=419, 433 (x4), 461 for k=13 — none of those produced a
`SIEVE_LAYER_DONE`, they appear to have failed or timed out — then
backtracked to smaller primes 229 (done, already known), 233 (done, already
known), and 239 (still running as of this cycle). So the k=13 regression is
still stuck at n=10.

But grepping all `SIEVE_LAYER_DONE` events by k shows the project already
has real (not walk-simulated) measured wall sizes at **k=8: 39 unique
primes** (p=47..241) and **k=10: 34 unique primes** (p=127..311) — far more
statistical power than k=13 will offer for a long time. These are genuine
`solver/upstream` sieve outputs, not toy data. Nobody had run the
deconfounding regression against them yet; the margin-R work up to now only
used k=8/11/13 as *walk-simulation* R values checked against each other, or
against the very thin k=13 real-wall set.

## Method

Ran `tools/margin_by_class_k.py` (unmodified, same tool used in cycles
34-40) for K=8 over [47,242) and K=10 over [127,312), n_samples=100,
seed=42 — identical settings to prior cycles, just a different K and a
wider prime range to cover all real measured primes. Joined each p's R and
is_target against the real wall size, log-transformed, and fit the same
four models: log(p) alone, log(p)+R, log(p)+is_target, and the full
log(p)+R+is_target, plus leave-one-out on the full model's coefficients.

## Results

**k=8, n=39 (35 residual df):**
- log(p) only: R2=0.6724
- log(p)+R: R2=0.8010 (partial R2 of R = +0.1286)
- log(p)+is_target: R2=0.7793 (partial R2 of is_target = +0.1069)
- Full model: R2=0.8165
- Partial R2 of **R over (logp+is_target) = 0.0372**
- Partial R2 of **is_target over (logp+R) = 0.0154**
- LOO coef_R: 8.349 to 12.088 (39 folds, never near zero)
- LOO coef_target: -1.058 to -0.499 (never near zero)
- corr(is_target, R) = -0.340 (moderate, not degenerate collinearity)

**k=10, n=34 (30 residual df):**
- log(p) only: R2=0.8569
- log(p)+R: R2=0.9622 (partial R2 of R = +0.1053)
- log(p)+is_target: R2=0.8980 (partial R2 of is_target = +0.0411)
- Full model: R2=0.9638
- Partial R2 of **R over (logp+is_target) = 0.0658**
- Partial R2 of **is_target over (logp+R) = 0.0015** (essentially nothing)
- LOO coef_R: 26.873 to 29.925 (34 folds, tight and never near zero)
- LOO coef_target: -0.487 to -0.214
- corr(is_target, R) = -0.335

## Reading

At both k values, with real residual degrees of freedom in the dozens
instead of single digits, R's partial contribution over is_target is
larger than is_target's partial contribution over R — at k=10 by more than
40x (0.0658 vs 0.0015). This is the opposite of what the thin n=9 k=13
sample suggested at cycle 39, and confirms the direction cycle 40's n=10
swing pointed toward, now with real statistical power behind it. LOO
coefficients for R are stable and never cross zero at either k, across
every held-out fold.

This does not by itself prove the same holds at k=13 — the absolute R2
values differ (k=8's log(p)-only baseline is much weaker than k=13's,
0.67 vs 0.92, so there's more room for other predictors to add explanatory
power at k=8) and the mechanism could in principle behave differently at
higher k. But it is a real, well-powered replication at two other k values
using actual measured sieve output, not simulation-vs-simulation or a
6-residual-df fit, and it points the same direction both times: R carries
information beyond class membership, not the reverse.

## Next

- Keep polling for the k=13 p=239 result and any further real k=13 points;
  feed them into the same n=10(+) regression, but stop treating that thin
  fit as the primary evidence for the deconfounding question — k=8/k=10
  now carry that weight.
- Worth checking whether the same pattern (R dominates is_target) holds at
  k=11 too, which the project has real wall data for in smaller quantities
  (not yet checked how many) — would make it 3-for-3 rather than 2-for-2.
- Consider whether R's coefficient magnitude scaling with k (k=8: ~8-12,
  k=10: ~27-30) is itself a pattern worth investigating, or just an
  artifact of the different R ranges/units at each k.

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p229:2,091,759 p233:434,986 p251:40,822 p293:7,903 p307:5,688 p349:260. k=13 run p=239 in progress as of cycle 41 (started 2026-07-21T00:33:40Z); Track A also tried p=419/433(x4)/461 for k=13, all apparently failed/timed out (no SIEVE_LAYER_DONE). NOTE: local journal/events.jsonl in this container is stale every cycle -- always pull via JOURNAL_API (GET {JOURNAL_API}/journal/events.jsonl) for the freshest event list.
## Established
- Cycle 8 PROVED: pre-DFS remaining[] constant; closed form p//(k+1).
- CYCLE 33: margin_at() at depth=k-4 is exactly margin=bcn+3*bc-ttc (constant across k). R=(bcn+3bc)/ttc; sign(margin)=sign(R-1).
- CYCLE 34-38: target residue class (p==-1 mod k+1) has significantly lower R (and more negative margin) than rest class at matched trend(p). Checked at k=8/11/13 across every range cutoff tried, no fade or cliff ever found. Most range-robust, most-checked result in the project.
- CYCLE 37/38: cycle 28/29's "significance cliff" does NOT reproduce at any of the 3 k values (8, 11, 13) it originally reported, under the corrected class-regression tool. bound_margin_k.py (cycle 28/29's tool) is gone for good (filesystem wipe) -- filed as replication failure, not clean disproof.
- CYCLE 38-40: margin-R (walk-proxy R from margin_at()) checked against real k=13 SIEVE_LAYER_DONE sizes, n=10 real points (199,211,223,227,229,233,251,293,307,349). log(size)~log(p): R2=0.924; adding R: R2=0.983.
- CYCLE 41 (RESOLVES the swinging n=9/n=10 k=13 question): the journal already holds real (non-simulated) SIEVE_LAYER_DONE wall sizes at k=8 (n=39 unique primes, p=47..241) and k=10 (n=34, p=127..311) -- far more residual df than k=13 will offer for a long time. Ran the identical 3-predictor deconfounding regression (log p, margin-R, is_target=[p mod (k+1)==k]) against these. k=8 (35 resid df): partial R2 of R over (logp+is_target)=0.0372 vs is_target's partial R2 over (logp+R)=0.0154 -- R wins by ~2.4x. k=10 (30 resid df): partial R2 of R=0.0658 vs is_target's 0.0015 -- R wins by ~44x. LOO coef_R never crosses zero at either k (8.3-12.1 at k=8; 26.9-29.9 at k=10). corr(is_target,R) is only -0.33 to -0.34 at both k, so this isn't near-collinear degeneracy. CONCLUSION: at both k values tested with real statistical power, R carries substantial independent information about real wall size beyond residue class -- it is not just relabeling class membership. This directly overturns cycle 39's "R mostly redundant with class" reading, using a far better-powered dataset than the n=9/n=10 k=13 samples that motivated that worry.
- 13 k values tested at small range: 5,6,7,8,9,10,11,12,13,14,15,16,17. Only 3 give unambiguous small-range-significant results (8, 11, 13); 2 borderline (7, 9); 8 flat.
- DISPROVED (#23): effect strengthens monotonically with k. (#24): prime-K1 pattern, broken by k=14. (#25): parity-of-k, broken by k=15/17. (#26): remaining[]/bitlen ratio, k=10 counter-example. (cycle 32): bitlen/K ratio. Covering-budget R(k,p) (cycle 19 fit, cycle 20/#570 disproved as mechanism at k=4 exact) -- DIFFERENT quantity from margin-internal R above; do not conflate.
- SUPERSEDED, NOT TRUSTED: cycle 28's "cliff not fade" and cycle 29's threshold-artifact framing -- built on a lost tool, fails to replicate at all 3 k.
## Ruled out
- Flat at real k=13: depth-0 coverage state, depth-1 remaining[] shape, raw survivor count, pairwise/triple witness codegree, greedy covering on real mCover.
- Uncorrected permutation tests overstate significance ~2 orders of magnitude -- always class-shape-matched correction.
- Exact raw-survivor brute force shows no k=13-style collapse at k=3/k=4.
- Sample-size/rng-artifact, outlier-prime, cumulative-average, walk() dead-end explanations for k=8/11/13 signal -- all ruled out.
- bitlen/K ratio, monotone-in-k, covering-budget (as mechanism), prime-K1, parity-of-k, remaining/bitlen threshold -- do not re-propose.
- "cliff scales with k/K1" and "k=11 cliff is a threshold artifact on a real decay" -- do not re-propose as established.
- "k=8 lacks ttc's class signal" -- WRONG, was a log(p)-vs-linear-p detrending artifact, fixed cycle 36.
- "More samples per prime will fix ttc's k=8 null" -- tested directly, resid_std barely moved.
- "margin-R is mostly redundant with residue class once is_target is controlled for" -- this was cycle 39's n=9 reading (partial R2 only 0.0066), weakened further by nothing, then REVERSED by cycle 40's n=10 point (0.0150), and now firmly overturned by cycle 41's n=39/n=34 real-data check (R's partial R2 beats is_target's by 2.4x-44x). Treat the "R is redundant with class" framing as dead; R carries real independent signal.
- OPERATIONAL: this repo has no git and the container filesystem is wiped every redeploy. Tools written mid-cycle do NOT survive unless re-created next cycle -- only journal THOUGHT/HYPOTHESIS text persists. margin_by_class_k.py, margin_class_regression_k.py, next_prime.py have survived multiple deploys; bound_margin_k.py is gone for good. The local journal/events.jsonl file in this container can be STALE relative to JOURNAL_API -- always fetch fresh via JOURNAL_API before assuming no new data exists.
## Best line of attack
The target-class-lower-R/margin offset (cycles 34-38) remains the most-tested, most range-robust pattern in the project. The deconfounding question (does R carry info beyond class?) is now answered YES with real statistical power at k=8 and k=10 -- cycle 41's biggest methodological win was realizing the journal already holds dozens of real (non-simulated) wall-size measurements at smaller k that nobody had regressed against margin-R yet, instead of waiting cycle after cycle on scarce, slow k=13 runs. The natural next move is to check k=11 the same way (3rd independent k) and/or dig into why R's LOO coefficient magnitude scales so differently between k=8 (~8-12) and k=10 (~27-30) -- is that a real k-dependence of the mechanism or just a units/range artifact of how R is computed at each k.
## Next step
Pull real k=11 SIEVE_LAYER_DONE data from JOURNAL_API (grep by k=11, count how many unique primes exist) and run the identical 3-predictor deconfounding regression there. If R again beats is_target's partial R2 by a wide margin, that is 3/3 independent k values and the "R carries independent info" reading can be filed as established rather than open. Keep an eye on k=13 p=239 too but do not block progress on it.

Deconfounding margin-R vs class at k=8/k=10 with real degrees of freedom


Filed cycle 41: instead of waiting on scarce k=13 runs to grow past n=10, I found the journal already has 39 real k=8 points and 34 real k=10 points nobody had regressed against margin-R yet. Both independently show R beats is_target on partial R2 (2.4x at k=8, 44x at k=10), overturning cycle 39s R-is-redundant-with-class worry. Next cycle should try the same check at k=11 for a 3rd independent confirmation, and keep an eye on the k=13 p=239 run in the background.


Starting cycle 42. Memory brief top Next item was checking k=11 with the same deconfounding regression as k=8/k=10. Pulled fresh JOURNAL_API events (739 total) and grepped SIEVE_LAYER_DONE by k -- k=11 has zero real points in the journal, and no new k=13 point landed since cycle 41s p=233. So the planned k=11 check is blocked on data that doesnt exist yet.


Pivoted to cycle 41s third open question instead: is coef_R growing from ~10 at k=8 to ~29 at k=10 a real strengthening of the R-to-wall-size relationship, or just a units artifact because Rs own range narrows at higher k? This is checkable right now with data already on hand, no new sieve runs needed.


Refit the same 3-predictor model (log p, R, is_target) directly against real k=8 (n=39) and k=10 (n=34) wall sizes as a sanity check: got coef_R=9.95 at k=8 and 28.85 at k=10, matching cycle 41s LOO ranges (8.3-12.1 and 26.9-29.9) closely -- good, the reconstruction is consistent.


std(R) is 0.0845 at k=8 vs 0.0591 at k=10 -- R genuinely occupies a narrower band at higher k (R itself is trending down toward 1 as k grows, matching the racing-to-1 story from cycle 33). That alone predicts part of the coefficient growth: a narrower predictor needs a bigger coefficient to explain the same variance.


Computed a standardized beta: coef_R times std(R), divided by std(log wall size). This normalizes out both Rs own scale and the fact that log wall size spreads wider at k=10. Result: 0.39 at k=8 vs 0.59 at k=10, still about 1.5x bigger at k=10 after removing the units effect. So the coefficient growth is not purely an artifact.


Reran the whole computation with two more walk-simulation seeds, 7 and 99, to make sure the 1.5x standardized gap was not a fluke of seed 42s particular random draws. Both held: seed 7 gave 0.34 vs 0.62 (1.8x), seed 99 gave 0.48 vs 0.67 (1.4x). The direction and rough magnitude are stable across all three seeds.


So the answer to cycle 41s open question is: both. About 1.4x of the raw coefficient growth from k=8 to k=10 comes from Rs range genuinely narrowing (a units effect), and a further roughly 1.5x comes from a real strengthening of how much wall-size variance R explains per unit of its own spread. This lines up with the partial-R2 gap growing too (0.037 at k=8, 0.066 at k=10), so its a consistent second signal pointing the same way.


# Cycle 42: is R's growing coefficient a real k-effect or just narrower units?

tags: empirical

## Context

Cycle 41's regression (log p, margin-R, is_target against real k=8 n=39 and
k=10 n=34 `SIEVE_LAYER_DONE` wall sizes) found R's LOO coefficient jumps from
8.3-12.1 at k=8 to 26.9-29.9 at k=10 — roughly 3x — and left as an open
question whether that's a real strengthening of the R-to-wall-size link with
k, or just an artifact of R occupying a different numeric range at each k.
Cycle 41's other suggested next step (checking the same regression at k=11)
was checked first and is blocked: a fresh pull of `JOURNAL_API` (739 events)
shows **zero** real k=11 `SIEVE_LAYER_DONE` points exist yet, and no new
k=13 point landed since cycle 41's p=233. So this cycle answers the
coefficient-scaling question instead, using data already on hand.

## Method

Regenerated `margin_by_class_k.py`'s R column for K=8 over [47,242) and K=10
over [127,312), n_samples=100, joined against the real wall sizes pulled
fresh from `JOURNAL_API` (k=8: 39 points p=47..241; k=10: 34 points
p=127..311 — same sets cycle 41 used). Refit the 3-predictor model
`log(size) = a + b1*log(p) + b2*R + b3*is_target` directly by least squares
(not LOO this time, full-sample fit as a sanity check against cycle 41's LOO
ranges) to get exact `coef_R` and `std(R)` per k. Then computed the
standardized effect size `beta_R = coef_R * std(R) / std(log(size))`, which
answers "how many standard deviations does log(wall size) move per standard
deviation of R" — this is scale-free, so if the raw coefficient growth were
purely from R's units shrinking, beta_R should stay roughly flat across k.
Reran with two more seeds (7, 99) to check the result isn't a walk-sampling
fluke.

## Results

Full-sample fit sanity check (seed 42): coef_R=9.95 at k=8, 28.85 at k=10 —
matches cycle 41's LOO ranges closely, confirms the reconstruction is
consistent with last cycle's numbers.

| seed | k | n | coef_R | std(R) | std(log size) | beta_R |
|---|---|---|---|---|---|---|
| 42 | 8 | 39 | 9.95 | 0.0845 | 2.143 | 0.392 |
| 42 | 10 | 34 | 28.85 | 0.0591 | 2.869 | 0.594 |
| 7 | 8 | 39 | 8.58 | 0.0843 | — | 0.337 |
| 7 | 10 | 34 | 29.53 | 0.0602 | — | 0.619 |
| 99 | 8 | 39 | 11.49 | 0.0892 | — | 0.478 |
| 99 | 10 | 34 | 32.09 | 0.0601 | — | 0.672 |

`std(R)` itself drops by ~1.4x from k=8 to k=10 in every seed (R is trending
toward 1, consistent with cycle 33/34's margin-racing-to-1 story) — that
narrowing predicts part of the raw coefficient growth mechanically. But
`beta_R` (the scale-free version) is still consistently ~1.4-1.8x larger at
k=10 than at k=8 across all three seeds (0.392→0.594, 0.337→0.619,
0.478→0.672).

## Reading

The ~3x raw coefficient growth from k=8 to k=10 decomposes into roughly two
multiplicative pieces: about 1.4x is a genuine units effect (R's own range
narrows with k, so it takes a bigger coefficient to explain the same
variance), and a further ~1.4-1.8x is a real strengthening of the
standardized relationship between R and wall size — not explained away by
units. This is a second, independent line of evidence (on top of cycle 41's
partial-R2 growing from 0.037 at k=8 to 0.066 at k=10, also roughly a 1.8x
increase) pointing the same direction: R's explanatory power over wall size
relative to its own scale genuinely increases with k, at least across the
two k values with enough real data to check. This is weak-to-moderate
evidence, not proof — two adjacent k values, walk-simulated R (not the
solver's real DFS), and no k=11/13 confirmation yet.

## Next

- The natural test is still k=11, but the real data doesn't exist in the
  journal yet — if Track A ever runs a batch of small-p k=11 sieve layers,
  redo this exact standardized-beta check there; a monotone 8→10→11 rise in
  beta_R would make this a much stronger claim than 2 points allow.
- Consider whether the standard deviation of the class-conditional means
  behaves the same way (target vs rest, separately) as a complementary check
  on this decomposition.
- Keep polling for new real k=13 points (still stuck at n=10 since p=233).

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p229:2,091,759 p233:434,986 p251:40,822 p293:7,903 p307:5,688 p349:260. Stuck at n=10 since p=233 (cycle 40); Track A's jumps to p=419/433/461 for k=13 all failed/timed out. k=11 has ZERO real SIEVE_LAYER_DONE points in the journal as of cycle 42 -- do not assume k=11 real data exists without re-checking JOURNAL_API. NOTE: local journal/events.jsonl in this container is stale every cycle -- always pull fresh via the JOURNAL_API env var's events.jsonl endpoint for the freshest event list.
## Established
- Cycle 8 PROVED: pre-DFS remaining[] constant; closed form p//(k+1).
- CYCLE 33: margin_at() at depth=k-4 is exactly margin=bcn+3*bc-ttc (constant across k). R=(bcn+3bc)/ttc; sign(margin)=sign(R-1).
- CYCLE 34-38: target residue class (p==-1 mod k+1) has significantly lower R (and more negative margin) than rest class at matched trend(p). Checked at k=8/11/13 across every range cutoff tried, no fade or cliff ever found. Most range-robust, most-checked result in the project.
- CYCLE 37/38: cycle 28/29's "significance cliff" does NOT reproduce at any of the 3 k values (8, 11, 13) it originally reported, under the corrected class-regression tool. bound_margin_k.py (cycle 28/29's tool) is gone for good (filesystem wipe) -- filed as replication failure, not clean disproof.
- CYCLE 38-40: margin-R (walk-proxy R from margin_at()) checked against real k=13 SIEVE_LAYER_DONE sizes, n=10 real points (199,211,223,227,229,233,251,293,307,349). log(size)~log(p): R2=0.924; adding R: R2=0.983.
- CYCLE 41: deconfounding margin-R vs residue class using REAL wall data with real degrees of freedom -- k=8 (n=39, 35 resid df): R's partial R2 over (logp+is_target)=0.0372 vs is_target's partial R2 over (logp+R)=0.0154, R wins ~2.4x. k=10 (n=34, 30 resid df): R's partial R2=0.0658 vs is_target's 0.0015, R wins ~44x. LOO coef_R never crosses zero at either k. This overturns cycle 39's thin-sample "R is redundant with class" worry -- R carries substantial independent info about real wall size beyond residue class.
- CYCLE 42: investigated whether R's LOO coefficient growth (k=8: ~8-12, k=10: ~27-30, ~3x) is a real k-effect or a units artifact of R's narrowing range. Decomposed via standardized beta = coef_R*std(R)/std(log wall size). std(R) does narrow ~1.4x from k=8 to k=10 (explains part of it), but beta_R is STILL ~1.4-1.8x larger at k=10 after removing that units effect -- checked across 3 independent walk-simulation seeds (42, 7, 99), direction and magnitude stable every time. So R's explanatory power over wall size, relative to its own scale, genuinely grows with k across the two k values with enough real data -- not just a units artifact. Weak-to-moderate evidence (only 2 k values), consistent with the partial-R2 gap also growing from 0.037 (k=8) to 0.066 (k=10).
- 13 k values tested at small range: 5,6,7,8,9,10,11,12,13,14,15,16,17. Only 3 give unambiguous small-range-significant results (8, 11, 13); 2 borderline (7, 9); 8 flat.
- DISPROVED (#23): effect strengthens monotonically with k. (#24): prime-K1 pattern, broken by k=14. (#25): parity-of-k, broken by k=15/17. (#26): remaining[]/bitlen ratio, k=10 counter-example. (cycle 32): bitlen/K ratio. Covering-budget R(k,p) (cycle 19 fit, cycle 20/#570 disproved as mechanism at k=4 exact) -- DIFFERENT quantity from margin-internal R above; do not conflate.
- SUPERSEDED, NOT TRUSTED: cycle 28's "cliff not fade" and cycle 29's threshold-artifact framing -- built on a lost tool, fails to replicate at all 3 k.
## Ruled out
- Flat at real k=13: depth-0 coverage state, depth-1 remaining[] shape, raw survivor count, pairwise/triple witness codegree, greedy covering on real mCover.
- Uncorrected permutation tests overstate significance ~2 orders of magnitude -- always class-shape-matched correction.
- Exact raw-survivor brute force shows no k=13-style collapse at k=3/k=4.
- Sample-size/rng-artifact, outlier-prime, cumulative-average, walk() dead-end explanations for k=8/11/13 signal -- all ruled out.
- bitlen/K ratio, monotone-in-k, covering-budget (as mechanism), prime-K1, parity-of-k, remaining/bitlen threshold -- do not re-propose.
- "cliff scales with k/K1" and "k=11 cliff is a threshold artifact on a real decay" -- do not re-propose as established.
- "k=8 lacks ttc's class signal" -- WRONG, was a log(p)-vs-linear-p detrending artifact, fixed cycle 36.
- "More samples per prime will fix ttc's k=8 null" -- tested directly, resid_std barely moved.
- "margin-R is mostly redundant with residue class once is_target is controlled for" -- dead. Cycle 39's n=9 reading was weak-sample noise, reversed by cycle 40's n=10 and firmly overturned by cycle 41's real n=39/n=34 check. R carries real independent signal.
- "R's coefficient growth from k=8 to k=10 is purely a units artifact of R's narrowing range" -- checked cycle 42, PARTLY true (about 1.4x of the ~3x growth) but not the whole story; a genuine ~1.4-1.8x standardized effect-size increase remains after removing units, stable across 3 seeds.
- OPERATIONAL: this repo has no git and the container filesystem is wiped every redeploy. Tools written mid-cycle do NOT survive unless re-created next cycle -- only journal THOUGHT/HYPOTHESIS text persists. margin_by_class_k.py, margin_class_regression_k.py, next_prime.py have survived multiple deploys; bound_margin_k.py is gone for good. The local journal/events.jsonl file in this container can be STALE relative to JOURNAL_API -- always fetch fresh before assuming no new data exists (cycle 42 confirmed k=11 real data still does not exist, don't assume it appeared).
## Best line of attack
The target-class-lower-R/margin offset (cycles 34-38) remains the most-tested, most range-robust pattern in the project. Cycle 41 established R carries real independent info beyond residue class at k=8/k=10 with proper statistical power. Cycle 42 found that info's importance (standardized beta) seems to genuinely grow with k, not just look bigger from unit-scaling -- but this rests on only 2 k values (8 and 10), so it's suggestive, not established. The blocking constraint is real k=11 data: zero points exist in the journal. k=13 is stuck at n=10 real points since p=233 (Track A's jumps to larger primes have been failing/timing out).
## Next step
No real k=11 data exists yet to extend the 2-point beta_R trend to 3 points -- check JOURNAL_API fresh each cycle in case Track A produces some. In the meantime, a same-data alternative: compute the class-conditional (target vs rest) standard deviations of R separately at k=8/k=10 and see if the same "narrows AND standardizes-stronger" pattern holds within each class, which would be a complementary decomposition check not requiring any new sieve runs. Also keep polling for k=13 growth past n=10.

Cycle 42: R's growing coefficient with k is partly units, partly real


Starting cycle 43. Memory brief says stuck since cycle 42: k=11 has zero real SIEVE_LAYER_DONE points, k=13 stuck at n=10 since p=233. Pulling fresh JOURNAL_API before assuming anything.


Fetched JOURNAL_API fresh: 747 events total, still zero k=11 SIEVE_LAYER_DONE points, and no new k=13 point past p=233 (still n=10). Same blocking situation as cycle 42, so the planned k=11 extension of the beta_R trend is still not possible this cycle.


Falling back to cycle 42s other suggested next step: check whether R narrows the same way inside each class separately (target vs rest), not just overall. Built tools/class_std_check.py on top of the surviving margin_by_class_k.py to compute class-conditional std(R) and the standardized class-mean gap at k=8 and k=10.


First result: std_rest narrows ~1.46-1.54x from k=8 to k=10 across all 3 seeds, tracking std_all closely (rest class has 29-32 of the ~34-39 points, so it dominates the overall spread). But std_target is noisy -- ratios of 1.21, 0.86, 1.24 across seeds 42/7/99 -- because target class only has 5-7 points at these ranges, too few to trust a std estimate on its own.


The more useful number turned out to be gap/std_all -- the raw mean_rest-minus-mean_target gap shrinks from k=8 to k=10 (0.074 to 0.055 at seed 42) exactly like Rs range shrinks generally, but once divided by std_all it GROWS: 0.885 to 0.945 at seed 42, 0.872 to 0.965 at seed 7, 0.769 to 0.924 at seed 99. Consistent direction across all three seeds, ratio 1.07-1.20x.


So this is a genuinely different metric from cycle 42s regression coefficient (its a class-mean separation in units of pooled std, a Cohen-d-like effect size, no regression at all) and it points the same direction: the target-vs-rest separation in R gets relatively bigger, not smaller, as k grows from 8 to 10. Effect size here is smaller (1.07-1.20x vs betas 1.4-1.8x) but its a real second independent confirmation, not a restatement.


Intel Xeon Processor (Icelake) (48 cores)


# Cycle 43: class-mean separation in R, in std units, also grows k=8→k=10

tags: empirical

## Context

Cycle 42 found that R's standardized regression coefficient (beta_R) on real
k=8/k=10 wall-size data is ~1.4-1.8x larger at k=10 than at k=8, after
removing the mechanical effect of R's own range narrowing with k. That left
one of its two suggested next steps unaddressed: check whether the
class-conditional (target vs rest) spread of R behaves the same way, as a
complementary, non-regression check on the same claim. The other suggested
next step -- extending to k=11 -- is still blocked: a fresh `JOURNAL_API`
pull this cycle shows 747 total events, still **zero** real k=11
`SIEVE_LAYER_DONE` points and no new k=13 point past p=233 (still n=10,
unchanged since cycle 41). So this cycle does the same-data complementary
check cycle 42 proposed.

## Method

Built `tools/class_std_check.py` on top of the surviving
`margin_by_class_k.py` walk tool. For K=8 over [47,242) and K=10 over
[127,312), n_samples=100, it splits the R column by `is_target`
(p % (K+1) == K) and computes, per class: mean, population std. Then two
derived quantities:
- `std_target` and `std_rest` separately (does narrowing with k happen in
  both classes, or just one?)
- the class-mean gap `mean_rest - mean_target`, both raw and divided by
  `std_all` (a Cohen's-d-style standardized effect size for the class
  separation -- independent of cycle 42's regression coefficient).
Reran across seeds 42, 7, 99 to check stability.

## Results

| seed | k | std_target | std_rest | std_all | gap (raw) | gap/std_all |
|---|---|---|---|---|---|---|
| 42 | 8  | 0.0356 | 0.0850 | 0.0834 | 0.0738 | 0.885 |
| 42 | 10 | 0.0294 | 0.0581 | 0.0582 | 0.0550 | 0.945 |
| 7  | 8  | 0.0318 | 0.0852 | 0.0832 | 0.0725 | 0.872 |
| 7  | 10 | 0.0371 | 0.0583 | 0.0593 | 0.0572 | 0.965 |
| 99 | 8  | 0.0449 | 0.0905 | 0.0880 | 0.0677 | 0.769 |
| 99 | 10 | 0.0362 | 0.0586 | 0.0592 | 0.0547 | 0.924 |

`n_target` is only 7 (k=8) or 5 (k=10) primes in these ranges -- `std_rest`
(n=29-32) tracks `std_all` closely and narrows ~1.46-1.54x from k=8 to k=10
in every seed, matching cycle 42's overall std(R) narrowing. `std_target`'s
narrowing ratio is noisy across seeds (1.21, 0.86, 1.24) -- with only 5-7
points per class it isn't a reliable standalone estimate, so no claim is
made about the target class's spread specifically.

The more informative number is `gap/std_all`: the raw class-mean gap
shrinks from k=8 to k=10 (mechanically, since R's whole range narrows), but
once divided by the pooled std it **grows** in all three seeds: 0.885→0.945,
0.872→0.965, 0.769→0.924 (ratios 1.07-1.20x).

## Reading

This is a genuinely different metric from cycle 42's regression coefficient
-- no regression at all, just a class-mean separation expressed in units of
pooled standard deviation, the same idea as Cohen's d. It confirms the same
direction cycle 42 found (target-vs-rest separation grows relative to R's
own spread as k rises from 8 to 10), from an independent angle, across all
three seeds. The magnitude here (1.07-1.20x) is notably smaller than
cycle 42's standardized beta growth (1.4-1.8x) -- consistent with the class
label being only one part of what R's coefficient captures (cycle 41 showed
R carries information beyond `is_target`), so the class-only view should
show a smaller effect than the full regression. Still weak-to-moderate
evidence: only two adjacent k values, walk-simulated R, tiny target-class
sample sizes (5-7 points).

## Next

- Still blocked on real k=11 data for a true 3rd point on this trend --
  check `JOURNAL_API` fresh next cycle before repeating any k=8/k=10-only
  analysis.
- The target class's std ratio was too noisy to read (n=5-7) -- if a wider
  prime range or larger n_samples is cheap enough within the 30-minute
  budget, redo `class_std_check.py` at K=8/K=10 over a bigger [lo,hi) to
  get more target-class points and see if that ratio stabilizes.
- Keep polling for k=13 growth past n=10 (stuck since p=233, cycle 41).

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p229:2,091,759 p233:434,986 p251:40,822 p293:7,903 p307:5,688 p349:260. Stuck at n=10 since p=233 (cycle 40, reconfirmed cycle 41/42/43); Track A's jumps to p=419/433/461 for k=13 all failed/timed out. k=11 has ZERO real SIEVE_LAYER_DONE points in the journal as of cycle 43 (747 events checked fresh) -- do not assume k=11 real data exists without re-checking JOURNAL_API each cycle. NOTE: local journal/events.jsonl in this container is stale every cycle -- always pull fresh via JOURNAL_API env var's events.jsonl endpoint.
## Established
- Cycle 8 PROVED: pre-DFS remaining[] constant; closed form p//(k+1).
- CYCLE 33: margin_at() at depth=k-4 is exactly margin=bcn+3*bc-ttc (constant across k). R=(bcn+3bc)/ttc; sign(margin)=sign(R-1).
- CYCLE 34-38: target residue class (p==-1 mod k+1) has significantly lower R (and more negative margin) than rest class at matched trend(p). Checked at k=8/11/13 across every range cutoff tried, no fade or cliff ever found. Most range-robust, most-checked result in the project.
- CYCLE 37/38: cycle 28/29's "significance cliff" does NOT reproduce at any of the 3 k values (8, 11, 13) it originally reported, under the corrected class-regression tool. bound_margin_k.py (cycle 28/29's tool) is gone for good (filesystem wipe) -- filed as replication failure, not clean disproof.
- CYCLE 38-40: margin-R (walk-proxy R from margin_at()) checked against real k=13 SIEVE_LAYER_DONE sizes, n=10 real points (199,211,223,227,229,233,251,293,307,349). log(size)~log(p): R2=0.924; adding R: R2=0.983.
- CYCLE 41: deconfounding margin-R vs residue class using REAL wall data with real degrees of freedom -- k=8 (n=39, 35 resid df): R's partial R2 over (logp+is_target)=0.0372 vs is_target's partial R2 over (logp+R)=0.0154, R wins ~2.4x. k=10 (n=34, 30 resid df): R's partial R2=0.0658 vs is_target's 0.0015, R wins ~44x. LOO coef_R never crosses zero at either k.
- CYCLE 42: coef_R's raw growth from k=8 (~10) to k=10 (~29, ~3x) decomposes into ~1.4x units effect (std(R) narrows ~1.4x with k, R trending to 1 per cycle 33's racing-to-1 story) plus a genuine further ~1.4-1.8x standardized-beta increase (beta_R=coef_R*std(R)/std(logsize): 0.39->0.59 seed42, 0.34->0.62 seed7, 0.48->0.67 seed99), stable across 3 seeds.
- CYCLE 43: complementary, non-regression check -- class-mean gap (mean_rest-mean_target) divided by pooled std_all (a Cohen's-d-style effect size) ALSO grows from k=8 to k=10 in all 3 seeds (0.885->0.945, 0.872->0.965, 0.769->0.924; ratio 1.07-1.20x). Smaller magnitude than cycle 42's beta_R growth (1.4-1.8x), as expected since class label is only part of what R's coefficient captures (cycle 41), but same direction, independent metric, second confirmation. std_rest narrows ~1.46-1.54x with k (tracks std_all, dominated by n=29-32 rest-class points); std_target's narrowing is too noisy to read (n=5-7 points only, ratios 1.21/0.86/1.24 across seeds) -- no claim made about target-class spread alone.
- 13 k values tested at small range: 5,6,7,8,9,10,11,12,13,14,15,16,17. Only 3 give unambiguous small-range-significant results (8, 11, 13); 2 borderline (7, 9); 8 flat.
- DISPROVED (#23): effect strengthens monotonically with k. (#24): prime-K1 pattern, broken by k=14. (#25): parity-of-k, broken by k=15/17. (#26): remaining[]/bitlen ratio, k=10 counter-example. (cycle 32): bitlen/K ratio. Covering-budget R(k,p) (cycle 19 fit, cycle 20/#570 disproved as mechanism at k=4 exact) -- DIFFERENT quantity from margin-internal R above; do not conflate.
- SUPERSEDED, NOT TRUSTED: cycle 28's "cliff not fade" and cycle 29's threshold-artifact framing -- built on a lost tool, fails to replicate at all 3 k.
## Ruled out
- Flat at real k=13: depth-0 coverage state, depth-1 remaining[] shape, raw survivor count, pairwise/triple witness codegree, greedy covering on real mCover.
- Uncorrected permutation tests overstate significance ~2 orders of magnitude -- always class-shape-matched correction.
- Exact raw-survivor brute force shows no k=13-style collapse at k=3/k=4.
- Sample-size/rng-artifact, outlier-prime, cumulative-average, walk() dead-end explanations for k=8/11/13 signal -- all ruled out.
- bitlen/K ratio, monotone-in-k, covering-budget (as mechanism), prime-K1, parity-of-k, remaining/bitlen threshold -- do not re-propose.
- "cliff scales with k/K1" and "k=11 cliff is a threshold artifact on a real decay" -- do not re-propose as established.
- "k=8 lacks ttc's class signal" -- WRONG, was a log(p)-vs-linear-p detrending artifact, fixed cycle 36.
- "More samples per prime will fix ttc's k=8 null" -- tested directly, resid_std barely moved.
- "margin-R is mostly redundant with residue class once is_target is controlled for" -- dead, overturned by cycle 41's real n=39/n=34 check.
- "R's coefficient growth from k=8 to k=10 is purely a units artifact" -- checked cycle 42, PARTLY true (~1.4x of ~3x) but not the whole story; cycle 43's independent class-gap-effect-size check confirms a real (smaller, 1.07-1.20x) growth too, from a totally different metric.
- OPERATIONAL: this repo has no git and the container filesystem is wiped every redeploy. Tools written mid-cycle do NOT survive unless re-created next cycle -- only journal THOUGHT/HYPOTHESIS text persists. margin_by_class_k.py, margin_class_regression_k.py, next_prime.py, class_std_check.py (new cycle 43) have survived/were created; bound_margin_k.py is gone for good. Local journal/events.jsonl can be STALE relative to JOURNAL_API -- always fetch fresh (cycle 43 reconfirmed: still 0 k=11 points, still n=10 at k=13).
## Best line of attack
The target-class-lower-R/margin offset (cycles 34-38) remains the most-tested, most range-robust pattern in the project. Cycle 41 established R carries real independent info beyond residue class at k=8/k=10. Cycles 42 and 43 now give TWO independent lines of evidence (standardized regression beta, and class-mean-gap effect size) that R's explanatory/separating power over wall size, relative to its own scale, genuinely grows with k -- both still resting on only 2 k values (8 and 10), so suggestive not established. The blocking constraint remains real k=11 data: zero points exist in the journal as of cycle 43.
## Next step
No real k=11 data exists yet (reconfirmed cycle 43, 747 events) to extend the 2-point trend to 3 points -- check JOURNAL_API fresh each cycle. Target-class std(R) ratio across k was too noisy to read this cycle (n=5-7 points) -- if budget allows, widen the prime range or n_samples in class_std_check.py to get more target-class points and see if it stabilizes. Keep polling for k=13 growth past n=10 (stuck since p=233, cycle 41).

Cycle 43: standardized class-mean gap in R also grows k=8→k=10 (independent of cycle 42's regression check)


Memory brief said k=13 was stuck at n=10 since p=233, but a fresh JOURNAL_API pull just now shows 11 real k=13 SIEVE_LAYER_DONE points -- theres a p=239 entry (1,449,830 tuples) that wasnt in the standing knowledge. Also reconfirmed: still zero k=11 points. So this cycle I have one new real data point to work with.


Refit the real-data falsification test cycle 39/40 set up, now with p=239 (k=13, size=1449830, non-target class, is_target=0) as an 11th point. Partial R2 of margin-R over (logp+is_target) keeps climbing: 0.0066 at n=9, 0.0150 at n=10, now 0.0172 at n=11. Thats three points in a row where adding a real non-target-class point pushes Rs independent contribution UP, not toward zero. p=239s residual in the full model is 0.226, mid-pack (range -0.69 to 0.43), so its not an outlier driving this through leverage.


# Cycle 44: an 11th real k=13 point extends the R-vs-class falsification test

tags: empirical

## Context

Cycle 43 was blocked: no new real k=13 or k=11 data existed, so it fell back
to a standard-deviation side check. Standing state going into this cycle
said "stuck at n=10 since p=233." First thing this cycle: pull JOURNAL_API
fresh anyway, per the brief's own rule, rather than trust that note.

## What's new

`JOURNAL_API` now has 758 events (up from 747 at cycle 43). Among the new
ones is a `SIEVE_LAYER_DONE` for **k=13, p=239, size=1,449,830** that was
missing from the standing knowledge's list (which jumped straight from
p=233 to p=251). That gives an 11th real k=13 first-sieve-layer point. Still
confirmed **zero** real k=11 `SIEVE_LAYER_DONE` points in the journal.

## Method

Computed `R` and `is_target` for p=239 at k=13 with the same settings used
for every other point in this series (`tools/margin_by_class_k.py 13 <lo>
<hi> 100 42`): `R=1.18392`, `is_target=0` (239 mod 14 = 1, not 13 -- a
non-target-class point, same as p=233 was at cycle 40).

Added it to the n=10 regression set from cycles 39/40 (`tools/_regress_n10.py`,
now `tools/_regress_n11.py`) and reran the same three-model comparison:
`log(size) ~ log(p)`, `~ log(p)+is_target`, `~ log(p)+R`, `~
log(p)+R+is_target`, plus leave-one-out on the full model. This continues
exactly the falsification test cycles 39/40 designed: does adding real
non-target-class points shrink `R`'s independent contribution over
`is_target` toward zero (demoting it), or hold/grow?

## Results

| fit | n=9 (cyc 39) | n=10 (cyc 40) | n=11 (this cycle) |
|---|---|---|---|
| log(size) ~ log(p) | 0.9232 | 0.9239 | 0.9076 |
| log(size) ~ log(p)+is_target | 0.9803 | 0.9711 | 0.9689 |
| log(size) ~ log(p)+R | 0.9830 | 0.9830 | 0.9829 |
| log(size) ~ log(p)+R+is_target | 0.9869 | 0.9861 | 0.9860 |

Partial R2 of R over (log p + is_target): **0.0066 (n=9) -> 0.0150 (n=10)
-> 0.0172 (n=11)** -- third consecutive real point that pushes this number
up, not toward zero.

Partial R2 of is_target over (log p + R): 0.0039 -> 0.0031 -> 0.0031 --
flat/shrinking, as before.

LOO on the full model (11 folds): `coef_R` ranges 18.39 to 28.39 (was 17.65
to 27.52 at n=10) -- never crosses zero, similar width. `coef_target` stays
negative every fold, -1.18 to -0.08.

Sanity check: p=239's residual in the full 3-predictor model is +0.226,
mid-pack among the 11 points (range -0.687 to +0.431) -- not an outlier
driving the result through leverage, same check cycle 40 ran for p=233.

## Reading

This is not new evidence of a different kind -- it is the third data point
in a row (233 at cycle 40, 239 now, plus the original n=9 baseline) landing
on the same side of the falsification test cycle 39 set up. Each real
non-target-class point that has arrived since has made `R`'s independent
contribution over class membership larger, not smaller. That is now three
strikes against the "R is just a relabeling of is_target" reading, and zero
strikes for it. Still thin -- n=11 with 4 free parameters leaves 7 residual
df, and the underlying `R` proxy is still the reconstructed random-walk
simulation from cycle 35, not the real solver's DFS -- but the trend is
consistent and has never once reversed across four additions (n=9→10→11,
counting cycle 34's original n=8 too, per cycle 41/42/43 notes).

## Next

- Keep pulling fresh real k=13 points every cycle before assuming any
  "stuck" note in the standing knowledge is still true -- it was wrong this
  cycle (n=10 -> n=11 sitting unnoticed in the journal).
- Still zero real k=11 points -- the planned 3-point (k=8/10/11) extension
  of cycle 42/43's beta_R and class-gap trends remains blocked. Keep
  checking.
- If a 12th k=13 point arrives, worth checking whether it's target-class
  (223, 251, 293, 307, 349 are the only target points so far, 6 of 11 are
  non-target) -- the test so far has only been fed non-target points since
  n=9; a fresh target-class point would test the other direction.

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p229:2,091,759 p233:434,986 p239:1,449,830 p251:40,822 p293:7,903 p307:5,688 p349:260. n=11 as of cycle 44 (p=239 was newly found in the journal this cycle, sitting between p=233 and p=251 -- the "stuck at n=10" note from cycles 41-43 was stale, always re-pull JOURNAL_API fresh). k=11 has ZERO real SIEVE_LAYER_DONE points in the journal as of cycle 44 (758 events checked fresh). NOTE: local journal/events.jsonl in this container is stale every cycle -- always pull fresh via JOURNAL_API env var's events.jsonl endpoint.
## Established
- Cycle 8 PROVED: pre-DFS remaining[] constant; closed form p//(k+1).
- CYCLE 33: margin_at() at depth=k-4 is exactly margin=bcn+3*bc-ttc (constant across k). R=(bcn+3bc)/ttc; sign(margin)=sign(R-1).
- CYCLE 34-38: target residue class (p==-1 mod k+1) has significantly lower R (and more negative margin) than rest class at matched trend(p). Checked at k=8/11/13 across every range cutoff tried, no fade or cliff ever found. Most range-robust, most-checked result in the project.
- CYCLE 37/38: cycle 28/29's "significance cliff" does NOT reproduce at any of the 3 k values (8, 11, 13) it originally reported, under the corrected class-regression tool. bound_margin_k.py (cycle 28/29's tool) is gone for good (filesystem wipe) -- filed as replication failure, not clean disproof.
- CYCLE 38-40: margin-R (walk-proxy R from margin_at()) checked against real k=13 SIEVE_LAYER_DONE sizes. log(size)~log(p) alone: R2 0.9232 (n=9) -> 0.9239 (n=10) -> 0.9076 (n=11, cycle 44). Adding R: R2 stays ~0.983 across all three.
- CYCLE 41: deconfounding margin-R vs residue class using REAL wall data with real degrees of freedom -- k=8 (n=39, 35 resid df): R's partial R2 over (logp+is_target)=0.0372 vs is_target's partial R2 over (logp+R)=0.0154, R wins ~2.4x. k=10 (n=34, 30 resid df): R's partial R2=0.0658 vs is_target's 0.0015, R wins ~44x. LOO coef_R never crosses zero at either k.
- CYCLE 42: coef_R's raw growth from k=8 (~10) to k=10 (~29, ~3x) decomposes into ~1.4x units effect (std(R) narrows ~1.4x with k) plus a genuine further ~1.4-1.8x standardized-beta increase (beta_R: 0.39->0.59 seed42, 0.34->0.62 seed7, 0.48->0.67 seed99), stable across 3 seeds.
- CYCLE 43: complementary check -- class-mean gap (mean_rest-mean_target)/std_all (Cohen's-d-style) ALSO grows from k=8 to k=10 in all 3 seeds (0.885->0.945, 0.872->0.965, 0.769->0.924; ratio 1.07-1.20x). Smaller than cycle 42's beta_R growth (1.4-1.8x) but same direction, independent metric, second confirmation.
- CYCLE 39/40/44: the real-k=13-data falsification test (does R's partial R2 over is_target shrink toward zero as non-target real points accumulate, or hold?) has now been fed 3 non-target-class points since n=9 (233 at cyc 40, 239 at cyc 44). Partial R2 of R over (logp+is_target): 0.0066 (n=9) -> 0.0150 (n=10) -> 0.0172 (n=11). Rises every time, never once toward zero. Partial R2 of is_target over (logp+R) is flat/shrinking: 0.0039->0.0031->0.0031. LOO coef_R at n=11: 18.39 to 28.39, never crosses zero. p=239's full-model residual (+0.226) is mid-pack (range -0.687 to +0.431), not a leverage outlier.
- 13 k values tested at small range: 5,6,7,8,9,10,11,12,13,14,15,16,17. Only 3 give unambiguous small-range-significant results (8, 11, 13); 2 borderline (7, 9); 8 flat.
- DISPROVED (#23): effect strengthens monotonically with k. (#24): prime-K1 pattern, broken by k=14. (#25): parity-of-k, broken by k=15/17. (#26): remaining[]/bitlen ratio, k=10 counter-example. (cycle 32): bitlen/K ratio. Covering-budget R(k,p) (cycle 19 fit, cycle 20/#570 disproved as mechanism at k=4 exact) -- DIFFERENT quantity from margin-internal R above; do not conflate.
- SUPERSEDED, NOT TRUSTED: cycle 28's "cliff not fade" and cycle 29's threshold-artifact framing -- built on a lost tool, fails to replicate at all 3 k.
## Ruled out
- Flat at real k=13: depth-0 coverage state, depth-1 remaining[] shape, raw survivor count, pairwise/triple witness codegree, greedy covering on real mCover.
- Uncorrected permutation tests overstate significance ~2 orders of magnitude -- always class-shape-matched correction.
- Exact raw-survivor brute force shows no k=13-style collapse at k=3/k=4.
- Sample-size/rng-artifact, outlier-prime, cumulative-average, walk() dead-end explanations for k=8/11/13 signal -- all ruled out.
- bitlen/K ratio, monotone-in-k, covering-budget (as mechanism), prime-K1, parity-of-k, remaining/bitlen threshold -- do not re-propose.
- "cliff scales with k/K1" and "k=11 cliff is a threshold artifact on a real decay" -- do not re-propose as established.
- "k=8 lacks ttc's class signal" -- WRONG, was a log(p)-vs-linear-p detrending artifact, fixed cycle 36.
- "More samples per prime will fix ttc's k=8 null" -- tested directly, resid_std barely moved.
- "margin-R is mostly redundant with residue class once is_target is controlled for" -- dead, overturned by cycle 41's real n=39/n=34 check, and now further overturned by 3 consecutive real k=13 points (cyc 39->40->44) all pushing partial R2 UP not down.
- "R's coefficient growth from k=8 to k=10 is purely a units artifact" -- checked cycle 42, PARTLY true (~1.4x of ~3x) but not the whole story; cycle 43's independent class-gap-effect-size check confirms a real (smaller, 1.07-1.20x) growth too.
- OPERATIONAL: this repo has no git and the container filesystem is wiped every redeploy. Tools written mid-cycle do NOT survive unless re-created next cycle -- only journal THOUGHT/HYPOTHESIS text persists. margin_by_class_k.py, margin_class_regression_k.py, next_prime.py, class_std_check.py, _regress_n11.py (new cycle 44) have survived/were created; bound_margin_k.py is gone for good. Local journal/events.jsonl can be STALE relative to JOURNAL_API -- always fetch fresh (cycle 44: brief said "stuck at n=10" but fresh pull found n=11, an unnoticed p=239 point).
## Best line of attack
The target-class-lower-R/margin offset (cycles 34-38) remains the most-tested, most range-robust pattern in the project. The real-data falsification test (cycles 39/40/44) is now the second-most load-bearing result: three non-target real k=13 points in a row have made R's independent contribution over class membership grow, never shrink. Cycles 42/43 give two independent lines of evidence that R's standardized separating power also grows with k, but that trend still rests on only 2 k values (8 and 10) -- blocked on real k=11 data (zero points as of cycle 44).
## Next step
Keep pulling JOURNAL_API fresh every cycle -- do not trust a prior cycle's "stuck at n" note without reverifying, it was wrong this cycle. Still no real k=11 data to extend the 2-point k=8/k=10 beta_R and class-gap trends to 3 points -- keep checking. If a 12th real k=13 point arrives, check whether it's target-class (only 5/11 points are target so far: 223,251,293,307,349) since the falsification test has only been fed non-target points since n=9; a target-class addition would test the test's other direction.


Filed cycle 44. The headline: this is now three non-target real points in a row (n9 baseline, then p=233, then p=239) where the falsification test cycle 39 designed comes out the same way -- R keeps carrying independent signal beyond residue class, never fading toward it. Still blocked on real k=11 data for the other open thread (beta_R / class-gap trend across k). Cleaning up scratch files now.


Fresh journal pull: still zero real SIEVE_LAYER_DONE points at k=11, and no new k=13 point past p=239 (still n=11, same 11 primes as cycle 44 confirmed). The blocked thread from cycles 42/43 -- extending the beta_R/class-gap trend past k=8,k=10 -- needs a real k=11 wall measurement that nobody has ever run. I have run_solver.py and the vendored solver right here, and nobody in the journal has ever started a k=11 RUN. Instead of waiting again, let me just run it myself on the smallest listed prime (p=23) with a bounded timeout and see if it is tractable.


Ran run_solver.py 11 --primes 23 and got a compile error, not a timeout. Tried p=131 too -- same error, so it is not a prime-specific issue, it happens at compile time before any prime-specific work runs. That is unexpected: I assumed k=11 was just slow, not broken.


Ran the raw clang++ command by hand with the SOLVER_CXXFLAGS=-stdlib=libc++ flag that run_solver.py actually uses (my first bare attempt hit a different, unrelated, missing-format-header error from skipping that flag). With it, I get the real error, in lift_strategy.h: the Squeeze strategy calls its own recursive iterate helper, passing along its input state as the second argument, but that helper param is hardcoded to expect a state whose lift-level is exactly 1. Clang reports a template match failure: could not match 1 against 4, and separately could not match 1 against 12.


Traced why: k=11 Config is Force2, Force2, Squeeze2, Force2, Force2, Force3, Squeeze3. Lift-level starts at 1 and each Force by Arg multiplies it by Arg. So Squeeze2 is invoked at lift-level 4 (1 times 2 times 2), and Squeeze3 is invoked at lift-level 12. Every other configured k in main.cpp (9, 10, 12, 13) only ever calls Squeeze right after the initial state or right after another Squeeze, both of which sit at lift-level 1, so they never trip this. k=11 is the only config that chains Force ops directly into Squeeze, and it is exactly that ordering that breaks compilation.


This resolves the thing that has blocked me since cycle 41: I kept saying real k=11 data was 0 points and treating that as a scheduling gap, waiting for another track to eventually run it. It is not a scheduling gap, it is a hard compile failure in the vendored solver that will hit anyone who tries K=11 as checked in, regardless of prime or machine. I am not going to patch the vendored solver myself this cycle -- that is Track A/upstream territory and a real fix needs to touch the actual algorithm semantics (Squeeze compares a projected set against the previous projected set to detect a fixed point; feeding it a non-projected lift-level-4 state as last changes what that comparison means, so a correct fix is not just a type signature change). Flagging it precisely is the useful step here.


# Cycle 45 — k=11 does not compile: the "zero real k=11 points" was never a scheduling gap

Tags: `empirical`

## Context

Cycles 41–44 established a beta_R / class-gap trend across real k=8 and k=10
wall data (margin-R's independent separating power between residue classes
grows as k grows) but could only check it at two k values, because the
journal has had **zero** real `SIEVE_LAYER_DONE` points at k=11 the entire
project — every cycle brief since ~44 notes "still zero, keep checking."
The standing assumption was that k=11 just hadn't been scheduled yet by
whichever track runs real sieve jobs.

This cycle: instead of waiting again, I ran the vendored solver at k=11
myself with `tools/run_solver.py`, which any track can invoke, to see if it
was actually tractable.

## What happened

`python3 tools/run_solver.py 11 --primes 23 --timeout 240` — failed
immediately, during **compilation**, not during the run. Same failure with
`--primes 131`. So it isn't a slow-prime problem; it fails before any
prime-specific work starts, for any prime.

Root cause, traced by hand-compiling
`solver/build/main_k11_p131.cpp` with the exact flags `run_solver.py` uses
(`clang++ -std=c++23 -march=native -O3 -stdlib=libc++`, the
`-stdlib=libc++` comes from `SOLVER_CXXFLAGS` and is required or `<format>`
doesn't resolve at all — a red herring the first time I tried it bare):

```
lift_strategy.h:116: error: no matching function for call to 'iterate'
  ...Squeeze<2>::operator()<4, 131, 11>...
  candidate template ignored: could not match 1 against 4
...
  ...Squeeze<3>::operator()<12, 131, 11>...
  candidate template ignored: could not match 1 against 12
```

In `lift_strategy.h`, `Squeeze<Arg>::operator()` is:

```cpp
template <int L, int P, int K> State<1, P, K> operator()(State<L, P, K> st) const {
  ...
  return iterate<MaxIter - 1>(Force<Arg>{}(st), std::move(st));
}
```

and the private helper is:

```cpp
template <int Remaining, int CurL, int P, int K>
static State<1, P, K> iterate(State<CurL, P, K> lifted, State<1, P, K> last)
```

`iterate`'s second parameter type is hardcoded `State<1, P, K>`. But
`std::move(st)` passed in has type `State<L, P, K>` for whatever `L`
`Squeeze::operator()` was actually invoked with — the literal `1` in the
signature is a non-deduced context, so this only type-checks when
`Squeeze` is called on a lift-level-1 state.

k=11's `Config` in `main.cpp` is:

```cpp
Force<2>, Force<2>, Squeeze<2>, Force<2>, Force<2>, Force<3>, Squeeze<3>
```

Lift-level starts at 1 and each `Force<Arg>` multiplies it by `Arg`
(`Force::operator()` returns `State<L*Arg,P,K>`). So:
- `Squeeze<2>` is reached at lift-level 1·2·2 = **4** → "could not match 1 against 4"
- `Squeeze<3>` is reached at lift-level 1(after Squeeze, always resets to 1)·2·2·3 = **12** → "could not match 1 against 12"

Checked every other k configured in `main.cpp` (9, 10, 12, 13) for the same
pattern: in all four, `Squeeze` is only ever invoked directly on the initial
state or directly after another `Squeeze` — both sit at lift-level 1 by
construction (`Squeeze` always returns `State<1,P,K>`, and `TightLargePrime`
is lift-level-preserving). k=11 is the only configured k whose `Config`
chains `Force` ops straight into a `Squeeze`, and that's exactly the
ordering that breaks. This is not an environment quirk (confirmed via a
from-scratch invocation with the exact production flags) and not a
compiler-strictness edge case — a non-deduced template parameter mismatch
(`1` vs `4`) is standard C++ behavior, not something a different compiler
version would paper over.

## Why I'm not fixing it this cycle

A correct fix isn't just relaxing the type signature. `Squeeze::iterate`
compares `projected.ansatz.size() == last.ansatz.size()` to detect a fixed
point of repeated lift+project. `last` needs to be a **previously projected**
(lift-level-1) set for that comparison to mean anything. If `last` on the
first call is instead the raw, un-projected lift-level-4 state chained in
from the prior `Force` ops, the fixed-point check compares two
different kinds of things. Fixing this touches solver semantics (Track
A/upstream territory, and the kind of change that needs its own
counter-testing before trusting any resulting "real" data), not a k=13
pruning lemma, which is Track C's actual charter. Flagging the exact
mechanism precisely, so whichever track owns the solver can fix it with
full context, is the right-sized step for one cycle.

## What this changes

The "blocked on real k=11 data" line in cycles 41–44's Next steps was
framed as "keep checking, it'll show up eventually." That framing was
wrong: it cannot show up from the vendored solver as currently checked in,
for any prime, on any machine running this toolchain. The beta_R / class-gap
trend (cycles 42–43) stays a 2-point (k=8, k=10) trend until either (a)
someone patches `Squeeze`'s fixed-point check to handle a non-1 starting
lift-level correctly, or (b) I fall back to a different sieve-derived proxy
that doesn't require compiling k=11 in this vendored form.

## Next

- Do not re-propose "wait for a real k=11 point to appear" as a next step —
  it needs a code fix first, not more waiting.
- If another track patches `Squeeze` for k=11, re-verify the fix compiles
  and re-check whether the resulting `SIEVE_LAYER_DONE` size for the
  smallest prime (23 or 131) looks sane before trusting it as a real point.
- Otherwise, look for a proxy for the beta_R/class-gap trend that doesn't
  require a 3rd real k value from this exact solver path — e.g. check
  whether margin_at()'s R statistic itself (computable without compiling
  the sieve at all, it's a closed-form quantity from cycle 33) shows the
  same growth pattern purely in the abstract k=11 case, decoupled from
  needing a real wall-size regression target.

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p229:2,091,759 p233:434,986 p239:1,449,830 p251:40,822 p293:7,903 p307:5,688 p349:260. n=11, unchanged since cycle 44 (fresh JOURNAL_API pull cycle 45 confirms no 12th point). k=11 has ZERO real SIEVE_LAYER_DONE points -- and CYCLE 45 FOUND WHY: the vendored solver's k=11 Config in main.cpp does not compile, on any prime, on any machine, with this toolchain. Root cause: lift_strategy.h's Squeeze<Arg>::iterate hardcodes its second parameter type to State<1,P,K> (lift-level 1), but k=11's Config (Force2,Force2,Squeeze2,Force2,Force2,Force3,Squeeze3) calls Squeeze2 at lift-level 4 and Squeeze3 at lift-level 12 -- a non-deduced-context template mismatch, standard C++ behavior not a compiler quirk. Every other configured k (9,10,12,13) only ever invokes Squeeze at lift-level 1 (right after the initial state or right after another Squeeze), so only k=11 trips this. This is NOT a scheduling gap -- do not file "wait for real k=11 data" as a next step anymore.
## Established
- Cycle 8 PROVED: pre-DFS remaining[] constant; closed form p//(k+1).
- CYCLE 33: margin_at() at depth=k-4 is exactly margin=bcn+3*bc-ttc (constant across k). R=(bcn+3bc)/ttc; sign(margin)=sign(R-1).
- CYCLE 34-38: target residue class (p==-1 mod k+1) has significantly lower R (and more negative margin) than rest class at matched trend(p). Checked at k=8/11/13 across every range cutoff tried, no fade or cliff ever found. Most range-robust, most-checked result in the project.
- CYCLE 37/38: cycle 28/29's "significance cliff" does NOT reproduce at any of the 3 k values (8, 11, 13) it originally reported, under the corrected class-regression tool. bound_margin_k.py (cycle 28/29's tool) is gone for good (filesystem wipe) -- filed as replication failure, not clean disproof.
- CYCLE 38-40/44: margin-R (walk-proxy R from margin_at()) checked against real k=13 SIEVE_LAYER_DONE sizes. log(size)~log(p) alone: R2 0.9232 (n=9) -> 0.9239 (n=10) -> 0.9076 (n=11). Adding R: R2 stays ~0.983 across all.
- CYCLE 41: deconfounding margin-R vs residue class using REAL wall data with real degrees of freedom -- k=8 (n=39): R's partial R2=0.0372 vs is_target's 0.0154, R wins ~2.4x. k=10 (n=34): R's partial R2=0.0658 vs is_target's 0.0015, R wins ~44x. LOO coef_R never crosses zero at either k.
- CYCLE 42: coef_R's raw growth k=8(~10)->k=10(~29,~3x) decomposes into ~1.4x units effect plus a genuine further ~1.4-1.8x standardized-beta increase (beta_R: 0.39->0.59, 0.34->0.62, 0.48->0.67 across 3 seeds).
- CYCLE 43: complementary check -- class-mean gap (Cohen's-d-style, gap/std_all) ALSO grows k=8->k=10 in all 3 seeds (ratio 1.07-1.20x). Smaller than cycle 42's beta_R growth but same direction, independent metric, second confirmation.
- CYCLE 39/40/44: real-k=13 falsification test (does R's partial R2 over is_target shrink toward zero as non-target points accumulate, or hold?) fed 3 non-target points since n=9 (233, 239). Partial R2 of R over (logp+is_target): 0.0066(n=9)->0.0150(n=10)->0.0172(n=11). Rises every time. Partial R2 of is_target over (logp+R) flat/shrinking: 0.0039->0.0031->0.0031.
- CYCLE 45: root-caused why real k=11 data has never existed -- vendored solver's k=11 Config fails to compile (Squeeze called at lift-level 4/12, its helper hardcodes lift-level 1). Confirmed prime-independent (p=23, p=131 both fail identically, at compile time before any prime-specific work). Confirmed environment-independent in principle (non-deduced template param mismatch is standard C++, not a clang quirk). Only k=11 among {9,10,12,13} chains Force ops directly into Squeeze.
- 13 k values tested at small range: 5-17. Only 3 unambiguous (8,11,13); 2 borderline (7,9); 8 flat.
- DISPROVED (#23-26, cycle 32): monotone-in-k, prime-K1, parity-of-k, remaining/bitlen ratio, bitlen/K ratio. Covering-budget R(k,p) disproved as mechanism at k=4 exact (different quantity from margin-internal R, do not conflate).
- SUPERSEDED, NOT TRUSTED: cycle 28/29's cliff/threshold framing -- built on a lost tool, fails to replicate at all 3 k.
## Ruled out
- Flat at real k=13: depth-0 coverage state, depth-1 remaining[] shape, raw survivor count, pairwise/triple witness codegree, greedy covering on real mCover.
- Uncorrected permutation tests overstate significance ~2 orders of magnitude -- always class-shape-matched correction.
- Exact raw-survivor brute force shows no k=13-style collapse at k=3/k=4.
- Sample-size/rng-artifact, outlier-prime, cumulative-average, walk() dead-end, bitlen/K ratio, monotone-in-k, covering-budget-as-mechanism, prime-K1, parity-of-k, remaining/bitlen threshold, "cliff scales with k/K1", "k=11 cliff is a threshold artifact", "k=8 lacks ttc's class signal" (was a detrending artifact, fixed cyc 36) -- do not re-propose any of these.
- "More samples per prime will fix ttc's k=8 null" -- tested directly, resid_std barely moved.
- "margin-R is mostly redundant with residue class once is_target is controlled for" -- dead, overturned repeatedly (cycles 41, 44).
- "R's coefficient growth k=8->k=10 is purely a units artifact" -- PARTLY true (~1.4x of ~3x) but cycle 43 confirms a real further ~1.07-1.20x growth too.
- NEW (#45): "zero real k=11 data is just a scheduling gap, keep waiting" -- WRONG. It is a hard compile failure in the vendored solver (Squeeze/lift-level bug), not a matter of scheduling or compute budget. Do not propose "wait for k=11 data to appear" again -- it needs a code fix upstream first.
- OPERATIONAL: this repo has no git and the container filesystem is wiped every redeploy. Tools written mid-cycle do NOT survive unless re-created. margin_by_class_k.py, margin_class_regression_k.py, next_prime.py, class_std_check.py have survived across cycles. Local journal/events.jsonl can be STALE -- always fetch fresh via JOURNAL_API.
## Best line of attack
The target-class-lower-R/margin offset (cycles 34-38) remains the most-tested, most range-robust pattern in the project. The real-data falsification test (cycles 39/40/44) is the second-most load-bearing result: three non-target real k=13 points in a row have made R's independent contribution over class membership grow, never shrink. Cycles 42/43's beta_R/class-gap-growth-with-k trend is now confirmed STRUCTURALLY BLOCKED at 2 points (k=8, k=10) until someone fixes the k=11 Squeeze/lift-level compile bug found this cycle -- it is not a matter of waiting.
## Next step
Do not re-propose "wait for real k=11 data" -- root cause is now known (Squeeze's iterate() hardcodes lift-level 1, k=11's Config invokes it at lift-level 4 and 12). Two ways forward: (a) if another track patches lift_strategy.h for k=11, re-verify compile success and sanity-check the resulting SIEVE_LAYER_DONE size before trusting it; (b) look for a proxy that extends the beta_R/class-gap trend to a 3rd k value without needing this exact solver to compile at k=11 -- e.g. check whether margin_at()'s R statistic (closed-form since cycle 33, no compile needed) shows the same abstract growth pattern at k=11 on its own, decoupled from a real wall-size regression target.

Cycle 45: real k=11 data was never a scheduling gap -- the vendored solver's k=11 config fails to compile


Memory brief is current with cycle 45 - the k=11 compile bug is a hard root cause, not a scheduling gap, and nobody has patched lift_strategy.h since. So the standing next step is option (b): extend the beta_R/class-gap-grows-with-k trend (cycles 42/43) to k=11 using margin_at()'s closed-form walk simulation, which needs no compiled solver at all. That decouples the abstract R-vs-class trend from the blocked real-wall-size regression.


Results are in, and they are not a clean extension of cycles 42/43. Using a k=11 range prime-count-matched to k8/k10 ([20,200), n=38), the standardized class-gap barely grows past k=10 (ratio 1.006-1.028 across 3 seeds) -- much weaker than the k8->k10 jump of 1.07-1.20x. Using the older, already-established k=11 baseline range from cycles 27-28 ([20,300), n=54), the gap actually REVERSES below k=10 (ratio 0.73-0.75).


This lines up with cycle 30, not against it: cycle 30 already found k=11 both classes converge (gap shrinks) as p grows within this same window, well before the real cliff at p~760-770. So the wider [20,300) range is just averaging in more already-decaying points than the tight [20,200) range. The k8->k10 growth trend is not wrong, but it does not survive being extrapolated to k=11 with a naively-matched range -- k=11 has its own known decay dynamic that swamps it.


# Cycle 46: the beta_R/class-gap growth trend does not cleanly extend to k=11 -- it is range-dependent

tags: empirical

## Context

Cycle 45 root-caused why real k=13-style `SIEVE_LAYER_DONE` data has never
existed for k=11: the vendored solver's k=11 `Config` fails to compile
(`Squeeze` invoked at lift-level 4 and 12, but its helper hardcodes
lift-level 1). That is not a scheduling gap -- it needs an upstream code
fix, not more waiting. Cycle 45's "Next" flagged an alternative: check
whether cycles 42/43's finding (the standardized class-mean gap in
margin-R grows going from k=8 to k=10, ratio ~1.07-1.20x across 3 seeds)
continues to grow at k=11, using ONLY `margin_by_class_k.py`'s closed-form
walk simulation -- no compiled solver, no real wall data needed at all.

## Method

Wrote `tools/class_std_check_k11.py`, extending cycle 43's
`class_std_check.py` (same methodology: `mean_rest - mean_target` in R,
standardized by `std_all` of R across the whole range) to two k=11 prime
ranges, run alongside the original k=8 `[47,242)` and k=10 `[127,312)`
for a same-run sanity replicate:

- k=11a: `[20,200)`, n=38 primes -- chosen to closely count-match k=8's
  n=39 and k=10's n=34, removing range-width as a confound.
- k=11b: `[20,300)`, n=54 primes -- the pre-existing k=11 baseline range
  from cycles 27/28, chosen with no reference to this cycle's question.

Same `n_samples=100`, same 3 seeds (42, 7, 99) as cycle 43.

## Results

Standardized gap (`(mean_rest - mean_target) / std_all(R)`), 3 seeds:

| seed | k=8 | k=10 | k=11a [20,200) | k=11b [20,300) |
|---|---|---|---|---|
| 42 | 0.8851 | 0.9448 | 0.9708 | 0.7061 |
| 7  | 0.8718 | 0.9648 | 0.9832 | 0.7272 |
| 99 | 0.7686 | 0.9238 | 0.9298 | 0.6733 |

Ratios relative to k=10:
- k11a/k10: 1.028, 1.019, 1.006 (essentially flat -- far weaker than the
  k8->k10 jump of 1.067-1.202x these same 3 seeds reproduce here as a
  sanity check, matching cycle 43's original numbers)
- k11b/k10: 0.747, 0.754, 0.729 (the trend *reverses* -- k=11's gap drops
  clearly below k=10's)

## Reading

This is not a clean extension of cycles 42/43, and not a clean disproof
either -- it is range-dependent, and the dependence is explainable rather
than mysterious. Cycle 30 already established, independently, that at
k=11 both the target-class and rest-class margin means *converge*
(gap shrinks) as p grows within this same window, well before the actual
significance cliff at p~760-770. `[20,300)` pulls in more of that
already-decaying tail than the tighter `[20,200)` range does, so it drags
the standardized gap down. `[20,200)`, which stays closer to the onset,
shows the gap holding roughly flat past k=10 rather than continuing to
grow by another ~1.1-1.2x.

So the honest reading: the k8->k10 growth trend itself is not
overturned (this cycle reproduces it exactly). But it does not
straightforwardly generalize to "gap keeps growing with k" once k=11 is
included, because k=11 has its own known range-dependent decay dynamic
(cycle 30) that a same-shape range comparison doesn't control for. Any
future claim about the trend continuing past k=10 needs to either stay
inside the pre-decay window or explicitly normalize by each k's own decay
onset -- not just count-match prime ranges.

## Next

- Try normalizing k=11's range by its own structural landmark (e.g. some
  fraction of the p~760 cliff distance from cycle 28/29) instead of raw
  prime count, and see if the growth trend re-emerges under that
  normalization -- would distinguish "k=11 breaks the trend" from "we
  compared the wrong slice of k=11."
- The margin_at() closed-form is available for any k with no compile
  step. Worth checking k=9 and k=12 (both currently unexamined for this
  specific gap-growth question) the same way, purely as closed-form
  cross-checks, before concluding anything about a general k-trend.
- Still flag for other tracks: k=11's Squeeze/lift-level compile bug in
  `lift_strategy.h` blocks ever validating any of this against real
  k=11 wall sizes, the way k=8/k=10/k=13 have been.

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p229:2,091,759 p233:434,986 p239:1,449,830 p251:40,822 p293:7,903 p307:5,688 p349:260. n=11, unchanged since cycle 44/45. k=11 has ZERO real SIEVE_LAYER_DONE points -- CYCLE 45 found why: vendored solver's k=11 Config fails to compile (lift_strategy.h's Squeeze<Arg>::iterate hardcodes lift-level 1, but k=11's Config calls Squeeze2 at lift-level 4 and Squeeze3 at lift-level 12 -- a non-deduced-context template mismatch). This is a hard compile bug needing an upstream fix, NOT a scheduling gap -- do not propose "wait for k=11 data" again.
## Established
- Cycle 8 PROVED: pre-DFS remaining[] constant; closed form p//(k+1).
- CYCLE 33: margin_at() at depth=k-4 is exactly margin=bcn+3*bc-ttc (constant across k). R=(bcn+3bc)/ttc; sign(margin)=sign(R-1).
- CYCLE 34-38: target residue class (p==-1 mod k+1) has significantly lower R (and more negative margin) than rest class at matched trend(p). Checked at k=8/11/13 across every range cutoff tried, no fade or cliff ever found. Most range-robust, most-checked result in the project.
- CYCLE 37/38: cycle 28/29's "significance cliff" does NOT reproduce at any of the 3 k values (8, 11, 13) it originally reported, under the corrected class-regression tool.
- CYCLE 38-44: margin-R (walk-proxy) checked against real k=13 SIEVE_LAYER_DONE sizes. log(size)~log(p) alone: R2 ~0.92-0.92 (n=9->11). Adding R: R2 stays ~0.983.
- CYCLE 41: deconfounding margin-R vs residue class using REAL wall data, real df -- k=8 (n=39): R's partial R2=0.0372 vs is_target's 0.0154, R wins ~2.4x. k=10 (n=34): R's partial R2=0.0658 vs is_target's 0.0015, R wins ~44x. LOO coef_R never crosses zero at either k.
- CYCLE 42: coef_R's raw growth k=8->k=10 decomposes into ~1.4x units effect plus a genuine further ~1.4-1.8x standardized-beta increase.
- CYCLE 43: complementary check -- class-mean gap (standardized by std_all of R) ALSO grows k=8->k=10 in all 3 seeds (ratio 1.07-1.20x). Independent metric, second confirmation.
- CYCLE 39/40/44: real-k=13 falsification test -- partial R2 of R over (logp+is_target) rises every time a new non-target point is added: 0.0066(n=9)->0.0150(n=10)->0.0172(n=11). Partial R2 of is_target over (logp+R) flat/shrinking.
- CYCLE 45: root-caused why real k=11 data has never existed -- hard compile failure, prime-independent, compiler-independent in principle.
- CYCLE 46: tested whether cycle 42/43's class-gap growth trend extends to k=11 using ONLY the closed-form margin_by_class_k.py walk (no compile needed). Result is range-dependent, not a clean extension: a range prime-count-matched to k=8/k=10 ([20,200), n=38) gives an essentially FLAT continuation past k=10 (ratio 1.006-1.028x, much weaker than the 1.07-1.20x k8->k10 jump); the older established k=11 baseline range ([20,300), n=54, from cycles 27/28) gives a REVERSAL (ratio 0.73-0.75x, gap drops below k=10). This reversal is explained by cycle 30's independent finding that k=11's two class means converge as p grows in this window well before the real cliff at p~760 -- the wider range just includes more already-decaying points. The k8->k10 growth trend itself was exactly reproduced this cycle (sanity check), so it is not overturned, but "gap keeps growing with k" does not straightforwardly generalize past k=10 without controlling for each k's own decay onset.
- 13 k values tested at small range: 5-17. Only 3 unambiguous (8,11,13); 2 borderline (7,9); 8 flat.
- DISPROVED (#23-26, cycle 32): monotone-in-k, prime-K1, parity-of-k, remaining/bitlen ratio, bitlen/K ratio. Covering-budget R(k,p) disproved as mechanism at k=4 exact.
- SUPERSEDED, NOT TRUSTED: cycle 28/29's cliff/threshold framing -- built on a lost tool, fails to replicate at all 3 k.
## Ruled out
- Flat at real k=13: depth-0 coverage state, depth-1 remaining[] shape, raw survivor count, pairwise/triple witness codegree, greedy covering on real mCover.
- Uncorrected permutation tests overstate significance ~2 orders of magnitude -- always class-shape-matched correction.
- Exact raw-survivor brute force shows no k=13-style collapse at k=3/k=4.
- Sample-size/rng-artifact, outlier-prime, cumulative-average, walk() dead-end, bitlen/K ratio, monotone-in-k, covering-budget-as-mechanism, prime-K1, parity-of-k, remaining/bitlen threshold, "cliff scales with k/K1", "k=11 cliff is a threshold artifact", "k=8 lacks ttc's class signal" -- do not re-propose any of these.
- "More samples per prime will fix ttc's k=8 null" -- tested directly, resid_std barely moved.
- "margin-R is mostly redundant with residue class once is_target is controlled for" -- dead, overturned repeatedly (cycles 41, 44).
- "R's coefficient growth k=8->k=10 is purely a units artifact" -- PARTLY true (~1.4x of ~3x) but cycle 43 confirms a real further ~1.07-1.20x growth too.
- "zero real k=11 data is just a scheduling gap, keep waiting" (cycle 45) -- WRONG, it is a hard compile bug. Needs an upstream fix to lift_strategy.h, not compute budget.
- NEW (#46): "the class-gap/beta_R growth trend keeps growing smoothly as k increases past 10" -- NOT SUPPORTED as a clean generalization. At k=11 it is at best flat (tight range) or reversed (wider established range), and the reversal is explained by k=11's own known convergence dynamic (cycle 30), not by the trend being false at k=8->k=10.
- OPERATIONAL: this repo has no git; container filesystem is wiped every redeploy, but notebook/ and tools/ have empirically persisted across recent cycles regardless -- still always re-verify a tool exists before assuming it survived. Local journal/events.jsonl can be STALE -- always fetch fresh via JOURNAL_API.
## Best line of attack
The target-class-lower-R/margin offset (cycles 34-38) remains the most-tested, most range-robust pattern in the project. The real-data falsification test (cycles 39/40/44) is the second-most load-bearing result: three non-target real k=13 points in a row have made R's independent contribution over class membership grow, never shrink. The k8->k10 class-gap/beta_R growth trend (cycles 42/43) is real and reproduced again this cycle, but cycle 46 shows it must NOT be casually extrapolated past k=10 without controlling for each k's own decay dynamics -- k=11's known p~600-760 convergence (cycle 30) swamps a naive range-matched comparison.
## Next step
Two live threads: (a) normalize k=11's range by its own structural landmark (fraction of the cycle 28/29 p~760 cliff distance) instead of raw prime count/width, and re-run cycle 46's gap-growth check -- would distinguish "k=11 breaks the trend" from "cycle 46 compared the wrong slice of k=11." (b) the margin_at() closed form needs no compile step for ANY k -- run the same class-gap check at k=9 and k=12 (currently unexamined for this question) as further cross-checks before concluding anything about a general multi-k trend. Do not re-propose waiting for real k=11 SIEVE_LAYER_DONE data -- that needs an upstream lift_strategy.h fix first (cycle 45).

Cycle 46: k=11 class-gap growth trend is range-dependent, not a clean k8->k10 extension


Memory brief and a fresh JOURNAL_API pull both show a 12th real k=13 SIEVE_LAYER_DONE point that cycle 44 did not have yet: p=241, size=516017, landed at seq 769 right around when cycle 46 was being written. That is exactly the kind of new data the falsification test (cycles 39/40/44) is built to absorb -- one more non-target real point to see if R keeps beating is_target.


Computed R for p=241 with the same margin_by_class_k.py 13 settings used for every other point: R=1.14963, and 241 mod 14 = 3 so is_target=0 -- another non-target point, same as the last three. That means the falsification test still has not been tested by a fresh target-class arrival since n=9; 7 of 12 points are now non-target, 5 target.


Ran the n=12 regression: partial R2 of R over (logp+is_target) went 0.0150(n=10) -> 0.0172(n=11) -> 0.0181(n=12). Still growing, fourth real point in a row on the same side, but the increments are shrinking fast: 0.0084, then 0.0022, then 0.0009. That deceleration reads as convergence to me, not as the effect dying -- if it were an artifact I would expect it to wobble or reverse, not smoothly slow down toward a limit.


Checked p=241 is not driving this through leverage: its residual in the full 3-predictor model is +0.036, the smallest-magnitude residual of all 12 points (range is -0.691 to +0.428). It sits right on the fitted line, so the small partial-R2 bump is a real if modest signal, not one influential outlier.


# Cycle 47: a 12th real k=13 point extends the falsification test again — still growing, still non-target

tags: empirical

## Context

Standing knowledge said the real k=13 `SIEVE_LAYER_DONE` set was stuck at
n=11 since cycles 44/45. Per the brief's own rule, pulled `JOURNAL_API`
fresh anyway rather than trust that note (this caught a missed point at
cycle 44 too).

## What's new

Fresh pull (`tools/_fetch_events.py`) shows a 12th real k=13 point that
wasn't in cycle 44's set: **p=241, size=516,017** (seq 769,
2026-07-21T01:07:01Z) — landed in the journal right around when cycle 46
was being written, so it slipped past that cycle's notes too.

## Method

Computed `R` and `is_target` for p=241 at k=13 with the same settings used
for every other point in this series
(`tools/margin_by_class_k.py 13 241 242 100 42`): `R=1.14963`. `241 mod 14
= 3`, not 13, so `is_target=0` — another **non-target-class** point (cycle
44 had already flagged that the test has only been fed non-target points
since n=9, and asked for a target-class point next; this one isn't it
either).

Added it to `tools/_regress_n11.py` (now `tools/_regress_n12.py`) and reran
the same model comparison: `log(size) ~ log(p)`, `~log(p)+is_target`,
`~log(p)+R`, `~log(p)+R+is_target`, plus leave-one-out on the full model.

## Results

| fit | n=10 (cyc 40) | n=11 (cyc 44) | n=12 (this cycle) |
|---|---|---|---|
| log(size) ~ log(p) | 0.9239 | 0.9076 | 0.9063 |
| log(size) ~ log(p)+is_target | 0.9711 | 0.9689 | 0.9681 |
| log(size) ~ log(p)+R | 0.9830 | 0.9829 | 0.9823 |
| log(size) ~ log(p)+R+is_target | 0.9861 | 0.9860 | 0.9861 |

Partial R2 of R over (log p + is_target): **0.0150 (n=10) -> 0.0172 (n=11)
-> 0.0181 (n=12)** — fourth consecutive real point that pushes this number
up, though the increment is shrinking (0.0084, 0.0022, 0.0009).

Partial R2 of is_target over (log p + R): 0.0031 -> 0.0031 -> 0.0039 —
flat, first uptick in the series but still small relative to R's partial
R2.

LOO on the full model (12 folds): `coef_R` ranges 19.34 to 27.92 (was
18.39 to 28.39 at n=11) — never crosses zero. `coef_target` stays negative
every fold, -1.08 to -0.24 (was -1.18 to -0.08) — also never crosses zero,
range narrowing slightly on both ends.

Residual check: p=241's residual in the full 3-predictor model is +0.036,
smallest-magnitude residual of all 12 points (range -0.691 to +0.428) —
not an outlier, not driving the result through leverage.

## Reading

Fourth real non-target point in a row lands on the same side of cycle 39's
falsification test: `R`'s independent contribution over class membership
keeps growing, never shrinking, toward the "R is just relabeling
is_target" alternative. But the growth is visibly decelerating (partial R2
deltas: 0.0084 -> 0.0022 -> 0.0009), which is exactly what you'd expect if
this is converging to a stable value rather than diverging — a point in
favor of the effect being real and finite, not an artifact that keeps
inflating with more data.

The open gap cycle 44 flagged is still open: 7 of 12 points are now
non-target (199, 211, 227, 229, 233, 239, 241), only 5 are target class
(223, 251, 293, 307, 349). The test has never yet been extended by a fresh
target-class point — every new arrival since n=9 has happened to be
non-target. That's not a flaw in the test, just a fact about which primes
the sieve runs have completed so far; worth flagging explicitly so a
future cycle doesn't read "still no target-class check" as suspicious.

## Next

- Keep pulling fresh real k=13 points every cycle before trusting a
  "stuck" note in standing knowledge — this is the second cycle in a row
  (44, now 47) where the note was already stale.
- If the next new k=13 point is target-class (223/251/293/307/349-style,
  p mod 14 == 13), that's the first chance to see whether R's partial R2
  still grows when the new point is on the *other* side of is_target —
  a meaningfully different test than four non-target points in a row.
- Cycle 46's two live threads (normalize k=11's range by its own p~760
  cliff distance; run the closed-form class-gap check at k=9/k=12) are
  still untouched and still don't need a compile step — worth picking up
  next if no new real k=13 point has landed.
- Still flag for other tracks: k=11's Squeeze/lift-level compile bug in
  `lift_strategy.h` (cycle 45) still blocks any real k=11 wall-size
  validation.

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p229:2,091,759 p233:434,986 p239:1,449,830 p241:516,017 p251:40,822 p293:7,903 p307:5,688 p349:260. n=12 (added p=241 at cycle 47). k=11 has ZERO real SIEVE_LAYER_DONE points -- CYCLE 45 found why: vendored solver's k=11 Config fails to compile (lift_strategy.h's Squeeze<Arg>::iterate hardcodes lift-level 1, but k=11's Config calls Squeeze2 at lift-level 4 and Squeeze3 at lift-level 12 -- a non-deduced-context template mismatch). This is a hard compile bug needing an upstream fix, NOT a scheduling gap -- do not propose "wait for k=11 data" again.
## Established
- Cycle 8 PROVED: pre-DFS remaining[] constant; closed form p//(k+1).
- CYCLE 33: margin_at() at depth=k-4 is exactly margin=bcn+3*bc-ttc (constant across k). R=(bcn+3bc)/ttc; sign(margin)=sign(R-1).
- CYCLE 34-38: target residue class (p==-1 mod k+1) has significantly lower R (and more negative margin) than rest class at matched trend(p). Checked at k=8/11/13 across every range cutoff tried, no fade or cliff ever found. Most range-robust, most-checked result in the project.
- CYCLE 37/38: cycle 28/29's "significance cliff" does NOT reproduce at any of the 3 k values (8, 11, 13) it originally reported, under the corrected class-regression tool.
- CYCLE 38-44: margin-R (walk-proxy) checked against real k=13 SIEVE_LAYER_DONE sizes. log(size)~log(p) alone: R2 ~0.91-0.92 (n=9->12). Adding R: R2 stays ~0.982-0.983.
- CYCLE 41: deconfounding margin-R vs residue class using REAL wall data, real df -- k=8 (n=39): R's partial R2=0.0372 vs is_target's 0.0154, R wins ~2.4x. k=10 (n=34): R's partial R2=0.0658 vs is_target's 0.0015, R wins ~44x. LOO coef_R never crosses zero at either k.
- CYCLE 42: coef_R's raw growth k=8->k=10 decomposes into ~1.4x units effect plus a genuine further ~1.4-1.8x standardized-beta increase.
- CYCLE 43: complementary check -- class-mean gap (standardized by std_all of R) ALSO grows k=8->k=10 in all 3 seeds (ratio 1.07-1.20x). Independent metric, second confirmation.
- CYCLE 39/40/44/47: real-k=13 falsification test -- partial R2 of R over (logp+is_target) rises every time a new non-target point is added: 0.0066(n=9)->0.0150(n=10)->0.0172(n=11)->0.0181(n=12, cycle 47). Four real points in a row, all non-target-class so far (7 of 12 total points are now non-target, only 5 target -- test has never yet absorbed a fresh target-class arrival). Partial R2 of is_target over (logp+R) stays flat/small (0.0039 at n=12, first tiny uptick but still much smaller than R's). Growth increments are shrinking fast (0.0084, 0.0022, 0.0009) -- reads as convergence, not an artifact still inflating. p=241's residual (+0.036) is the smallest-magnitude of all 12 points, not an outlier driving the result.
- CYCLE 45: root-caused why real k=11 data has never existed -- hard compile failure, prime-independent, compiler-independent in principle.
- CYCLE 46: tested whether cycle 42/43's class-gap growth trend extends to k=11 using ONLY the closed-form margin_by_class_k.py walk (no compile needed). Result is range-dependent: count-matched range [20,200) n=38 gives flat continuation (ratio 1.006-1.028x); older baseline range [20,300) n=54 gives a REVERSAL (ratio 0.73-0.75x) explained by cycle 30's finding that k=11's two class means converge well before the real cliff at p~760.
- 13 k values tested at small range: 5-17. Only 3 unambiguous (8,11,13); 2 borderline (7,9); 8 flat.
- DISPROVED (#23-26, cycle 32): monotone-in-k, prime-K1, parity-of-k, remaining/bitlen ratio, bitlen/K ratio. Covering-budget R(k,p) disproved as mechanism at k=4 exact.
- SUPERSEDED, NOT TRUSTED: cycle 28/29's cliff/threshold framing -- built on a lost tool, fails to replicate at all 3 k.
## Ruled out
- Flat at real k=13: depth-0 coverage state, depth-1 remaining[] shape, raw survivor count, pairwise/triple witness codegree, greedy covering on real mCover.
- Uncorrected permutation tests overstate significance ~2 orders of magnitude -- always class-shape-matched correction.
- Exact raw-survivor brute force shows no k=13-style collapse at k=3/k=4.
- Sample-size/rng-artifact, outlier-prime, cumulative-average, walk() dead-end, bitlen/K ratio, monotone-in-k, covering-budget-as-mechanism, prime-K1, parity-of-k, remaining/bitlen threshold, "cliff scales with k/K1", "k=11 cliff is a threshold artifact", "k=8 lacks ttc's class signal" -- do not re-propose any of these.
- "More samples per prime will fix ttc's k=8 null" -- tested directly, resid_std barely moved.
- "margin-R is mostly redundant with residue class once is_target is controlled for" -- dead, overturned repeatedly (cycles 41, 44, 47).
- "R's coefficient growth k=8->k=10 is purely a units artifact" -- PARTLY true (~1.4x of ~3x) but cycle 43 confirms a real further ~1.07-1.20x growth too.
- "zero real k=11 data is just a scheduling gap, keep waiting" (cycle 45) -- WRONG, it is a hard compile bug. Needs an upstream fix to lift_strategy.h, not compute budget.
- "the class-gap/beta_R growth trend keeps growing smoothly as k increases past 10" (cycle 46) -- NOT SUPPORTED as a clean generalization. At k=11 it is at best flat (tight range) or reversed (wider range), explained by k=11's own known convergence dynamic (cycle 30), not by the trend being false at k=8->k=10.
- OPERATIONAL: this repo has no git; container filesystem is wiped every redeploy, but notebook/ and tools/ have empirically persisted across recent cycles regardless -- still always re-verify a tool exists before assuming it survived. Local journal/events.jsonl can be STALE -- always fetch fresh via JOURNAL_API (caught a missed point at cycles 44 AND 47 -- this is now a recurring failure mode of trusting the "stuck" note, not a one-off).
## Best line of attack
The target-class-lower-R/margin offset (cycles 34-38) remains the most-tested, most range-robust pattern in the project. The real-data falsification test (cycles 39/40/44/47) is the second-most load-bearing result: four non-target real k=13 points in a row have made R's independent contribution over class membership grow, never shrink, though the growth is now visibly decelerating (converging, not runaway). The one clear gap in this test: every new point since n=9 has happened to be non-target-class -- the test has never been challenged by a fresh target-class arrival, which would be a meaningfully different check. The k8->k10 class-gap/beta_R growth trend (cycles 42/43) is real and reproduced again at cycle 46, but must NOT be casually extrapolated past k=10 -- k=11's own decay dynamics (cycle 30) swamp a naive range-matched comparison.
## Next step
Three live threads, no compile step needed for any: (a) watch for the next real k=13 SIEVE_LAYER_DONE point and check its class -- if target-class (p mod 14 == 13), it is the first out-of-sample test of the falsification trend from the other direction. (b) normalize k=11's range by its own structural landmark (fraction of the p~760 cliff distance) and re-run cycle 46's gap-growth check. (c) run the closed-form class-gap check at k=9 and k=12 (unexamined for this question) as further cross-checks. Always pull JOURNAL_API fresh before trusting any "stuck at n=X" note in this file -- it has been stale twice now (cycles 44, 47).

Cycle 47: a 12th real k=13 point extends the falsification test again -- still growing, still non-target


Pulled JOURNAL_API fresh (learned from cycles 44/47 that the local file can be stale) and confirmed: no new SIEVE_LAYER_DONE point has landed since p=241 at seq 769, so the falsification-test target-class gap is still open. Nothing new to react to there, so picking up cycle 47's thread (c): run the closed-form class-gap check at k=9 and k=12, which have never been touched by this line of attack -- they sit between the established k8->k10 growth and the range-dependent k=11/real-data k=13.


Results are in for k=9 and k=12 (count-matched windows, ~34-39 primes each, same margin_by_class_k.py tool, 3 seeds). k=11 reproduced cycle 46's exact tight-range numbers (1.006-1.028), which is a nice sanity check that the pipeline is deterministic and correct. But k=9 and k=12 do NOT extend the k8->k10 growth: k9/k8 ratio is ~0.92-1.05 (flat, mixed sign across seeds), and k12/k11 actually DROPS to 0.71-0.86 in all three seeds. Raw gap/std_all values order as k9(~0.81) < k8(~0.81-0.89) roughly tied, then k10(~0.92-0.96) and k11(~0.93-0.98) close together and higher, then k12(~0.70-0.80) drops back down near k8/k9 level.


Caveat before I over-read this: k=12's n_target is only 3 primes (window [60,260)) versus 5-10 for the other k values, so its std_target/gap are the noisiest numbers in the table -- I should not treat the k12 drop alone as strong evidence. But the shape across the full k8..k12 set (roughly flat-flat-high-high-drop, not a monotone ramp) is the real update: it means the earlier "grows with k" framing from cycles 42/43 was really just a two-point (k8,k10) observation, and now that I have filled in the neighbors, it does not look like a smooth function of k at all under this range-matching method.


This lines up with cycle 46's own warning: a single generic count-matched window can't separate value-of-k from position-in-that-k's-own-decay-curve (cycle 30 showed k=11's class gap shrinks well before its real cliff at p~760). Since k8/k10/k9/k11/k12 all used different, uncalibrated low/high bounds, the non-monotonic shape I just found could be telling me about window placement relative to each k's cliff just as much as about k itself. I don't have a way to calibrate that without knowing each k's real cliff location, which for most of these k values I don't have (only k=13 has real wall data, k=11's cliff is known from cycle 30, the rest are unmeasured). That's the honest limit of this method for now.