fix: per-fold model flags, and an AF3 pipeline seam that is not a global - #640
Merged
Merged
Conversation
run_structure_prediction.main() decided final_model_flags inside its loop over folds and read it after the loop, so one flag set -- whichever the last fold with protein objects produced -- was applied to every object. Queue a monomer behind a multimer and the monomer was predicted with model_name "multimer". Nothing raised; it silently predicted the wrong thing. This is the same failure fold_preparation.py was extracted to fix, where metadata was reassigned inside a loop and read outside it. That one was found and fixed; this sibling survived because the batch path computes flags per job and only this copy did not. Each job now carries the flags it needs, and inference_flags.group_by_model_flags batches jobs by flag set, so like folds still share one predict_structure call while unlike folds no longer have to. test_main_routes_protein_and_json_jobs_to_predict_structure asserted the old behaviour -- one call in which an AlphaFold 3 JSON input inherited model_name "multimer" from the protein fold beside it. That expectation was the bug, so it is updated rather than preserved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…obal Both batch scripts imported a 1027-line CLI as a library and called create_arguments(), whose job is to mutate the module-global FLAGS by filling in database paths, then called create_pipeline_af3() and get_af3_feature_metadata(), which read that mutation back. The interface between the scripts was the shape of a global and was correct only if the three calls happened in that order. alphapulldown/af3_pipeline.py states the same thing as data: AF3PipelineSettings resolves every binary and database path once and writes nothing back, and carries resolved_flag_values so provenance can record the paths actually used without a global having been rewritten to hold them. The database path resolver is injected, so the module does not depend on the CLI it came out of. create_pipeline_af3() keeps its signature and error, so existing callers are unaffected; get_af3_feature_metadata() gains an optional flag_values argument. The batch scripts no longer call create_arguments() at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DimaMolod
marked this pull request as ready for review
September 6, 2026 06:59
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
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.
Two findings from an architecture review of the recently merged batch work. Both are in already-merged code, not in #638 or #639.
1. Model flags followed the last fold, not the object (a correctness bug)
run_structure_prediction.main()decidedfinal_model_flagsinside its loop over folds and read it after the loop, so one flag set — whichever the last fold with protein objects produced — was applied to every object.Queue a monomer behind a multimer and the monomer was predicted with
model_name: "multimer". Nothing raised; it silently predicted the wrong thing.This is the same failure
fold_preparation.pywas extracted to fix, where metadata was reassigned inside a loop and read outside it. That instance was found and fixed; this sibling survived because the batch path computes flags per job and only this copy did not.Each job now carries the flags it needs, and
inference_flags.group_by_model_flagsbatches jobs by flag set — so like folds still share a singlepredict_structurecall and unlike folds are no longer forced to.A test changed rather than being preserved.
test_main_routes_protein_and_json_jobs_to_predict_structureasserted one call in which an AlphaFold 3 JSON input inheritedmodel_name: "multimer"from the protein fold beside it. That expectation was the bug.2. The batch scripts' interface to the CLI was a global
create_batch_features.pyandfinalize_batch_features.pyboth calledlegacy_features.create_arguments()— whose job is to mutate module-globalFLAGSwith resolved database paths — and then calledcreate_pipeline_af3()andget_af3_feature_metadata(), which read that mutation back. A wide, ordering-dependent, implicit interface across a script boundary.alphapulldown/af3_pipeline.pystates it as data instead.AF3PipelineSettings.from_flagsresolves every binary and database path once and writes nothing back; it also carriesresolved_flag_values, so provenance metadata records the paths actually used without a global having been rewritten to hold them. The path resolver is injected, so the new module does not depend on the CLI it came out of.Backwards compatible:
create_pipeline_af3()keeps its signature and its ImportError;get_af3_feature_metadata()gains an optionalflag_values. Neither batch script callscreate_arguments()any more.Deliberately not included
Unifying
run_structure_prediction_batch.pywithmain(). The two carry near-identical bodies, but they have already diverged in ways that need a decision rather than a merge —main()supportsshared_output_root=Trueand the batch adapter hardcodesFalse. Folding them together would silently pick a winner for real prediction behaviour.create_batch_features.pywas also flagged as having no Snakemake consumer, but it is documented in the wiki and inworkflows/mmseqs2-gpu.mdas the supported one-process mode. Having no scheduler consumer is the design, so it stays.Tests
564 passed, 7 skipped, 0 failed. New:
test_model_flag_grouping.py(5) andtest_af3_pipeline_settings.py(5), both free of heavy dependencies.🤖 Generated with Claude Code