[FIX] The closure rule reads three header forms the register writes, and declines a fourth
ruled_pendings() intended to detect "the PENDING ids that rulings actually DISPOSE OF" and matched exactly one header form. The register writes four. Censused over 132 placed rulings: 80 em-dash single, 3 parenthetical, 1 plus-joined, 1 slash-joined, 47 naming no PENDING at all. Eight items were counted open while ruled — four of them by the three most recent rulings — which is how the queue reported 64 when 56 was defensible. [FIX] against existing specification: the code failed its own stated intent, and no ruling widens it. Also read: closure declared on an item's own **Awaiting:** line. Two items were counted open with their own bodies saying otherwise (PENDING-82 "CLOSED 2026-08-08", the STATE-CLAIM marker "DISCHARGED 2026-08-26"), because the rule read headers only. THE SLASH-JOINED FORM IS DECLINED, AND THAT IS THE LOAD-BEARING PART. Its sole instance is REVIEWED-116 — PENDING-131/132/133/134, a design gate on a package rather than a disposition of four items, and PENDING-133's body still reads "Awaiting: Steward authorization". Reading it would have falsely closed a live item. Closure detection HIDES items, so an unrecognised form never yields the permissive answer (REVIEWED-132 condition 1). unreadable_ruling_headers() reports the decline so the gap is visible rather than looking like a clean pass. The same reasoning set the body-closure anchor. A bare \bCLOSED\b search of item bodies matches 20 items, including PENDING-95, -108 and -109 — all live, all merely discussing closure. Anchored to the Awaiting line it matches exactly the two closed. Controls are paired throughout: every form that is read has a negative twin holding the form that must not be. 99 controls pass. Verified end-to-end against the live register, not by selftest alone: 64 -> 56, and PENDING-133 still visible. PENDING.md is NOT touched. Widening the instrument to the record is authorized; normalising the record to fit the instrument is not (REVIEWED-132 §6). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X3L79vgAnt1x2kxvf23Qt7
This commit is contained in:
co-authored by
Claude Opus 5
parent
8031db0e26
commit
9d152f1d48
+91
-5
@@ -74,12 +74,37 @@ def item_spans(text):
|
|||||||
for k, (h, s) in enumerate(heads)]
|
for k, (h, s) in enumerate(heads)]
|
||||||
|
|
||||||
|
|
||||||
|
# An item is also closed by its OWN body saying so, on the `**Awaiting:**` line.
|
||||||
|
# ANCHORED deliberately, and the anchor is the whole point: closure detection HIDES
|
||||||
|
# items, so an unrecognised form must never yield the permissive answer (REVIEWED-132
|
||||||
|
# condition 1). Measured 2026-09-04 against the live register: this anchored form finds
|
||||||
|
# exactly the two items closed in their own body (PENDING-82 "CLOSED 2026-08-08", the
|
||||||
|
# STATE-CLAIM marker "DISCHARGED 2026-08-26") and nothing else, while a bare \bCLOSED\b
|
||||||
|
# search of item bodies matches TWENTY — including PENDING-95, -108 and -109, all live,
|
||||||
|
# all of which merely discuss closure. The negative control below holds that line.
|
||||||
|
AWAITING_CLOSED_RE = re.compile(
|
||||||
|
r"^\*\*Awaiting:\*\*.*?\b(?:CLOSED|DISCHARGED|WITHDRAWN)\b", re.M)
|
||||||
|
|
||||||
|
|
||||||
def open_items(text):
|
def open_items(text):
|
||||||
"""-> [(header, line_no)] for every item lacking closure evidence. Closure
|
"""-> [(header, line_no)] for every item lacking closure evidence. Closure
|
||||||
evidence = a REVIEWED-N (resolved by the caller) or CLOSED/COMPLETED in the
|
evidence = a REVIEWED-N (resolved by the caller), CLOSED/COMPLETED in the
|
||||||
header."""
|
header, or an `**Awaiting:**` line declaring the item closed.
|
||||||
return [(h, s) for h, s, _e in item_spans(text)
|
|
||||||
if "CLOSED" not in h and not h.startswith("COMPLETED")]
|
The third form was added 2026-09-04. Two items were being counted open with
|
||||||
|
their own bodies saying otherwise, because this read the header only."""
|
||||||
|
lines = text.split("\n")
|
||||||
|
out = []
|
||||||
|
for h, s, e in item_spans(text):
|
||||||
|
if "CLOSED" in h or h.startswith("COMPLETED"):
|
||||||
|
continue
|
||||||
|
# header sits at 0-based s-1; body ends before the NEXT header at 0-based e-1,
|
||||||
|
# and that exclusion matters — otherwise a following header carrying CLOSED
|
||||||
|
# would close the item above it.
|
||||||
|
if AWAITING_CLOSED_RE.search("\n".join(lines[s:e - 1])):
|
||||||
|
continue
|
||||||
|
out.append((h, s))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def tag_of(text, header):
|
def tag_of(text, header):
|
||||||
@@ -445,8 +470,38 @@ def ruled_pendings(reviewed_text):
|
|||||||
neither until it matches on the SUBJECT — the title or the decision — rather than
|
neither until it matches on the SUBJECT — the title or the decision — rather than
|
||||||
on the presence of an id token in a header. Remedy is PENDING-142, unbuilt; this
|
on the presence of an id token in a header. Remedy is PENDING-142, unbuilt; this
|
||||||
note exists so the code does not keep asserting the opposite while it waits.
|
note exists so the code does not keep asserting the opposite while it waits.
|
||||||
|
|
||||||
|
⚠ WIDENED 2026-09-04, and the widening is deliberately PARTIAL. The single
|
||||||
|
em-dash form below was the only one recognised, while the register writes four.
|
||||||
|
Censused over 132 placed rulings: 80 em-dash single, 3 parenthetical, 1
|
||||||
|
plus-joined, 1 slash-joined, 47 naming no PENDING at all. The parenthetical and
|
||||||
|
plus-joined forms are now read — they cost eight items their closure, four of them
|
||||||
|
ruled by the three most recent rulings, which is how a queue reported 64 while 56
|
||||||
|
was defensible.
|
||||||
|
|
||||||
|
THE SLASH-JOINED FORM IS NOT READ, AND THAT IS A DECISION RATHER THAN AN OMISSION.
|
||||||
|
Its sole instance is `REVIEWED-116 — PENDING-131/132/133/134 —`, a DESIGN-GATE on a
|
||||||
|
package, and PENDING-133's own body still reads `Awaiting: Steward authorization`.
|
||||||
|
Reading it as disposition would falsely close a live item, which is the direction
|
||||||
|
this function must never guess in. It is reported instead — see
|
||||||
|
`unreadable_ruling_headers`, which exists so the gap is visible rather than silent.
|
||||||
"""
|
"""
|
||||||
return set(re.findall(r"^## REVIEWED-\S+\s*—\s*PENDING-(\S+?)\s*—", reviewed_text, re.M))
|
ids = set(re.findall(r"^## REVIEWED-\S+\s*—\s*PENDING-(\S+?)\s*—", reviewed_text, re.M))
|
||||||
|
# REVIEWED-N (PENDING-M) — : the form of the three most recent rulings.
|
||||||
|
ids |= set(re.findall(r"^## REVIEWED-\S+\s*\(PENDING-([^)\s]+)\)\s*—", reviewed_text, re.M))
|
||||||
|
# REVIEWED-N — PENDING-A + PENDING-B — : an explicitly joint ruling disposes of both.
|
||||||
|
for joint in re.findall(r"^## REVIEWED-\S+\s*—\s*((?:PENDING-\d+\s*\+\s*)+PENDING-\d+)\s*—",
|
||||||
|
reviewed_text, re.M):
|
||||||
|
ids |= set(re.findall(r"PENDING-(\d+)", joint))
|
||||||
|
return ids
|
||||||
|
|
||||||
|
|
||||||
|
def unreadable_ruling_headers(reviewed_text):
|
||||||
|
"""-> [header] for rulings that name PENDING ids in a form `ruled_pendings` will
|
||||||
|
not treat as closure. Honest degradation: the closure rule declines to guess, and
|
||||||
|
this is how the declining becomes visible instead of looking like a clean pass."""
|
||||||
|
return [h for h in re.findall(r"^## (REVIEWED-.*)$", reviewed_text, re.M)
|
||||||
|
if re.search(r"PENDING-\d+(?:/\d+)+", h)]
|
||||||
|
|
||||||
|
|
||||||
def sec_pending():
|
def sec_pending():
|
||||||
@@ -1028,6 +1083,37 @@ def selftest():
|
|||||||
len(open_items("## PENDING-S2 — x\n## PENDING — ICP-19")) == 2)
|
len(open_items("## PENDING-S2 — x\n## PENDING — ICP-19")) == 2)
|
||||||
chk("open_items excludes CLOSED / COMPLETED",
|
chk("open_items excludes CLOSED / COMPLETED",
|
||||||
open_items("## PENDING-1 — x (CLOSED)\n## COMPLETED — y") == [])
|
open_items("## PENDING-1 — x (CLOSED)\n## COMPLETED — y") == [])
|
||||||
|
# --- closure-rule widening, 2026-09-04. Every control below is paired: the form is
|
||||||
|
# read, AND the form that must NOT be read stays open. Closure hides items, so the
|
||||||
|
# negative halves are the load-bearing ones.
|
||||||
|
_AWT_CLOSED = "## PENDING-2 — x\n**Awaiting:** ~~steward~~ → **INSTALLED. CLOSED 2026-08-08.**"
|
||||||
|
chk("open_items honours closure declared on the Awaiting line",
|
||||||
|
open_items(_AWT_CLOSED) == [])
|
||||||
|
chk("open_items honours DISCHARGED on the Awaiting line",
|
||||||
|
open_items("## PENDING-2 — x\n**Awaiting:** nothing — **DISCHARGED 2026-08-26**") == [])
|
||||||
|
chk("CLOSED elsewhere in the body does NOT close an item "
|
||||||
|
"[negative control — bare word-match would close 20, three of them live]",
|
||||||
|
[h for h, _ in open_items("## PENDING-2 — x\nthis waits until PENDING-9 is CLOSED\n"
|
||||||
|
"**Awaiting:** steward authorization")] == ["PENDING-2 — x"])
|
||||||
|
chk("a following header's CLOSED does not close the item above it [span boundary]",
|
||||||
|
[h for h, _ in open_items("## PENDING-2 — x\nbody\n## PENDING-3 — y (CLOSED)")]
|
||||||
|
== ["PENDING-2 — x"])
|
||||||
|
chk("ruled_pendings reads the em-dash form",
|
||||||
|
"12" in ruled_pendings("## REVIEWED-9 — PENDING-12 — t"))
|
||||||
|
chk("ruled_pendings reads the PARENTHETICAL form [3 rulings; cost 4 items closure]",
|
||||||
|
"137" in ruled_pendings("## REVIEWED-133 (PENDING-137) — t"))
|
||||||
|
chk("ruled_pendings reads a PLUS-JOINED joint ruling, BOTH ids",
|
||||||
|
{"157", "158"} <= ruled_pendings("## REVIEWED-127 — PENDING-157 + PENDING-158 — t"))
|
||||||
|
chk("ruled_pendings does NOT read the slash-joined design-gate form "
|
||||||
|
"[negative control — PENDING-133 is live and must stay visible]",
|
||||||
|
not ({"131", "132", "133", "134"} & ruled_pendings(
|
||||||
|
"## REVIEWED-116 — PENDING-131/132/133/134 — design gate")))
|
||||||
|
chk("a ruling header naming no PENDING suppresses nothing [FALSE-OPEN class, kept]",
|
||||||
|
ruled_pendings("## REVIEWED-128 — The rejection log against §9") == set())
|
||||||
|
chk("unreadable_ruling_headers surfaces the form the closure rule declines",
|
||||||
|
len(unreadable_ruling_headers("## REVIEWED-116 — PENDING-131/132/133/134 — x")) == 1)
|
||||||
|
chk("unreadable_ruling_headers is silent on forms that ARE read [negative control]",
|
||||||
|
unreadable_ruling_headers("## REVIEWED-133 (PENDING-137) — t") == [])
|
||||||
chk("open_items returns empty on empty input", open_items("") == [])
|
chk("open_items returns empty on empty input", open_items("") == [])
|
||||||
FENCED = "## PENDING-9 — real\nbody\n```markdown\n## REVIEWED-9 — a draft\n```\ntail"
|
FENCED = "## PENDING-9 — real\nbody\n```markdown\n## REVIEWED-9 — a draft\n```\ntail"
|
||||||
chk("open_items ignores a header inside a fenced block [drafting-habit trigger]",
|
chk("open_items ignores a header inside a fenced block [drafting-habit trigger]",
|
||||||
|
|||||||
Reference in New Issue
Block a user