diff --git a/application/execution_receipt_adapter.py b/application/execution_receipt_adapter.py index c856080..f8906bc 100644 --- a/application/execution_receipt_adapter.py +++ b/application/execution_receipt_adapter.py @@ -116,11 +116,16 @@ def attach_unknown_failure_execution_receipt(report: dict[str, Any]) -> dict[str if _is_legacy_unattested(report): return report - outcome, confirmation = resolve_execution_receipt_fact( - dry_run=bool(report.get("dry_run")), - submission_attempted=True, - failed=True, - ) + if report.get("dry_run"): + # An escaped exception is a failure even when no broker call is possible. + # Keep this fact independent of the shared resolver's dry-run precedence. + outcome, confirmation = "failed", "not_applicable" + else: + outcome, confirmation = resolve_execution_receipt_fact( + dry_run=False, + submission_attempted=True, + failed=True, + ) return attach_runtime_execution_receipt( report, outcome=outcome, diff --git a/tests/test_execution_receipt_adapter.py b/tests/test_execution_receipt_adapter.py index 883ac29..f427e3f 100644 --- a/tests/test_execution_receipt_adapter.py +++ b/tests/test_execution_receipt_adapter.py @@ -136,6 +136,12 @@ def test_dry_run_never_claims_submission(self) -> None: self.assertEqual(report["execution_receipt"]["outcome"], "no_action") + def test_live_exception_preserves_submission_uncertainty(self) -> None: + report = _report() + attach_unknown_failure_execution_receipt(report) + self.assertEqual(report["execution_receipt"]["outcome"], "failed") + self.assertEqual(report["execution_receipt"]["broker_confirmation"], "not_observed") + def test_dry_run_exception_is_failed_without_live_submission_uncertainty(self) -> None: report = _report() report["dry_run"] = True