fix(788): one declarative H10 verdict vocabulary, derived by both sides (#846)
Build ErsatzTV Image / CI toolchain image resolves (push) Successful in 6s
Build ErsatzTV Image / Delimiter ban (release path) (push) Successful in 25s
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 8m34s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 6m17s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (push) Successful in 5m50s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Skipped
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Skipped
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 4m22s
Build ErsatzTV Image / CI toolchain image resolves (push) Successful in 6s
Build ErsatzTV Image / Delimiter ban (release path) (push) Successful in 25s
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 8m34s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 6m17s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (push) Successful in 5m50s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Skipped
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Skipped
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 4m22s
The verdict words lived in two hand-written shell copies — the `case` arms of post-review-verdict.sh (write) and the POS_RE/NEG_RE regexes of check-review-verdict.sh (read) — held together by nothing but a comment that had already gone stale. scripts/lib/review-verdict-vocabulary.sh now declares them once and both sides derive; neither script enumerates a verdict word any more. Only the WORD SET moved. The grammar stays in check-review-verdict.sh, where every #629 false-open actually lived. No parity test: #774 shipped one and withdrew it after six rounds, because a regex over shell source is not a shell parser. The proof is behavioural and graded MUTATION — the harness restores the pre-#788 hardcoded POS_RE each run and requires it to redden. Enforcement is a DATA dependency, not a control-flow gate. Review round 1 found a real fail-open in the first commit: `${#arr[@]}` is nounset-safe only for a declared-empty array, and under `set -u` that error inside a function called as `if ! validate` skips BOTH branches — so on the reader (deliberately no `set -e`) an explicit BLOCKED @ head classified `positive`, exit 0. Validation now sets a sentinel on its last line and the derived views refuse without it. Six cold review rounds; rounds 2-6 found no fail-open across differential fuzzing (4788 / 2612 / 7560 payloads, zero divergences from origin/main's grammar), sentinel forgery, environment poisoning, declare -p evasion on bash 5.3 and 3.2, path/symlink resolution and probe TOCTOU. Every malformation fails closed: reader exit 2, writer exit 1 with nothing posted. Also corrected: CLAUDE.md and release.review-verdict-gate both enumerated the vocabulary without LGTM, a word the code has accepted since #629. fixes #788 Co-authored-by: Timothy <timothy@noreply.gitea.tblindustries.be>
This commit was merged in pull request #846.
This commit is contained in:
@@ -429,7 +429,9 @@ def test_non_hex_head_is_an_input_error():
|
||||
# completeness claim: the property below is PER-MEMBER — "each of these words classifies as exactly
|
||||
# one thing" — so a word missing from this list is simply an untested word, not a defect the list
|
||||
# conceals. It is emphatically NOT a claim that these are the only words the scripts accept. Proving
|
||||
# THAT needs one shared vocabulary both scripts read, which is ersatztv#788.
|
||||
# THAT is what the shared vocabulary in `scripts/lib/review-verdict-vocabulary.sh` supplies
|
||||
# (ersatztv#788, landed); `test_review_verdict_vocabulary.py` makes the completeness claim against
|
||||
# that one declaration, which is why this list may stay a per-member literal.
|
||||
POSITIVE_WORDS = ["MERGEABLE", "APPROVED", "LGTM"]
|
||||
NEGATIVE_WORDS = ["BLOCKED", "NOT-MERGEABLE"]
|
||||
|
||||
@@ -463,7 +465,7 @@ def test_each_verdict_word_retains_its_established_polarity(word, expected):
|
||||
both flags and precedence decides.
|
||||
|
||||
WHICH DIRECTION THIS CATCHES, MEASURED RATHER THAN REASONED — the first draft of this docstring
|
||||
asserted it and was checked afterwards, which is the wrong order. `check-review-verdict.sh:212`
|
||||
asserted it and was checked afterwards, which is the wrong order. `check-review-verdict.sh:284`
|
||||
reads `if [ "$is_pos" = 1 ]; then head_pos=1; else head_neg=1; fi`, so `is_pos` wins per line
|
||||
and an overlapping word resolves POSITIVE. Both mutations were run against this test:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user