What happens
A model that reads static (baseline) data sets static_inclusion_mode: INCLUDE on the datamodule. The fast conformance tier passes — the meds_testing_helpers fixture is simple_static_MEDS_dataset_with_task, which has EYE_COLOR//… and HEIGHT static rows. Then pytest -m slow fails before the model is ever called:
File ".../meds_torchdata/pytorch_dataset.py", line 1822, in collate
static_data = JointNestedRaggedTensorDict(
File ".../nested_ragged_tensors/ragged_numpy.py", line 927, in _initialize_tensors
self._schema[k] = self._infer_dtype(flat_vals)
ValueError: Cannot infer dtype from empty values; provide an explicit `schema=`.
Why
meds_model_base/testing/synthetic.py::build_signal_dataset writes only timestamped events — every row it emits has a time, so the cohort has zero static measurements. With INCLUDE, the static tensors are empty for the whole batch, and nested_ragged_tensors cannot infer a dtype from nothing.
So the template's flagship learnability test cannot exercise INCLUDE at all, and any model that reads static data hits this on the one tier that proves the model learns.
Why it is not a niche case
Static data is a third of TECO's input: the paper concatenates age, sex, ethnicity and race onto every 15-minute interval. Dropping them to make the test pass is exactly the move docs/PORTING-A-MODEL.md step 4 rules out ("it breaks the test fixture" is an illegitimate justification), so the fixture is what has to change.
Suggested fixes
Either or both:
build_signal_dataset emits static measurements. One value-less code and one numeric one per subject, assigned independently of the label, is enough to cover both branches and costs the designed signal nothing. A with_statics: bool = True parameter would keep existing callers working while making the default exercise the path.
- meds-torch-data handles the empty-static case — pass an explicit schema, or skip the static JNRT when there is nothing in it. Arguably the more correct place: an empty static set is a legitimate cohort, not a malformed one.
Workaround in the meantime
tests/test_property.py in the generated repo injects the statics itself before build_workspace:
def add_baseline_variables(root: Path, seed: int) -> Path:
"""One value-less and one numeric static per subject, drawn from a generator independent of the
one that decides the labels — so the baseline variables carry no information about the outcome and
the negative control stays a control."""
That is a fixture change rather than a model change, which is the right side of the line, but every model that reads statics will have to rediscover and rewrite it.
Found while porting TECO; recorded in that repo's IMPLEMENTATION_REPORT.md §7.2.
What happens
A model that reads static (baseline) data sets
static_inclusion_mode: INCLUDEon the datamodule. The fast conformance tier passes — themeds_testing_helpersfixture issimple_static_MEDS_dataset_with_task, which hasEYE_COLOR//…andHEIGHTstatic rows. Thenpytest -m slowfails before the model is ever called:Why
meds_model_base/testing/synthetic.py::build_signal_datasetwrites only timestamped events — every row it emits has atime, so the cohort has zero static measurements. WithINCLUDE, the static tensors are empty for the whole batch, andnested_ragged_tensorscannot infer a dtype from nothing.So the template's flagship learnability test cannot exercise
INCLUDEat all, and any model that reads static data hits this on the one tier that proves the model learns.Why it is not a niche case
Static data is a third of TECO's input: the paper concatenates age, sex, ethnicity and race onto every 15-minute interval. Dropping them to make the test pass is exactly the move
docs/PORTING-A-MODEL.mdstep 4 rules out ("it breaks the test fixture" is an illegitimate justification), so the fixture is what has to change.Suggested fixes
Either or both:
build_signal_datasetemits static measurements. One value-less code and one numeric one per subject, assigned independently of the label, is enough to cover both branches and costs the designed signal nothing. Awith_statics: bool = Trueparameter would keep existing callers working while making the default exercise the path.Workaround in the meantime
tests/test_property.pyin the generated repo injects the statics itself beforebuild_workspace:That is a fixture change rather than a model change, which is the right side of the line, but every model that reads statics will have to rediscover and rewrite it.
Found while porting TECO; recorded in that repo's
IMPLEMENTATION_REPORT.md§7.2.