From a bug sweep of the live parse/solve/export path. The three safe, non-benchmark-affecting fixes from the same sweep were already applied (SCC convergence residual now reports the worst loop instead of the last; REACTOME_CACHE guarded with a lock; multipart upload filename sanitized). The items below change behavior/output and need a decision + likely a benchmark check.
1. Self-loop nodes evaluated once instead of iterated to a fixed point (major)
src/solvers/steady_state.jl solve_scc_ordered! classifies a component as acyclic purely by node count (comp_size[c] == 1). A node with a genuine self-edge (a reaction whose target is also one of its own activators/inhibitors, i.e. parent_uuid == child_uuid) is a real 1-node cycle but takes the acyclic single-eval branch, reading its own pre-update value once instead of relaxing.
- Fix: route size-1 components that have an intra-component input edge through the iterated (loop) branch.
- Impact bounded by how many literal
parent==child reactions the decomposed networks contain — needs a count + benchmark check before changing.
2. Observation condition column silently ignored (major)
cli/deltasignal.jl keys observations by node UUID only; condition is never read. Any observations file where a node appears under more than one condition collapses last-write-wins with no error, and per-condition solving isn't possible. Decide: group/solve per condition, or explicitly error on duplicate node keys.
3. No range/scale validation on observation values (major)
The CLI accepts any value with no clamping, while the documented contract is 0–100 (internal = ui/100). The bundled examples/sample_observations.csv is actually log2-fold-change data (negatives, values <1), so the documented example "succeeds" while producing meaningless clamped output.
- Fix: validate/clamp observation values to [0,100] in the CLI (and warn), and correct the sample file to the 0–100 scale.
4. Dead --mode solve flag (minor)
cli/deltasignal.jl defines --mode but never reads it; the method is hardcoded to "penalty". Remove the flag or thread it into SteadyStateParams.
Also noted (minor, no action assumed)
--output (0–100) vs --output-pathway (0–1) scale mismatch in the same solve.
export --format pathway-browser doesn't aggregate despite the docs listing aggregation methods under export; export_pathway_browser_overlay in reactome_mapper.jl is dead code.
parse_set_mappings docstring describes a 3-column format but the code requires the 4-column long form (sample matches the code).
🤖 Generated with Claude Code
From a bug sweep of the live parse/solve/export path. The three safe, non-benchmark-affecting fixes from the same sweep were already applied (SCC convergence residual now reports the worst loop instead of the last;
REACTOME_CACHEguarded with a lock; multipart upload filename sanitized). The items below change behavior/output and need a decision + likely a benchmark check.1. Self-loop nodes evaluated once instead of iterated to a fixed point (major)
src/solvers/steady_state.jlsolve_scc_ordered!classifies a component as acyclic purely by node count (comp_size[c] == 1). A node with a genuine self-edge (a reaction whose target is also one of its own activators/inhibitors, i.e.parent_uuid == child_uuid) is a real 1-node cycle but takes the acyclic single-eval branch, reading its own pre-update value once instead of relaxing.parent==childreactions the decomposed networks contain — needs a count + benchmark check before changing.2. Observation
conditioncolumn silently ignored (major)cli/deltasignal.jlkeys observations by node UUID only;conditionis never read. Any observations file where a node appears under more than one condition collapses last-write-wins with no error, and per-condition solving isn't possible. Decide: group/solve percondition, or explicitly error on duplicate node keys.3. No range/scale validation on observation values (major)
The CLI accepts any
valuewith no clamping, while the documented contract is 0–100 (internal = ui/100). The bundledexamples/sample_observations.csvis actually log2-fold-change data (negatives, values <1), so the documented example "succeeds" while producing meaningless clamped output.4. Dead
--modesolve flag (minor)cli/deltasignal.jldefines--modebut never reads it; the method is hardcoded to"penalty". Remove the flag or thread it intoSteadyStateParams.Also noted (minor, no action assumed)
--output(0–100) vs--output-pathway(0–1) scale mismatch in the same solve.export --format pathway-browserdoesn't aggregate despite the docs listing aggregation methods underexport;export_pathway_browser_overlayinreactome_mapper.jlis dead code.parse_set_mappingsdocstring describes a 3-column format but the code requires the 4-column long form (sample matches the code).🤖 Generated with Claude Code