feat(pre-push-safety-net): render the experimental evaluation explanation (M1b 10.10)

The M1b exit run established the comparison but could not show a developer-readable
consequence or repair direction, because both belong to an evaluated capability
declaration and the installed registry is deliberately empty.

The experimental evaluation output now renders, for each change-attributed finding,
its family, exact location, witness, change attribution, provenance, engine method
and operation, together with a consequence and repair direction produced from a
supplied declaration through the same grounded-template path the admitted case
uses. No prose is invented: when no declaration matches, or a template is not
grounded in the operation and context, or the declaration does not cover the
operation symbol, the explanation is absent and the reason is stated.

Declarations reach this rendering only. The runner never passes them to admission,
so nothing in that file can enable a capability or emit an alert however it is
written, and a control asserts that even a declaration claiming PASS admits
nothing. The flag requires explicit base/head replay and the recorded-veto flag.

The evaluation instrument generates its own unreviewed declaration bound to the
run's analysis semantics, asserting that it is neither enabled nor PASS, so the
demonstration cannot drift into a qualified claim.

1,377 tests passed, nine skipped. Rollout stays NO-GO.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
Marius Ciepluch
2026-09-16 19:59:12 +02:00
co-authored by Claude Opus 5
parent 57d6ddcbba
commit cec1c4a428
6 changed files with 266 additions and 7 deletions
+16 -1
View File
@@ -132,6 +132,12 @@ def main(argv: list[str] | None = None) -> int:
replay_parser.add_argument("--max-regions", type=int, default=500)
replay_parser.add_argument("--mode", choices=("advisory", "blocking"), default="advisory")
replay_parser.add_argument("--incomplete-coverage", choices=("allow", "block"), default="allow")
replay_parser.add_argument(
"--experimental-declarations",
type=Path,
help="explicit --base/--head replay only: unreviewed capability declarations used to render the experimental "
"evaluation explanation; never consulted by admission and cannot enable any capability",
)
replay_parser.add_argument(
"--experimental-record-vetoes",
action="store_true",
@@ -243,9 +249,18 @@ def main(argv: list[str] | None = None) -> int:
parser.error("--prior-hook requires Git stdin mode")
if args.experimental_record_vetoes and not args.base:
parser.error("--experimental-record-vetoes requires explicit --base/--head replay; it is never a hook capability")
if args.experimental_declarations and not args.experimental_record_vetoes:
parser.error("--experimental-declarations requires --experimental-record-vetoes")
prior_data = None
if args.base:
delivery = replay(args.path, base=args.base, head=args.head, record_vetoes=args.experimental_record_vetoes, **options)
delivery = replay(
args.path,
base=args.base,
head=args.head,
record_vetoes=args.experimental_record_vetoes,
declarations=args.experimental_declarations,
**options,
)
else:
# multiprocessing closes sys.stdin in its child; duplicate the Git pipe first.
with os.fdopen(os.dup(0), "rb") as stream:
+5 -2
View File
@@ -202,9 +202,12 @@ def _experimental_line(experimental: Mapping[str, object]) -> str:
vetoes = sum(len(f.get("vetoes", [])) for f in findings if isinstance(f, dict)) if isinstance(findings, list) else 0
base = experimental.get("base_only_findings")
quiet = len(base) if isinstance(base, list) else 0
evaluation = experimental.get("evaluation")
explained = len(evaluation) if isinstance(evaluation, list) else 0
return (
f"recorded-veto evaluation retained {count} raw finding(s) with {vetoes} recorded veto(es) and "
f"{quiet} base-only finding(s) in the detailed result; recorded, not applied; not an alert."
f"recorded-veto evaluation retained {count} raw finding(s) with {vetoes} recorded veto(es), "
f"{quiet} base-only finding(s) and {explained} change-attributed evaluation finding(s) in the detailed "
f"result; recorded, not applied; not an alert."
)
+16 -3
View File
@@ -42,7 +42,7 @@ from openultrasast.push.policy import (
from openultrasast.push.report import PushReport, ReportDelivery, ScanRecord, _completed_scan, deliver_report, render_report
from openultrasast.push.reuse import ReusingBackend, declaration_identity, discovery
from openultrasast.push.snapshot import SnapshotAdapter
from openultrasast.push.vetoes import FLAG, LABEL, record_vetoes
from openultrasast.push.vetoes import FLAG, LABEL, load_declarations, record_vetoes
_T = TypeVar("_T")
@@ -179,9 +179,15 @@ def _record(
reasons: Sequence[str],
admission: AdmissionResult,
provenance: dict[str, str],
declarations: Path | None = None,
) -> dict[str, object]:
"""Experimental M1a: the same policy over lifted evidence, reported only, never admitted."""
"""Experimental M1a: the same policy over lifted evidence, reported only, never admitted.
`declarations` supplies templates for the experimental evaluation rendering ONLY. They are
never passed to admission, so nothing read from that file can enable a capability.
"""
registry = load_registry(current=provenance)
supplied = load_declarations(declarations) if declarations is not None else ()
report = record_vetoes(
head=head,
base=delta.base_scan,
@@ -192,6 +198,7 @@ def _record(
production_admission={d.candidate.delta.defect_id: d.reasons for d in admission.dispositions},
coverage_reasons=tuple(dict.fromkeys(reasons)),
capabilities=registry.capabilities,
declarations=supplied,
)
return report.to_payload()
@@ -216,6 +223,7 @@ def _analyze(
execution_budget: ExecutionBudget,
resolved: PushComparison | None = None,
record_vetoes: bool = False,
declarations: Path | None = None,
) -> PushReport:
"""Run a single explicit comparison; exit policy never stands for coverage.
@@ -380,7 +388,8 @@ def _analyze(
stage, stage_started = "recorded_vetoes", time.monotonic()
assert context is not None
recorded = _prepare(
lambda: _record(head_scan, delta, context, comparison, tuple(reasons), admission, provenance), budget
lambda: _record(head_scan, delta, context, comparison, tuple(reasons), admission, provenance, declarations),
budget,
)
experimental = {**recorded, "status": "evaluated"}
timings[stage + "_seconds"] = time.monotonic() - stage_started
@@ -447,8 +456,11 @@ def replay(
cache_dir: Path | None = None,
model_config: Path | None = None,
record_vetoes: bool = False,
declarations: Path | None = None,
) -> ReportDelivery:
config = config or PushConfig()
if declarations is not None and not record_vetoes:
raise ValueError("experimental declarations require the recorded-veto evaluation flag")
budget = ExecutionBudget(time.monotonic() + config.deadline_seconds, config.cancellation_allowance_seconds)
report = _analyze(
repository,
@@ -461,6 +473,7 @@ def replay(
cache_dir=cache_dir,
execution_budget=budget,
record_vetoes=record_vetoes,
declarations=declarations,
)
from openultrasast.push.assistance import assist
+98
View File
@@ -18,6 +18,7 @@ import json
from collections import Counter
from collections.abc import Sequence
from dataclasses import dataclass, replace
from pathlib import Path
from openultrasast.contracts import Contract
from openultrasast.model.contracts import ChangeContext, ExecutionBudget, QuestionIdentity
@@ -33,6 +34,7 @@ from openultrasast.push.policy import (
_compare_evidence,
_context_boundaries,
_counterpart,
_grounded_template,
admit_candidates,
operation_provenance,
)
@@ -134,6 +136,36 @@ class BaseOnlyFinding(Contract):
head_counterparts: tuple[QuestionReceipt, ...]
@dataclass(frozen=True)
class EvaluationFinding(Contract):
"""A developer-readable rendering of one evaluation finding, for reading, never for alerting.
Consequence and repair come from a supplied declaration's templates through the same
grounded-template path the admitted case uses, so no prose is invented here. When no
declaration matches, both are absent with the reason stated. This record is produced outside
admission and cannot become an alert.
"""
family: str
path: str
line: int
novelty: str
reason: str
witness: str
change_evidence: str
provenance: str
question_function: str | None
engine_method: str | None
operation: str
operation_symbol: str
consequence: str | None
repair: str | None
unavailable: tuple[str, ...]
declaration: str | None
declaration_verdict: str | None
declaration_enabled: bool
@dataclass(frozen=True)
class RecordedVetoReport(Contract):
label: str
@@ -145,6 +177,7 @@ class RecordedVetoReport(Contract):
base_only_findings: tuple[BaseOnlyFinding, ...]
lifted_coverage_reasons: tuple[str, ...]
remaining_coverage_reasons: tuple[str, ...]
evaluation: tuple[EvaluationFinding, ...] = ()
def boundary_kind(boundary: str) -> str | None:
@@ -314,6 +347,67 @@ def _finding_vetoes(
return tuple(vetoes)
def load_declarations(path: Path) -> tuple[CapabilityAdmission, ...]:
"""Read experimental declarations for the evaluation rendering only.
These never reach admission. The installed registry remains the sole source of eligibility,
so a declaration read here cannot enable a capability or emit an alert however it is written.
"""
content = path.read_bytes()[: 1024**2 + 1]
if len(content) > 1024**2:
raise ValueError("declaration_size_limit")
payload = json.loads(content)
if not isinstance(payload, list):
raise ValueError("declarations must be a list")
return tuple(CapabilityAdmission.from_payload(item) for item in payload)
def _evaluation(delta: CandidateDelta, declarations: Sequence[CapabilityAdmission], semantics: str) -> EvaluationFinding | None:
"""Render one established finding. Returns None for anything not attributed to the change."""
op = delta.head_operation
if op is None or delta.novelty not in ("new", "worsened") or delta.witness is None or not delta.change_evidence:
return None
key = CapabilityKey(op.question.language, "unspecified", "unspecified", delta.family, op.mechanism, "unreviewed", semantics)
matching = [declaration for declaration in declarations if declaration.key == key]
symbol = op.operation.partition("(")[0].strip()
unavailable: list[str] = []
consequence = repair = None
declaration = matching[0] if len(matching) == 1 else None
if not matching:
unavailable.append("no_matching_declaration")
elif len(matching) > 1:
unavailable.append("ambiguous_declaration")
if declaration is not None:
consequence = _grounded_template(declaration.consequence_template, op, key.context)
repair = _grounded_template(declaration.repair_template, op, key.context)
if consequence is None:
unavailable.append("consequence_template_ungrounded")
if repair is None:
unavailable.append("repair_template_ungrounded")
if symbol not in declaration.operation_symbols:
unavailable.append("declaration_does_not_cover_operation_symbol")
return EvaluationFinding(
delta.family,
op.path,
op.line,
delta.novelty,
delta.reason,
delta.witness,
delta.change_evidence[0],
operation_provenance(op),
op.question.function,
op.method,
op.operation,
symbol,
consequence,
repair,
tuple(unavailable),
declaration.evaluation_id if declaration else None,
declaration.verdict if declaration else None,
bool(declaration.enabled) if declaration else False,
)
def record_vetoes(
*,
head: ModelScanResult,
@@ -325,6 +419,7 @@ def record_vetoes(
production_admission: dict[str, tuple[str, ...]],
coverage_reasons: Sequence[str],
capabilities: Sequence[CapabilityAdmission] = (),
declarations: Sequence[CapabilityAdmission] = (),
execution_budget: ExecutionBudget | None = None,
) -> RecordedVetoReport:
"""Re-run the production comparison and admission over lifted evidence and list what was lifted.
@@ -431,4 +526,7 @@ def record_vetoes(
tuple(base_only),
tuple(dict.fromkeys((*lifted_reasons, *lifted_boundaries))),
remaining,
# Rendered from the PRODUCTION comparison, so the demonstration shows what the production
# rules established, not what the lifted view would have.
tuple(item for delta in production for item in (_evaluation(delta, declarations, semantics),) if item is not None),
)