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
|
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
|
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
|
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):
|
([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
|
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
|
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):
|
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
|
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()
|
text = open(path, encoding="utf-8").read()
|
||||||
m = re.match(r"^---\n.*?\n---\n?", text, re.S)
|
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, 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)
|
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"):
|
for chunk in body.split("\n\n"):
|
||||||
stripped = "\n".join(re.sub(r"^\s*>\s?", "", l) for l in chunk.split("\n")).strip()
|
stripped = "\n".join(re.sub(r"^\s*>\s?", "", l) for l in chunk.split("\n")).strip()
|
||||||
if stripped:
|
if stripped:
|
||||||
heading = re.match(r"^#{1,6}\s+(.*)", stripped)
|
heading = re.match(r"^#{1,6}\s+(.*)", stripped)
|
||||||
if heading:
|
if heading:
|
||||||
section = heading.group(1).strip()
|
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
|
# 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.
|
# issue named in one item tracks nothing in the next.
|
||||||
items = re.split(r"\n(?=[-*] |\d+\. )", stripped)
|
items = re.split(r"\n(?=[-*] |\d+\. )", stripped)
|
||||||
at = line + chunk[: len(chunk) - len(chunk.lstrip())].count("\n")
|
at = line + chunk[: len(chunk) - len(chunk.lstrip())].count("\n")
|
||||||
for item in items:
|
for item in items:
|
||||||
out.append((at, section, item))
|
out.append((at, section, chapter, item))
|
||||||
at += item.count("\n") + 1
|
at += item.count("\n") + 1
|
||||||
line += chunk.count("\n") + 2
|
line += chunk.count("\n") + 2
|
||||||
return out
|
return out
|
||||||
@@ -309,17 +312,18 @@ def main():
|
|||||||
if status != "accepted":
|
if status != "accepted":
|
||||||
continue
|
continue
|
||||||
paras = paragraphs(path)
|
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)
|
held = decided >= DEFERRALS_FROM or any(d >= DEFERRALS_FROM for d, _, _ in insights)
|
||||||
if not held:
|
if not held:
|
||||||
continue
|
continue
|
||||||
# A dated insight naming an issue covers the deferrals it speaks about -- those in its own section,
|
# 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.
|
# 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)]
|
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)
|
m = DEFERRAL.search(text)
|
||||||
# A rejected option is a decision not to do it, not work put off.
|
# A rejected option is a decision not to do it, not work put off -- judged by its chapter, so an
|
||||||
if re.match(r"(?i)(options? rejected|considered options|rejected)", section):
|
# option under a `###` subheading of "## Considered Options" is skipped as well.
|
||||||
|
if re.match(r"(?i)(options? rejected|considered options|rejected)", chapter):
|
||||||
continue
|
continue
|
||||||
if not m or issue_refs(text, seen):
|
if not m or issue_refs(text, seen):
|
||||||
continue
|
continue
|
||||||
|
|||||||
Reference in New Issue
Block a user