Batch helper: edit rows in place, and recover DMRs orphaned by a closed batch
Closes #60 (closed) Closes #62 (closed)
Two fixes to scripts/python/dmr_mr_helper, both about the batch run leaving the wrong thing behind.
Amendments and removals edit the existing row (#60 (closed))
The helper had one write path — append_locode_row() — and called it for every approved DMR without looking at the change indicator. payload_to_csv_row() hardcodes blanks for the location code and status columns, which is right for a new entry and wrong for anything else.
A removal therefore appended an orphan row and left the entry it named untouched:
existing ,PT,FAO,Faro,Faro,08,1234----,AI,0401,,3701N 00756W,
appended X,PT,,Faro,Faro,08,1234----,,2607,,3701N 00756W,
modify_locode_row() now matches on country + code and edits that row in place; + still appends. Neither branch writes the location code or the status — those stay the secretariat's (CLAUDE.md hard rules 1 and 2).
On the ticket wording: a removal marks the row X rather than deleting it. Manual §7.1.1 requires an X-marked row to persist for a 12-month notice period; prune_aged_x.py does the physical removal later.
Load-bearing detail: marking X also stamps the date column. prune_aged_x_rows_from_source judges the notice period from that column, so marking a row dated 0401 would make it 22 years old and eligible for deletion at the very next publish — skipping the notice period entirely. A test is named for this so it does not get tidied away.
Orphaned DMRs return to Approved (#62 (closed))
DMR::Batched was a one-way door. The helper sets it when a batch MR opens and list_approved_dmrs() excludes it, so closing that MR instead of merging it stranded every issue it carried — approved in substance, invisible to the next batch run, never closed by a merge.
reconcile_orphaned_batches() finds closed MRs from dmr/batch-* branches, asks GitLab's closes_issues endpoint which issues each claimed, and swaps DMR::Batched back to DMR::Approved with a comment saying why.
It runs at the start of every batch run, before the queue is read, so orphans are picked up by that same run. A dmr-reconcile CI job runs the pass alone (--reconcile-only) on a schedule or on demand.
There is no trigger on MR close — GitLab runs merge-request pipelines on open, push and reopen only. The pre-batch pass is what guarantees nothing is missed; the scheduled job only keeps the board tidy in between.
Scoped so ordinary code MRs are unaffected: only dmr/batch-* source branches are considered. Left alone are issues claimed by a batch MR still open or already merged, issues marked DMR::Failed, and issues closed by hand. A failure in the pass is warned about and the batch continues.
Six issues in this project are currently orphaned (#61 (closed), #59 (closed), #56 (closed), #50 (closed), #46 (closed), #41 (closed)) across MRs !40 (closed), !44 (closed), !47 (closed) and !48 (closed). Once this is merged, the next batch run — or dmr-reconcile — will return them to DMR::Approved.
Follow-up not in this MR
- A pipeline schedule needs creating (CI/CD → Schedules, ref
main, variableDMR_RECONCILE=true) for the standalone job to run nightly. - Orphan rows written into
locodes/*.csvby earlier broken batch MRs, if any of those merged, still need removing by hand.
Testing
18 new tests (257 passing). Amendment and removal paths verified against copies of the real locodes/PT.csv and AE.csv; the reconcile logic dry-run against this project's real MRs read-only.