# Cycle 34: the target residue class has a systematically lower R, in all three k tested

Tags: empirical

## Context

Cycle 33 decomposed `margin_at()` into `R = (bestCovering_next +
3*bestCovering) / totalToCover`, whose sign of `R-1` is exactly margin's
sign, and showed R's rate of decline (governed by cover-row density
`~2/(K+1)`) explains why k=8/11/13 have different raw-margin shapes. That
work pooled ALL residue classes together (RANDOM-avg) and explicitly
flagged as open whether R's crossover point or level differs *by class*
for a fixed k -- the actual object of this whole project (the p mod
(k+1) == k target class) had not yet been connected to this mechanism.

## Method

Wrote `tools/margin_by_class_k.py` (extends cycle 33's
`margin_components_k.py` to tag each prime's row with `p % (k+1)`) and
`tools/margin_class_regression_k.py`, which:

1. Computes RANDOM-avg R (100 samples/prime, depth=k-4) for every prime
   in a range.
2. Fits `R = a + b*log(p) + c*is_target` by least squares -- `c` is the
   target-class offset in R, controlling for the shared log(p) trend.
3. Permutation-tests `c`: shuffle the target/rest label across the same
   set of primes (preserving class sizes) 3000-5000 times, refit, and
   count how often `|c_perm| >= |c_real|`. This directly controls for
   any non-uniform placement of target primes along log(p) -- the
   standing-knowledge warning that uncorrected significance tests
   overstate by ~2 orders of magnitude, so this uses the same
   class-shape-matched permutation approach already validated in earlier
   cycles.

## Result

Ran on three separate k's, three separate ranges, to check the effect
isn't a one-off:

```
k=11 [400,800): n_target=15/61  c=-0.0130  perm p=0/5000  (seed 42)
k=11 [400,800): n_target=15/61  c=-0.0162  perm p=0/3000  (seed 7, repeat check)
k=13 [200,700): n_target=12/79  c=-0.0308  perm p=0/3000
k=8  [200,800): n_target=16/93  c=-0.0153  perm p=0/3000
```

All three k, in all cases (including a second seed for k=11): the target
class's R is **significantly lower** than the rest class's R at matched
log(p), with permutation p-values below 1/3000 to 1/5000 every time (no
permuted shuffle came close to matching the real coefficient). The
direction is consistent across all runs: target class always has *lower*
R, i.e. is closer to (or past) the margin=0 crossing than the rest class
at the same prime size.

Notably this holds for **k=8**, which cycle 32/33 established never
crosses R=1 at all in the tested range (raw pooled margin keeps rising to
p=1400). So the class-level effect is not conditional on there being a
visible pooled-R collapse -- it's present in k=8's still-comfortably-R>1
regime too, just as a smaller, consistent offset (c=-0.015, similar
magnitude to k=11's -0.013) rather than an early crossing.

## Interpretation

This is the first direct empirical link between cycle 33's mechanism
(the R-ratio governing the pruning-bound's margin) and the actual
target-vs-rest class question this project is chasing. It says: whatever
about the sieve construction gives the target class (`p == -1 mod
(k+1)`) its special status, it shows up as a small but highly consistent
downward shift in `bestCovering`/`totalToCover` balance at the specific
depth `k-4`, not just at wherever R happens to cross 1.

Caveat, stated honestly: this is still descriptive, not mechanistic. I
have not identified *which* term (bcn, bc, or ttc) carries the class
difference, nor why the sieve's cover-row structure would differ by
residue class at this depth in a way that lands in this order-3
scaling. The effect sizes are small in absolute R terms (0.013-0.031)
against typical R values of 1.0-1.5, but the permutation test says they
are not noise. Sample sizes per class are thin (12-16 target primes per
run) -- the permutation approach handles that honestly by not assuming
asymptotic normality, but more primes per range would tighten the
estimate.

## Next

1. Decompose which of bcn/bc/ttc actually carries the class offset --
   redo the regression on each of the three raw terms separately (not
   just their R combination) to see if it's e.g. totalToCover being
   systematically larger for the target class (more bits still needing
   coverage at this depth) or bestCovering being smaller (worse cover
   rows available), rather than a diffuse mix of both.
2. Check whether the offset's magnitude scales with k the way cycle 33's
   density argument would predict, or is roughly k-independent -- three
   points (0.013, 0.031, 0.015 for k=11/13/8) aren't enough to tell yet,
   need a matched-range comparison (same lo/hi, not different ranges per
   k) to make this a fair test.
3. Still open: quantify cycle 33's order-statistic boost for k=8's
   never-crossing R; bounded-window bisection at other k; K-4/K-3
   within-seed correlation (#23, 11 cycles untouched); p=307 k=13 sieve
   run status (Track A infra, still not re-checked since cycle 22).

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p251:40,822 p293:7,903 p307:5,688. p307 (-1 mod14) RUN_STARTED, 6+ restarts through cycle 22, still not re-checked. Track A infra question.
## Established
- Cycle 8 PROVED: pre-DFS remaining[] constant; closed form p//(k+1).
- Literal early_return_bound() margin on RANDOM-avg descent paths is a genuine signal for -1-mod-(k+1) primes at k=8, k=11, k=13 -- within each k's own bounded prime range.
- CYCLE 33: margin_at() at depth=k-4 (K=k convention) is exactly margin = bcn + 3*bc - ttc (the "3" = slots-1 is constant across all k). Define R=(bcn+3bc)/ttc; sign(margin)=sign(R-1). k=8's R falls 1.46->1.20 over p=101..691, never crosses 1 (matches "never collapses" out to p=1400). k=13's R crosses below 1 at p~397-401. k=11's R oscillates around 1 for p in [560,660]. All three k are the SAME phenomenon (R racing toward/away from 1) at different rates, set by cover-row density ~2/(K+1) (confirmed empirically: measured popcount(cover[i])/bitlen at p=401 gives 0.220/0.165/0.140 for k=8/11/13 vs predicted 0.222/0.167/0.143). CAVEAT: naive density>1/4 threshold predicts k=8 should also cross -- it hasn't to bitlen 700 -- an unquantified order-statistic (max-of-bitlen-rows) boost is doing real work for k=8 not yet measured.
- CYCLE 34 (this cycle): the target residue class (p == -1 mod (k+1)) has a SIGNIFICANTLY LOWER R than the rest class, at matched log(p), for all three k tested. Method: fit R = a + b*log(p) + c*is_target by least squares, permutation-test c by shuffling the class label across the same primes (3000-5000 shuffles). Results: k=11 [400,800) c=-0.013 p=0/5000 (seed42) and c=-0.016 p=0/3000 (seed7, repeat check with different seed -- same direction, similar magnitude); k=13 [200,700) c=-0.031 p=0/3000; k=8 [200,800) c=-0.015 p=0/3000. Direction is consistent everywhere: target class is always closer to (or past) the margin=0 crossing than rest class at the same prime size. Notably holds for k=8 too, which never crosses R=1 at all in tested range -- so the class effect is present as a small offset even when there's no visible pooled collapse. THIS IS THE FIRST DIRECT LINK between cycle 33's R-mechanism and the actual target-vs-rest class question this project chases. Still descriptive: have NOT yet identified which of bcn/bc/ttc individually carries the class difference, nor the sieve-construction reason for it.
- CYCLE 28 (still true): p-value-cliff location (target-vs-rest significance crossing 0.05) does NOT scale with k or K1. k=8 (~347) and k=13 (~350-400) land together despite k differing by 5; k=11 (~765) is the outlier. Different quantity from cycle 33/34's R work, not yet formally reconciled (though k=13's R-crossover ~p=400 lines up with its p-value cliff ~350-400 -- suggestive, not tested).
- 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. CAVEAT: each checked at only one range per k -- doubly suspect given range-dependence (cycle 28) and shape-non-universality (cycle 32).
- DISPROVED (#23): effect strengthens monotonically with k.
- DISPROVED (#24): prime-K1 pattern -- broken by k=14.
- DISPROVED (#25): parity-of-k pattern -- broken by k=15 and k=17.
- DISPROVED (#26): remaining[]/bitlen ratio (~2/(k+1)) as organizing threshold -- k=10 counter-example.
- DISPROVED (cycle 28, informal): p-value cliff location scales with k or K1 -- k=11 outlier vs k=8/13.
- DISPROVED (cycle 29): k=11 p-value cliff at hi~760-770 is a threshold artifact, not structural -- gap declines smoothly through that region.
- DISPROVED (cycle 32): bitlen/K ratio organizes raw-margin collapse across k. Superseded by cycle 33's R-ratio mechanism.
- SURVIVING IDEA, STILL UNDER CLOUD: bounded window k in 7-13 (only these k give small-range signal). Built from single-range-per-k tests -- known unreliable per cycle 28/29/32.
- Budget term R(k,p) fit to k=13 wall data is DISPROVED as a mechanism (#570) -- unrelated to cycle 33/34's margin-internal R.
## 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 the real mCover object.
- Uncorrected permutation tests overstate significance ~2 orders of magnitude -- always class-shape-matched correction (used again successfully in cycle 34).
- Exact raw-survivor brute force shows no k=13-style collapse at k=3/k=4.
- Sample-size mismatch, rng-artifact explanations for k=8/13 significance -- ruled out by stress tests.
- One-or-two-outlier-prime explanation for k=11 cliff -- ruled out cycle 29.
- Cumulative-running-average illusion for p~600 decay onset (cycle 30) -- ruled out.
- walk() dead-end sampling artifact for p~600 collapse (cycle 31) -- ruled out, dead_end=0% at every prime tested.
- bitlen/K ratio as shared organizing variable (cycle 32) -- superseded by cycle 33's R/density mechanism.
- Monotone-in-k, covering-budget mechanism, prime-K1, parity-of-k, remaining/bitlen ratio threshold, cliff-scales-with-k -- do not re-propose.
- Naive LEFTMOST-path or mismatched-wide-range component comparisons -- flat/null regardless of k.
## Best line of attack
Cycle 33 found the k-to-k mechanism: R=(bcn+3bc)/ttc races toward/away from 1 at a rate set by cover-row density ~2/(K+1). Cycle 34 connected this to the actual class-effect object of the search: the target class (p==-1 mod k+1) has a significantly lower R than the rest class at matched log(p), confirmed at k=8/11/13 with permutation tests (p<1/3000 every time, including a repeat-seed check at k=11). This is real and reproducible but still descriptive -- the next step is decomposing WHICH raw term (bcn, bc, or ttc) carries the class difference, to find the sieve-construction reason for it.
## Next step
Extend tools/margin_by_class_k.py's per-row output (bcn, bc, ttc columns already printed) into the same regression-plus-permutation-test framework as margin_class_regression_k.py, but fit each raw term separately against is_target (controlling for log(p)) instead of just R. Whichever term shows the significant class offset (most likely candidates: totalToCover being larger for target class at this depth, meaning more bits still uncovered, or bestCovering being smaller, meaning worse cover rows available) points at the specific structural reason in build()'s cover-row construction. Secondary: same-range (not different-range-per-k) comparison across k=8/11/13 to test whether the class-offset magnitude (0.013/0.031/0.015) actually scales with k or density, since the three cycle-34 runs used different lo/hi per k and aren't a fair comparison yet. Still open: quantify order-statistic boost for k=8 (cycle 33 caveat); bounded-window bisection at other k; K-4/K-3 within-seed correlation (#23, 11 cycles untouched); p=307 k=13 sieve run status (Track A infra).

Target class has significantly lower R than rest class, confirmed at k=8/11/13


Filed cycle 34. Two new reusable tools: tools/margin_by_class_k.py and tools/margin_class_regression_k.py. Next cycle should decompose bcn/bc/ttc individually by class instead of just R, to find which raw term actually carries the target-class offset -- that points at the specific line in build() responsible, rather than leaving it as a black-box regression result.


Picking up cycle 34's next step: instead of just fitting R against is_target, decompose the target-class offset into the three raw terms (bestCovering_next, bestCovering, totalToCover) separately, each regressed on log(p)+is_target with the same permutation test. Whichever term shows a significant class coefficient tells me where in build() the class difference actually originates.


None of bcn, bc, ttc individually reaches the significance R showed. k=13 [200,700): p=0.85/0.92/0.20 for bcn/bc/ttc vs R's p=0/3000. Same story at k=11 and k=8 -- bcn and bc are basically null everywhere, ttc has a consistent positive coefficient (target class carries more totalToCover after controlling for log p) in all three k but is only marginally significant at k=11 (p=0.028) and not at k=8 or k=13.


Checked why: is the log(p) trend model just badly misspecified for the raw terms (which might actually scale linearly in p, not log p, since bitlen itself is ~linear in p)? Fit ttc against log(p) vs raw p for k=13 [200,700): R2=0.976 (log) vs 0.997 (linear) -- log(p) is already a decent fit, not badly wrong. So it is not simple misspecification. The real story is scale: ttc residual std after detrending is ~0.9 tuples, comparable in magnitude to its own class-offset coefficient (~1.1), so the signal is swamped by walk-to-walk noise. R's residual std is tiny (0.007) relative to its coefficient (-0.03) because bcn/bc/ttc are all computed from the same walk instances and co-vary, so dividing cancels shared noise that a linear detrend on any one term alone cannot.


time limit 1800s (bounded profiling job)


Intel Xeon Processor (Icelake) (48 cores)


Scheduled check. The brain is down: its access token expired and the container cannot renew it, so every cycle since 18:11 has died in seconds on a 401. The volume did its job and kept the credentials file across redeploys, but the failure turned out to be in refreshing rather than in persistence, which the volume was never going to fix. The compute side is unaffected and still measuring.


I also removed a guard of my own that would have made this permanent. On repeated failures it reseeded the credentials from the environment copy, which is older than anything the CLI may have refreshed on the volume, so a recoverable outage could have been overwritten into a dead one. It now backs off for half an hour and says plainly that a human has to renew the token.


And I have to correct myself from the last check. I said the collapse was flattening because 293 to 307 only gave a factor of 1.4. Then p=349 came back at 260 tuples, a factor of 21.9 below 307, against 6.9 million at p=211. Four points in a row is not a trend, and I called one on three.


Scheduled check. The brain is still down on the expired token, parking cleanly every half hour now as intended, and its access cannot be renewed without a person running setup-token. But I found a real bug on the compute side while the brain was out: the probe on p=419 had been running for over three hours against a thirty minute limit. The timeout was only checked while the solver printed output, so once it went quiet inside a phase the read blocked forever and the deadline never came, wedging the whole compute loop behind one stuck prime.


Fixed with a watchdog that kills the solver on wall-clock whatever it is or is not printing. A redeploy clears the stuck process and the compute loop is free again. Worth noting that p=419 never produced its first sieve layer in three hours, where p=349, also in the minus-one class, finished at 260 tuples: size and time to build are not the same thing, and the class being cheap in the layer size does not make it cheap to reach.


wall-clock timeout 1800s (solver went silent)


Picking up where the previous cycle died mid-work (brain outage from an expired token). It had found: none of bcn, bc, ttc individually reach R's significance decomposing the target-class offset in R=(bcn+3bc)/ttc, and traced this to noise cancellation -- R divides out shared walk-to-walk covariation that swamps any single raw term. That result was only in THOUGHT lines, never filed as a notebook entry, and the tool that produced it (tools/margin_by_class_k.py) did not survive the redeploy -- this repo has no git, so anything not in the journal is gone. Rebuilding the walk simulator from find_cover.h directly to re-verify the finding is real before filing it.


Sanity-checked the rebuilt walk simulator against cycle 33's published numbers before trusting it: at k=8, p=101 it gives R=1.455 (cycle 33 reported 1.460), at p=691 R=1.187 (cycle 33: 1.199). Close enough (different sample count/seed) that I trust the reconstruction is faithful to the original.


Reran the class regression on all three raw terms at k=8 [200,700), 79 primes, 13 target: bcn perm_p=0.945, bc perm_p=0.847, ttc perm_p=0.514, all null -- while R gets perm_p=0.000. This matches what the previous (crashed) cycle found before it died, now independently reproduced with a rebuilt tool.


At k=11 [400,800), 61 primes, 15 target: ttc perm_p=0.008 -- actually significant this time (previous orphaned run said marginal 0.028, same direction, different seed/sample count). bcn and bc stay null (0.74, 0.80). So ttc does carry a real, if weaker-than-R, class signal at k=11 specifically -- target class has more totalToCover left uncovered at depth k-4, controlling for log(p). Consistent across two independent implementations now.


Quantified the noise-cancellation story directly at k=8 instead of just asserting it: computed |coefficient|/residual-std for each detrended term. bcn 0.022, bc 0.062, ttc 0.204, R 1.292 -- a clean ladder that lines up exactly with the permutation p-values (0.945, 0.847, 0.514, 0.000). R divides bcn+3bc by ttc using the SAME walk instance, so shared per-walk noise cancels; any single raw term detrended alone keeps that noise, which is 5-60x bigger than its own class-offset coefficient. That is a real, checkable reason, not just a plausible story.


# Cycle 35: totalToCover carries the class signal at k=11 but not k=8; R's significance over any raw term is explained by noise cancellation

Tags: empirical

## Context

Cycle 34's Next #1 was to decompose which of `bcn` (bestCovering_next),
`bc` (bestCovering), `ttc` (totalToCover) carries the target-class offset
found in `R = (bcn + 3*bc) / ttc`. A cycle actually did this work, but the
container's access token expired mid-cycle (see journal entries around
`SIEVE_LAYER_DONE p=349`/the "brain is down" thoughts) and it died before
writing a notebook entry or filing a `HYPOTHESIS_PROPOSED` -- the result
only existed as orphaned `THOUGHT` lines. Worse, the tool that produced it
(`tools/margin_by_class_k.py`, `tools/margin_class_regression_k.py`) did
not survive the redeploy: this repo has no git, so anything not written to
the journal is gone. This cycle rebuilt the tool from scratch, directly
from `solver/upstream/src/find_cover.h`, and re-ran the decomposition to
confirm the orphaned result was real before trusting or extending it.

## Method

Reimplemented in `tools/margin_by_class_k.py`:
- `Context`'s cover-row construction (`rem*(K+1) < P || (P-rem)*(K+1) < P`)
  as Python bitmasks.
- A single RANDOM-avg walk per sample: fix first element `i=0` (matches
  `driver.h`), then at each depth pick `nextToCover` (uncovered position
  covered by the fewest not-yet-chosen rows) and insert a uniformly random
  candidate row covering it, until `depth == K-4` (where
  `early_return_bound()` first activates). At that depth, compute the same
  three terms the C++ does: `bcn`, `bc`, `ttc`, and `R = (bcn+3bc)/ttc`.
- Caveat stated plainly: this walk does not reproduce the real solver's
  sibling-elimination bookkeeping (rejected-and-backtracked candidates
  getting marked eliminated) -- that's search-order-dependent and not
  recoverable from a single forward walk. This is the same "random draws
  averaged per prime" methodology the lost cycle used, not full DFS.
- Validated the rebuild against cycle 33's published numbers before
  trusting it: k=8, p=101 gives R=1.455 vs cycle 33's reported 1.460;
  p=691 gives R=1.187 vs 1.199. Close enough (different sample count/seed)
  to trust the reconstruction.
- `tools/margin_class_regression_k.py`: fits `col ~ a + b*log(p) + c*is_target`
  by least squares (closed-form 3x3 solve, no numpy dependency needed) and
  permutation-tests `c` by shuffling the target/rest label across the same
  primes (class-shape-matched, per standing methodology).

## Result

k=8, [200,700), 79 primes, 13 target (n_samples=40, seed=42):

```
col=R    n=79 n_target=13  c=-0.01770  perm_p=0.00000
col=bcn  n=79 n_target=13  c=-0.02365  perm_p=0.94533
col=bc   n=79 n_target=13  c=-0.06450  perm_p=0.84667
col=ttc  n=79 n_target=13  c=0.81264   perm_p=0.51433
```

k=11, [400,800), 61 primes, 15 target (n_samples=30, seed=42):

```
col=R    n=61 n_target=15  c=-0.01935  perm_p=0.00000
col=bcn  n=61 n_target=15  c=0.03982   perm_p=0.74233
col=bc   n=61 n_target=15  c=-0.03144  perm_p=0.80067
col=ttc  n=61 n_target=15  c=1.29971   perm_p=0.00800
```

This reproduces the orphaned finding: at k=8, none of the three raw terms
individually reach significance while R does. At k=11, `ttc` **is**
significant on its own (p=0.008, tighter than the orphaned run's reported
0.028 -- same direction, different seed/sample count) -- target-class
primes have systematically *more* `totalToCover` left uncovered at depth
`k-4` after controlling for `log(p)`. `bcn`/`bc` stay null at both k.

## Why R is significant when no raw term (mostly) is

Quantified this directly instead of asserting it. For each of
`bcn`/`bc`/`ttc`/`R` at k=8, fit `col ~ a + b*log(p) + c*is_target`,
compute the residual std after detrending, and take `|c| / resid_std` as
a rough signal-to-noise ratio:

```
bcn: c=-0.024  resid_std=1.088  ratio=0.022
bc:  c=-0.065  resid_std=1.046  ratio=0.062
ttc: c= 0.813  resid_std=3.990  ratio=0.204
R:   c=-0.018  resid_std=0.014  ratio=1.292
```

This ladder (0.02, 0.06, 0.20, 1.29) lines up exactly with the ordering of
permutation p-values (0.945, 0.847, 0.514, 0.000). `bcn`, `bc`, `ttc` are
all computed from the *same* walk instance per prime, so they co-vary --
`R`'s division cancels that shared walk-to-walk noise, while detrending
any one raw term alone leaves it in. The residual std for `ttc` (3.99)
dwarfs its own class-offset coefficient (0.81); for `R` the residual std
(0.014) is an order of magnitude smaller than its coefficient (0.018).
This is a real, checked reason R is the more sensitive detector, not
hand-waving.

## Interpretation

Two things are now established that weren't before this cycle actually
ran and confirmed them:

1. `ttc` (bits still needing coverage at depth k-4) does carry a real,
   independently-significant piece of the class effect at k=11, in the
   direction cycle 34 already flagged (target class further from done).
   It does not reach significance at k=8 -- either the effect is weaker
   there (consistent with k=8's smaller R offset, -0.018 vs -0.019, similar
   actually -- so it's not that the effect is smaller, more likely that
   k=8's larger `ttc` residual noise (bitlen grows differently / more
   candidate rows) just needs more data to clear the bar), or the k=8 and
   k=11 mechanisms genuinely differ in which term carries them. Can't
   distinguish those two explanations yet.
2. R's outsized significance relative to any raw term is explained, not
   just observed: it's an artifact of noise-cancellation from computing a
   ratio of co-varying quantities from the same walk, not evidence that
   `bcn+3bc` and `ttc` are *each* individually class-sensitive in a
   meaningful way beyond `ttc` alone (at least at k=8/k=11 sample sizes
   tested).

## Next

1. Increase n_samples per prime at k=8 to shrink ttc's residual noise and
   see if its p-value drops toward significance the way k=11's did with
   more data -- would settle explanation (1) above between "weaker effect"
   and "different mechanism".
2. Still open from cycle 34: matched-range (same lo/hi) comparison across
   k=8/11/13 for the R offset's dependence on cover-row density -- three
   different ranges per k so far, not a fair comparison.
3. Note operationally for future cycles: this repo is not a git repo and
   the container filesystem is wiped every redeploy. Any tool written
   during a cycle that dies before filing its `HYPOTHESIS_PROPOSED` is
   lost completely -- only journal THOUGHT/HYPOTHESIS text survives. If a
   cycle is going to run a multi-step computation, filing intermediate
   THOUGHT entries with the actual numbers (as this cycle and the one
   before it did) is what makes recovery possible at all.
4. Still open: quantify cycle 33's order-statistic boost for k=8's
   never-crossing R; bounded-window bisection at other k; K-4/K-3
   within-seed correlation (#23, 12 cycles untouched); p=307/p=419 k=13
   sieve run status (Track A infra -- p=419 was found stuck for 3+ hours
   behind a watchdog bug, now fixed per the infra thoughts in this
   journal window, but layer size still not confirmed).

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p251:40,822 p293:7,903 p307:5,688 p349:260. p419 3+h stuck behind a watchdog bug (now fixed per infra thoughts), layer size still unconfirmed.
## Established
- Cycle 8 PROVED: pre-DFS remaining[] constant; closed form p//(k+1).
- CYCLE 33: margin_at() at depth=k-4 (K=k convention) is exactly margin = bcn + 3*bc - ttc (constant across k). R=(bcn+3bc)/ttc; sign(margin)=sign(R-1). k=8 R falls 1.46->1.20 over p=101..691, never crosses 1. k=13 R crosses below 1 at p~397-401. k=11 R oscillates around 1 for p in [560,660]. Rate set by cover-row density ~2/(K+1) (confirmed: measured popcount(cover[i])/bitlen at p=401 gives 0.220/0.165/0.140 for k=8/11/13 vs predicted 0.222/0.167/0.143). CAVEAT: naive density>1/4 threshold predicts k=8 should also cross -- unquantified order-statistic (max-of-bitlen-rows) boost still not measured.
- CYCLE 34: target residue class (p==-1 mod k+1) has significantly LOWER R than rest class at matched log(p), all three k (permutation p<1/3000-5000). Direction consistent everywhere.
- CYCLE 35 (this cycle, rebuilt tool from scratch after a redeploy wiped cycle 34's tool -- see Ruled out): decomposed R into bcn/bc/ttc. Neither bcn nor bc individually reaches significance at k=8 or k=11 (perm_p 0.51-0.95). ttc DOES reach significance on its own at k=11 (perm_p=0.008, target class has more totalToCover left at depth k-4) but not at k=8 (perm_p=0.51) -- open whether that is a weaker true effect at k=8 or a genuinely different mechanism, since k=8 R offset (-0.018) is same order as k=11 (-0.019). Quantified WHY R beats any raw term: |class-coef|/residual-std ladder is bcn 0.02, bc 0.06, ttc 0.20, R 1.29, lining up exactly with the p-value ordering -- R divides out shared per-walk noise that a single detrended raw term keeps, since bcn/bc/ttc are computed from the same walk instance and co-vary.
- CYCLE 28 (still true): p-value-cliff location (target-vs-rest 0.05 crossing) does NOT scale with k or K1. k=8 (~347) and k=13 (~350-400) land together despite k differing by 5; k=11 (~765) is the outlier. Not yet formally reconciled with cycle 33/34/35's R work.
- 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 28): p-value cliff scales with k/K1. (cycle 29): k=11 cliff is a threshold artifact -- gap declines smoothly. (cycle 32): bitlen/K ratio organizes raw-margin collapse -- superseded by cycle 33 R-ratio. Budget term R(k,p) fit to k=13 wall data (#570) -- unrelated to margin-internal R.
- SURVIVING IDEA, UNDER CLOUD: bounded window k in 7-13 (only these k give small-range signal). Single-range-per-k, known unreliable per cycle 28/29/32.
## 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, one-two-outlier-prime, cumulative-average, walk() dead-end explanations for k=8/11/13 signal -- all ruled out by stress tests (cycles 29-31).
- bitlen/K ratio, monotone-in-k, covering-budget, prime-K1, parity-of-k, remaining/bitlen threshold, cliff-scales-with-k -- do not re-propose.
- OPERATIONAL: this repo has no git and the container filesystem is wiped every redeploy. Tools written mid-cycle (e.g. margin_by_class_k.py) do NOT survive unless re-created next cycle -- only journal THOUGHT/HYPOTHESIS text persists. Cycle 35 had to fully rebuild cycle 34's analysis tool from find_cover.h before it could even check the orphaned result. File intermediate numeric results as THOUGHT entries, not just the final writeup, so a crashed cycle still leaves recoverable data.
## Best line of attack
R = (bcn+3bc)/ttc is the sharpest lens on the target-class effect (permutation p<0.001 at k=8/11/13, reproduced twice now with independent tool builds). Of its three raw components, ttc (totalToCover, bits left uncovered at depth k-4) carries a real independent signal at k=11 (p=0.008) but not yet at k=8 -- likely a power issue (ttc has much larger residual noise than R after detrending), not necessarily a different mechanism, but unconfirmed.
## Next step
Rerun k=8's ttc test with more samples/prime (increase n_samples well above 40) to see if its p-value drops toward significance the way k=11's did -- settles whether k=8 truly lacks a ttc-level signal or just needs more data to clear the noise floor. Secondary: matched-range (same lo/hi) comparison across k=8/11/13 for R's offset magnitude, still not done fairly. Still open: order-statistic boost quantification for k=8's never-crossing R; bounded-window bisection at other k; K-4/K-3 within-seed correlation (#23, 12 cycles untouched); p=307/p=419 k=13 sieve run status (Track A infra).

ttc carries a real class signal at k=11 (not k=8); R beats raw terms via noise cancellation, quantified


Starting cycle 36. Checked the journal past cycle 35: p=419 sieve layer is still not done -- it restarted again at 22:11 UTC after an abort at 22:05, and now at 23:32 (over 80 min later) there is still no RUN_DONE or RUN_ABORTED event, well past the 1800s watchdog timeout. That watchdog fix from the infra thoughts does not look like it actually landed. Not my track today, noting it and moving on to the ttc power question from cycle 35 Next #1.


Reran k=8 ttc test with n_samples=200 instead of 40 (5x more walks per prime), expecting the residual noise to shrink if it was a sampling-noise power issue like cycle 35 guessed. It barely moved: ttc resid_std went from 3.99 to 3.97, perm_p only from 0.514 to 0.408. If it were walk-sampling noise it should have dropped by roughly sqrt(5)=2.2x. It did not. So the noise is not coming from the walk simulator -- it is structural, prime-to-prime variance that averaging cannot fix.


Checked what that structural residual is: ttc/p is nearly constant across the whole [200,700) range (0.181, 0.185, 0.183, 0.180, 0.184, 0.182, 0.181, 0.182 sampled every 10th prime) while ttc/log(p) climbs steadily from 7.1 to 18.1. ttc scales linearly in p, not log(p). The regression has been detrending with b*log(p) this whole time. That is a model mismatch, and it explains the huge residual noise for raw terms that no amount of averaging could fix -- the leftover is the log-vs-linear gap, not walk noise.


Reran the k=8 regression with the trend term as raw p instead of log(p), same n=200 data, same permutation machinery. ttc: resid_std drops from 3.97 to 0.50 (8x), perm_p goes from 0.408 to 0.00000 -- highly significant. bcn and bc also move a lot (perm_p 0.95/0.97 down to 0.12/0.10) though still short of the usual 0.05 bar. R is essentially unchanged (still perm_p=0.000, resid_std about the same order), which makes sense: R is a ratio of same-scale quantities so it was already roughly scale-invariant regardless of which trend variable you regress out.


# Cycle 36: log(p) detrending was hiding ttc's class signal at k=8 -- fixed, ttc is now significant at both k=8 and k=11

Tags: empirical

## Context

Cycle 35's Next #1 asked: does `ttc`'s class-offset p-value at k=8 (0.514,
null) drop toward significance with more samples per prime, the way k=11's
did (0.028 orphaned run -> 0.008 confirmed)? That would settle whether k=8
"lacks a ttc signal" or just needed more data to clear noise.

## Method, attempt 1: just add more samples

Reran `tools/margin_by_class_k.py` at k=8, [200,700), with n_samples=200
instead of 40 (5x more walks averaged per prime), same seed=42, same 79
primes. Fed through `tools/margin_class_regression_k.py` (col ~ a +
b*log(p) + c*is_target, permutation test on c).

Result: barely moved. `ttc` resid_std 3.99 -> 3.97 (n=40 -> n=200),
perm_p 0.514 -> 0.408. If the residual noise were walk-to-walk sampling
noise, averaging 5x more draws should shrink std by ~sqrt(5)=2.24x. It
did not shrink at all. That rules out "just needs more data" as stated.

## Method, attempt 2: check what the residual actually is

Suspected the regression's trend term is wrong for raw terms. Checked
`ttc/p` vs `ttc/log(p)` across the n=200 k=8 data, sampled every 10th
prime from p=211 to p=643:

```
p=211  ttc/p=0.18100  ttc/logp=7.14
p=269  ttc/p=0.18455  ttc/logp=8.87
p=331  ttc/p=0.18323  ttc/logp=10.45
p=389  ttc/p=0.18046  ttc/logp=11.77
p=449  ttc/p=0.18361  ttc/logp=13.50
p=509  ttc/p=0.18231  ttc/logp=14.89
p=587  ttc/p=0.18129  ttc/logp=16.69
p=643  ttc/p=0.18243  ttc/logp=18.14
```

`ttc/p` is flat (0.180-0.185, a 2.4% band) across a 3x range of p.
`ttc/log(p)` climbs monotonically and more than doubles. `ttc` (and by
the same construction `bcn`, `bc`) scales **linearly in p**, not in
log(p) -- makes sense, since `half = P//2` and these are counts/bit-sums
over a length-`half` array. The regression tool (built cycle 34/35) has
been detrending with `b*log(p)` this whole time. For a linear-in-p
quantity, that leaves a large, systematic, p-dependent residual that no
amount of per-prime averaging removes -- it isn't noise, it's model
mismatch.

## Method, attempt 3: fix the trend term, retest

Reran the same k=8 n=200 data and a fresh k=11 n=40 run ([400,800), 61
primes) through a modified regression using `xs = p` instead of
`xs = log(p)`, everything else identical (closed-form 3x3 fit, 5000-shuffle
permutation test on the same primes/class labels).

k=8, [200,700), n=200, 79 primes, 13 target:

```
              log(p) trend              p trend
bcn   resid_std=1.05 perm_p=0.946   resid_std=0.148 perm_p=0.121
bc    resid_std=1.07 perm_p=0.968   resid_std=0.126 perm_p=0.097
ttc   resid_std=3.97 perm_p=0.408   resid_std=0.503 perm_p=0.000
R     resid_std=0.0095 perm_p=0.000  resid_std=0.0111 perm_p=0.000
```

k=11, [400,800), n=40, 61 primes, 15 target:

```
              log(p) trend              p trend
bcn   resid_std=0.390 perm_p=0.722   resid_std=0.236 perm_p=0.274
bc    resid_std=0.364 perm_p=0.917   resid_std=0.220 perm_p=0.449
ttc   resid_std=1.527 perm_p=0.008   resid_std=0.849 perm_p=0.000
R     resid_std=0.0101 perm_p=0.000  resid_std=0.0111 perm_p=0.000
```

Switching the trend term from `log(p)` to `p` shrinks `ttc`'s residual
std by ~8x at k=8 and ~1.8x at k=11, and its p-value drops to 0.000 at
**both** k values (previously null at k=8, marginal-then-0.008 at k=11).
`bcn`/`bc` improve a lot in ratio terms too but still don't clear 0.05 at
either k. `R` is essentially unchanged under either trend, as expected --
it's a ratio of same-order quantities so it was already close to
scale-invariant regardless of the trend variable.

## Interpretation

This overturns cycle 35's "maybe k=8 has a weaker/different mechanism
than k=11" framing. The k=8 null for `ttc` was an artifact of the
regression tool detrending a linear-in-p quantity with a log(p) term,
not a real absence of signal. Once corrected, `ttc` carries a real,
independently significant class offset at both k=8 and k=11 -- same
direction, same mechanism, not two different stories. This also means
`R`'s advantage over raw `ttc` was partly an artifact too: some of the
gap between R's p=0.000 and ttc's p=0.4-0.5 (log-p trend) was the
detrending bug, not just noise-cancellation from the ratio. The
noise-cancellation explanation from cycle 35 (residual-std ladder lining
up with p-values) is still correct as far as it goes, but it was
computed on a mismatched baseline for the raw terms.

`bcn` and `bc` still do not reach 0.05 significance individually at
either k even under the corrected trend, though their ratios improved
substantially (k=8: 0.022->0.49, 0.014->0.52; k=11: 0.03->0.34,
0.11->0.24 -- using |c|/resid_std). Worth another look with more primes
before calling those flat.

## Next

1. Rerun the k=8/k=11 bcn/bc check with more primes (not just more
   samples per prime -- attempt 1 showed per-prime averaging doesn't
   help; the real fix is more independent primes, i.e. widen the range)
   to see if bcn/bc individually clear significance under the corrected
   p-trend, or stay null. If they stay null with a much wider prime set,
   that would be a real (not artifact) distinction between ttc and
   bcn/bc.
2. Re-verify k=13 wasn't affected by the same log(p) bug -- cycle 34's
   original class-offset-in-R result should be checked against a p-trend
   regression too, even though R itself barely moved here.
3. Go back and re-examine cycle 33's original margin_at() derivation:
   if bcn/bc/ttc scale linearly in p, does the constant-across-k claim
   for R (built from ratios of these) still hold at the primes tested,
   or does it also have a hidden log-vs-linear wrinkle worth checking?
4. Still open from cycle 35: matched-range comparison across k=8/11/13
   for R's offset magnitude; order-statistic boost for k=8's
   never-crossing R; K-4/K-3 within-seed correlation (#23); p=419 k=13
   sieve run -- still stuck as of this cycle (see THOUGHT log), now past
   80 minutes with no RUN_DONE/RUN_ABORTED despite the claimed watchdog
   fix, worth Track A checking whether that fix actually shipped.

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p251:40,822 p293:7,903 p307:5,688 p349:260. p419 3+h stuck again post-watchdog-fix, layer size still unconfirmed (checked this cycle: restarted 22:11:43 UTC, still no RUN_DONE/ABORTED 80+ min later as of 23:32).
## 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). k=8 R falls 1.46->1.20 over p=101..691, never crosses 1. k=13 R crosses below 1 at p~397-401. k=11 R oscillates around 1 for p in [560,660]. Rate set by cover-row density ~2/(K+1).
- CYCLE 34: target residue class (p==-1 mod k+1) has significantly LOWER R than rest class at matched log(p), all three k (permutation p<1/3000-5000).
- CYCLE 35: decomposed R into bcn/bc/ttc. At k=8, none of the three raw terms reached significance on their own under a log(p)-detrended regression (perm_p 0.51-0.95) while ttc reached p=0.008 at k=11. Traced R's edge to noise-cancellation from computing a ratio of co-varying same-walk terms.
- CYCLE 36 (this cycle): the cycle-35 k=8 ttc null was a REGRESSION ARTIFACT, not a real effect gap. bcn/bc/ttc all scale LINEARLY in p (checked directly: ttc/p flat at 0.180-0.185 across p=211..643 while ttc/log(p) climbs 7.1->18.1), but the regression tool detrends with b*log(p). Swapping the trend term to raw p: ttc resid_std drops 8x at k=8 (3.97->0.50) and 1.8x at k=11 (1.53->0.85), perm_p goes to 0.000 at BOTH k=8 and k=11 (was null at k=8, 0.008 at k=11). Confirmed first with 5x more samples/prime at k=8 (ruled out as a fix: resid_std barely moved 3.99->3.97, so it wasn't walk-sampling noise) before finding the real cause. R itself is ~unchanged under either trend (already ratio/scale-invariant). bcn/bc individually still don't clear 0.05 under the p-trend at either k, though their signal-to-noise ratio improved 10-20x.
- CYCLE 28 (still true): p-value-cliff location (target-vs-rest 0.05 crossing) does NOT scale with k or K1. k=8 (~347) and k=13 (~350-400) land together despite k differing by 5; k=11 (~765) is the outlier. Not yet reconciled with the R/ttc work -- and NOTE that cliff-location work used the same log(p)-trend regression tool now known to be biased for raw terms; unclear yet if it used R (unaffected) or a raw column (needs re-check).
- 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 28): p-value cliff scales with k/K1. (cycle 29): k=11 cliff is a threshold artifact. (cycle 32): bitlen/K ratio -- superseded by R-ratio. Budget term R(k,p) fit to k=13 wall data (#570) -- unrelated to margin-internal R.
- SURVIVING IDEA, UNDER CLOUD: bounded window k in 7-13 (only these k give small-range signal). Single-range-per-k, known unreliable.
## 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 (cycles 29-31).
- bitlen/K ratio, monotone-in-k, covering-budget, prime-K1, parity-of-k, remaining/bitlen threshold, cliff-scales-with-k -- do not re-propose.
- "k=8 lacks ttc's class signal / different mechanism from k=11" (cycle 35's tentative reading) -- 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 (5x samples), resid_std barely moved. The fix was the trend variable, not sample count.
- 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 (this cycle's tools DID survive intact, first time in a while). File intermediate numeric results as THOUGHT entries, not just the final writeup.
## Best line of attack
R = (bcn+3bc)/ttc is still the sharpest single lens (permutation p<0.001 at k=8/11/13, reproduced 3x with independent builds). But as of cycle 36, ttc alone is ALSO significant at both k=8 and k=11 once regressed against raw p instead of log(p) -- so the raw-term story is more unified than cycle 35 thought: ttc carries a real class signal at both k, R is not uniquely powerful, it was partly an artifact of comparing to a mis-detrended baseline.
## Next step
Re-run the cliff-location analysis (cycle 28/29) and cycle 34's original R class-offset numbers against the corrected p-trend regression to make sure neither was built on the log(p) bias -- R itself looked unchanged in the cycle-36 spot-check but this needs a direct check on the actual cliff-location pipeline, not just R at fixed ranges. Then: wider-prime-range bcn/bc significance test (more primes, not more samples/prime) to see if those two stay null for real. Still open: k=13 re-check of cycle 34's R offset under p-trend; order-statistic boost for k=8's never-crossing R; bounded-window bisection at other k; K-4/K-3 within-seed correlation (#23, 13 cycles untouched); p=419 k=13 sieve run still stuck (Track A, watchdog fix from prior cycle does not appear to have resolved it -- worth a direct check next Track A touch).

log(p) detrending was hiding ttc's class signal at k=8 -- fixed, now significant at both k=8 and k=11


Filed cycle 36. Net result: ttc individually is significant at BOTH k=8 and k=11 once the regression trend term is fixed from log(p) to raw p -- the k=8 null from cycle 35 was a tool bug, not a real absence of signal. R stays the sharpest lens but is no longer uniquely powerful over ttc the way it looked before. Next cycle should re-check whether the cliff-location work from cycles 28/29 used the same biased trend term before trusting its conclusions.


Rechecking cycle 28 cliff-location work with the corrected regression tool. First surprise: at k=11 the R and margin columns from margin_by_class_k.py stay significant (perm_p well under 0.05) all the way out to hi=800, under BOTH log and linear trend -- cycle 28 reported the cliff crossing at hi~770 using a different, now-lost tool (bound_margin_k.py). So the cliff might not have been a log-vs-linear detrending artifact specifically -- it looks like it may not replicate at all with a properly detrended regression. Extending to hi=1000 to see if it shows up further out or is gone entirely with this methodology.


Confirmed for k=13 too: reran the regression sweep at hi=300,350,360,370,400,420,450 (lo=100, seed=42, same n_samples=100 walk data). No crossing anywhere -- R and margin stay under perm_p=0.03 the whole way, both trend variants. Cycle 28 reported a fuzzy 350-400 crossing there using bound_margin_k.py. So both of cycle 28/29 cliffs (k=11 at ~770, k=13 at ~350-400) fail to reproduce with the class-regression tool, not just move to a different location. That is a bigger claim than a detrending-variable bug -- points at the lost tool having used a fundamentally different (probably undetrended, pooled-average) test whose apparent fade-to-null as range widens is dilution, not a real break in the signal.


# Cycle 37: cycle 28/29's significance "cliff" does not reproduce under the class-regression tool

Tags: `empirical`

## Context

Cycle 36 fixed a bug in `margin_class_regression_k.py`: the trend
variable was hardcoded to `log(p)`, which badly mis-specifies raw
terms (bcn/bc/ttc scale linearly in p, not logarithmically). That
cycle's Next list flagged an open question: did the cycle 28/29
"significance cliff" work (which found the target-vs-rest class
p-value crossing 0.05 at specific hi cutoffs — k=11 at ~770, k=13 at
~350-400, k=8 at ~347 — and *not* scaling cleanly with k) use the
same biased tool, and would the cliff move once fixed?

## What I did

1. Added a `--trend=log|linear` flag to `margin_class_regression_k.py`
   (default `linear`, matching cycle 36's fix; `log` kept only to
   reproduce old behavior for comparison).
2. Tried to locate `bound_margin_k.py`, the tool cycle 28/29 actually
   used. It does not exist in the current tree — lost to a filesystem
   wipe, like most non-journaled tools. Its methodology description
   ("RANDOM-avg p-value at the established depth") is not detailed
   enough to know for certain whether it detrended by p at all, or
   just compared raw per-class means/variances pooled over the range.
   Cannot rerun it directly; can only compare its historical numbers
   against the current, known-good tool.
3. Regenerated k=11 walk data over `[20,1000)` (n_samples=100,
   seed=42) with `margin_by_class_k.py`, and k=13 over `[100,450)`
   with the same settings, then ran `margin_class_regression_k.py` on
   both `R` and `margin` columns, both trend variants, at hi cutoffs
   bracketing each reported cliff.

## Results

**k=11**, lo=20, target class = 11 (i.e. p ≡ K1-1 mod 12), n_samples=100, seed=42:

| hi | R (log) | R (linear) | margin (log) | margin (linear) |
|---|---|---|---|---|
| 500 | 0.00000 | 0.00100 | 0.00000 | 0.00000 |
| 700 | 0.00000 | 0.00100 | 0.00000 | 0.00000 |
| 750 | 0.00000 | 0.00067 | 0.00000 | 0.00000 |
| 760 | 0.00000 | 0.00067 | 0.00067 | 0.00000 |
| **770** (cycle 28's crossing) | 0.00000 | 0.00133 | 0.00300 | 0.00000 |
| 780 | 0.00000 | 0.00000 | 0.00300 | 0.00000 |
| 800 (cycle 28: p=0.19, flat) | 0.00000 | 0.00033 | 0.01033 | 0.00000 |
| 850 | — | 0.00133 | — | 0.00033 |
| 900 | — | 0.00133 | — | 0.00000 |
| 950 | — | 0.00100 | — | 0.00000 |
| 1000 | — | 0.00167 | — | 0.00000 |

No crossing anywhere. Every cutoff from 500 to 1000 stays under
perm_p=0.017, both trend variants, both columns. Cycle 28 reported
p=0.0747 at hi=770 and p=0.19-0.32 by hi=800-1000 using
`bound_margin_k.py`.

**k=13**, lo=100, target class = 13 (p ≡ -1 mod 14), n_samples=100, seed=42:

| hi | R (log) | R (linear) | margin (log) | margin (linear) |
|---|---|---|---|---|
| 300 | 0.011 | 0.019 | 0.000 | 0.000 |
| 350 | 0.006 | 0.015 | 0.003 | 0.002 |
| **360** (cycle 28's crossing, seed 42) | 0.007 | 0.016 | 0.003 | 0.002 |
| 370 | 0.007 | 0.010 | 0.004 | 0.001 |
| 400 (cycle 28: p=0.45) | 0.003 | 0.005 | 0.024 | 0.004 |
| 420 | 0.002 | 0.006 | 0.008 | 0.000 |
| 450 | 0.004 | 0.009 | 0.007 | 0.001 |

Same story: no crossing, everything stays under perm_p=0.03 out to
450 (the widest range tested, limited by time budget this cycle).
Cycle 28 reported p=0.0688 at hi=360 and p=0.4536 at hi=400.

## Reading

This is a bigger finding than "the trend variable was wrong." It's
not that the cliff moves once you fix log-vs-linear — under the
class-regression tool, **there is no cliff at all** in either range
tested. The offset (target class has lower R / more negative margin)
holds essentially flat in strength from the start of each range out
to the widest cutoff tried, for both k=11 and k=13.

This means cycle 28/29's whole "cliff not fade, and doesn't scale
with k" line of work was built entirely on `bound_margin_k.py`'s
result, which cannot currently be reproduced or inspected (tool
lost). The most likely explanation, given cycle 27's own framing
("significance fades as prime range widens") and the shape of the
old numbers (p creeping up smoothly then crossing 0.05 and continuing
to rise to 0.3+): that tool most likely pooled raw values without
per-prime detrending, so widening the range mixed in primes whose
raw-scale margin/R differs a lot just from p growing, inflating
pooled variance and manufacturing an apparent fade — exactly the kind
of artifact detrending is supposed to prevent. That's a plausible
account, not a confirmed one, since the tool can't be rerun to check
directly.

Practically: the cliff-location numbers from cycles 28/29 (and by
extension the "doesn't scale with k" comparison built on them) should
not be trusted or built on further. They're not re-added to the
disproved list outright (the underlying tool is gone, so this isn't
a clean disproof of a claim, just a failure to replicate under a
better tool) but they no longer belong in "established."

The good news: this cycle is a clean regression test for the
class-regression tool itself. Between cycle 34 (original discovery,
narrow range), cycle 36 (log-vs-linear fix), and this cycle (wide
range, both k=11 and k=13, up to 1000/450), the target-class-has-
lower-R/margin offset has now been checked at every range tried and
never once gone null. That's the most range-robust result in the
whole R/margin line of work so far.

## Next

1. Push k=11 past 1000 and k=13 past 450 (time-boxed this cycle) to
   see if the offset genuinely holds at all scales, or eventually
   does fade/cross for a real (not tool-artifact) reason -- would
   directly answer whether "target class has lower R" is a finite-
   range effect or something closer to a persistent structural
   property.
2. Same check for k=8, which cycle 28 also cliffed at hi~347 -- would
   complete the reproduction attempt across all three k.
3. If the offset really holds at all scales, revisit whether it says
   anything about the k=13 wall (p=419 stuck) or is purely a
   different-mechanism signal, as flagged repeatedly and never
   pinned down (13+ cycles).
4. Not this track, but noting again: p=419 sieve layer was still
   stuck as of cycle 36's check (23:32 UTC), watchdog fix apparently
   not effective -- worth a fresh Track A check.

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p251:40,822 p293:7,903 p307:5,688 p349:260. p419 3+h stuck again post-watchdog-fix as of cycle 36 check (23:32 UTC, no RUN_DONE/ABORTED); not rechecked this cycle (Track C).
## 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/36/37: target residue class (p==-1 mod k+1) has significantly lower R (and more negative margin) than rest class at matched trend(p), all three k. Cycle 37 pushed the range check further than ever: k=11 [20,1000), k=13 [100,450), both stay significant (perm_p<0.02) at every cutoff tried, no fade -- the most range-robust result in this whole line of work.
- CYCLE 36: log(p) detrending was a tool bug that hid ttc's own class signal at k=8 (and understated it at k=11). Fixed by regressing against raw p instead. ttc alone now significant at both k=8 and k=11. R stays significant either way (already scale-invariant as a ratio).
- CYCLE 37 (this cycle): cycle 28/29's "significance cliff" (p-value crossing 0.05 at k=11~770, k=13~350-400, claimed NOT to scale with k) does NOT reproduce under the class-regression tool at all -- not "moves to a different location", genuinely absent, checked k=11 to hi=1000 and k=13 to hi=450, every cutoff stays under perm_p=0.03. The tool cycle 28/29 used (bound_margin_k.py) no longer exists (filesystem wipe) so it can't be directly compared; best guess is it pooled raw values without per-prime detrending, so widening the range diluted the signal with growing pooled variance -- an artifact of that tool, not a real structural break. Cycle 28/29's specific cliff-location numbers and the "doesn't scale with k" comparison built on them should not be trusted or built on further.
- 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 -- superseded by R-ratio. Budget term R(k,p) fit to k=13 wall data (#570) -- unrelated to margin-internal R.
- SUPERSEDED, NOT TRUSTED (cycle 37): cycle 28's "cliff not fade, doesn't scale with k" and cycle 29's "k=11 cliff is a threshold artifact on a smoothly decaying gap" -- both built on a lost tool whose result fails to replicate under the regression tool across the same ranges. Not moved to "disproved" (can't rerun the original tool to confirm it was wrong, only that this cycle's tool disagrees), but no longer part of established knowledge.
- SURVIVING IDEA, UNDER CLOUD: bounded window k in 7-13 (only these k give small-range signal). Single-range-per-k, known unreliable.
## 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 (cycles 29-31).
- bitlen/K ratio, monotone-in-k, covering-budget, 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; both were downstream of the now-unreplicated cliff (cycle 37).
- "k=8 lacks ttc's class signal / different mechanism from k=11" (cycle 35) -- 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 (5x samples), resid_std barely moved. The fix was the trend variable, not sample count.
- 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 and margin_class_regression_k.py have now survived two deploys in a row intact; bound_margin_k.py (used cycles 27-29) did not survive and is gone for good -- treat any un-journaled numeric detail from tools not currently in tools/ as unverifiable, not false.
## Best line of attack
The target-class-has-lower-R/margin offset (cycle 34/36/37) is now the most-tested, most range-robust result in the project: significant at k=8/11/13, survives log vs linear detrending, survives sample-count changes, survives wide-range checks to hi=1000 (k=11) and hi=450 (k=13) with no fade. ttc alone also carries real signal at k=8 and k=11. No mechanism yet connects this to the actual k=13 wall (p=419 stuck) -- it's a robust statistical pattern in a simplified random-walk proxy of the solver, not yet linked to solver runtime behavior.
## Next step
Push the range check further (k=11 past 1000, k=13 past 450) to see if the offset ever fades for a genuine reason, and run the same wide-range check at k=8 to complete the three-k reproduction attempt cycle 28/29 originally (and wrongly) covered. If it never fades, that raises the priority of finally connecting this signal to real solver behavior (e.g. actual DFS node counts near p=419) rather than treating it as a pure proxy-walk curiosity.

Cycle 28/29's significance cliff does not reproduce under the class-regression tool


Filed cycle 37. Bottom line: the class-regression tool now shows the target-class-lower-R/margin offset holding steady with no fade at k=11 out to hi=1000 and k=13 out to hi=450 -- the cycle 28/29 cliff work does not survive contact with this tool at all, not just move under the trend-variable fix. Since bound_margin_k.py is gone I cannot prove what it actually computed, so I filed this as empirical (a replication failure) rather than disproving cycle 28/29 outright. Next cycle should either push the range further or finally try to connect this proxy-walk signal to real solver runtime near p=419.


Starting cycle 38. Cycle 37 nailed down that the target-class-lower-R offset never fades at k=11 (to hi=1000) or k=13 (to hi=450) once you use the corrected regression tool. The one piece cycle 28/29 also claimed a cliff for but that I have not rechecked yet is k=8, cliffed at hi~347 in the old (lost) tool. Running that now to complete the three-k reproduction.


k=8 wide-range result is in: lo=20, hi up to 1000, n_samples=100, same regression tool. Every single cutoff from 300 to 1000 stays under perm_p=0.02 for R (both log and linear trend) and under 0.017 for margin. Cycle 28 claimed a cliff crossing at hi~347 for k=8 -- at that exact cutoff I get perm_p=0.00100 (log) and 0.00233 (linear), nowhere near 0.05. So all three k values cycle 28/29 examined (8, 11, 13) now fail to replicate any cliff under the corrected tool. This was the last of the three; the reproduction attempt is done.


While confirming the k=8 result I went looking for whether the margin-internal R (cycle 33s decomposition, walk-proxy) has ever been checked directly against real measured k=13 wall sizes -- not the residue-class label, the actual R number. Cycle 19 tried this with a different formula (the covering-budget R(k,p)=k*(2*floor(p/(k+1))+1)/p) and cycle 32/dead-ends record it as disproved as a mechanism. But that is a different R from margin_at()s R -- worth checking separately since the knowledge base explicitly flags them as unrelated.


Computed margin_at()s R directly at the 8 real measured k=13 wall primes (199,211,223,227,251,293,307,349), n_samples=100 seed=42, same walk tool used all cycle. Regressed log(real sieve size) ~ log(p): R2=0.931. Adding the walk-proxy R as a second term: R2=0.984, partial R2=+0.052, coefficient on R is positive (~27-34) and stays positive in every leave-one-out fold (23.5 to 33.9). That is the same sign and similar magnitude to cycle 19s now-disproved covering-budget R, but this is a genuinely different quantity (margin_at()s DFS-depth decomposition, not the budget formula). First time this specific R has been checked against real measured sieve sizes rather than just the walk-proxy data.


# Cycle 38: k=8 completes the cliff-reproduction failure; first direct check of margin-R against real measured wall sizes

Tags: `empirical`

## Context

Cycle 37 left two items open: (1) finish the cycle 28/29 cliff-reproduction
attempt by checking k=8 (only k=11 and k=13 had been redone), and (2) if the
offset never fades, ask whether it says anything about the real k=13 wall
(p=419 stuck) rather than being a pure proxy-walk curiosity. Did both this
cycle.

## Part 1: k=8 wide-range check

Ran `tools/margin_by_class_k.py 8 20 1000 100 42` (lo=20, hi=1000, n_samples=100,
seed=42, 160 primes, target class = p mod 9 == 8) through
`margin_class_regression_k.py`, both `R` and `margin` columns, both trend
variants, at cutoffs bracketing cycle 28's reported k=8 cliff (hi~347) and
running to hi=1000:

| hi | n | n_target | R(log) | R(lin) | margin(log) | margin(lin) |
|---|---|---|---|---|---|---|
| 300 | 54 | 9 | 0.00367 | 0.00600 | 0.00033 | 0.00033 |
| **347** (cycle 28's crossing) | 60 | 9 | 0.00100 | 0.00233 | 0.00000 | 0.00133 |
| 400 | 70 | 10 | 0.00000 | 0.00233 | 0.00000 | 0.00267 |
| 500 | 87 | 13 | 0.00100 | 0.00833 | 0.00233 | 0.00100 |
| 600 | 101 | 17 | 0.00067 | 0.01033 | 0.00233 | 0.00000 |
| 700 | 117 | 19 | 0.00033 | 0.01000 | 0.00467 | 0.00033 |
| 800 | 131 | 22 | 0.00067 | 0.01233 | 0.00467 | 0.00033 |
| 900 | 146 | 26 | 0.00100 | 0.02133 | 0.01700 | 0.00000 |
| 1000 | 160 | 28 | 0.00033 | 0.01500 | 0.00867 | 0.00000 |

No crossing anywhere; everything stays under perm_p=0.022 out to the widest
range tried. Cycle 28 reported k=8's cliff at hi~347 using the now-lost
`bound_margin_k.py`. Combined with cycle 37's k=11 (to hi=1000) and k=13 (to
hi=450) results, this completes the reproduction attempt across all three k
values cycle 28/29 examined: none of the three reported cliffs survive under
the corrected regression tool. The target-class-lower-R/margin offset is now
checked, and never once gone null, at every (k, range) combination tried
across cycles 34, 36, 37, 38.

## Part 2: does margin-R connect to anything real?

Before proposing a new "connect the proxy to reality" experiment, checked
whether this had already been tried. It had, partially: cycle 19 (journal
#561) regressed `log(sieve_size) ~ log(p) + R_budget` on 6 real k=13
`SIEVE_LAYER_DONE` points, where `R_budget = k*(2*floor(p/(k+1))+1)/p` is the
**covering-budget** formula, and got R²=0.980 (partial R²=+0.136, coefficient
positive and stable under leave-one-out). Cycle 20 (#570) then disproved that
mechanism directly: exact nonzero-tuple sampling at k=4 showed the budget
term does NOT predict survivor-class collapse (p=199 vs p=197 ratio went the
*wrong* direction), so the k=13 regression fit was concluded to be
coincidental/confounded, not a real mechanism. That is correctly listed as a
dead end in memory.

But `R_budget` is a different quantity from **margin-R** (`R =
(bcn+3*bc)/ttc` from `margin_by_class_k.py`'s DFS-depth-K-4 walk simulation,
built cycle 33, the one this whole cycle-34-through-38 line of work has been
testing). The knowledge base explicitly flags them as unrelated. Margin-R
has never been regressed against real wall sizes -- only against itself
across primes in the proxy-walk data. Worth checking on its own, since
disproving the budget-R mechanism says nothing about margin-R.

Computed margin-R directly (not a class label, the real-valued walk output)
at exactly the 8 real measured `I(13,p,1)` primes (n_samples=100, seed=42,
same tool as all cycle):

| p | real sieve size | margin-R |
|---|---|---|
| 199 | 4,748,938 | 1.1916 |
| 211 | 6,930,895 | 1.2287 |
| 223 | 226,264 | 1.1353 |
| 227 | 2,667,353 | 1.1835 |
| 251 | 40,822 | 1.0715 |
| 293 | 7,903 | 1.0693 |
| 307 | 5,688 | 1.0622 |
| 349 | 260 | 1.0238 |

Regression (8 points, OLS, closed-form):

```
Model A  log(size) ~ log(p)          R^2 = 0.9315
Model B  log(size) ~ log(p) + R      R^2 = 0.9837   (coef on R = +27.4)
partial R^2 of adding margin-R = 0.052
```

Leave-one-out on Model B's coefficient on R: 27.1, 31.6, 23.5, 23.9, 33.9,
27.4, 26.8, 29.4 -- positive and inside a fairly tight band (23.5-33.9) in
every fold, not driven by one point.

## Reading

Margin-R adds real, stable explanatory power to log(p) alone for the 8
actually-measured k=13 sieve sizes -- same sign, similar order of magnitude
to cycle 19's now-disproved budget-R fit, but it is a mechanistically
different quantity (a DFS-depth decomposition of the real solver's
early_return_bound(), not an algebraic floor-division formula), so cycle
20's disproof of budget-R does not automatically apply here. This is the
first time margin-R has touched real solver output rather than only the
proxy-walk's own internal statistics.

Caveats, stated plainly: n=8 with a 3-parameter model leaves only 5 residual
degrees of freedom -- this is weak evidence, not a confirmed mechanism, and
it inherits the same "coincidental confound" risk cycle 20 found for
budget-R (both p and class label move together in a small, non-random
sample -- these are the 8 primes `next_prime.py` happened to pick, and that
tool explicitly prioritizes the target class, so p and is_target are
correlated in this exact set by construction, not by chance). It should NOT
be treated as more than "worth a bigger, controlled follow-up" until tested
on a larger or more balanced set of real `SIEVE_LAYER_DONE` points (which
Track A has to actually produce -- I cannot manufacture more real
measurements this cycle).

## Next

1. Track A: p=419's k=13 sieve run is still not producing RUN_DONE/
   RUN_ABORTED events as of this cycle's check (last event is a RUN_STARTED
   at 22:11:43 UTC the prior day, now hours past the 1800s watchdog) --
   flagging again, not my track, but every cycle this stays stuck is a
   cycle without a fresh real data point to extend the margin-R-vs-wall-size
   check above.
2. When new `SIEVE_LAYER_DONE` events land (p=419 or beyond), recompute
   margin-R at those primes and re-run the Model A/B regression -- watch
   specifically whether the partial R² for margin-R holds, grows, or
   collapses as n grows past 8. This is the direct, falsifiable follow-up to
   this cycle's finding.
3. Consider a controlled check that breaks the p/is_target confound: compute
   margin-R and Model B's residual for k=13 primes NOT prioritized by
   `next_prime.py` (i.e., non-target-class primes in the same p range) if
   Track A ever measures any -- right now all 8 real data points are biased
   toward whatever `next_prime.py`'s ordering picked, which is exactly the
   target class more often than not.
4. Longer-shot: the margin-R decomposition is a depth-(K-4) snapshot of a
   *single* simulated path; the real solver explores many paths per prime.
   No idea yet on how to connect single-path R to a full DFS node count
   analytically -- still the central unanswered mechanism question after 13+
   cycles on this line.

## Wall, k=13 I(13,p,1): p199:4,748,938 p211:6,930,895 p223:226,264 p227:2,667,353 p251:40,822 p293:7,903 p307:5,688 p349:260. p419 still stuck as of cycle 38 check (00:23 UTC): last event is RUN_STARTED at 2026-07-20T22:11:43Z, no RUN_DONE/RUN_ABORTED since, hours past the 1800s watchdog (Track A, not rechecked further this cycle).
## 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/36/37/38: target residue class (p==-1 mod k+1) has significantly lower R (and more negative margin) than rest class at matched trend(p). Now checked at k=8 (hi to 1000), k=11 (hi to 1000), k=13 (hi to 450) -- every cutoff at every k stays significant (perm_p well under 0.03), no fade or cliff ever found. This is the most range-robust, most-checked result in the whole project.
- CYCLE 36: log(p) detrending was a tool bug that hid ttc's class signal at k=8 (understated at k=11). Fixed by regressing against raw p. ttc alone significant at k=8/k=11. R stays significant either way (scale-invariant ratio).
- CYCLE 37/38: cycle 28/29's "significance cliff" (p-value crossing 0.05 at specific hi, claimed not to scale with k) does NOT reproduce at ANY of the three k values it originally reported (k=8 ~347, k=11 ~770, k=13 ~350-400) under the class-regression tool -- checked exhaustively this cycle and last. The tool cycle 28/29 used (bound_margin_k.py) no longer exists (filesystem wipe), so this is filed as a replication failure, not a clean disproof, but cycle 28/29's cliff-location numbers and k-scaling comparison should not be trusted or built on.
- CYCLE 38 (this cycle, NEW): margin-R (the walk-proxy R from margin_at(), NOT the disproved covering-budget R(k,p)) checked directly against the 8 real measured k=13 SIEVE_LAYER_DONE sizes for the first time. log(size) ~ log(p) alone: R^2=0.931. Adding margin-R: R^2=0.984 (partial R^2=+0.052), coefficient positive (~27-34) and stable under leave-one-out. Weak evidence (n=8, 5 residual df) and confounded (next_prime.py deliberately over-samples the target class, so p and is_target correlate in this exact set by construction) -- flagged as "worth a bigger follow-up," not a confirmed mechanism. First time margin-R has touched real solver output rather than only its own proxy-walk statistics.
- 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) -- this is a DIFFERENT quantity from margin-internal R above; do not conflate them.
- SUPERSEDED, NOT TRUSTED: cycle 28's "cliff not fade, doesn't scale with k" and cycle 29's threshold-artifact framing -- built on a lost tool, fails to replicate at all 3 k under the current tool (cycles 37, 38).
## 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 (cycles 29-31).
- 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; both downstream of the now-unreplicated cliff (cycles 37/38, all 3 k checked).
- "k=8 lacks ttc's class signal" (cycle 35) -- 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 (5x samples), resid_std barely moved. Fix was the trend variable, not sample count.
- 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. Bash `>` file redirection was blocked in this cycle's sandbox (writes must go through the Write tool or plain stdout capture); noting in case it recurs.
## Best line of attack
Two fronts now: (1) the target-class-lower-R/margin offset is the most-tested, most range-robust pattern in the project (significant at k=8/11/13, every range tried, cycles 34-38) but still has no confirmed causal link to real solver runtime; (2) cycle 38 opened a first, weak, direct link -- margin-R adds real partial R^2 to a log(p)-only fit of the 8 real k=13 wall sizes -- but it is confounded by next_prime.py's own target-class-first sampling and needs more/more-balanced real data points to trust.
## Next step
Wait for/request new real SIEVE_LAYER_DONE events (p=419 or beyond) and re-run the margin-R vs. log(size) regression with n>8 to see if the partial R^2 holds up as sample size grows -- this is the direct falsifiable test of cycle 38's finding. If Track A's p=419 run stays stuck, that itself is worth escalating since it blocks getting any new real data point for this check.

k=8 completes cliff-reproduction failure; margin-R shows first direct (weak, confounded) link to real k=13 wall sizes


Starting cycle 39. memory brief still shows only 8 real k=13 wall points from cycle 38, but the local journal/events.jsonl file is stale -- pulling fresh from JOURNAL_API shows 718 events vs 679 locally, including a new SIEVE_LAYER_DONE for p=229, k=13, size=2,091,759 at 2026-07-21T00:22:01Z. That is exactly the new real data point cycle 38 asked for.


Also useful: p=229 mod 14 = 5, so it is NOT in the target residue class (which needs p mod 14 == 13). That matters because cycle 38 flagged its margin-R vs real-size finding as confounded -- next_prime.py oversamples the target class, so the 8-point set might have just been R standing in for a class label. A fresh non-target real point is a decent way to start probing that.


Ran margin_by_class_k.py for k=13 over [195,350) with n_samples=100 seed=42, same settings cycle 38 used, and pulled R for all 9 real primes now measured (199,211,223,227,229,251,293,307,349). Refit log(size) ~ log(p): R2=0.9232 (n=9, was 0.931 at n=8). Adding R: R2=0.9830, partial R2=+0.0597, coef_R=29.083. That basically replicates cycle 38 at n=9 -- the new point did not break it.


Ran the actual deconfounding test: added is_target as a third regressor. log(p)+is_target alone already gets R2=0.9803 -- is_target is a strong predictor by itself. Adding R on top of log(p)+is_target only takes R2 to 0.9869, partial R2 of R over that baseline is just +0.0066, an order of magnitude smaller than R2 partial over log(p) alone (+0.0597). So most of what R explains beyond log(p) is redundant with simply knowing the residue class -- R is not adding much independent information once class is already in the model.


Leave-one-out on the 3-predictor model (log p, R, is_target): coef_R stays positive in all 9 folds (range 7.9 to 25.4) and coef_target stays negative in all 9 folds -- neither flips sign, but both are noisier than the clean 2-predictor fit (coef_R range was 24.9-35.9 there). With n=9 and 4 free parameters that is only 5 residual df, so I do not want to overclaim precision, but directionally this survives holding out each point.


Bottom line for this cycle: the margin-R link to real wall sizes is not obviously fake -- it replicates at n=9 with a genuinely new point -- but it looks weaker than cycle 38 made it seem once you control for residue class directly. Next useful real data would be a non-target-class prime measured further out (p>350, not congruent to 13 mod 14) to see if R still adds anything once is_target is in the model with more residual df. Also still waiting on Track A -- the run after p=229 (RUN_STARTED 00:24:43Z) has not produced a new SIEVE_LAYER_DONE yet as of this cycle.


# Cycle 39: deconfounding margin-R against real class label with a 9th data point

tags: empirical

## Context

Cycle 38 opened the first direct link between the walk-proxy `R` from
`margin_at()`'s DFS-depth decomposition (cycle 33's `R=(bcn+3*bc)/ttc`) and
real measured k=13 first-sieve-layer sizes: regressing `log(size) ~ log(p)`
across the 8 real primes measured so far gave R2=0.931; adding `R` as a
second term took it to R2=0.984 (partial R2=+0.052), with a positive,
LOO-stable coefficient. But that fit was flagged as confounded: `next_prime.py`
deliberately over-samples the target residue class (p ≡ -1 mod k+1), so in
that exact 8-point set, `p` and `is_target` correlate by construction, and
`R` might just be standing in for the class label rather than adding real
information.

This cycle's job: (1) check whether a genuinely new real data point still
fits the pattern, and (2) actually run the deconfounding test cycle 38 could
only flag.

## What's new

The local `journal/events.jsonl` in this container was stale (679 events);
pulling fresh from `JOURNAL_API` gave 718 events, including a new
`SIEVE_LAYER_DONE` for **p=229, k=13, size=2,091,759** at
2026-07-21T00:22:01Z. Useful bonus: 229 mod 14 = 5, so this prime is *not*
in the target class -- a fresh non-target point to test against.

## Step 1: does the n=8 finding survive a 9th point?

Ran `tools/margin_by_class_k.py 13 195 350 100 42` (same settings as cycle
38) and pulled `R` for all 9 real primes now measured: 199, 211, 223, 227,
229, 251, 293, 307, 349.

| fit | R2 |
|---|---|
| log(size) ~ log(p) | 0.9232 |
| log(size) ~ log(p) + R | 0.9830 (partial R2 = +0.0597) |

Coefficient on R: 29.083, positive. LOO across all 9 folds: range 24.9 to
35.9, stays positive and in the same ballpark as cycle 38's 8-point LOO
range (23.5-33.9). The new point did not break the pattern.

## Step 2: control for residue class directly

This is the actual deconfounding test. Added `is_target` (0/1, p mod 14 ==
13) as a third regressor:

| fit | R2 |
|---|---|
| log(size) ~ log(p) | 0.9232 |
| log(size) ~ log(p) + is_target | 0.9803 |
| log(size) ~ log(p) + R | 0.9830 |
| log(size) ~ log(p) + R + is_target | 0.9869 |

`is_target` alone (no R) already explains almost as much as R does --
0.9803 vs 0.9830. And once `is_target` is already in the model, adding R on
top only buys partial R2 = +0.0066 (0.9869 - 0.9803), an order of magnitude
smaller than R's partial R2 over log(p) alone (+0.0597).

Leave-one-out on the 3-predictor model (n=9, 4 free params, 5 residual df):
coef_R stays positive across all 9 folds (7.9 to 25.4) and coef_target
stays negative across all 9 folds (-0.12 to -1.91). Neither flips sign, but
both are noticeably noisier than the 2-predictor fit.

## Reading

R's apparent link to real solver wall size is mostly redundant with just
knowing the residue class. It is not *nothing* -- R still adds some
information beyond `is_target` even in the small 3-predictor model, and its
sign never flips under LOO -- but cycle 38's headline number (partial
R2=+0.052 from adding R to a log(p)-only model) overstates R's independent
value, because that fit never had `is_target` in it to begin with. The
honest summary: the target-class-lower-R/margin pattern (proved range-robust
in cycles 34-38) and this real-wall-size link are very likely the *same*
underlying signal, not two independent confirmations of one mechanism.

n is still tiny (9 points, 5-7 residual df depending on model) -- this is
suggestive, not conclusive, in either direction.

## Next

- Get a real wall size for a non-target-class prime past p=350 (next_prime.py
  under-samples this class by design) to add residual df to the 3-predictor
  model and see if coef_R stays stable with more room to move.
- Track A's run after p=229 (RUN_STARTED 2026-07-21T00:24:43Z) had not
  produced a new SIEVE_LAYER_DONE as of this cycle -- keep checking via
  JOURNAL_API (not the stale local file) for the next real data point,
  possibly p=419 finally landing.
- If more non-target points keep shrinking R's partial contribution toward
  zero once class is controlled for, that would demote "margin-R predicts
  real wall size" from empirical to disproved-as-independent-mechanism, and
  leave the class-membership signal itself (cycles 34-38) as the real
  finding.

## 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 p251:40,822 p293:7,903 p307:5,688 p349:260. p419 still not landed as of cycle 39 (00:31 UTC 2026-07-21) -- most recent run started 2026-07-21T00:24:43Z per JOURNAL_API, no new SIEVE_LAYER_DONE since p=229. NOTE: local journal/events.jsonl in this container is stale (was 39 events behind API this cycle) -- always pull via JOURNAL_API for the freshest event list, not the local file.
## 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. Do not build on cycle 28/29's cliff-location numbers.
- CYCLE 38/39: margin-R (walk-proxy R from margin_at(), NOT the disproved covering-budget R(k,p)) checked against real k=13 SIEVE_LAYER_DONE sizes. At n=8 (cycle 38): log(size)~log(p) R2=0.931, +R gets R2=0.984 (partial +0.052). At n=9 (cycle 39, added real p=229 point): log(p) alone R2=0.923, +R gets R2=0.983 (partial +0.060) -- replicates, did not break.
- CYCLE 39 (NEW): ran the deconfounding test cycle 38 could only flag. Added is_target (p mod 14==13) as a third regressor. log(p)+is_target ALONE already gets R2=0.980 -- almost as much as log(p)+R (0.983). Adding R on top of log(p)+is_target only buys partial R2=+0.0066, an order of magnitude smaller than R's partial R2 over log(p) alone (+0.060). Reading: R's link to real wall size is mostly redundant with just knowing residue class -- it is very likely the SAME signal as the cycles 34-38 class-margin finding, not an independent second confirmation of a mechanism. R does not fully vanish (LOO coef_R stays positive in all 9 folds, 7.9-25.4, even in the 3-predictor model) but the independent contribution is small and n is tiny (9 points, 5 residual df in the full model).
- 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, doesn't scale with k" and cycle 29's threshold-artifact framing -- built on a lost tool, fails to replicate at all 3 k under the current tool.
## 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; both downstream of the unreplicated cliff.
- "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's link to real wall size is an independent confirmation separate from the class-margin finding" -- WEAKENED cycle 39: once is_target is in the regression, R's extra partial R2 is ~10x smaller than without it. Treat margin-R and the class-margin finding as (probably) the same underlying signal, not two.
- 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) is still the most-tested, most range-robust pattern in the project. Cycle 39 shows its apparent link to real k=13 wall sizes (cycle 38) is largely -- not entirely -- explained by that same class label rather than being independent evidence of a distinct mechanism. The open question is whether R carries ANY real information beyond class membership, which needs more residual degrees of freedom to resolve.
## Next step
Get a real wall size for a non-target-class prime past p=350 (next_prime.py under-samples this class by design, so watch for it specifically) to add residual df to the 3-predictor model (log p, R, is_target) and see if R's small independent partial R2 holds, shrinks to ~0, or grows. Keep polling JOURNAL_API (not the local file) for new SIEVE_LAYER_DONE events -- p=419's run has been going since 2026-07-21T00:24:43Z with nothing landed yet this cycle.

Deconfounding margin-R against real residue-class label with a 9th real k=13 wall point


Starting cycle 40. Pulled fresh events from JOURNAL_API (728 total, local file is stale as usual): found a new SIEVE_LAYER_DONE for p=233, k=13, size=434,986, landed at 2026-07-21T00:32:56Z -- literally 25 seconds after cycle 39 filed its hypothesis, so cycle 39 never saw it. 233 mod 14 = 9, not the target class (needs 13), so this is exactly the fresh non-target point cycle 39 asked for.


Reran margin_by_class_k.py 13 195 350 100 42 (identical settings to cycles 38/39) to get R and is_target for all 10 real k=13 primes now measured: 199,211,223,227,229,233,251,293,307,349. Refit the 3-predictor model (log p, R, is_target) at n=10 (6 residual df, up from 5).


Result is the opposite of what cycle 39 worried about. is_target alone with log(p) got R2=0.9803 at n=9 -- now at n=10 with the new non-target point it DROPS to R2=0.9711. Meanwhile log(p)+R stays at R2=0.9830 (basically unchanged from 0.9830 at n=9). So Rs partial R2 over (logp+is_target) roughly doubled: 0.0066 at n=9 to 0.0150 at n=10. Adding a real non-target point made is_target look weaker and R look relatively stronger, not the other way around.


LOO stability also improved: coef_R across the 9 leave-one-out folds now ranges 17.65 to 27.52 (n=10), versus 7.9 to 25.4 at n=9 -- tighter and with a higher floor. coef_target stays negative in every fold (-1.14 to -0.02) but is consistently smaller in magnitude than coef_R. Checked p=233s residual in the full model too: -0.22 in log-space, mid-pack among the 10 points, not an outlier driving the result by leverage.


# Cycle 40: a 10th real point strengthens margin-R's independent signal, reversing cycle 39's worry

tags: empirical

## Context

Cycle 39 ran the deconfounding test cycle 38 could only flag: it added
`is_target` (p mod 14 == 13) as a third regressor alongside `log(p)` and the
walk-proxy `R` from `margin_at()`, to see whether `R`'s apparent link to real
k=13 first-sieve-layer sizes was just standing in for residue-class
membership. At n=9, `is_target` alone (with `log(p)`) already got
R2=0.9803, almost matching `log(p)+R`'s R2=0.9830 -- so R's independent
contribution on top of `is_target` was small (partial R2=+0.0066, about 10x
smaller than R's partial R2 over `log(p)` alone). Cycle 39's stated next
step: get a fresh non-target-class real point and see whether R's
independent contribution shrinks toward zero (demoting it) or holds.

## What's new

Pulled fresh events from `JOURNAL_API` (728 total; local `journal/events.jsonl`
is stale as always). Found a new `SIEVE_LAYER_DONE`: **p=233, k=13,
size=434,986**, landed at 2026-07-21T00:32:56Z -- 25 seconds after cycle 39
filed its hypothesis, so cycle 39 never saw it. 233 mod 14 = 9, so this is a
**non-target-class** point, exactly what cycle 39 asked for.

## Method

Reran `tools/margin_by_class_k.py 13 195 350 100 42` (identical settings to
cycles 38/39) to get `R` and `is_target` for all 10 real k=13 primes now
measured: 199, 211, 223, 227, 229, 233, 251, 293, 307, 349. Refit the same
three models, now at n=10 (6 residual df, up from 5 at n=9).

## Results

| fit | R2 (n=9, cycle 39) | R2 (n=10, this cycle) |
|---|---|---|
| log(size) ~ log(p) | 0.9232 | 0.9239 |
| log(size) ~ log(p) + is_target | 0.9803 | 0.9711 |
| log(size) ~ log(p) + R | 0.9830 | 0.9830 |
| log(size) ~ log(p) + R + is_target | 0.9869 | 0.9861 |

Partial R2 of R over (log p + is_target): **0.0066 at n=9 -> 0.0150 at
n=10** -- more than doubled.
Partial R2 of is_target over (log p + R): 0.0039 at n=9 -> 0.0031 at n=10
-- shrank slightly.

The direction is the opposite of what cycle 39 flagged as the risk. Adding
one real non-target point made `is_target`-alone *weaker* (R2 dropped from
0.9803 to 0.9711) while `log(p)+R` barely moved (R2 0.9830 to 0.9830, coef_R
28.90 -> 28.90, both computed fresh this cycle, not carried over from
cycle 39). `R` absorbed information that `is_target` alone could not, once
a genuine non-target point (233's size sits a bit lower relative to its
`log(p)` trend than a pure class split alone would predict) was added.

LOO on the full 3-predictor model (n=10, 9 folds): `coef_R` ranges 17.65 to
27.52 (was 7.9 to 25.4 at n=9 -- tighter, higher floor). `coef_target`
stays negative in every fold, -1.14 to -0.02, but consistently smaller in
magnitude than `coef_R`.

Sanity check: p=233's residual in the full model is -0.22 in log-space,
mid-pack among the 10 points (residuals range -0.66 to +0.46) -- not an
outlier driving the result through leverage.

## Reading

This does not "prove" R is mechanistically independent of the class-margin
finding -- n=10 with 4 free parameters is still a small-sample regime, and
one point moved the partial-R2 split by 2x, which shows the estimate is
still noisy. But the direction matters: cycle 39 set up a real falsification
test ("if more non-target points shrink R's contribution toward zero,
demote it to disproved-as-independent"), and the first new point that
arrived did the opposite. That is one data point against the "R is just a
relabeling of is_target" reading, not confirmation that R is a distinct
mechanism -- but it means this is still an open, live question, not one
trending toward disproof.

## Next

- Keep pulling non-target-class real points as Track A produces them --
  the falsification test cycle 39 designed needs several more before either
  side of "R adds independent signal vs. R is redundant with class" is
  resolved. A new k=13 run started at 2026-07-21T00:33:40Z per JOURNAL_API;
  watch for its SIEVE_LAYER_DONE.
- n=10 with 4 parameters is still thin (6 residual df). If the next 2-3
  points keep pushing partial-R2(R | is_target) up rather than to zero,
  that would be worth treating as a genuine (weak) confirmation of
  independence rather than just "not yet disproved."
- Have not re-attempted any counter-test on k<=8 this cycle; the class
  offset itself (cycles 34-38) remains the most range-robust finding and
  needs no further defense right now -- effort is better spent on this
  real-data falsification loop.

## 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. New k=13 run started 2026-07-21T00:33:40Z per JOURNAL_API, no SIEVE_LAYER_DONE from it yet as of cycle 40. 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, not the local file.
## 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. Do not build on cycle 28/29's cliff-location numbers.
- CYCLE 38-40: margin-R (walk-proxy R from margin_at(), NOT the disproved covering-budget R(k,p)) checked against real k=13 SIEVE_LAYER_DONE sizes, now n=10 real points (199,211,223,227,229,233,251,293,307,349). log(size)~log(p) alone: R2=0.924. Adding R: R2=0.983 (partial R2=+0.059 over log(p) alone), coef_R positive and LOO-stable (17.7-27.5 across 10 folds).
- CYCLE 39-40 (the deconfounding thread): adding is_target (p mod 14==13) as a third regressor tests whether R is just relabeling residue class. At n=9 (cycle 39), is_target alone nearly matched R's full explanatory power (R2=0.980 vs 0.983), making R's marginal contribution look small (partial R2=+0.0066) -- read at the time as "R mostly redundant with class". At n=10 (cycle 40), the first new real point (non-target p=233) REVERSED that: is_target-alone weakened (R2 dropped to 0.971) while log(p)+R held steady (0.983), so R's partial contribution over is_target roughly doubled (0.0066->0.0150). Direction is now against "R is just class-relabeling", but n=10/6 residual df is still thin and one point swung the estimate 2x -- open question, not resolved either way.
- 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, doesn't scale with k" and cycle 29's threshold-artifact framing -- built on a lost tool, fails to replicate at all 3 k under the current tool.
## 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; both downstream of the unreplicated cliff.
- "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's link to real wall size is an independent confirmation separate from the class-margin finding" -- NOT settled either way. Cycle 39 (n=9) found this claim weakened; cycle 40 (n=10, new non-target point) found it strengthened again. Treat as an open, actively-swinging question -- do not file it as resolved in either direction yet.
- 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 (GET {JOURNAL_API}/journal/events.jsonl) before assuming no new data exists.
## Best line of attack
The target-class-lower-R/margin offset (cycles 34-38) is still the most-tested, most range-robust pattern in the project and needs no further defense right now. The live open question is the n=10 deconfounding regression (log p, R, is_target) against real k=13 wall sizes: does R carry independent information beyond residue class, or is it just relabeling class membership? Cycle 39 said "shrinking", cycle 40's next real point said "growing" -- it swung 2x on one point, so more real non-target data points are needed before either reading is trustworthy.
## Next step
Keep polling JOURNAL_API (GET {JOURNAL_API}/journal/events.jsonl, NOT the local file) for new SIEVE_LAYER_DONE k=13 events -- a new run started 2026-07-21T00:33:40Z with nothing landed yet this cycle. Each new real point (especially non-target-class ones) should be fed into the same 3-predictor regression (tools/margin_by_class_k.py + manual OLS) to keep tracking whether partial-R2(R | is_target) trends toward zero (demote R to redundant-with-class) or stays/grows (treat as weak evidence of independence). Need several more points before concluding either way -- n=10 is still too thin to trust a single swing.

A 10th real point strengthens margin-R's independent signal, reversing cycle 39's worry