Skip to content

Winners-curse revs 3–4: the growth lookahead as a virtual injection + the yield rule#196

Open
gfrmin wants to merge 4 commits into
masterfrom
exploration-budget/winners-curse-code
Open

Winners-curse revs 3–4: the growth lookahead as a virtual injection + the yield rule#196
gfrmin wants to merge 4 commits into
masterfrom
exploration-budget/winners-curse-code

Conversation

@gfrmin

@gfrmin gfrmin commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Code PR for the ratified winners-curse design (#195) plus its ratified-in-conversation §8 amendment (rev 4). Gate status: HALT THE LINE — opened for review, not for merge on this run (see the results commit and the findings below).

What this builds

  • The union coherent injection (add_programs_to_state!(state, ::Vector{Grammar}, …)): one joint newcomers-only replay over the globally-deduped union of all candidates' programs — one ledger, one construction. Joint-not-sequential is load-bearing for exactness; commutation is inherited from Coherent injection: hypothesis addition commutes with conditioning (dominance halt-the-line fix) #187's theorem and asserted for the vector method (test_virtual_injection.jl §5). The single-grammar method's per-gid dedup is untouched (bit-stability of re-enumeration); the injection arithmetic is extracted verbatim into _inject_coherently!.
  • GrowthProposal (scratch, n_added, yield_nats, p_newcomers) — one virtual injection, projected by the score, the op log, and the transition (Invariant 3). All candidates injected (Q3); the Occam charge rides inside the mixture (Q4 — GW_FEATURE_PRIOR_TERM deleted, no prior term at any seam).
  • The yield rule (§8.2): score = net_value(injection_yield_nats(scratch), op_compute_cost) — the union-over-incumbent window Bayes factor under the complexity prior, net of the declared price. The rev-3 flow is never written: any own-posterior forward flow equals KL(P_union‖P_inc) ≥ 0 (Gibbs), so the §1b story was unsatisfiable by theorem — TDD caught it (§8.1). No ×H (the wait-option/Gittins argument — the far-term value is common to adopt-now and wait-and-re-decide), no plateau (realised yield already prices reality-of-gain).
  • FIRE = adopt the scratch (adopt!, ratified Q1 memo via growth_cache): score ≡ transition as an === identity (T-3.55), pinned through the host seam. The cache epoch now bumps on every space change (the proposal depends on the live belief; a stale scratch must never be priced or adopted).
  • T-3.53 exact in form: escape ops net_value(E[next yield], cost) (learned); growth ops net_value(computed yield, cost) (exact). One observable, one currency, one score form, two fidelities.
  • Retired: _grammar_marginal_log_loss, the residual-mass screen, both per-candidate argmax cores, explore_grammar/explore_features/exploration_voi/exploration_fit/feature_discovery_voi/feature_discovery_fit, GW_FEATURE_PRIOR_TERM, the host's h_events/n_cond_events horizon bookkeeping (nothing consumed it — the §1 stationarity residual discharged by deletion at this seam).

Verification

  • test_virtual_injection.jl (new, 27 checks): the seed-6 chance window waits at −0.56 nats while the retired score's counter-oracle fires at +5.12 on the same fixture; the informed fire lands from n = 8; multiplicity-by-mixture; commutation inheritance; Removal consumption: replacement semantics for applied removals (ratified #192) #193 self-healing end-to-end; score ≡ transition as ===.
  • Re-baselines: test_threshold_explore §3, test_feature_discovery §3–§4 (stronger pin: realised yield strictly below the fit-axis Δℓ — the mixture pricing the prior axis), test_growth_returns §6, test_grid_world_meta §1/§3/§4. Full 56-file suite green; credence-lint 178 files, 0 violations.

Gate findings (the honest part)

The winner's curse itself is dead: every eu_max fire is informed (min yield 0.748, min P_newcomers 0.613 across verbose seeds — mechanism claim (i) verified), churn stays dead (13.1 metas/run), the headline vs never_explore holds (+0.106 CI > 0; final-regime 17–3, p = 0.0026), and the union replay is ~3× faster than the retired lookahead.

But 8 assertions still fail, and the must-not-degrade clause binds: the shared adopt-the-union transition made blind frequent firing much stronger for every policy (fixed_k5: 48.5 → 52.9 AUC, now significantly above eu_max on the primary). The ε-price counterfactual (20 seeds, reported-not-asserted) shows the cost slot is not the fix: eu_max recovers only +0.04, the escape tier churns (a learned E[yield] never reaches exactly 0 — only the price stops it), and the refinement-first gate starves features. The real finding is one level up: the gate's utility charges zero compute, so "move the boundary every 5 steps for free" dominates any priced selectivity by construction — the gate cannot reward the thing the mechanism optimises (eu_max: 13 metas/16.2s; fixed_k5: 42 metas/1.9s — invisible to the gate). Clairvoyant is now degenerate for the same reason (its forced at-change fires all no-op on the yield floor; trajectories identical to eu_max).

Proposed next move (needs ratification): a dominance-design amendment charging compute in the gate's utility — the one-currency exchange rate (evidence-nats price ↔ energy ↔ replay compute) declared as task data in advance — then re-run. This is measure-matches-declared-utility one level up: the measure set was fixed in advance, but the utility itself under-specifies compute.

🤖 Generated with Claude Code

Guy Freeman and others added 4 commits July 3, 2026 17:00
…he score (rev 4)

Gibbs kills the flow: any own-posterior forward flow equals
KL(P_union ‖ P_inc) ≥ 0 per context, so rev-3 §1b's zero-or-negative
chance-window story is unsatisfiable by theorem, and ×H amplifies the
residue (measured: +0.55-nat fire at P_newcomers ≈ 0.11, violating the
design's own mechanism claim (i)).

The resolution is a further deletion: the ratified yield observable IS
the union-over-incumbent window Bayes factor under the complexity
prior, so score = net_value(yield, op_compute_cost). The wait-option
(Gittins-style) argument earns the ×H deletion — the far-term value is
common to adopt-now and wait-and-re-decide, so only the
evidence-vs-price timing survives. Plateau retires at the growth seam
(realised yield already prices reality-of-gain). Two named assumptions
pinned: the cost slot is the #189-inherited declared price (no-tuning
discipline), and the wait-arm regeneration assumption is the named
bridge to the non-stationarity work. §8.5 records the boundary framing
from ratification.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion coherent injection + the yield rule

Engine half of winners-curse revs 3-4:

- add_programs_to_state! gains a Vector{Grammar} method: the UNION
  injection — one joint newcomers-only replay over the deduped union
  (global expr dedup: against all incumbents and across candidates),
  one two-ledger scale restoration, one construction. Joint-not-
  sequential is load-bearing (sequential injections would misalign
  later groups' ledgers by earlier groups' normalisation shifts);
  commutation is inherited from the single-injection theorem
  (test_virtual_injection.jl §5 asserts it for this method). The
  single-grammar method keeps its per-gid dedup untouched (bit-
  stability of re-enumeration); the injection arithmetic is extracted
  verbatim into _inject_coherently!, shared by both.
- GrowthProposal (scratch, n_added, yield_nats, p_newcomers): one
  virtual injection, projected by score, op log, and transition
  (Invariant 3). threshold_growth_proposal / feature_growth_proposal
  inject ALL candidates (ratified Q3); the Occam charge rides inside
  the mixture (Q4 — no prior term at any seam).
- The score is the yield rule (§8.2): injection_yield_nats(scratch) =
  the union-over-incumbent window Bayes factor, netted against the
  declared price by the caller. No flow (Gibbs-degenerate, §8.1), no
  ×H, no plateau. T-3.53 exact in FORM: escape ops net_value(E[next
  yield], cost) learned; growth ops net_value(computed yield, cost)
  exact.
- copy_agent_state + adopt!: FIRE = adopt the scratch — score ≡
  transition as an identity (T-3.55), not a shared candidate function.
- Retired: _grammar_marginal_log_loss, _candidate_residual_mass,
  _best_threshold_refinement, _best_feature_addition, explore_grammar,
  explore_features, exploration_voi/fit, feature_discovery_voi/fit —
  the per-candidate argmax was an order statistic over chance fits
  (selection unpriced), its window rate extrapolated by H
  (stationarity unlicensed), and installing the winner an
  argmax_m P(m|D) collapse (average-not-collapse, applied to the
  transition).
- test_virtual_injection.jl (new, 6 sections + host-seam §1): the
  seed-6 chance window WAITS at -0.56 nats while the retired score's
  counter-oracle fires at +5.12; the informed fire lands from n = 8;
  multiplicity-by-mixture; commutation inheritance; #193 self-healing;
  score ≡ transition as ===.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…coring; test re-baselines

Host half of winners-curse revs 3-4:

- score seam: gw_growth_proposal is the ONE candidate function score
  and transition share, memoised in growth_cache keyed by (op,
  cache_epoch, gid, n_buf, depth). Scores are
  net_value(prop.yield_nats, op_compute_cost). GW_FEATURE_PRIOR_TERM
  retired (Q4). The attribution gate re-expresses as refinement-fires-
  first (-Inf on add_feature iff the threshold proposal's own score
  clears the floor).
- execute: growth branches adopt the memoised scratch (ratified Q1;
  score-blind callers recompute — the same function). Per-fire log
  carries (yield, P_newcomers, n_added) — the gate mechanism-claim
  read.
- cache_epoch now bumps on EVERY space change alongside space_epoch
  (the proposal depends on the live belief, unlike the retired pure-
  fit cache — a stale scratch must never be priced or adopted).
- h_events / n_cond_events horizon bookkeeping deleted (nothing
  consumes a horizon at this seam any more — §8.3's residual
  discharged by deletion); plateau no longer multiplies scores (regime
  maintenance unchanged).
- Re-baselines: test_threshold_explore §3 (discovery via the union;
  structural completeness replaces the residual-order guard),
  test_feature_discovery §3/§4 (yield strictly below fit-axis Δℓ — the
  mixture prices the prior axis), test_growth_returns §6 (one score
  form, both fidelities), test_grid_world_meta §1/§3/§4 (yield-rule
  pins; empty buffer scores exactly -price, not a veto).

Full 56-file suite green; credence-lint 178 files 0 violations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…echanism claims verified, must-not-degrade fails on a benchmark-utility finding

HALT THE LINE: 8 assertions still fail; not merged on this run alone.
What the run shows, honestly:

- Winner's curse: DEAD. Every eu_max growth fire is informed (verbose
  seeds 0/5/6: min yield 0.748 nats, min P_newcomers 0.613, most ≥ 0.9
  — mechanism claim (i) verified; the step-4-8 chance fires of rounds
  3-4 no longer exist). Meta churn stays dead (13.1 metas/run).
  Headline vs never_explore holds (+0.106 [0.004, 0.21]; final-regime
  17-3, p = 0.0026). Tails vs random_p005 marginally improved
  (worst -0.45 from -0.50, q10 -0.45 from -0.48).
- Must-not-degrade FAILS vs the tuned fixed schedule — which switched
  to fixed_k5 and jumped 48.5 → 52.9 AUC: the shared adopt-the-union
  transition made blind frequent firing much stronger for every
  policy. eu_max - fixed_k5 primary CI (-0.254, -0.017), significantly
  negative.
- Diagnosis (epsilon-price counterfactual, 20 seeds, reported not
  asserted): at op_compute_cost ≈ 0 eu_max recovers only +0.04 (0.42
  vs fixed_k5's 0.517), the escape tier churns (630 metas — a learned
  E[yield] never reaches exactly 0; only the price stops it), and the
  refinement-first gate starves add_feature. The price is not the fix.
- The finding is one level up (measure-matches-declared-utility): the
  gate's utility charges ZERO compute, so 'move the boundary every 5
  steps for free' dominates ANY priced selectivity by construction —
  while eu_max pays 13 metas + per-step proposal replays (16.2s
  wall-clock vs fixed_k5's 1.9s) that the gate cannot see. Under the
  gate's own declared utility, always-fire is genuinely EU-optimal;
  the gate as constructed cannot reward the thing the mechanism
  optimises. Clairvoyant is now degenerate for the same reason (its
  forced at-change fires all no-op on the yield floor — trajectories
  identical to eu_max, +6 no-op metas).

Next move (needs ratification): a dominance-design amendment charging
compute in the gate's utility (the one-currency exchange rate declared
as task data), then re-run. Wall-clock note: the union replay is ~3x
faster than the retired K-replay lookahead (46.2s → 16.2s per 20
seeds).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant