fix(tools): okf_adjudicate exits 2 on a malformed plan
A SegmentationError raised by the plan grammar escaped main() as a traceback and exit 1, while every other malformed-plan case in the same file already returned 2. Exit codes are the interface a caller scripts against, and exit 1 with a traceback is the code an unhandled bug produces -- it says "this command broke" where the truth is "this file is not a plan". The refusal itself is unchanged: nothing was written before and nothing is written now, and the grammar in src/ is untouched. What changes is one line on stderr naming the error code, and the exit code. Both branches that can raise are covered: the pre-write parse of a non-empty plan, and the required-field check reached through the empty branch. The old behaviour was pinned by test_an_entries_value_that_is_not_a_list_is_still_refused, which asserted that a wrongly-typed `entries` reaches the caller as a raised SegmentationError and recorded that as a finding rather than fixing it. That test is rewritten here, in the same commit as the code, to assert exit 2 plus the code on stderr. A second test pins the one-line stderr shape on the non-empty branch. Suite 1072 -> 1073 passed; ruff and mypy --strict clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
acf2ac24d7
commit
a72053f66f
3 changed files with 68 additions and 8 deletions
|
|
@ -325,21 +325,57 @@ def test_an_empty_plan_missing_a_required_field_is_still_refused(
|
|||
assert not verdict.exists()
|
||||
|
||||
|
||||
def test_an_entries_value_that_is_not_a_list_is_still_refused(tmp_path: Path) -> None:
|
||||
def test_an_entries_value_that_is_not_a_list_is_still_refused(
|
||||
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
"""Empty is a judgement; the wrong TYPE is a malformed plan, and the two
|
||||
must not collapse. The malformed one still meets the unchanged grammar.
|
||||
|
||||
It reaches the caller as a raised SegmentationError rather than as exit 2,
|
||||
which is pre-existing behaviour for every malformed plan and is left alone
|
||||
here rather than repaired inside a change about empty ones. Recorded as a
|
||||
finding, not fixed."""
|
||||
It reaches the caller as EXIT 2, the same code every other malformed plan
|
||||
already got. A grammar refusal used to escape as a traceback and exit 1,
|
||||
which said "this command crashed" where the truth was "this file is not a
|
||||
plan" -- and exit codes are the interface callers script against."""
|
||||
plan_path = empty_proposal(tmp_path)
|
||||
written = payload(plan_path)
|
||||
written["entries"] = "none"
|
||||
plan_path.write_text(json.dumps(written), encoding="utf-8", newline="")
|
||||
|
||||
with pytest.raises(SegmentationError) as excinfo:
|
||||
adjudicate_empty(tmp_path, plan_path)
|
||||
code, _ = adjudicate_empty(tmp_path, plan_path)
|
||||
|
||||
assert excinfo.value.code == "segmentation_plan_invalid"
|
||||
assert code == 2
|
||||
assert "segmentation_plan_invalid" in capsys.readouterr().err
|
||||
assert not (tmp_path / "verdict.json").exists()
|
||||
|
||||
|
||||
def test_a_malformed_non_empty_plan_exits_two_with_one_stderr_line(
|
||||
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
"""The same refusal on the other branch: a plan with entries is parsed
|
||||
BEFORE anything is written, and that parse failing is a malformed plan too.
|
||||
|
||||
One line, because a caller reading stderr to tell malformed from missing
|
||||
should not have to parse a traceback to do it."""
|
||||
plan_path = proposal(tmp_path)
|
||||
written = payload(plan_path)
|
||||
written["entries"][0]["span"] = [10, 3]
|
||||
plan_path.write_text(json.dumps(written), encoding="utf-8", newline="")
|
||||
capsys.readouterr() # the proposer's own report is not what is under test
|
||||
|
||||
code = okf_adjudicate.main(
|
||||
[
|
||||
"--plan",
|
||||
str(plan_path),
|
||||
"--out",
|
||||
str(tmp_path / "verdict.json"),
|
||||
"--adjudicator",
|
||||
ADJUDICATOR,
|
||||
"--adjudicated-at",
|
||||
AT,
|
||||
]
|
||||
)
|
||||
|
||||
assert code == 2
|
||||
stderr = capsys.readouterr().err
|
||||
assert len(stderr.strip().splitlines()) == 1
|
||||
assert "segmentation_span_invalid" in stderr
|
||||
assert not (tmp_path / "verdict.json").exists()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue