diff --git a/docs/guard-inventory.md b/docs/guard-inventory.md index 3e126e9e1..64482c0bf 100644 --- a/docs/guard-inventory.md +++ b/docs/guard-inventory.md @@ -145,17 +145,30 @@ withdrawal silently dropped one and claimed otherwise, which is | Invariant it asserted | Where it is now | |---|---| -| Bidirectional write/read vocabulary parity | **Not covered.** The reason for the withdrawal; #788 | +| Bidirectional write/read vocabulary parity | **LOST.** The reason for the withdrawal; #788 | +| No READ-side word is both positive and negative | **LOST** as a universal property; #788 | +| No WRITE-side word is both success and failure | **LOST** as a universal property; #788 | | Strict extractor consumes every case arm | Retired with the extractor; #788 | | `POS_RE`/`NEG_RE` each assigned exactly once | Retired with the extractor; #788 | | Both extractors find non-empty sets (anti-vacuity) | Retired with the extractor; #788 | | A wrong write source makes the extractors disagree | Retired with the extractor; #788 | -| Read-side polarity of the established tokens | `test_check_review_verdict.py::test_each_verdict_word_retains_its_established_polarity` | -| Write-side polarity of the established tokens | `test_post_review_verdict.py::test_each_verdict_word_posts_its_established_polarity` | -The two surviving rows are **polarity regressions over five named tokens** — not disjointness, not -parity. They pin that `BLOCKED` still both posts and reads as negative, in each script separately. -A token added to one script and not the other is untested by them, which is the whole of #788. +Two guards were ADDED in its place. They are **not** replacements for rows 2 and 3 and the table +above deliberately does not list them as such — an earlier draft did, and cold review was right that +relabelling a lost invariant as a narrower surviving one is the exact failure this table exists to +prevent, committed by the table: + +| Added | What it pins | +|---|---| +| `test_check_review_verdict.py::test_each_verdict_word_retains_its_established_polarity` | the five established tokens still READ with their established polarity | +| `test_post_review_verdict.py::test_each_verdict_word_posts_its_established_polarity` | the five established tokens still POST with their established polarity | + +**Polarity is strictly weaker than disjointness, and the gap is demonstrable.** Put `MERGEABLE` in +BOTH `case` arms of `post-review-verdict.sh`: the success arm wins, every polarity assertion stays +green, and the withdrawn disjointness test failed. What the two added guards do catch is the +dangerous direction — a token that a reviewer means as `BLOCKED` silently reading or posting as +approval, which writes a green `review-verdict/h10`. A token added to one script and not the other +is untested by either, which is the whole of #788. The 21 include every `PreToolUse` hook except merge-consent — the same population #776 found we cannot even observe firing. A guard that is neither proven nor observable is an assertion about the