Why
Production scoring is hardwired to a single asset class. Both production callers pass
weights_by_asset_class=weights_by_asset_class_for("credit"):
src/inv_man_intake/v1_smoke.py:303-306 (also asset_class="credit") and
app/streamlit_app.py:197-200. But weights_by_asset_class_for (scoring/weights.py:111-117) returns a
single-key dict {that_one_class: weights}. So compute_score's weight_sets[canonical_asset_class]
(engine.py:116) only has credit_long_short. Verified by execution: a submission with
asset_class="macro" and the credit weights dict raises
ValueError: missing weight set for canonical asset class 'macro'.
Consequence: the #592 fix wired only credit. The other 7 launch asset-class TOMLs
(config/scoring_weights/{activist,macro,quant,multi_strat,trend_following,credit_relative_value,equity_market_neutral}.toml)
— which load_weight_registry validates must all exist (weights.py:91-93) — are never used in any
production scoring path and would crash if used. This is a current break for any non-credit manager.
Scope
Make the production scoring path use the weight set for the submission's actual asset class, so all 8
launch TOMLs are live. Either (a) have callers pass the full registry shaped for compute_score, or
(b) add a weights_for_registry() helper returning all classes and use it in v1_smoke.py + streamlit_app.py,
and stop hardcoding asset_class="credit" where a real asset class is available.
Non-Goals
- Do NOT change the weight VALUES in the TOMLs or
default_weights_by_asset_class().
- Do NOT change
compute_score's selection logic (it already picks by canonical asset class).
- Scaffold-only completion does NOT count: wiring that still only loads credit, or that leaves a non-credit
submission raising, is a failure. The multi-class test below must pass.
Tasks
Acceptance Criteria
Implementation Notes
- Confirmed:
compute_score(ScoreSubmission(asset_class="macro", components=[...]), weights_by_asset_class=weights_by_asset_class_for("credit")) → ValueError.
load_weight_registry() (weights.py:75-94) already loads + validates all 8; the only gap is the single-key
reshaping in weights_by_asset_class_for and the hardcoded "credit" at the call sites.
Why
Production scoring is hardwired to a single asset class. Both production callers pass
weights_by_asset_class=weights_by_asset_class_for("credit"):src/inv_man_intake/v1_smoke.py:303-306(alsoasset_class="credit") andapp/streamlit_app.py:197-200. Butweights_by_asset_class_for(scoring/weights.py:111-117) returns asingle-key dict
{that_one_class: weights}. Socompute_score'sweight_sets[canonical_asset_class](
engine.py:116) only hascredit_long_short. Verified by execution: a submission withasset_class="macro"and the credit weights dict raisesValueError: missing weight set for canonical asset class 'macro'.Consequence: the #592 fix wired only credit. The other 7 launch asset-class TOMLs
(
config/scoring_weights/{activist,macro,quant,multi_strat,trend_following,credit_relative_value,equity_market_neutral}.toml)— which
load_weight_registryvalidates must all exist (weights.py:91-93) — are never used in anyproduction scoring path and would crash if used. This is a current break for any non-credit manager.
Scope
Make the production scoring path use the weight set for the submission's actual asset class, so all 8
launch TOMLs are live. Either (a) have callers pass the full registry shaped for
compute_score, or(b) add a
weights_for_registry()helper returning all classes and use it inv1_smoke.py+streamlit_app.py,and stop hardcoding
asset_class="credit"where a real asset class is available.Non-Goals
default_weights_by_asset_class().compute_score's selection logic (it already picks by canonical asset class).submission raising, is a failure. The multi-class test below must pass.
Tasks
scoring/weights.py::weights_for_registry(config_dir=None) -> dict[str, dict[str, float]]returningevery launch class from
load_weight_registryincompute_scoreshape.v1_smoke.py:300-306, pass the manager's real asset class (not the literal"credit") and thefull-registry weights (or
weights_by_asset_class_for(<real_class>)).app/streamlit_app.py:194-200(and_browser_safe_demo_fixture), do the same.tests/scoring/test_weights_config.py::test_compute_score_works_for_all_launch_classesscoring onesubmission per launch class through the registry weights.
Acceptance Criteria
test_compute_score_works_for_all_launch_classespasses: each of the 8 launch asset classesscores without raising, using its own TOML weights.
config/scoring_weights/macro.toml) to change aweight (keeping sum=1.0); the macro case in the named test must observe the changed score (assert the
contribution reflects the edit). Revert; assertion returns to baseline. Capture both. (Proves operator edits
to non-credit TOMLs now affect scores.)
pytest tests/scoring/ tests/baseline/ -qgreen.Implementation Notes
compute_score(ScoreSubmission(asset_class="macro", components=[...]), weights_by_asset_class=weights_by_asset_class_for("credit"))→ValueError.load_weight_registry()(weights.py:75-94) already loads + validates all 8; the only gap is the single-keyreshaping in
weights_by_asset_class_forand the hardcoded"credit"at the call sites.