A per-observable noise_model override or cumulative flag whose observable name matches no data column is silently ignored; that column is scored with the default noise model
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 70/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- python
- Domain
- backend, testing-qa
Research direction
The bug is in pybnf/objective.py lines 1116-1120 and 1130-1131 where noise model overrides and cumulative flags are stored without validation. Start by reading the _build_noise_overrides and _build_cumulative_cols methods. Check how _spec_for (line 1211) falls back to defaults. The fix is to validate observable names against data columns, similar to the normalization check in config.py lines 4072-4073. Run the provided reproduction scripts (typo.conf, good.conf) to verify the fix changes the score when the name is corrected.
Written by the indexing model from the issue text.
Description
_build_noise_overrides (lines 1116-1120) stores an override for whatever name the line gives. _build_cumulative_cols (1130-1131) does the same for the cumulative flag. Neither name is checked against the data columns. _spec_for (1211) falls back to the whole-fit default for any column without an override, and _is_cumulative (800) is a plain membership test, so a mistyped name matches nothing and nothing is reported. The noise parameter the override names is still required and declared (required_free_noise_params), so it is searched as a dead dimension and counted in k. By contrast, per-observable normalization names are validated as typos (config.py:4072-4073), and so are observable: overrides.
Failure scenario
05_noisy_decay with objective = chi_sq plus noise_model ObsA = laplace, scale = fit b__FREE (the column is Obs_A) and uniform_var = b__FREE 0.1 10. The run finishes without a warning. Obs_A is still scored by chi_sq, and b__FREE does not affect the score: gen1ind5 (b=1.61) and gen0ind2 (b=5.80) with identical k and A0 both score 488.60048070741726. The reported b__FREE is meaningless, and k=3 in AIC includes it. With the correct name, Obs_A, the same seed gives 91.88. A typo'd cumulative flag would likewise leave a cumulative column undifferenced.
Reproduction (independent re-run)
Objective level. The script ran load_config then conf.obj.evaluate_multiple on the real config path. The simulated trajectory is the exact analytic A0·exp(-kt). pybnf was imported from pybnf/init.py.
typo.conf (noise_model ObsA): the override is keyed ['ObsA'], the data columns are ['time','Obs_A','Obs_A_SD'], and required_free_noise_params is ['b']. At k=0.5, A0=100:
| b | pybnf | independent chi_sq (Obs_A) | independent Laplace NLL (scipy) |
|---|---|---|---|
| 0.5 | 8.4945313933 | 8.4945313933 | 89.1933353978 |
| 2 | 8.4945313933 | 8.4945313933 | 51.4105154330 |
| 5 | 8.4945313933 | 8.4945313933 | 57.2736204927 |
The score is chi_sq and does not depend on b.
good.conf (noise_model Obs_A): pybnf gives 89.1933353978, 51.4105154330 and 57.2736204927 for the same three b values, matching scipy's Laplace NLL exactly.
cumtypo.conf: _cumulative_cols is ['obs_A'], and _is_cumulative('Obs_A') is False.
End to end. pybnf -c typo.conf (de, pop 6, 3 iterations, seed 1) exits 0 with no config error or warning about the name.
- sorted_params_final.txt: gen1ind5 (b=1.6127) and gen0ind2 (b=5.7983) have identical k and A0 and both score 488.60048070741726.
- The best fit scores 279.11 and reports b=6.2826, a value that never entered the objective.
- information_criteria.txt has k=3.
The same seed with the correct name gives a best score of 91.876.
Reachability
Any edition-2 conf with a per-observable noise_model line whose observable name differs from the data column, including by case only. Example:
edition = 2
model: noisy_decay.bngl
objective = chi_sq
noise_model ObsA = laplace, scale = fit b
experiment: timecourse, data: noisy_decay.exp
uniform_var = b 0.1 10
The data column is Obs_A. The cumulative case is the same: noise_model obs_A = normal, sigma = fix_at 3, cumulative. Per report #29, edition-1 per-observable lines take the same code path; I did not run that case.
Where
pybnf/objective.py:1117 pybnf/objective.py:1211
Found in a whole-codebase audit for silently wrong results (2026-09-23); the reproduction above was re-run independently of the original finding.
- Dominant language
- Python
- Stars
- 25
- Forks
- 25
- Avg merge
- 2h 24m
- Merged PRs (30d)
- 85
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from lanl/PyBNF
-
A transient error from the BioNetGen download turns a whole test matrix leg red before any test runs Openenhancement
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 65/100
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 65/100
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 45/100
Similar issues
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
stephrobert/dsoxlab#238 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
sublimehq/package_control#1780 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
nwg-piotr/nwg-displays#145 ·