Story: Lock down uppercase UUID invariant

Table of Contents

This page documents a story in Sprint 18. It captures the goal, current status, acceptance criteria, and the tasks that compose it.

Goal

Make uppercase UUIDs a hard invariant of the documentation system: every :ID: property and every [[id:UUID]] link in doc/ and projects/*/modeling/ must use uppercase hex, and every code path that mints or templates a UUID must produce uppercase by construction. Prior commits (abe6686ce, a8ddd4920, d1022161e) normalised the existing corpus and uppercased the freshly-minted ID in the v2 doc generator; this story closes the remaining holes so the invariant cannot drift back.

Status

Field Value
State DONE
Parent sprint Sprint 18
Now Completed 2026-05-24.
Waiting on Nothing.
Next None.
Last touched 2026-05-24

Acceptance

  • All v2_doc_*.org.mustache templates carry uppercase concept-link UUIDs (story, task, sprint, version, capture, investigation, product identity).
  • v2_doc_generate.py uppercases parent_id and predecessor_id defensively, so a lowercase value passed via --parent-id / --predecessor-id still produces an uppercase link in the output.
  • build/scripts/generate_release_notes.py uppercases the generated release-notes UUID.
  • projects/ores.codegen/scripts/regenerate_backlog_indexes.py holds its hardcoded UUID constants in uppercase.
  • A sweep across doc/ and projects/*/modeling/ for lowercase :ID: properties and lowercase [[id:...]] links returns zero matches. Recipe placeholders such as [[id:UUID]] and [[id:<parent_id>]] are excluded by design.
  • Generating a fresh story or task end-to-end through generate_v2_doc.sh produces a file in which every UUID is uppercase, without manual touch-up.

Tasks

Task State Start End Description
Task: Enforce uppercase UUID invariant in codegen and audit docs DONE 2026-05-24 2026-05-24 Patch v2 doc templates and Python scripts so every generated UUID and link is uppercase; sweep org docs for stragglers.

Decisions

  • Why hardcode uppercase in the templates rather than post-process the rendered output. The concept-link UUIDs are not generated, they are author-baked content. Uppercasing them at the template source matches how the rest of the doc graph already stores them, and avoids a post-render rewrite step in the generator.
  • Why also keep the defensive .upper() on parent_id and predecessor_id. The generator auto-detects parent IDs from on-disk org files (already uppercase), but a user may pass --parent-id or --predecessor-id manually from a copy-paste source where casing is unknown. Belt-and-braces.
  • Why uppercase GLOSS_CAPTURE and INDEX_IDS constants in regenerate_backlog_indexes.py even though the on-disk index pages were already uppercased by prior normalisation. The script regenerates near.org and far.org from these constants; if it ran with the old lowercase constants it would silently undo the on-disk normalisation. Sourcing them as uppercase makes the regen idempotent against the invariant.
  • Where the invariant is documented. A single sentence under :PROPERTIES: :ID: in document types points at this story for the rationale and audit trail. Future contributors editing UUIDs by hand discover the rule there.
  • Malformed UUIDs in v1 plans treated as a separate bug. The exhaustive sweep surfaced three v1 plan documents whose :ID: values were uppercase but contained H and G characters — invalid hex, predating this work. Rather than fold them into the case-enforcement commits, they ship as a self-contained [doc] Fix invalid (non-hex) UUIDs in 3 v1 plan files commit so the case/validity concerns stay distinct in git log.

Out of scope

  • Postgres / generated SQL UUID literals (00000000-0000-0000-0000-000000000000 and live workspace sentinels). SQL has its own conventions and case rules; this story is about the documentation graph only.
  • External docs in external/ and third-party samples.

Emacs 29.1 (Org mode 9.6.6)