🤖 This issue was written by Claude Code, acting on Jack's behalf.
BaseForecasterConfig is a plain pydantic BaseModel, so it inherits pydantic's default
extra="ignore". A config_overrides key that does not name a real field is silently dropped:
registers happily, trains with n_estimators=500 from the base YAML, and produces a run that
looks like a valid experiment.
Why this matters more than a typo usually would
Both planned search mechanisms are programmatic and unattended, so nobody reads the resolved
config before the runs go out:
One misspelled key in either produces a grid of identical runs that all score plausibly and all
land on the leaderboard. That is a principle 8
problem, not just an ergonomics one: the scores are real, but the experiments are not what they
claim to be, and nothing distinguishes the bad grid from a genuine null result.
It is also a naming-poka-yoke case — make the wrong usage fail to parse rather than merely be discouraged.
Proposed change
Add model_config = ConfigDict(extra="forbid") to BaseForecasterConfig
(packages/ml_core/src/ml_core/base_forecaster.py), so an unknown key raises ValidationError at
registration time, before any fold runs.
Check before landing: _resolve_forecaster_config pops both _target_ keys before construction,
so those must not trip the new strictness; and conf/model/xgboost.yaml's model_params must
contain no key that is not a declared field.
Out of scope
Not part of #228 — the
behaviour is identical before and after the Hydra removal (Hydra's instantiate also just called
the constructor). Filed separately so the removal stays a pure swap.
BaseForecasterConfigis a plain pydanticBaseModel, so it inherits pydantic's defaultextra="ignore". Aconfig_overrideskey that does not name a real field is silently dropped:{"n_estimtors": 5000}registers happily, trains with
n_estimators=500from the base YAML, and produces a run thatlooks like a valid experiment.
Why this matters more than a typo usually would
Both planned search mechanisms are programmatic and unattended, so nobody reads the resolved
config before the runs go out:
One misspelled key in either produces a grid of identical runs that all score plausibly and all
land on the leaderboard. That is a principle 8
problem, not just an ergonomics one: the scores are real, but the experiments are not what they
claim to be, and nothing distinguishes the bad grid from a genuine null result.
It is also a naming-poka-yoke case — make the wrong usage fail to parse rather than merely be discouraged.
Proposed change
Add
model_config = ConfigDict(extra="forbid")toBaseForecasterConfig(
packages/ml_core/src/ml_core/base_forecaster.py), so an unknown key raisesValidationErroratregistration time, before any fold runs.
Check before landing:
_resolve_forecaster_configpops both_target_keys before construction,so those must not trip the new strictness; and
conf/model/xgboost.yaml'smodel_paramsmustcontain no key that is not a declared field.
Out of scope
Not part of #228 — the
behaviour is identical before and after the Hydra removal (Hydra's
instantiatealso just calledthe constructor). Filed separately so the removal stays a pure swap.