compass sprint pull: move carried stories from inbox into a sprint

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.

What

(One paragraph: the idea.)

Why

(Motivation, problem being solved, related context.)

References

See also

Prototype source

The one-off script used for the sprint 19→20 pull, to seed the compass implementation:

"""Pull carried stories from the inbox into sprint_20: git mv (IDs
travel), rewrite sprint_19 references to sprint_20, emit table rows."""
import re
import subprocess
from pathlib import Path

ROOT = Path("/mnt/development/Development/OreStudio/OreStudio.local3")
INBOX = ROOT / "doc/agile/product_backlog/inbox"
S20 = ROOT / "doc/agile/versions/v0/sprint_20"
S19_ID = "76AE36A4-A3ED-4F48-BDA0-977B362F2238"
S20_ID = "D366207F-9E8D-46A2-A7DC-6808DC7FBF31"

# (inbox name, flat?) — commissioning first, then codegen
FLAT = [
    "commission_book", "commission_book_status",
    "commission_business_centre", "commission_business_unit",
    "commission_contact_type", "commission_counterparty",
    "commission_country", "commission_party",
    "commission_party_id_scheme", "commission_party_status",
    "commission_party_type", "commission_portfolio",
    "commission_purpose_type",
    "codegen_ci_zero_diff", "codegen_safety_guardrails",
    "codegen_unified_qt_derivation", "codegen_unified_temporal",
]
DIRS = [
    "commission_currency",
    "codegen_org_model_migration", "refactor_codegen_cpp",
    "decommission_codegen_bash_scripts",
]


def git_mv(src, dst):
    r = subprocess.run(["git", "mv", str(src), str(dst)],
                       capture_output=True, text=True, cwd=str(ROOT))
    if r.returncode:
        raise SystemExit(f"git mv failed: {src} -> {dst}: {r.stderr}")


def rewrite(path):
    s = path.read_text(encoding="utf-8")
    s = s.replace(f"id:{S19_ID}", f"id:{S20_ID}")
    s = s.replace("[[id:" + S20_ID + "]][Sprint 19]]", "")  # no-op guard
    s = s.replace(f"[[id:{S20_ID}][Sprint 19]]", f"[[id:{S20_ID}][Sprint 20]]")
    s = re.sub(r":sprint_19:", ":sprint_20:", s)
    s = re.sub(r"^#\+updated:.*$", "#+updated: 2026-06-06", s,
               count=1, flags=re.M)
    path.write_text(s, encoding="utf-8")


rows = []
for name in FLAT:
    src = INBOX / f"{name}.org"
    dstdir = S20 / name
    dstdir.mkdir()
    git_mv(src, dstdir / "story.org")
    rewrite(dstdir / "story.org")
    s = (dstdir / "story.org").read_text(encoding="utf-8")
    sid = re.search(r":ID:\s+([0-9A-Fa-f-]{36})", s).group(1)
    title = re.sub(r"^Story:\s*", "",
                   re.search(r"^#\+title:\s*(.+)$", s, re.M).group(1))
    desc = re.search(r"^#\+description:\s*(.+)$", s, re.M).group(1)
    state = re.search(r"\| State\s*\|\s*(\w+)", s).group(1)
    rows.append((name, sid, title, state, desc))

for name in DIRS:
    src = INBOX / name
    git_mv(src, S20 / name)
    for f in (S20 / name).glob("*.org"):
        rewrite(f)
    s = (S20 / name / "story.org").read_text(encoding="utf-8")
    sid = re.search(r":ID:\s+([0-9A-Fa-f-]{36})", s).group(1)
    title = re.sub(r"^Story:\s*", "",
                   re.search(r"^#\+title:\s*(.+)$", s, re.M).group(1))
    desc = re.search(r"^#\+description:\s*(.+)$", s, re.M).group(1)
    state = re.search(r"\| State\s*\|\s*(\w+)", s).group(1)
    rows.append((name, sid, title, state, desc))

print("pulled", len(rows), "stories\n")
for name, sid, title, state, desc in rows:
    d = desc if len(desc) <= 110 else desc[:107] + "..."
    print(f"| [[id:{sid}][{title}]] | {state} | | | {d} |")

Emacs 29.1 (Org mode 9.6.6)