{"record":{"id":"20ca05f0682c965d","repo":"a-b-street/abstreet","slug":"this-intersection-doesn-t-use-fixed-timing","errorCode":null,"errorMessage":"This intersection doesn't use fixed timing.","messagePattern":"This intersection doesn't use fixed timing\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"map_model/src/objects/traffic_signals.rs","lineNumber":236,"sourceCode":"        // What's the rank of each road?\n        let mut rank_per_road: BTreeMap<RoadID, usize> = BTreeMap::new();\n        for r in &map.get_i(self.id).roads {\n            rank_per_road.insert(*r, map.get_r(*r).get_detailed_rank());\n        }\n        let mut ranks: Vec<usize> = rank_per_road.values().cloned().collect();\n        ranks.sort_unstable();\n        ranks.dedup();\n        if ranks.len() == 1 {\n            bail!(\"This intersection doesn't have major/minor roads; they're all the same rank.\");\n        }\n        let highest_rank = ranks.pop().unwrap();\n\n        // Try to apply the transformation\n        let orig = self.clone();\n        for stage in &mut self.stages {\n            match stage.stage_type {\n                StageType::Fixed(_) => {}\n                _ => bail!(\"This intersection doesn't use fixed timing.\"),\n            }\n            // Ignoring crosswalks, do any of the turns come from a major road?\n            if stage\n                .protected_movements\n                .iter()\n                .any(|m| !m.crosswalk && highest_rank == rank_per_road[&m.from.road])\n            {\n                stage.stage_type = StageType::Fixed(major);\n            } else {\n                stage.stage_type = StageType::Fixed(minor);\n            }\n        }\n\n        if self.simple_cycle_duration() != major + minor {\n            bail!(\"This intersection didn't already group major/minor roads together.\");\n        }\n\n        if self == &orig {","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/map_model/src/objects/traffic_signals.rs#L218-L254","documentation":"adjust_major_minor_timing only rewrites StageType::Fixed stages. If any stage uses a different StageType (e.g. adaptive/variable timing), the method bails rather than silently overwriting a non-fixed timing policy.","triggerScenarios":"Calling adjust_major_minor_timing on a signal whose stages include a non-Fixed StageType variant, encountered in the loop over self.stages before any duration is modified.","commonSituations":"Signals loaded from a scenario or edited with adaptive timing; mixing timing plugins/experiments with the fixed major/minor retiming helper.","solutions":["Convert all stages to StageType::Fixed before calling adjust_major_minor_timing","Skip signals using non-fixed timing, or use the appropriate API for that timing type","Recreate the signal assignment with default fixed stages","Persist/restore fixed timing before applying major/minor durations"],"exampleFix":"// before\nsignal.adjust_major_minor_timing(major, minor, map)?;\n// after\nif signal.stages.iter().all(|s| matches!(s.stage_type, StageType::Fixed(_))) {\n    signal.adjust_major_minor_timing(major, minor, map)?;\n}","handlingStrategy":"validation","validationCode":"if !signal.stages.iter().all(|s| matches!(s.stage_type, StageType::Fixed(_))) {\n    return Err(anyhow!(\"signal {} uses non-fixed timing\", signal.id));\n}","typeGuard":"fn all_fixed(signal: &TrafficSignal) -> bool {\n    signal.stages.iter().all(|s| matches!(s.stage_type, StageType::Fixed(_)))\n}","tryCatchPattern":"if all_fixed(signal) {\n    signal.adjust_major_minor_timing(major, minor, map)?;\n} else {\n    skip_non_fixed(signal.id);\n}","preventionTips":["Convert stages to StageType::Fixed before fixed-duration retiming","Track which signals use adaptive timing and route them to the right API","Avoid mixing timing policies on the same signal"],"tags":["traffic-signals","stage-type","precondition"],"backgroundTag":"unsupported-operation","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}