Control arms, objective-family ablation, and store hygiene - #36
Merged
Conversation
width2_tasks()/width2_tier() re-run `feasibility` under a width-2 contact predicate (ContactPredicate.TRACTABLE_WIDTH) in place of its Ehrlich-adjacency rule, so the headline mask-vs-rejection comparison exists on a second predicate family, not only in support_study's diagnostic instance. protocol-alde is left out: EhrlichLandscape._evaluate zeroes reward by its own transition matrix independent of Task.feasibility, and an unmasked arm that doesn't consult the injected predicate crashes re-anchoring the moment it picks an infeasible best. support_study avoids this by being reanchor=False everywhere; feasibility-w2 inherits that safety. Fixing re-anchoring against an injected predicate is out of scope here. Per-contact density is calibrated by Monte Carlo (not matched to the source task's own transition_density, which leaves ~0 of the local neighbourhood feasible at width 2) so genetic and genetic-feasible both have something to search from every round.
GeneticAlgorithm gains construct_feasible, a variation operator that walks each bred offspring toward its target through the environment's own forward_mask -- the identical mask a masked GFlowNet policy is scored against -- rather than accepting or rejecting the whole target the way feasible_only does. An edit the mask forbids at its turn is dropped; nothing is redrawn and no whole offspring is discarded. Registered as the genetic-masked arm. This is the second control for the feasibility claim, alongside genetic-feasible (rejection): construction is available to a GA too, so a GFlowNet's margin over a GA that is *also* masked is attributable to learning rather than to rejection's mechanics. Also adds construction_attempted/construction_dropped to the result schema, the construction-side analogue of draws_attempted/draws_rejected. Campaign run at 100 seeds on feasibility, protocol-alde and protocol-evolvepro (results/, gitignored, not part of this commit).
round_sweep halves batch size from 96, which lands exactly on 4x96 and
8x48 at the 384-assay budget and skips every split between them -- a
two-point curve standing in for a trend. 6x64 is the one integer split
the halving cannot reach, so it is added explicitly in rounds_curve
rather than by changing what round_sweep enumerates for its other
callers.
Ran all three rungs at 50 seeds (results/rounds-{4x96,6x64,8x48}). The
third point does not confirm a trend -- it breaks the monotonicity a
two-point read would have implied. GFlowNet regret is 0.383 / 0.345 /
0.381 across 4x96 / 6x64 / 8x48, and the margin over every baseline
(genetic, cmaes, genetic-feasible) peaks at the middle rung rather than
growing or shrinking with rounds count.
The mask-aware construction control adds an arm, and the ladder test pins the arm set exactly so that adding one is a deliberate edit rather than a silent drift. Record it in the 'ours, not published' group. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013WkACTq6CTiwkqmuv6Mhet
Carries the training-objective comparison from the diagnostic landscape onto the tasks whose graph actually constrains construction, and adds a learned-P_B rung. Threads learn_backward through the policy factory (it was on SequencePolicy but never exposed), registers gfn-tb-learnpb, and adds an objective-family tier over feasibility/protocol-alde/protocol-evolvepro that reuses the headline gfn-tb/gfn-subtb cells so only the four new arms cost a campaign. Also adds experiments/bless_merge.py, the merge-hygiene tool that restamps the records the solidify-paper-controls edits staled but provably could not alter. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013WkACTq6CTiwkqmuv6Mhet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds control arms, an objective ablation, and a store-hygiene tool.
results/is gitignored, so no data is in the diff.What it adds
genetic-maskedarm): a variation operator that constructs feasible offspring through the environment's ownforward_mask— one legal substitution at a time — instead of rejection-sampling whole offspring and discarding infeasible ones.width2tier): runsfeasibilityunder a width-2 contact predicate in place of its Ehrlich-adjacency rule.label_noise_stdon the ensemble: a knob that adds Gaussian noise to the surrogate's fit targets, guarded to be a no-op at the default0.0.P_Barm on the constrained tasks.learn_backwardis threaded through the policy factory (previously only onSequencePolicy); the tier reuses the existinggfn-tb/gfn-subtbcells so only the four new arms run.experiments/bless_merge.py: restamps records staled by these edits' fingerprint changes, each of which is a guarded no-op or a new-arm-only path for existing arms.The arm-set test is updated to include
genetic-masked. ruff and mypy-strict pass.🤖 Generated with Claude Code