From 4168fc6d7f2d5c47c0150a3d90de7e3ce2572847 Mon Sep 17 00:00:00 2001 From: Xiwei Pan Date: Sun, 2 Aug 2026 09:02:52 +0800 Subject: [PATCH 1/4] Add plan for #1096: MinimumDominatingSet to MinimumHittingSet --- ...m-dominating-set-to-minimum-hitting-set.md | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 docs/plans/2026-08-02-minimum-dominating-set-to-minimum-hitting-set.md diff --git a/docs/plans/2026-08-02-minimum-dominating-set-to-minimum-hitting-set.md b/docs/plans/2026-08-02-minimum-dominating-set-to-minimum-hitting-set.md new file mode 100644 index 000000000..555823867 --- /dev/null +++ b/docs/plans/2026-08-02-minimum-dominating-set-to-minimum-hitting-set.md @@ -0,0 +1,79 @@ +# Implement MinimumDominatingSet/One to MinimumHittingSet + +Issue: #1096 + +Base: `1075-growth-domain` at `a9067297` + +## Scope + +Add one witness-preserving reduction from +`MinimumDominatingSet` to `MinimumHittingSet`. The source +vertices become target universe elements, and every source vertex contributes +its closed neighborhood as one target set. Target configurations map back by +identity, preserving feasibility and cardinality. + +The construction follows Bannach and Tantau, *Computing Hitting Set Kernels By +AC^0-Circuits* (STACS 2018, DOI 10.4230/LIPIcs.STACS.2018.9), which states the +closed-neighborhood equivalence directly. Garey and Johnson (1979) supplies the +endpoint definitions already cited by the issue. + +## Batch 1: Verify and implement the reduction + +Follow `add-rule` Steps 1-5 and 7 for the code, tests, and canonical example. + +1. Run the full `verify-reduction` workflow before editing Rust: + - prove that `D subset.eq V` dominates `G` iff it hits every closed + neighborhood `N[v]`; + - verify identity extraction and exact objective preservation; + - verify `universe_size = num_vertices` and + `num_sets = num_vertices` symbolically and concretely; + - exercise all simple graphs through five vertices with at least 5,000 + constructor checks and an independent adversary implementation; + - include a five-vertex path as the feasible/optimal example and a + three-vertex instance with an impossible fixed candidate configuration as + the negative feasibility example. +2. Add + `src/rules/minimumdominatingset_minimumhittingset.rs`: + - build one sorted closed-neighborhood vector per vertex; + - construct `MinimumHittingSet::new(num_vertices, sets)`; + - implement identity `extract_solution`; + - register the exact endpoint pair with overhead fields + `universe_size = "num_vertices"` and + `num_sets = "num_vertices"`. +3. Register the module and its canonical example specs in `src/rules/mod.rs`. +4. Add focused tests in + `src/unit_tests/rules/minimumdominatingset_minimumhittingset.rs`: + - required optimization closed loop on the five-vertex path; + - exact target closed-neighborhood structure; + - identity extraction; + - empty, isolated, disconnected, star, and complete graph behavior; + - exhaustive objective/feasibility equivalence for all simple graphs + through four vertices. +5. Add the issue's path example to the rule's canonical example specs with + source and target witness `[0, 1, 0, 1, 0]`. +6. Run focused tests and formatting, then regenerate the graph, schemas, and + example fixture required by the paper. + +## Batch 2: Document the rule in the paper + +Follow `add-rule` Step 6 with fresh context after Batch 1 has produced the +canonical fixture. + +1. Add the Bannach--Tantau citation to `docs/paper/references.bib` if it is not + already present. +2. Add a `reduction-rule("MinimumDominatingSet", "MinimumHittingSet", ...)` + entry to `docs/paper/reductions.typ`, selecting the source variant + `(graph: "SimpleGraph", weight: "One")`. +3. Derive the `pred create --example` command from the loaded fixture via the + existing `problem-spec`/`target-spec` helpers. +4. Explain construction, both correctness directions, exact overhead, + identity extraction, and the five-vertex path round trip in tutorial form. +5. Run `make paper` and correct any paper or fixture mismatch. + +## Final verification + +Run `cargo run --example export_graph`, +`cargo run --example export_schemas`, `make regenerate-fixtures`, +`make test`, `make clippy`, `make fmt-check`, and `make paper`. Inspect the +working tree so only issue-required tracked changes are committed and the plan +file is removed before the final push. From 6bb24bfd1c1928c5b28ec406081cd8b2082cee78 Mon Sep 17 00:00:00 2001 From: Xiwei Pan Date: Sun, 2 Aug 2026 09:12:56 +0800 Subject: [PATCH 2/4] Implement #1096: reduce dominating set to hitting set --- .../minimumdominatingset_minimumhittingset.rs | 83 +++++++++++ src/rules/mod.rs | 2 + .../minimumdominatingset_minimumhittingset.rs | 138 ++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 src/rules/minimumdominatingset_minimumhittingset.rs create mode 100644 src/unit_tests/rules/minimumdominatingset_minimumhittingset.rs diff --git a/src/rules/minimumdominatingset_minimumhittingset.rs b/src/rules/minimumdominatingset_minimumhittingset.rs new file mode 100644 index 000000000..f4ba1871c --- /dev/null +++ b/src/rules/minimumdominatingset_minimumhittingset.rs @@ -0,0 +1,83 @@ +//! Reduction from unit-weight MinimumDominatingSet to MinimumHittingSet. +//! +//! Vertices become universe elements, and each vertex contributes its closed +//! neighborhood as a set. A dominating set is exactly a hitting set for this +//! collection. + +use crate::models::graph::MinimumDominatingSet; +use crate::models::set::MinimumHittingSet; +use crate::reduction; +use crate::rules::traits::{ReduceTo, ReductionResult}; +use crate::topology::{Graph, SimpleGraph}; +use crate::types::One; + +/// Result of reducing MinimumDominatingSet to MinimumHittingSet. +#[derive(Debug, Clone)] +pub struct ReductionDominatingSetToHittingSet { + target: MinimumHittingSet, +} + +impl ReductionResult for ReductionDominatingSetToHittingSet { + type Source = MinimumDominatingSet; + type Target = MinimumHittingSet; + + fn target_problem(&self) -> &Self::Target { + &self.target + } + + fn extract_solution(&self, target_solution: &[usize]) -> Vec { + target_solution.to_vec() + } +} + +#[reduction( + overhead = { + universe_size = "num_vertices", + num_sets = "num_vertices", + } +)] +impl ReduceTo for MinimumDominatingSet { + type Result = ReductionDominatingSetToHittingSet; + + fn reduce_to(&self) -> Self::Result { + let num_vertices = self.graph().num_vertices(); + let sets = (0..num_vertices) + .map(|vertex| { + let mut closed_neighborhood: Vec<_> = + self.closed_neighborhood(vertex).into_iter().collect(); + closed_neighborhood.sort_unstable(); + closed_neighborhood + }) + .collect(); + + ReductionDominatingSetToHittingSet { + target: MinimumHittingSet::new(num_vertices, sets), + } + } +} + +#[cfg(feature = "example-db")] +pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + + vec![crate::example_db::specs::RuleExampleSpec { + id: "minimumdominatingset_to_minimumhittingset", + build: || { + let source = MinimumDominatingSet::new( + SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)]), + vec![One; 5], + ); + crate::example_db::specs::rule_example_with_witness::<_, MinimumHittingSet>( + source, + SolutionPair { + source_config: vec![0, 1, 0, 1, 0], + target_config: vec![0, 1, 0, 1, 0], + }, + ) + }, + }] +} + +#[cfg(test)] +#[path = "../unit_tests/rules/minimumdominatingset_minimumhittingset.rs"] +mod tests; diff --git a/src/rules/mod.rs b/src/rules/mod.rs index 95eb5f477..3d37abcfe 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -92,6 +92,7 @@ pub(crate) mod maximumsetpacking_qubo; pub(crate) mod minimumcostmaximumflow_minimumcostcirculation; pub(crate) mod minimumcoveringbycliques_minimumintersectiongraphbasis; pub(crate) mod minimumdiscreteplanarinversekinematics_qubo; +pub(crate) mod minimumdominatingset_minimumhittingset; pub(crate) mod minimumfeedbackarcset_maximumlikelihoodranking; pub(crate) mod minimumfeedbackvertexset_minimumcodegenerationunlimitedregisters; pub(crate) mod minimummaximalmatching_maximumachromaticnumber; @@ -498,6 +499,7 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, +) -> MinimumDominatingSet { + MinimumDominatingSet::new( + SimpleGraph::new(num_vertices, edges), + vec![One; num_vertices], + ) +} + +fn assert_config_equivalent( + problem: &MinimumDominatingSet, + target: &MinimumHittingSet, + config: &[usize], +) { + let selected = config.iter().sum::(); + let source_value = problem.evaluate(config).0.map(|value| value as usize); + let target_value = target.evaluate(config).0; + let expected = problem.is_valid_solution(config).then_some(selected); + + assert_eq!(source_value, expected); + assert_eq!(target_value, expected); +} + +#[test] +fn test_minimumdominatingset_to_minimumhittingset_closed_loop() { + let problem = source(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)]); + let reduction = ReduceTo::::reduce_to(&problem); + + assert_optimization_round_trip_from_optimization_target( + &problem, + &reduction, + "MinimumDominatingSet(One)->MinimumHittingSet closed loop", + ); +} + +#[test] +fn test_closed_neighborhood_structure() { + let problem = source(5, vec![(0, 2), (0, 1), (1, 3), (3, 4)]); + let reduction = ReduceTo::::reduce_to(&problem); + let target = reduction.target_problem(); + + assert_eq!(target.universe_size(), 5); + assert_eq!(target.num_sets(), 5); + assert_eq!( + target.sets(), + &[ + vec![0, 1, 2], + vec![0, 1, 3], + vec![0, 2], + vec![1, 3, 4], + vec![3, 4], + ] + ); +} + +#[test] +fn test_identity_extraction() { + let problem = source(3, vec![(0, 1), (1, 2)]); + let reduction = ReduceTo::::reduce_to(&problem); + + assert_eq!(reduction.extract_solution(&[0, 1, 0]), vec![0, 1, 0]); +} + +#[test] +fn test_empty_graph() { + let problem = source(0, vec![]); + let reduction = ReduceTo::::reduce_to(&problem); + + assert_eq!(reduction.target_problem().universe_size(), 0); + assert!(reduction.target_problem().sets().is_empty()); + assert_config_equivalent(&problem, reduction.target_problem(), &[]); +} + +#[test] +fn test_isolated_and_disconnected_vertices() { + let problem = source(5, vec![(0, 1), (2, 3)]); + let reduction = ReduceTo::::reduce_to(&problem); + + assert_eq!( + reduction.target_problem().sets(), + &[vec![0, 1], vec![0, 1], vec![2, 3], vec![2, 3], vec![4],] + ); + assert_config_equivalent(&problem, reduction.target_problem(), &[1, 0, 1, 0, 1]); +} + +#[test] +fn test_star_and_complete_graphs() { + let star = source(4, vec![(0, 1), (0, 2), (0, 3)]); + let star_reduction = ReduceTo::::reduce_to(&star); + assert_config_equivalent(&star, star_reduction.target_problem(), &[1, 0, 0, 0]); + + let complete = source(4, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]); + let complete_reduction = ReduceTo::::reduce_to(&complete); + assert!(complete_reduction + .target_problem() + .sets() + .iter() + .all(|set| set == &vec![0, 1, 2, 3])); + assert_config_equivalent( + &complete, + complete_reduction.target_problem(), + &[0, 0, 1, 0], + ); +} + +#[test] +fn test_exhaustive_equivalence_through_four_vertices() { + for num_vertices in 0..=4 { + let possible_edges: Vec<_> = (0..num_vertices) + .flat_map(|u| ((u + 1)..num_vertices).map(move |v| (u, v))) + .collect(); + + for graph_mask in 0..(1_usize << possible_edges.len()) { + let edges = possible_edges + .iter() + .enumerate() + .filter_map(|(index, &edge)| ((graph_mask >> index) & 1 == 1).then_some(edge)) + .collect(); + let problem = source(num_vertices, edges); + let reduction = ReduceTo::::reduce_to(&problem); + + assert_eq!(reduction.target_problem().universe_size(), num_vertices); + assert_eq!(reduction.target_problem().num_sets(), num_vertices); + + for config_mask in 0..(1_usize << num_vertices) { + let config: Vec<_> = (0..num_vertices) + .map(|vertex| (config_mask >> vertex) & 1) + .collect(); + assert_config_equivalent(&problem, reduction.target_problem(), &config); + } + } + } +} From 7824fe3b1787cb74e37eea3f08b279aa37819b8e Mon Sep 17 00:00:00 2001 From: Xiwei Pan Date: Sun, 2 Aug 2026 09:16:56 +0800 Subject: [PATCH 3/4] Document #1096 dominating set reduction --- docs/paper/reductions.typ | 47 +++++++++++++++++++++++++++++++++++++++ docs/paper/references.bib | 11 +++++++++ 2 files changed, 58 insertions(+) diff --git a/docs/paper/reductions.typ b/docs/paper/reductions.typ index 88cd07556..6cac0e2a4 100644 --- a/docs/paper/reductions.typ +++ b/docs/paper/reductions.typ @@ -14321,6 +14321,53 @@ The following reductions to Integer Linear Programming are straightforward formu _Remark._ Zero-weight edges are excluded because they allow degenerate optimal ILP solutions containing redundant cycles at no cost; following the convention of practical solvers (e.g., SCIP-Jack @kochmartin1998steiner), such edges should be contracted before applying the reduction. ] +#let mds_hs = load-example( + "MinimumDominatingSet", + "MinimumHittingSet", + source-variant: (graph: "SimpleGraph", weight: "One"), +) +#let mds_hs_sol = mds_hs.solutions.at(0) +#let mds_hs_graph = mds_hs.source.instance.graph +#let mds_hs_sets = mds_hs.target.instance.sets +#let mds_hs_dominators = mds_hs_sol.source_config.enumerate().filter(((i, x)) => x == 1).map(((i, _)) => i) +#let mds_hs_hits = mds_hs_sol.target_config.enumerate().filter(((i, x)) => x == 1).map(((i, _)) => i) +#let mds_hs_incidences = mds_hs_sets.map(s => s.len()).sum() +#reduction-rule("MinimumDominatingSet", "MinimumHittingSet", + example: true, + example-source-variant: (graph: "SimpleGraph", weight: "One"), + example-caption: [Five-vertex path: closed neighborhoods form a Hitting Set instance], + extra: [ + #pred-commands( + "pred create --example " + problem-spec(mds_hs.source) + " -o dominating-set.json", + "pred reduce dominating-set.json --to " + target-spec(mds_hs) + " -o bundle.json", + "pred solve bundle.json", + "pred evaluate dominating-set.json --config " + mds_hs_sol.source_config.map(str).join(","), + ) + + *Step 1 -- Read the source path.* The fixture has $n = #mds_hs_graph.num_vertices$ vertices and $m = #mds_hs_graph.edges.len()$ edges, ordered as #mds_hs_graph.edges.map(((u, v)) => [$(#u, #v)$]).join(", "). Thus it is the path $0 dash 1 dash 2 dash 3 dash 4$, and its canonical dominating-set witness is $D = {#mds_hs_dominators.map(str).join(", ")}$. In indicator order this is $(#mds_hs_sol.source_config.map(str).join(", "))$. + + *Step 2 -- Replace vertices by closed neighborhoods.* Keep the vertex labels as the universe $U = {0, dots, #(mds_hs.target.instance.universe_size - 1)}$. For each vertex $v$, insert the set $N[v]$ consisting of $v$ and its neighbors. In source-vertex order the fixture yields #mds_hs_sets.enumerate().map(((v, s)) => [$N[#v] = {#s.map(str).join(", ")}$]).join(", "). + + *Step 3 -- Account for the exact overhead.* The target has $#mds_hs.target.instance.universe_size = n$ universe elements and $#mds_hs_sets.len() = n$ sets. Across those sets there are $#mds_hs_incidences = n + 2 m = #(mds_hs_graph.num_vertices + 2 * mds_hs_graph.edges.len())$ incidences: each vertex contributes itself once, and each undirected edge contributes its two endpoints to one another's closed neighborhoods. The construction therefore takes $O(n + m)$ time and space. + + *Step 4 -- Verify the round trip.* The target witness chooses $H = {#mds_hs_hits.map(str).join(", ")}$, with indicator vector $(#mds_hs_sol.target_config.map(str).join(", "))$. It intersects every displayed neighborhood: $1$ hits $N[0], N[1], N[2]$, while $3$ hits $N[2], N[3], N[4]$. Hence $H$ is a hitting set of size #mds_hs_hits.len(). Identity extraction returns the same coordinates, so the recovered source set is $D = H$ and dominates every path vertex #sym.checkmark + + *Multiplicity:* The fixture stores one canonical witness, not all optimal witnesses. Every minimum dominating set of this path is also a minimum hitting set under the same indicator vector, and conversely, because the construction and extraction preserve selected vertex labels exactly. + ], +)[ + The closed-neighborhood reduction noted by Bannach and Tantau @bannachTantau2018 maps a unit-weight graph $G = (V, E)$ to the Hitting Set instance whose universe is $V$ and whose sets are the closed neighborhoods $N[v]$. It is computable in $O(n + m)$ time and space and produces exactly $n$ universe elements, $n$ sets, and $n + 2m$ element-set incidences. +][ + _Construction._ Let $G = (V, E)$ be a simple undirected graph with $n = |V|$ vertices and $m = |E|$ edges. For $v in V$, define its closed neighborhood by + $ N[v] = {v} union {u in V : {u, v} in E}. $ + Construct the Minimum Hitting Set instance with universe $U = V$ and collection + $ cal(S) = {N[v] : v in V}. $ + A target coordinate $h_v$ represents the same selected vertex as the source coordinate $d_v$. Consequently, $|U| = n$, $|cal(S)| = n$, and $sum_(S in cal(S)) |S| = n + 2m$: every vertex supplies one self-incidence and every edge supplies two neighbor incidences. + + _Correctness._ ($arrow.r.double$) Let $D subset.eq V$ be a dominating set. For every $v in V$, either $v in D$ or a neighbor of $v$ lies in $D$. Equivalently, $D inter N[v] != emptyset$. Thus $D$ hits every set in $cal(S)$ and is a hitting set. ($arrow.l.double$) Let $H subset.eq U$ hit every set in $cal(S)$. For every $v in V$, $H inter N[v] != emptyset$, so either $v in H$ or some neighbor of $v$ lies in $H$. Hence $H$ dominates every vertex and is a dominating set. The correspondence preserves the selected vertex set and therefore its cardinality, so minimum solutions and optimal values coincide. + + _Solution extraction._ Return the target indicator vector unchanged: $d_v = h_v$ for every $v in V$. This identity extraction is valid for every target witness, not only the canonical fixture witness. +] + #let mvc_hs = load-example("MinimumVertexCover", "MinimumHittingSet") #let mvc_hs_sol = mvc_hs.solutions.at(0) #let mvc_hs_cover = mvc_hs_sol.source_config.enumerate().filter(((i, x)) => x == 1).map(((i, x)) => i) diff --git a/docs/paper/references.bib b/docs/paper/references.bib index 186f70de2..f8653049e 100644 --- a/docs/paper/references.bib +++ b/docs/paper/references.bib @@ -2143,3 +2143,14 @@ @article{berlekampMcElieceTilborg1978 doi = {10.1109/TIT.1978.1055873} } +@inproceedings{bannachTantau2018, + author = {Max Bannach and Till Tantau}, + title = {Computing Hitting Set Kernels By {$AC^0$}-Circuits}, + booktitle = {35th Symposium on Theoretical Aspects of Computer Science (STACS 2018)}, + series = {Leibniz International Proceedings in Informatics (LIPIcs)}, + volume = {96}, + pages = {9:1--9:14}, + year = {2018}, + publisher = {Schloss Dagstuhl -- Leibniz-Zentrum f{\"u}r Informatik}, + doi = {10.4230/LIPIcs.STACS.2018.9} +} From 177b561fe462a219fc7aa1c87708408eb8d9f6b8 Mon Sep 17 00:00:00 2001 From: Xiwei Pan Date: Sun, 2 Aug 2026 09:25:18 +0800 Subject: [PATCH 4/4] chore: remove plan file after implementation --- ...m-dominating-set-to-minimum-hitting-set.md | 79 ------------------- 1 file changed, 79 deletions(-) delete mode 100644 docs/plans/2026-08-02-minimum-dominating-set-to-minimum-hitting-set.md diff --git a/docs/plans/2026-08-02-minimum-dominating-set-to-minimum-hitting-set.md b/docs/plans/2026-08-02-minimum-dominating-set-to-minimum-hitting-set.md deleted file mode 100644 index 555823867..000000000 --- a/docs/plans/2026-08-02-minimum-dominating-set-to-minimum-hitting-set.md +++ /dev/null @@ -1,79 +0,0 @@ -# Implement MinimumDominatingSet/One to MinimumHittingSet - -Issue: #1096 - -Base: `1075-growth-domain` at `a9067297` - -## Scope - -Add one witness-preserving reduction from -`MinimumDominatingSet` to `MinimumHittingSet`. The source -vertices become target universe elements, and every source vertex contributes -its closed neighborhood as one target set. Target configurations map back by -identity, preserving feasibility and cardinality. - -The construction follows Bannach and Tantau, *Computing Hitting Set Kernels By -AC^0-Circuits* (STACS 2018, DOI 10.4230/LIPIcs.STACS.2018.9), which states the -closed-neighborhood equivalence directly. Garey and Johnson (1979) supplies the -endpoint definitions already cited by the issue. - -## Batch 1: Verify and implement the reduction - -Follow `add-rule` Steps 1-5 and 7 for the code, tests, and canonical example. - -1. Run the full `verify-reduction` workflow before editing Rust: - - prove that `D subset.eq V` dominates `G` iff it hits every closed - neighborhood `N[v]`; - - verify identity extraction and exact objective preservation; - - verify `universe_size = num_vertices` and - `num_sets = num_vertices` symbolically and concretely; - - exercise all simple graphs through five vertices with at least 5,000 - constructor checks and an independent adversary implementation; - - include a five-vertex path as the feasible/optimal example and a - three-vertex instance with an impossible fixed candidate configuration as - the negative feasibility example. -2. Add - `src/rules/minimumdominatingset_minimumhittingset.rs`: - - build one sorted closed-neighborhood vector per vertex; - - construct `MinimumHittingSet::new(num_vertices, sets)`; - - implement identity `extract_solution`; - - register the exact endpoint pair with overhead fields - `universe_size = "num_vertices"` and - `num_sets = "num_vertices"`. -3. Register the module and its canonical example specs in `src/rules/mod.rs`. -4. Add focused tests in - `src/unit_tests/rules/minimumdominatingset_minimumhittingset.rs`: - - required optimization closed loop on the five-vertex path; - - exact target closed-neighborhood structure; - - identity extraction; - - empty, isolated, disconnected, star, and complete graph behavior; - - exhaustive objective/feasibility equivalence for all simple graphs - through four vertices. -5. Add the issue's path example to the rule's canonical example specs with - source and target witness `[0, 1, 0, 1, 0]`. -6. Run focused tests and formatting, then regenerate the graph, schemas, and - example fixture required by the paper. - -## Batch 2: Document the rule in the paper - -Follow `add-rule` Step 6 with fresh context after Batch 1 has produced the -canonical fixture. - -1. Add the Bannach--Tantau citation to `docs/paper/references.bib` if it is not - already present. -2. Add a `reduction-rule("MinimumDominatingSet", "MinimumHittingSet", ...)` - entry to `docs/paper/reductions.typ`, selecting the source variant - `(graph: "SimpleGraph", weight: "One")`. -3. Derive the `pred create --example` command from the loaded fixture via the - existing `problem-spec`/`target-spec` helpers. -4. Explain construction, both correctness directions, exact overhead, - identity extraction, and the five-vertex path round trip in tutorial form. -5. Run `make paper` and correct any paper or fixture mismatch. - -## Final verification - -Run `cargo run --example export_graph`, -`cargo run --example export_schemas`, `make regenerate-fixtures`, -`make test`, `make clippy`, `make fmt-check`, and `make paper`. Inspect the -working tree so only issue-required tracked changes are committed and the plan -file is removed before the final push.