From 6514c8aa3e04617bae49421fa5204e465346224c Mon Sep 17 00:00:00 2001 From: Jonathan Borduas Date: Fri, 21 Aug 2026 13:26:35 +0100 Subject: [PATCH 1/2] label-precedence: the tool I merged an hour ago was an instance of #466, and my first fix could not fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #466 leg 1 asks for the population of instruments that state a total and then partition it. Screening for it found my own tool, and only because I named it as a known-positive before looking: it printed "dev:N labels on 110 open issues" and then four buckets summing to 31. The other 79 fell out of every bucket and were never counted. The line reads as a total and is not one -- #466's shape exactly, forty minutes after the tool merged. Two screens missed it. A one-line "·"-separated scan needs the buckets on one line; mine prints them on five. A multi-line scan keyed on len() in the total line found three other files and not this one. Both counts are FLOORS, per (d), and neither says so on its face. The complement is now a NAMED bucket, NO-DEV-LABEL, and the partition is asserted against the stated population where it is printed. A mismatch refuses with exit 2 ESTABLISHED NOTHING rather than reporting a verdict, per #466 leg 2 and #58. My first version of that invariant was vacuous. It summed buckets.values(), which by construction contains every row, so it equalled the population no matter what and could never fail. The known-negative required by leg 3 is what caught it -- planting a kind the printer does not enumerate returned 0 instead of 2. The sum is now taken over KINDS, the buckets a reader can actually SEE, so a row landing in an unprinted bucket makes the total short and the tool refuses. That is also the live failure mode: it is #39's shape, a classifier gaining a state while the printer keeps the old space. Both directions are wired to a caller that still runs them: the plant returns 2, the same rows without the plant return 0 and print PARTITION. A control that only ever fails proves the check is stuck, not working. Gates: check-orientation 0, check-tools-index 0, check-goal-conformance 0, gate-selftests 0. 15 hermetic tests, rc=0. Filed by ARCHITECT, session c83ecf77. Refs #466 (legs 2 and 3 on one instrument; leg 1's population reported on the issue), #39, #58, #461. --- tools/label-precedence.py | 35 +++++++++++++++++++++++------- tools/test_label_precedence.py | 39 +++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/tools/label-precedence.py b/tools/label-precedence.py index e29406b..43c7bdc 100644 --- a/tools/label-precedence.py +++ b/tools/label-precedence.py @@ -27,7 +27,8 @@ 0 no HAZARD collisions -- provenance collisions may exist and are reported, not counted against 1 at least one HAZARD -- a dev:N beside a reserved queue. A finding, established. - 2 ESTABLISHED NOTHING -- the forge could not be read. ⛔ NEVER read as "all clear". + 2 ESTABLISHED NOTHING -- the forge could not be read, OR the buckets did not sum to the + stated population (#466). ⛔ NEVER read as "all clear". ⚠ WHAT THIS TOOL CANNOT DO. It cannot tell an intentional provenance label from a mislabelling: both render as `dev:N` on a non-DEV issue. ⇒ It reports the provenance set so a reader can look; @@ -40,6 +41,8 @@ import sys RESERVED = ("role:OPERATOR",) # queues whose work a pane must not self-assign +# ⛔ #466: every row must land in one of these, and the sum is asserted against the population. +KINDS = ("HAZARD", "ADDRESS", "PROVENANCE", "UNROUTED", "NO-DEV-LABEL") def fetch(repo): @@ -62,7 +65,7 @@ def classify(row): devs = sorted(n for n in names if n.startswith("dev:")) roles = sorted(n for n in names if n.startswith("role:")) if not devs: - return None, devs, roles + return "NO-DEV-LABEL", devs, roles if any(r in RESERVED for r in roles): return "HAZARD", devs, roles if "role:DEV" in roles: @@ -81,16 +84,32 @@ def report(repo, out=sys.stdout): buckets = {} for r in rows: kind, devs, roles = classify(r) - if kind: - buckets.setdefault(kind, []).append((r["number"], devs, roles, r.get("title", ""))) + buckets.setdefault(kind, []).append((r["number"], devs, roles, r.get("title", ""))) print(f"dev:N labels on {len(rows)} open issues in {repo}", file=out) - for kind in ("HAZARD", "ADDRESS", "PROVENANCE", "UNROUTED"): + for kind in KINDS: items = buckets.get(kind, []) print(f" {kind:<11} {len(items):>3}", file=out) for n, devs, roles, title in items: if kind in ("HAZARD", "UNROUTED"): print(f" #{n:<5} {','.join(devs)} / {','.join(r[5:] for r in roles) or '(none)'}" f" {title[:52]}", file=out) + # ⛔ #466: a count is a partition of a stated population. If the parts do not sum to the + # whole, the summary has not measured the thing it names -- so it REFUSES (exit 2, established + # nothing) instead of reporting a verdict. ⚠ This convicts the output on its own face; it needs + # no reference run and no second environment. + # ⚠ Summed over KINDS -- the buckets a reader can SEE -- and NOT over buckets.values(). + # Summing the dict would include a kind the printer never enumerates, so the total would equal + # the population by construction and the check could never fail. It was written that way first + # and the known-negative below caught it: an invariant that cannot fail is decoration. + shown = sum(len(buckets.get(k, [])) for k in KINDS) + print(f" {'PARTITION':<11} {shown:>3} = sum of the {len(KINDS)} buckets above", file=out) + if shown != len(rows): + missing = sorted(set(buckets) - set(KINDS)) + print(f"⛔ VOID — the printed buckets sum to {shown} against a stated population of" + f" {len(rows)}. {len(rows) - shown} row(s) landed in a bucket nothing prints" + f" {missing}. A summary that cannot add up has not measured what it names." + f" ESTABLISHED NOTHING.", file=out) + return 2 print("", file=out) print("⚠ PROVENANCE is not a defect and its count is not a target. Stripping those labels to" " reach zero destroys the record of which pane produced the work (#461, Done-when leg 3).", @@ -116,8 +135,8 @@ def self_test(out=sys.stdout): ({"number": 2, "labels": [{"name": "dev:3"}, {"name": "role:DEV"}]}, "ADDRESS"), ({"number": 3, "labels": [{"name": "dev:5"}, {"name": "role:DEVOPS"}]}, "PROVENANCE"), ({"number": 4, "labels": [{"name": "dev:1"}]}, "UNROUTED"), - ({"number": 5, "labels": [{"name": "role:DX"}]}, None), - ({"number": 6, "labels": []}, None), + ({"number": 5, "labels": [{"name": "role:DX"}]}, "NO-DEV-LABEL"), + ({"number": 6, "labels": []}, "NO-DEV-LABEL"), # ⚠ the discriminating pair: role:DEV must NOT rescue a reserved queue ({"number": 7, "labels": [{"name": "dev:4"}, {"name": "role:DEV"}, {"name": "role:OPERATOR"}]}, "HAZARD"), @@ -130,7 +149,7 @@ def self_test(out=sys.stdout): bad += 1 print(f" {flag} #{row['number']}: want={want} got={got}", file=out) seen = {classify(r)[0] for r, _ in cases} - if seen != {"HAZARD", "ADDRESS", "PROVENANCE", "UNROUTED", None}: + if seen != {"HAZARD", "ADDRESS", "PROVENANCE", "UNROUTED", "NO-DEV-LABEL"}: print(f" FAIL not every bucket exercised: {seen}", file=out) bad += 1 else: diff --git a/tools/test_label_precedence.py b/tools/test_label_precedence.py index b564dfb..34ea172 100644 --- a/tools/test_label_precedence.py +++ b/tools/test_label_precedence.py @@ -34,7 +34,7 @@ def test_319_historical_state_is_a_hazard(self): def test_319_current_state_is_not(self): """The other side of the same pair, on the same real issue.""" - self.assertIsNone(lp.classify(row(319, "role:OPERATOR"))[0]) + self.assertEqual(lp.classify(row(319, "role:OPERATOR"))[0], "NO-DEV-LABEL") def test_role_dev_does_not_rescue_a_reserved_queue(self): """⚠ A reserved queue outranks a legitimate address. Order of checks matters.""" @@ -50,10 +50,11 @@ def test_dev_n_with_another_role_is_provenance(self): def test_dev_n_with_no_role_is_unrouted(self): self.assertEqual(lp.classify(row(4, "dev:1"))[0], "UNROUTED") - def test_no_dev_label_is_not_classified_at_all(self): - """⚠ Two-sided: the classifier must be able to return 'not my business'.""" - self.assertIsNone(lp.classify(row(5, "role:DX"))[0]) - self.assertIsNone(lp.classify(row(6))[0]) + def test_an_issue_with_no_dev_label_still_gets_a_NAMED_bucket(self): + """⛔ #466: the complement must be NAMED, not silent. A row that falls out of every bucket + is the 79 issues this tool used to print a 110-population line about and never count.""" + self.assertEqual(lp.classify(row(5, "role:DX"))[0], "NO-DEV-LABEL") + self.assertEqual(lp.classify(row(6))[0], "NO-DEV-LABEL") class Reporting(unittest.TestCase): @@ -89,6 +90,34 @@ def test_a_clean_board_and_an_unreadable_one_differ(self): void, _ = self._report([], ok=False) self.assertNotEqual(clean, void) + def test_a_bucket_the_printer_does_not_know_makes_it_REFUSE(self): + """#466 leg 3 — the KNOWN-NEGATIVE, run by this caller on every suite run. + + ⛔ The invariant is not decoration. Its live failure mode is #39's: the classifier gains a + state and the printer keeps the old space. Planting exactly that -- a kind the print list + does not enumerate -- must produce exit 2 ESTABLISHED NOTHING, never a verdict. + """ + real = lp.classify + lp.classify = lambda r: ("A-KIND-NOBODY-PRINTS", [], []) + try: + rc, out = self._report([row(1, "dev:1"), row(2, "role:DX")]) + finally: + lp.classify = real + self.assertEqual(rc, 2) + self.assertIn("ESTABLISHED NOTHING", out) + self.assertNotIn("no HAZARD collisions", out) + + def test_the_same_run_WITHOUT_the_plant_reports_normally(self): + """⚠ The other side. A control that only ever fails proves the check is stuck, not working.""" + rc, out = self._report([row(1, "dev:1"), row(2, "role:DX")]) + self.assertEqual(rc, 0) + self.assertIn("PARTITION", out) + + def test_partition_line_states_the_sum(self): + rc, out = self._report([row(1, "dev:5", "role:DX"), row(2, "role:DX")]) + self.assertIn("PARTITION", out) + self.assertEqual(rc, 0) + def test_states_flag_matches_the_codes_report_can_return(self): buf = io.StringIO() old = sys.stdout From 5cebd944d0240780d97bb872fe5efbb16f7fb26f Mon Sep 17 00:00:00 2001 From: Jonathan Borduas Date: Fri, 21 Aug 2026 14:29:19 +0100 Subject: [PATCH 2/2] label-precedence: the self-test hard-coded the bucket set KINDS already defines Found in review by TEAMLEAD. KINDS is defined at line 45; the self-test re-typed the same five strings a hundred lines below to assert that every bucket was exercised. Add a bucket to KINDS and the copy keeps the old space -- which is #39's producer/consumer drift sitting inside the check built to catch drift, in a PR about a partition invariant. Now derived: `if seen != set(KINDS)`. Controlled both ways, named before running: with KINDS unmodified the self-test returns 0; with a bucket appended that no case exercises it returns 1. A fix that could not fail would have been the third vacuous check in this file's history today. Gates: check-orientation 0, check-tools-index 0, check-goal-conformance 0, paired suite green, --self-test 0. Filed by ARCHITECT, session c83ecf77. Refs #466, #39. --- tools/label-precedence.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/label-precedence.py b/tools/label-precedence.py index 43c7bdc..6fd4ccb 100644 --- a/tools/label-precedence.py +++ b/tools/label-precedence.py @@ -149,7 +149,10 @@ def self_test(out=sys.stdout): bad += 1 print(f" {flag} #{row['number']}: want={want} got={got}", file=out) seen = {classify(r)[0] for r, _ in cases} - if seen != {"HAZARD", "ADDRESS", "PROVENANCE", "UNROUTED", "NO-DEV-LABEL"}: + # ⛔ Derived from KINDS, never re-typed. A hard-coded copy of the bucket set is #39's shape + # inside the check built to catch it: add a bucket to KINDS and the copy keeps the old space. + # Found in review by TEAMLEAD -- the definition is 100 lines above and the copy read as correct. + if seen != set(KINDS): print(f" FAIL not every bucket exercised: {seen}", file=out) bad += 1 else: