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

@ -35,7 +35,7 @@ from collections.abc import Mapping, Sequence
from pathlib import Path
from typing import TYPE_CHECKING, Any
from portfolio_optimiser.validator import Rejection, ValidatedProposal
from portfolio_optimiser.validator import Rejection, Unsupported, ValidatedProposal
if TYPE_CHECKING: # provenance imports agent_framework — keep it out of the runtime import graph
from portfolio_optimiser.provenance import ProvenanceStamp
@ -113,7 +113,21 @@ def outcome_payload(
validated/rejected branching, shared by ``write_outbox`` and the hosted invocations
response (``hosting._response_payload``). Two copies of the branch would drift, and a
drifted copy would let the HTTP surface describe an outcome the outbox never wrote —
the ``to_ore`` single-source rule (kø-(p)) applied to a payload shape."""
the ``to_ore`` single-source rule (kø-(p)) applied to a payload shape.
``unsupported`` (row 6) is checked FIRST because it subclasses ``Rejection``: it carries the
validator's percentiles (the numbers held) AND the reason, so a reader sees both halves."""
if isinstance(outcome, Unsupported):
return {
"outcome_type": "unsupported",
"reason": outcome.reason,
"p10": outcome.validated.p10,
"p50": outcome.validated.p50,
"p90": outcome.validated.p90,
"nominal_feasible": outcome.validated.nominal_feasible,
"checker_verdict": checker_verdict,
"verdict_id": verdict_id,
}
if isinstance(outcome, ValidatedProposal):
return {
"outcome_type": "validated",