The shell recipe inventory ships unresolved conflict markers, and its gate cannot see them

Table of Contents

This page is a capture in the inbox bucket of the product backlog — a pre-sprint idea, not yet pulled into a sprint as a story.

1. What

doc/recipes/shell/shell.org is a generated document, and it is committed with unresolved conflict markers. The markers are present in the working tree, in the blob at HEAD, and in the blob on origin/main:

553: <<<<<<< HEAD
603: =======
606: <<<<<<< HEAD
628: =======
638: >>>>>>> af11271b7e ([workflow] List the generated shell recipes in the inventory)
640: >>>>>>> ddab9ae787 ([workflow] List the generated shell recipes in the inventory)

The conflict is nested, and the two sides differ in content rather than in order. The outer HEAD side carries twelve sections, from Folders to Tags. The outer second side carries the inner conflict, whose two alternatives are the five sections from Pricing Engine Types to Testing, or the two Workflow sections. Whichever resolution a reader assumes, the file loses the sections the other branch added, and the workflow_steps link that closes the Workflow Steps section sits after the closing marker rather than inside its section. The document has therefore been corrupt on main since the merge that produced it.

(Revision ids here are abbreviated; git show HEAD:doc/recipes/shell/shell.org and git show origin/main:doc/recipes/shell/shell.org print the markers.)

2. Why

The gate that owns this file cannot see the damage. projects/ores.codegen/scripts/regenerate_shell_recipe_inventory.py --check exits 0 on the corrupt file. In check mode the generator rebuilds the whole inventory and compares it to the file on disk, so any drift should fail. It does not, because the rebuild reads the current file first and carries its prose forward unchanged: the head of the file and the lines under each heading are copied through, and only the link list under each heading is rewritten. A conflict marker is neither a heading nor a link, so each marker is prose. The rebuild reproduces the markers byte for byte, the comparison matches, and the gate reports the file as up to date.

Two failures follow. First, the inventory is published with the markers in it, so a reader sees them and two nested alternatives hide the sections one branch added. Second, the gate that exists to protect derived files will accept any hand-written line, which is the property that let this reach main.

The fix is in two parts: resolve the conflict and regenerate the file, then make the check reject a file that contains a conflict marker, before it compares. A guard on the shape of the input is the honest check here, because the generator cannot otherwise distinguish intended prose from a merge accident.

3. References

  • doc/recipes/shell/shell.org:553, :603, :606, :628, :638, :640 — the markers
  • git af11271b7e, ddab9ae787 — the two sides named in the markers
  • projects/ores.codegen/scripts/regenerate_shell_recipe_inventory.py:105 — split_index carries prose forward
  • projects/ores.codegen/scripts/regenerate_shell_recipe_inventory.py:196-220 — main compares the rebuild against the current file
  • projects/ores.codegen/tests/test_shell_recipe_inventory.py — the existing tests

4. See also

Emacs 29.3 (Org mode 9.6.15)