Skip to content

state_weight_profiles is decorative too -- the SAME bug as fixed_policies, in the SAME loop #111

Description

@maraxen

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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions