Skip a rejected option by its chapter, so one under a ### subheading is skipped too
cycle.py skipped a rejected option only when "Options rejected" was its nearest heading; a record that lists its options under ### subheadings of "## Considered Options" had them held as deferrals.
This commit is contained in:
@@ -66,7 +66,8 @@ off — "until renamed", "left for later", "not decided here", "postponed", "fut
|
||||
change" — names the issue that tracks it, as tracking it ("tracked by issue N", or "issue N tracks"), in that
|
||||
paragraph or list item, or in a dated progressive insight that speaks about it: one in the same section, or one
|
||||
that quotes it. An issue cited for another reason tracks nothing, and one insight does not excuse every deferral
|
||||
in a record. A rejected option is not work put off and is not held
|
||||
in a record. A rejected option is not work put off and is not held, judged by its `##` section, so an option under a
|
||||
`###` subheading of "Considered Options" is skipped too
|
||||
([issue 354](../../04-ISSUES/354-a-decided-rename-was-never-scheduled-and-the-operator-believed-it-live/00-report.md):
|
||||
ADR 0244 deferred the code renames with no issue, and two days later the operator believed them done). Held to
|
||||
it: a record dated from 2026-10-09, and an older one corrected under the rule. Measured from ADR 0244's date
|
||||
|
||||
+12
-8
@@ -78,26 +78,29 @@ INSIGHT = re.compile(r"\*\*Progressive insights?[ \t]*[—–-][ \t]*(\d{4}-\d{2
|
||||
|
||||
|
||||
def paragraphs(path):
|
||||
"""A record's body as (first line number, section heading, text) paragraphs: frontmatter and fenced
|
||||
"""A record's body as (first line number, section heading, chapter, text) paragraphs: frontmatter and fenced
|
||||
code left out, a block quote's markers stripped, so a quoted insight reads as the paragraph it is. The
|
||||
section is the nearest heading above the paragraph; a heading is its own paragraph and its own section."""
|
||||
section is the nearest heading above the paragraph; a heading is its own paragraph and its own section.
|
||||
The chapter is the nearest `#` or `##` heading, which a `###` subheading inside it does not change."""
|
||||
text = open(path, encoding="utf-8").read()
|
||||
m = re.match(r"^---\n.*?\n---\n?", text, re.S)
|
||||
body, first = (text[m.end():], text[: m.end()].count("\n") + 1) if m else (text, 1)
|
||||
body = re.sub(r"(?ms)^\s*```.*?^\s*```", lambda x: re.sub(r"[^\n]", " ", x.group(0)), body)
|
||||
out, line, section = [], first, ""
|
||||
out, line, section, chapter = [], first, "", ""
|
||||
for chunk in body.split("\n\n"):
|
||||
stripped = "\n".join(re.sub(r"^\s*>\s?", "", l) for l in chunk.split("\n")).strip()
|
||||
if stripped:
|
||||
heading = re.match(r"^#{1,6}\s+(.*)", stripped)
|
||||
if heading:
|
||||
section = heading.group(1).strip()
|
||||
if len(stripped) - len(stripped.lstrip("#")) <= 2:
|
||||
chapter = section
|
||||
# A list's top-level items are units of their own: a Consequences list is one paragraph, and an
|
||||
# issue named in one item tracks nothing in the next.
|
||||
items = re.split(r"\n(?=[-*] |\d+\. )", stripped)
|
||||
at = line + chunk[: len(chunk) - len(chunk.lstrip())].count("\n")
|
||||
for item in items:
|
||||
out.append((at, section, item))
|
||||
out.append((at, section, chapter, item))
|
||||
at += item.count("\n") + 1
|
||||
line += chunk.count("\n") + 2
|
||||
return out
|
||||
@@ -309,17 +312,18 @@ def main():
|
||||
if status != "accepted":
|
||||
continue
|
||||
paras = paragraphs(path)
|
||||
insights = [(d, sec, text) for line, sec, text in paras for d in INSIGHT.findall(text)]
|
||||
insights = [(d, sec, text) for line, sec, _, text in paras for d in INSIGHT.findall(text)]
|
||||
held = decided >= DEFERRALS_FROM or any(d >= DEFERRALS_FROM for d, _, _ in insights)
|
||||
if not held:
|
||||
continue
|
||||
# A dated insight naming an issue covers the deferrals it speaks about -- those in its own section,
|
||||
# or ones it quotes -- and no other: one insight must not excuse every deferral in the record.
|
||||
tracking = [(sec, text) for d, sec, text in insights if issue_refs(text, seen)]
|
||||
for line, section, text in paras:
|
||||
for line, section, chapter, text in paras:
|
||||
m = DEFERRAL.search(text)
|
||||
# A rejected option is a decision not to do it, not work put off.
|
||||
if re.match(r"(?i)(options? rejected|considered options|rejected)", section):
|
||||
# A rejected option is a decision not to do it, not work put off -- judged by its chapter, so an
|
||||
# option under a `###` subheading of "## Considered Options" is skipped as well.
|
||||
if re.match(r"(?i)(options? rejected|considered options|rejected)", chapter):
|
||||
continue
|
||||
if not m or issue_refs(text, seen):
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user