Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ of them, which is why it is stated here rather than in a docstring.
| `exists-anywhere.py` | does this name exist at ANY ref, or only on the one checked out? | 0 on the ref · 1 exists unmerged · 2 absent everywhere · **3 established nothing** |
| `memory-index-check.py` | does the memory index cover the memory files, and can it be loaded whole? | 0 covered · 1 orphans/dangling/oversize · **2 established nothing** |
| `marker-reachability.py` | can any CI invocation actually collect this test? | 0 all reachable · 1 unreachable found · **2 established nothing** |
| `close-condition-scan.py` | which open issues carry no close condition — and which hide one in a comment? | 0 every open issue has one **in its body** · 1 `NONE` or `BURIED` found · **2 established nothing (failed query, empty board, or a truncated reading)** · **3 known-positive failed** · `--self-test` `--states` |
| `close-condition-scan.py` | which open issues carry no close condition — and which hide one in a comment? | 0 every open issue has one **in its body** · 1 `NONE` or `BURIED` found · **2 established nothing (failed query, empty board, or a truncated reading)** · **3 known-positive failed** · `--self-test` `--states` (DECLARES the space) `--by-state` (REPORTS subjects) |
| `runnable-condition.py` | can this close condition be RUN, or only agreed with? | 0 every condition RUNNABLE · 1 at least one ASSERTED · 2 established nothing · 3 control failed | ⚙ GENERATED-FROM: --states |
| `states-index-check.py` | does a tool's README row agree with the exit codes the tool ITSELF emits? | 0 rows agree · 1 a row disagrees · **2 established nothing** · 3 control failed |
| `truncation-guard.py` | can we show this reading was not truncated by a page bound? | 0 **SAFE** (bound known AND count strictly below it) · 1 **TRUNCATED** (count == bound) · **2 UNKNOWN — no bound determinable; ⛔ never read as SAFE** · **3 known-positive failed** · `--self-test` `--quiet` |
Expand Down
35 changes: 34 additions & 1 deletion tools/close-condition-scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,18 @@ def main():
ap.add_argument("--label", default=None, help="restrict to one label")
ap.add_argument("--limit", type=int, default=400)
ap.add_argument("--self-test", action="store_true")
# ⛔ RENAMED from --states. `--states` collided across three tools with TWO
# RELATIONS under one name: doctrine-version.py and runnable-condition.py DECLARE
# a state space; this printed SUBJECTS GROUPED BY STATE. ⇒ A format convention
# cannot fix a name that means two things (ARCHITECT, #498). Priority is theirs by
# 62 minutes (e8e1cff 19:07 vs 2fcd8e1 20:09), the count is theirs 2-to-1, and the
# NAME FITS THEIR RELATION — `--states` reads as "tell me the states". So this one
# moved. ⚠ No caller invoked it; only the index row named it.
ap.add_argument("--by-state", action="store_true", dest="by_state",
help="print only `<STATE> <issue-number>` lines, for piping")
ap.add_argument("--states", action="store_true",
help="print only `<state> <number>` lines, for piping")
help="DECLARE this tool's state space and exit codes (TAB-separated), "
"so an index row can be GENERATED rather than hand-written")
a = ap.parse_args()

if a.self_test:
Expand Down Expand Up @@ -252,6 +262,29 @@ def main():
buckets[classify(it)].append(it)

if a.states:
# ⇒ The DECLARE relation, conforming to tools/states-index-check.py's contract:
# VERDICT\t<name>\t<meaning> the state space
# EXIT\t<code>\t<meaning> what a caller reads
# ⛔ Emitted BEFORE any network call, so declaring the space never depends on
# reaching the forge — a tool that cannot say what it CAN report is worse than
# one that cannot report.
for name, why in (
("BODY", "a close condition is in the issue BODY, where a closer reads it"),
("BURIED", "a condition exists ONLY in a comment — a body-reader sees none"),
("NONE", "no close condition anywhere — cannot be closed, only declared"),
):
print(f"VERDICT\t{name}\t{why}")
for code, why in (
(0, "every open issue carries a clause in its body"),
(1, "NONE or BURIED found — a finding, established"),
(2, "established nothing (failed query, empty board, or a truncated reading)"),
(3, "the known-positive control failed"),
):
print(f"EXIT\t{code}\t{why}")
result("STATES-DECLARED")
return 0

if a.by_state:
for state in ("NONE", "BURIED", "BODY"):
for it in buckets[state]:
print(f"{state} {it['number']}")
Expand Down
33 changes: 33 additions & 0 deletions tools/test_close_condition_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,39 @@ def test_the_BURIED_remedy_warns_about_superseded_dispositions(self):
self.assertIn("LAST comment", out)
self.assertIn("WITHDRAWN", out)

def test_states_DECLARES_the_space_and_conforms_to_the_index_contract(self):
"""⛔ `--states` is the DECLARE relation, matching doctrine-version.py and
runnable-condition.py. It must emit TAB-separated VERDICT and EXIT lines so
tools/states-index-check.py can GENERATE a row instead of returning VOID."""
code, out, _ = run([], 2, [issue(1, "x")] )
# --states short-circuits before any query; drive it directly
import sys as _s
real = _s.argv
_s.argv = ["close-condition-scan.py", "--states"]
import io as _io
from contextlib import redirect_stdout as _rs
buf = _io.StringIO()
try:
with _rs(buf):
rc = ccs.main()
finally:
_s.argv = real
o = buf.getvalue()
self.assertEqual(rc, 0)
self.assertEqual(len([l for l in o.splitlines() if l.startswith("EXIT\t")]), 4)
self.assertEqual(len([l for l in o.splitlines() if l.startswith("VERDICT\t")]), 3)
for l in o.splitlines():
self.assertEqual(len(l.split("\t")), 3, l)

def test_by_state_REPORTS_subjects_and_is_a_different_relation(self):
"""⚠ The two must not be the same flag. `--by-state` names subjects; `--states`
names the space. One flag answering both is the collision #498 recorded."""
code, out, _ = run(["--by-state"], 2, [issue(1, "## Done when\nx"),
issue(2, "nothing")])
self.assertEqual(code, 1)
self.assertIn("NONE 2", out)
self.assertNotIn("VERDICT", out)

def test_empty_board_is_void_not_clean(self):
"""⚠ Zero open issues is what a MISTYPED LABEL returns. `gh issue list
--label <nonexistent>` exits 0 with zero bytes on stdout and stderr, which is
Expand Down
Loading