feat(row6): a proposal whose approach declared no requirement is unsupported

Stress round 6 validated three falsification arms, and every validated
approach rested only on run-level declarations nobody can attribute to one
approach. declare_requirement now takes a required approach_id (a mandate
id or own-proposal; an unknown id is refused naming the valid ones), and a
ValidatedProposal whose approach has neither a mandate requirement nor a
declaration under its own id becomes validator.Unsupported - a Rejection
subclass carrying the validator's own ruling, reported as `unsupported` in
coverage, the outcome artefact, the settlement and the judge, and never
counted or summed. The rule is active whenever the debate held the
declaration tool, the micro base included; the road and pre-pass paths are
untouched. Declaration quality is not judged, so the rule can be satisfied
by declaring any document the run read.

The v1 gate's row 6 probes pass; its artefact half reads IKKE MÅLT because
stress round 6 predates approach-addressed declarations, and IKKE MÅLT is
never green - it fails the exit code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-17 16:40:54 +02:00
commit 938a1ca30e
23 changed files with 718 additions and 115 deletions

View file

@ -328,13 +328,47 @@ def test_row6_green_needs_both_the_probes_and_zero_undeclared() -> None:
assert gate.score_undeclared(_PROBES, failing, _CLEAN, "s").status == gate.RED
def test_row6_missing_artefacts_are_never_zero() -> None:
def test_row6_missing_artefacts_are_never_zero_and_never_green() -> None:
"""Probes passing and artefacts absent (clean clone, CI, a base mid-rebuild) is NOT a pass:
the row says IKKE MÅLT and fails the exit code."""
row = gate.score_undeclared(
_PROBES, _all_pass(_PROBES), gate.StressMeasure(missing="ut finnes ikke"), "s"
)
assert row.k is None
assert "ikke målt, artefakter mangler" in row.reason
assert "ikke målt" in row.reason
assert " av " in row.line()
assert (row.status, row.failing) == (gate.NOT_MEASURED, True)
assert gate.exit_code([row]) == 1
def test_row6_artefacts_older_than_the_rule_are_not_measured() -> None:
old = gate.StressMeasure(validated=10, undeclared=10, unaddressed=12, where="x")
row = gate.score_undeclared(_PROBES, _all_pass(_PROBES), old, "s")
assert (row.k, row.status) == (None, gate.NOT_MEASURED)
assert "eldre enn regelen" in row.reason and "approach_id mangler" in row.reason
def test_row7_not_measured_is_not_green_either() -> None:
row = gate.score_named(gate.StressMeasure(missing="borte"), "s")
assert (row.k, row.status, row.failing) == (None, gate.NOT_MEASURED, False)
@pytest.mark.parametrize("missing", ["all", "outcome0", "kept"])
def test_rows_1_2_4_with_missing_files_are_red(tmp_path: Path, missing: str) -> None:
root = _green_rounds(tmp_path / "r")
if missing == "all":
root = tmp_path / "absent"
elif missing == "outcome0":
(root / "0" / "outcome.json").unlink()
else:
(root / "3" / "report.kept.md").unlink()
rows = [
gate.score_rounds(root, 3, _AI),
gate.score_changes(root, 3, _AI),
gate.score_kept(root, 0.8),
]
assert gate.exit_code(rows) == 1
assert gate.GREEN not in {r.status for r in rows} or missing != "all"
def test_row6_measures_the_stress_outboxes_when_they_exist(tmp_path: Path) -> None:
@ -353,6 +387,9 @@ def test_row6_measures_the_stress_outboxes_when_they_exist(tmp_path: Path) -> No
assert m.validated == 0
pytest.skip(f"stress artefacts not judgeable right now: {m.missing}")
assert (m.validated, m.undeclared, m.named, m.commissioned) == (10, 10, 1, 20)
assert m.unaddressed > 0 # stress round 6 predates approach-addressed declarations
row = gate.score_undeclared(_PROBES, _all_pass(_PROBES), m, "s")
assert (row.k, row.status) == (None, gate.NOT_MEASURED)
def test_row7_is_a_diagnosis_and_never_moves_the_exit_code() -> None:
@ -427,5 +464,7 @@ def test_the_command_is_red_today_with_every_row_in_its_output(tmp_path: Path) -
assert (rows["types"]["k"], rows["types"]["n"]) == (3, 8)
assert rows["kept"]["status"] == gate.RED
assert (rows["maf"]["k"], rows["maf"]["n"], rows["maf"]["status"]) == (3, 8, gate.RED)
assert rows["undeclared"]["status"] == gate.RED
# Probes green since row 6; stress round 6 predates the rule (or is absent) -> never green.
assert rows["undeclared"]["status"] == gate.NOT_MEASURED
assert rows["undeclared"]["k"] is None
assert rows["named"]["failing"] is False