[HARDENING] PENDING-142: the open/closed criterion verifies an adjacent property
Filed from Task 1 of the 2026-08-17 jurist relay. `governance_state()` computes openness from one signal — whether a REVIEWED header names the PENDING id — and never reads the item's `Awaiting:` field, any status field, or the ruling's `Decision:`. Six items are misclassified in both directions: - 3 falsely OPEN (78, 81, 82): rulings that name the title, not the id. All AUTHORIZED 2026-07-28. REVIEWED-78's own Notes record that it was filed as a separate entry precisely to satisfy the closure rule as it then stood; the rule later changed, breaking the entries written to comply with it. - 3 suppressed under a design gate rather than a steward authorization, one of which (PENDING-121) is marked HELD OPEN by its own ruling. - 2 structurally unclosable: no `PENDING-N` in the header, so no ruling can ever close them. One is the ICP-19 item gating Observer Problem work. - 39 suppressed items still carry a live-reading `Awaiting:` line. Removing the false opens and restoring the false closures leaves 29 — the number the tool reports. The change proof standing behind the current implementation measured exactly that count (18 to 19). A count-based control cannot see a classification wrong in both directions by equal amounts: its subject was the population size, the claim's subject was each item's disposition. Addendum 1 flags that the selftest asserts the defect as intended behaviour, with one of the three hidden items as its fixture. Nothing patched — the relay scoped this to findings only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013Y6t6qx7cpaCu5xGdD36u4
This commit is contained in:
co-authored by
Claude Opus 5
parent
b6e1b5e470
commit
69e258116a
+57
@@ -3168,3 +3168,60 @@ So **PENDING-138 and this entry are worded to avoid the bare uppercase token**,
|
||||
**Awaiting:** Steward direction on (a)–(d). Not urgent — (a) is the null action and is in force by default while this is open.
|
||||
|
||||
---
|
||||
## PENDING-142 — The open/closed criterion answers "does a REVIEWED header name this id?", not "is this item still awaiting the steward"
|
||||
**Date:** 2026-08-17
|
||||
**Tag:** [HARDENING]
|
||||
**Summary:** `governance_state()` / the wake digest compute openness from one signal — whether some `## REVIEWED-… — PENDING-<id> —` header exists — and that signal is adjacent to the property claimed. Six items are misclassified in both directions, and the item count is right by coincidence.
|
||||
|
||||
**Origin:** Task 1 of the jurist relay of 2026-08-17, which asked why PENDING-81 shows open against an AUTHORIZED REVIEWED-81, and why PENDING-76/-77 carry live `Awaiting:` lines but never appear. Both answers are below; the census found more than the three items asked about.
|
||||
|
||||
**The criterion, exactly as computed** (`wake-digest.py:sec_pending` → `open_items` + `ruled_pendings`; `governance-mcp.py:t_state` delegates wholly to it). An item is OPEN iff:
|
||||
1. it has an unfenced `## ` header in `PENDING.md`; **and**
|
||||
2. that header contains no `CLOSED` and does not begin with `COMPLETED`; **and**
|
||||
3. the id parsed by `PENDING-(\S+?)\s*—` is not in the set produced by `^## REVIEWED-\S+\s*—\s*PENDING-(\S+?)\s*—` over `REVIEWED.md`.
|
||||
|
||||
So closure is signalled **only** by a REVIEWED *header* naming the PENDING id, or by a marker in the PENDING *header*. The criterion never reads the item's `**Awaiting:**` field, never reads any status field, and never reads the ruling's `**Decision:**`. It matches on **header-id presence**, not on subject and not on disposition.
|
||||
|
||||
**Verified against the live files** (script: `census_open_criterion.py`, importing wake-digest's own functions rather than reimplementing them; 86 `##` items, 69 after the CLOSED/COMPLETED filter, 29 reported open; 118 REVIEWED entries, of which 74 name a PENDING id in the header and 44 do not):
|
||||
|
||||
- **Class A — 2 items structurally unclosable.** `PENDING — ICP-19 Remit Expansion (Observer Problem)` (L88) and `PENDING — Fault Line 1 Response` (L99) have no `PENDING-<id>` in their headers, so step 3's regex never matches and **no ruling of any kind can ever close them.** They will report open forever. Note the ICP-19 item is the gate on Observer Problem mechanism work.
|
||||
- **Class B — 3 items falsely OPEN: PENDING-78, -81, -82.** `REVIEWED-78/-81/-82` exist, are dated 2026-07-28, are `**Decision:** AUTHORIZED`, and carry **titles identical to the PENDING items they rule**, but name the title instead of the id in their headers. REVIEWED-81 additionally names "PENDING-81" twice in its body and resolves that item's findings one by one.
|
||||
- ⚠ **And the reason is recorded in the substrate.** `REVIEWED-78`'s own Notes say it was filed as a separate entry *precisely to satisfy the closure rule as it then stood*: "the closure rule in `wake-digest.py` matches a PENDING item to `REVIEWED-<same number>`, so a cross-numbered closure stated only in prose would leave PENDING-78 listed as open at every wake." The rule was later changed from number-matching to header-id-matching. **The change broke the three entries that had been deliberately authored to satisfy the old rule** — and `ruled_pendings`'s docstring records them as "like-numbered rulings … concerning other matters", which is the opposite of what the record says. They were like-numbered *on purpose*.
|
||||
- **Class C — false CLOSED, the dangerous direction.** 7 items are suppressed under a ruling whose `**Decision:**` is not AUTHORIZED. Four are genuine closures (REJECTED, WITHDRAWN, NOT OBJECTED TO, DISPOSED). Three are **design gates**, which under the taxonomy precede steward authorization rather than replace it: PENDING-124 (REVIEWED-106), PENDING-128 (REVIEWED-111), and **PENDING-121 (REVIEWED-110), whose own Decision line reads "DESIGN GATE PASSED WITH CONDITIONS (1-4), then HELD OPEN"** — an item explicitly held open by its ruling and hidden by the tool. *Scope honesty: only PENDING-121 is certain. For -124 and -128 the rulings read closer to discharged, and I did not establish their true status; they are flagged as unestablished, not asserted as open.*
|
||||
- **Class D — 39 suppressed items still carry an `**Awaiting:**` line.** Most were updated in-body ("RULED … REVIEWED-88 placed"); a substantial number were not, and read as live requests on the steward. This answers the relay's PENDING-76/-77 question: **both are correctly suppressed** (REVIEWED-76/-77 do name their ids; REVIEWED-76 is REJECTED, a genuine closure). Their `Awaiting:` lines are simply never retired. The field is not a status and cannot be read as one.
|
||||
|
||||
⚠ **THE FINDING THAT GENERALIZES, and it is the third instance this week.** Removing 3 false-opens and adding back 3 false-closeds leaves **29 — the same number the tool reports.** The change proof cited in `ruled_pendings`'s docstring measured exactly that: a count delta (18 → 19 visible). **A count-based control cannot see a classification wrong in both directions by equal amounts.** The control's subject was the population size; the claim's subject was each item's disposition. Kin to the 2026-08-14 finding (the control tested transcription while the claim was an inference) and to REVIEWED-83 A1 (a control must sit at the layer the defect lives in).
|
||||
|
||||
**Options:**
|
||||
- **(a) Match on subject, not on header shape.** Resolve a PENDING↔REVIEWED pair by normalized title when the header carries no id, in addition to the current id match. Closes Class B. Cheap; risks joining two genuinely distinct items that share a title.
|
||||
- **(b) Read the ruling's `**Decision:**` and treat design gates as non-closing.** Closes Class C. Requires enumerating which decision verbs close — itself a judgment, and the enumeration is the same "gate on the class, not the instances" trap unless it defaults to *not closed* on an unrecognized verb.
|
||||
- **(c) Make closure explicit at the PENDING side** — a `**Status:**` line the tool reads, retired `Awaiting:` on ruling. Closes A, B, C and D at once, but requires touching ~40 existing items and makes the record depend on a field humans must maintain.
|
||||
- **(d) Three-valued reporting.** OPEN · CLOSED · **UNDETERMINED** for any item whose disposition the criterion cannot establish (Class A by construction, Class B/C by disagreement between header-id and title/decision). Consistent with REVIEWED-104's ruled doctrine that a check whose subject can be absent may not be two-valued.
|
||||
|
||||
**Recommendation: (d) as the frame, with (a) and (b) inside it.** (d) is the only option that makes the tool report its own limit rather than guessing, which is Constitutional Constraint #4 applied to the instrument that reports governance state. (a) and (b) then reduce how large the UNDETERMINED bucket is, rather than pretending it is empty. **(c) is not recommended alone** — a hand-maintained status field is exactly the surface that produced the 39 stale `Awaiting:` lines.
|
||||
|
||||
⚠ **Whatever is built, the acceptance check may not be a count.** It must be a per-item disposition comparison against a hand-read answer key over all 69 filtered items — the defect above is invisible to any aggregate.
|
||||
|
||||
**Files affected:** `~/dotfiles/scripts/wake-digest.py` (`sec_pending`, `ruled_pendings`, `open_items`), `~/dotfiles/scripts/governance-mcp.py` (`t_state` — consumer only), and `ruled_pendings`'s docstring, which carries a substrate-contradicted claim about REVIEWED-78/-81/-82 and should be corrected regardless of which option is taken.
|
||||
**Awaiting:** Steward authorization. Nothing has been patched — the relay filing this scoped Task 1 to findings only, and the parsing logic is untouched.
|
||||
|
||||
---
|
||||
## PENDING-142 — ADDENDUM 1: the selftest encodes the defect as intended behaviour
|
||||
**Date:** 2026-08-17
|
||||
**Tag:** [HARDENING]
|
||||
**Summary:** `wake-digest.py --selftest` contains a check asserting the Class-B behaviour is correct, and its fixture is one of the three items the defect hides.
|
||||
|
||||
**The line** (`wake-digest.py`, selftest, "extractor controls"):
|
||||
```python
|
||||
chk("ruled_pendings ignores a ruling that names no PENDING",
|
||||
ruled_pendings("## REVIEWED-82 — Read-only MCP server: eyes on the substrate") == set())
|
||||
```
|
||||
`REVIEWED-82` is not a neutral example. It is the real, AUTHORIZED ruling on PENDING-82 — one of the three items reported open because of exactly the behaviour this line certifies. **Whoever implements PENDING-142 will make this check fail, and the cheapest way to make a suite green is to change the test.** Flagged now so that the failure is read as the fix working, not as the fix breaking something.
|
||||
|
||||
⚠ The same shape appeared a second time today, one function along. The unwrapped-session detector's real-substrate gate demanded that both verdicts occur across live transcripts, and **passed on 2026-08-17 while that detector was systematically broken** — a spread of outcomes is not evidence that any outcome is right. That gate has been demoted from an assertion to a printed note with its limit stated beside it (`[FIX]`, this session).
|
||||
|
||||
**Recommendation:** whichever option is taken on the parent item, the selftest line above must be **re-derived from the property** ("does this ruling dispose of that item?") rather than from the check's own vocabulary ("does this string lack a `PENDING-N` token?"), using a fixture that is genuinely two unrelated documents rather than a real matched pair.
|
||||
**Files affected:** `~/dotfiles/scripts/wake-digest.py` (selftest only).
|
||||
**Awaiting:** Steward authorization, with the parent item. Nothing changed in `ruled_pendings` or its test.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user