Found 2026-07-15 while diffing aminx's user surface against the LigandMPNN reference (PR #108 audit). This is the identical failure to --fixed-policies, one line above it in the same loop, and I walked past it while fixing that one.
The bug
plan_campaign_manifest's grid (campaign.py:815-844):
for fixed_policy, (arm_mask, arm_tokens) in resolved_arms.items():
for state_weight_profile in state_weight_profiles: # <- this axis
for ligand_on in (False, True):
for sidechain_on in (False, True):
spec_variant = replace(
base_spec,
ligand_conditioning=ligand_on,
sidechain_conditioning=sidechain_on,
fixed_mask=..., # fixed in dd6618c
# state_weights is NEVER set from state_weight_profile
)
state_weight_profile is:
- a parameter (
campaign.py:64)
- hashed into
manifest_row_hash (:94)
- written into the row dict (
:111)
- validated for non-emptiness (
:168, :224)
and never resolved to a numeric weight vector anywhere in the codebase. grep confirms state_weight_profile appears only in campaign.py and cli.py, and is never assigned to SamplingSpecification.state_weights (specs.py:597).
Consequence
--state-weight-profiles equal,weighted produces 2× the rows, differently labelled, identically weighted. Duplicate work counted as diversity — the exact defect tev_design already found and worked around on the ligand×sidechain axis (build_necklace_p2_manifest.py:282-304, where 3 of every 4 groups were byte-identical after patching).
Not currently biting the necklace campaign, which uses the default ("equal",) — one profile, so no duplication. But any multi-profile campaign is generating duplicate rows and calling them an ablation.
Why it's the same bug
--fixed-policies took a bare NAME aminx could not resolve, wrote it to the row as a label, and never to the spec. --state-weight-profiles takes a bare NAME ("equal") aminx cannot resolve, writes it to the row as a label, and never to the spec. Both are validated for string non-emptiness — which is a check that the label is present, not that it did anything.
The fix shape is the same as fixed_arms (dd6618c): the declaration must carry its own referent. state_weight_profiles: tuple[str, ...] → a mapping from label to an actual weight vector, so the arm can't name something the planner cannot resolve.
Recommendation
Do it in the same pass as the fixed_arms work, and audit the loop for a third instance rather than assuming there isn't one. Two of the four grid axes in this loop have now been found decorative; ligand_on/sidechain_on are the other two and they DO reach the spec (verified) — but they are hardcoded (False, True) with no way to suppress, which is its own problem (see the tev_design workaround above).
Related: PR #108, aminx#110 (fixed_mask inert at decode), debt #690 (layer parity green while composition void).
Found 2026-07-15 while diffing aminx's user surface against the LigandMPNN reference (PR #108 audit). This is the identical failure to
--fixed-policies, one line above it in the same loop, and I walked past it while fixing that one.The bug
plan_campaign_manifest's grid (campaign.py:815-844):state_weight_profileis:campaign.py:64)manifest_row_hash(:94):111):168,:224)and never resolved to a numeric weight vector anywhere in the codebase. grep confirms
state_weight_profileappears only incampaign.pyandcli.py, and is never assigned toSamplingSpecification.state_weights(specs.py:597).Consequence
--state-weight-profiles equal,weightedproduces 2× the rows, differently labelled, identically weighted. Duplicate work counted as diversity — the exact defect tev_design already found and worked around on the ligand×sidechain axis (build_necklace_p2_manifest.py:282-304, where 3 of every 4 groups were byte-identical after patching).Not currently biting the necklace campaign, which uses the default
("equal",)— one profile, so no duplication. But any multi-profile campaign is generating duplicate rows and calling them an ablation.Why it's the same bug
--fixed-policiestook a bare NAME aminx could not resolve, wrote it to the row as a label, and never to the spec.--state-weight-profilestakes a bare NAME ("equal") aminx cannot resolve, writes it to the row as a label, and never to the spec. Both are validated for string non-emptiness — which is a check that the label is present, not that it did anything.The fix shape is the same as
fixed_arms(dd6618c): the declaration must carry its own referent.state_weight_profiles: tuple[str, ...]→ a mapping from label to an actual weight vector, so the arm can't name something the planner cannot resolve.Recommendation
Do it in the same pass as the
fixed_armswork, and audit the loop for a third instance rather than assuming there isn't one. Two of the four grid axes in this loop have now been found decorative;ligand_on/sidechain_onare the other two and they DO reach the spec (verified) — but they are hardcoded(False, True)with no way to suppress, which is its own problem (see the tev_design workaround above).Related: PR #108, aminx#110 (fixed_mask inert at decode), debt #690 (layer parity green while composition void).