Twinned from https://github.com/cfsh/ninefold/issues/585 by tools/beads/import_github.py's reconcile pass.
tools/pr/review_now.py (new in #578) decides what to tell the session by string-matching dispatch.py's human-readable stdout. Nothing binds the two. Rename a dispatcher log line and review_now silently starts reporting the wrong outcome — no test fails, no error, just a confident sentence that is not true.
Nine literals in conclusion() are load-bearing, and all nine currently appear in dispatch.py:
``` '#{number}: done' 'delta re-verified' 'up to date' '#{number}: FAILED' 'no review ever requested' 'reviewer muted for this PR' 'review in flight' 'skip (' 'backoff' ```
That they all match today is luck plus recency, not a guarantee — the check above is a script I ran by hand, not something in the suite.
conclusion() shipped with an unreachable branch: the dispatcher's fresh-failure line is
``` #N: FAILED — see <log> (backoff 45m; rev:pending stays on; --force retries) ```
which contains the word "backoff", so a backoff test placed first swallowed it and reported a just-failed spawn as a pre-existing one, in the wrong tense, dropping the log pointer.
The root cause was in the test, and it is the same coupling problem one layer down: ConclusionTest fed *paraphrases* of the dispatcher's lines rather than the lines themselves, and the paraphrase dropped the one word that distinguished the two branches. Both branches passed against inputs that could not tell them apart. #578 pins the real strings as named constants, which fixes the two known cases and does nothing for the tenth literal someone adds next.
nflib/verdict.py's docstring:
> ⚠️ CHARTER.md is the authority; nflib/verdict.py is the only parser. This line was stale for months — it lost CONVERGED when that result was added, because the schema existed in four places and no place at all. A contract test in test_nflib_verdict.py now reads CHARTER.md and fails if the parser and the charter disagree.
Design 001 §2.6 states the principle: *prompt files are source code*. The same argument applies to a sibling tool's stdout vocabulary — it is an interface, it just is not spelled like one.
conclusion() matches is present in dispatch.py's source, mirroring test_nflib_verdict.py. Catches a rename; will not catch a rewording that keeps the substring.review_now matches on the constant.dispatch.py a machine-readable per-PR outcome (one JSON line, or a --porcelain mode) and have review_now read that, leaving prose free to change. This is design 001's own objection to parsing prose, applied to a caller inside the tier rather than to gh output.Unclaimed. Found working #576; not folding it into that chunk.
None.
No comments.