From f619370e0aececa0a1b84c4c0c70128eea4ad800 Mon Sep 17 00:00:00 2001 From: desp0042 Date: Mon, 3 Aug 2026 00:27:43 +0200 Subject: [PATCH 1/2] fix(report): expose exact AMR field JVP envelope --- docs/ARCHITECTURE.md | 14 +++++--- python/pops/_capabilities_report.py | 36 ++++++++++++++----- .../amr/test_amr_runtime_inspect.py | 15 ++++++-- .../unit/codegen/test_fail_closed_reports.py | 25 +++++++++++++ 4 files changed, 73 insertions(+), 17 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index fc2783636..7ecab40c4 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -415,11 +415,15 @@ registry lookup. For field-coupled finite-difference JVPs, the exact boundary evaluation level must also equal the active Program resource level before the perturbed field solve or the frozen-field restoration is allowed to dispatch. A fine-level caller therefore cannot forge a coarse point and reuse level 0. -This identity guard does not create a fine-level tangent-field solve. Supporting a boundary JVP that -reads solved fields requires a provider contract that materializes the field tangent from the state -direction on every participating level, couples those tangents across CompositeFAC when requested, -and restores the frozen primal field transactionally. Reusing the primal field pointer would omit -the derivative of the field solve and is therefore not a valid fallback. +The generated finite-difference route materializes that derivative by re-solving the exact prepared +provider from the perturbed state on every participating level, evaluating the complete residual, +and restoring the frozen primal field transactionally; it never reuses the unperturbed field pointer +as a tangent. This proof currently covers host execution in a single process only; PoPS does not +advertise this route as MPI-capable until a real multi-rank oracle is part of the validation matrix. +A partially refined CompositeFAC hierarchy with a dynamic physical boundary remains a separate +explicit refusal until its correction owns a level-qualified homogeneous/JVP boundary operator. +The public report exposes that unsupported subcase separately as +`amr:composite_dynamic_boundary`; it is not hidden behind the available level-qualified JVP row. Linear and nonlinear field routes both retain the accepted warm start until their `SolveReport` is consumed; an invalid boundary evaluation or iteration limit restores that value and cannot update the published aux channel. diff --git a/python/pops/_capabilities_report.py b/python/pops/_capabilities_report.py index 2d7d47e93..4e3f1306b 100644 --- a/python/pops/_capabilities_report.py +++ b/python/pops/_capabilities_report.py @@ -574,19 +574,37 @@ def _python_contract_rows(flags: Any, source: str) -> list[Any]: _row( "amr:field_coupled_rhs_jacvec", layout="amr", - backend="none", + backend="production", platform="host", - mpi=mpi, - gpu=gpu, - status="unavailable", + mpi=False, + gpu=False, + status="available", + limitation=( + "field-coupled finite-difference rhs_jacvec re-solves the exact prepared field " + "provider from the perturbed state on level zero and every refined level, then " + "restores the frozen primal publication transactionally; the proved execution " + "envelope is host single-process, with no multi-rank MPI route claimed" + ), + source=source, + ), + _row( + "amr:composite_dynamic_boundary", + layout="amr", + backend="production", + platform="host", + mpi=False, + gpu=False, + status="partial", limitation=( - "field-coupled rhs_jacvec has no level-qualified tangent-field provider ABI " - "for AMR level > 0" + "a fully refined hierarchy passes the exact finest-level logical time, state " + "dependencies and nonlinear/JVP context to its dynamic field boundary; a " + "partially refined CompositeFAC hierarchy is refused because its coarse-fine " + "correction lacks a level-qualified homogeneous/JVP boundary operator" ), - requested="field_coupled rhs_jacvec on AMR level > 0", - available_route="field_coupled rhs_jacvec on AMR level 0", + available_route="fully refined host single-process CompositeFAC hierarchy", alternative=( - "use the level-0 route or implement a level-qualified tangent-field provider ABI" + "use a fully refined hierarchy or implement the level-qualified homogeneous/JVP " + "coarse-fine correction boundary" ), source=source, ), diff --git a/tests/python/integration/amr/test_amr_runtime_inspect.py b/tests/python/integration/amr/test_amr_runtime_inspect.py index aa15cedd4..aea86ecea 100644 --- a/tests/python/integration/amr/test_amr_runtime_inspect.py +++ b/tests/python/integration/amr/test_amr_runtime_inspect.py @@ -294,11 +294,20 @@ def test_inspect_before_build_reports_unbuilt_patches_honestly(): assert report.regrid.frozen is True -def test_inspect_no_longer_lists_the_served_fine_level_field_jacvec_as_a_limitation(): +def test_inspect_separates_served_field_jacvec_from_partial_composite_boundary(): report = AmrSystem(n=16, L=1.0, periodicity=(True, True)).amr.inspect() - rows = [row for row in report.limitations if row["feature"] == "amr:field_coupled_rhs_jacvec"] + field_rows = [ + row for row in report.limitations if row["feature"] == "amr:field_coupled_rhs_jacvec" + ] + boundary_rows = [ + row for row in report.limitations if row["feature"] == "amr:composite_dynamic_boundary" + ] - assert rows == [] + assert field_rows == [] + assert len(boundary_rows) == 1 + assert boundary_rows[0]["status"] == "partial" + assert "partially refined CompositeFAC hierarchy is refused" in boundary_rows[0]["reason"] + assert "level-qualified homogeneous/JVP boundary operator" in boundary_rows[0]["reason"] # --- compiled static delegation ------------------------------------------------ diff --git a/tests/python/unit/codegen/test_fail_closed_reports.py b/tests/python/unit/codegen/test_fail_closed_reports.py index 6773f344d..3335972c8 100644 --- a/tests/python/unit/codegen/test_fail_closed_reports.py +++ b/tests/python/unit/codegen/test_fail_closed_reports.py @@ -91,6 +91,31 @@ def test_mpi_world_route_reports_only_proved_native_availability(supports_mpi, e assert external_amr.available_route == ( "external FieldSolver@2 on one uniform host/serial level" ) + field_jacvec = routes["amr:field_coupled_rhs_jacvec"] + assert field_jacvec.status == "available" + assert field_jacvec.layout == "amr" + assert field_jacvec.backend == "production" + assert field_jacvec.mpi is False + assert field_jacvec.gpu is False + assert "level zero and every refined level" in field_jacvec.limitation + assert "restores the frozen primal publication transactionally" in field_jacvec.limitation + assert "host single-process" in field_jacvec.limitation + assert "no multi-rank MPI route claimed" in field_jacvec.limitation + assert field_jacvec.available_route == "" + assert field_jacvec.alternative == "" + composite_boundary = routes["amr:composite_dynamic_boundary"] + assert composite_boundary.status == "partial" + assert composite_boundary.layout == "amr" + assert composite_boundary.backend == "production" + assert composite_boundary.mpi is False + assert composite_boundary.gpu is False + assert "fully refined hierarchy" in composite_boundary.limitation + assert "partially refined CompositeFAC hierarchy is refused" in composite_boundary.limitation + assert "level-qualified homogeneous/JVP boundary operator" in composite_boundary.limitation + assert composite_boundary.available_route == ( + "fully refined host single-process CompositeFAC hierarchy" + ) + assert "coarse-fine correction boundary" in composite_boundary.alternative def test_transport_boundary_routes_report_exact_supported_envelope_and_missing_kernels(): From 5efeeb69b54fbe8822aa62cd1feeff577e055990 Mon Sep 17 00:00:00 2001 From: desp0042 Date: Mon, 3 Aug 2026 01:07:43 +0200 Subject: [PATCH 2/2] fix(report): qualify AMR field JVP claims --- docs/ARCHITECTURE.md | 13 ++++---- python/pops/_capabilities_report.py | 30 +++++++++-------- .../unit/codegen/test_fail_closed_reports.py | 33 ++++++++++++++----- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 7ecab40c4..3980899a7 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -416,12 +416,13 @@ For field-coupled finite-difference JVPs, the exact boundary evaluation level mu active Program resource level before the perturbed field solve or the frozen-field restoration is allowed to dispatch. A fine-level caller therefore cannot forge a coarse point and reuse level 0. The generated finite-difference route materializes that derivative by re-solving the exact prepared -provider from the perturbed state on every participating level, evaluating the complete residual, -and restoring the frozen primal field transactionally; it never reuses the unperturbed field pointer -as a tangent. This proof currently covers host execution in a single process only; PoPS does not -advertise this route as MPI-capable until a real multi-rank oracle is part of the validation matrix. -A partially refined CompositeFAC hierarchy with a dynamic physical boundary remains a separate -explicit refusal until its correction owns a level-qualified homogeneous/JVP boundary operator. +provider from the perturbed state on both levels of the proved 2D ratio-2 L0/L1 hierarchy, evaluating +the complete residual, and restoring the frozen primal field transactionally; it never reuses the +unperturbed field pointer as a tangent. A two-rank native consensus/numerical oracle covers this +algebra, but the generated-Program route has no installed MPI end-to-end proof. The public capability +row therefore advertises only host single-process execution. A partially refined CompositeFAC +hierarchy with a dynamic physical boundary remains a separate explicit refusal until its correction +owns a level-qualified homogeneous/JVP boundary operator. The public report exposes that unsupported subcase separately as `amr:composite_dynamic_boundary`; it is not hidden behind the available level-qualified JVP row. Linear and nonlinear field routes both retain the accepted warm start until their `SolveReport` is diff --git a/python/pops/_capabilities_report.py b/python/pops/_capabilities_report.py index 4e3f1306b..1ee7e84b6 100644 --- a/python/pops/_capabilities_report.py +++ b/python/pops/_capabilities_report.py @@ -373,6 +373,8 @@ def _python_contract_rows(flags: Any, source: str) -> list[Any]: mpi = bool(_flag_value(flags, "supports_mpi")) gpu = bool(_flag_value(flags, "supports_gpu")) + amr_status = _status_from_flag(flags, "supports_amr") + composite_boundary_status = "partial" if amr_status == "available" else amr_status return [ _row( "boundary:prepared_transport", @@ -494,9 +496,7 @@ def _python_contract_rows(flags: Any, source: str) -> list[Any]: "solver outcome, block counter, or restart metadata; a typed candidate failure " "rejects the step and never substitutes another solver" ), - requested=( - "prepared Riemann recovery chain with requested/used solver diagnostics" - ), + requested=("prepared Riemann recovery chain with requested/used solver diagnostics"), available_route=( "one explicitly selected Riemann solver with typed rejection and transactional " "rollback" @@ -578,12 +578,14 @@ def _python_contract_rows(flags: Any, source: str) -> list[Any]: platform="host", mpi=False, gpu=False, - status="available", + status=amr_status, limitation=( "field-coupled finite-difference rhs_jacvec re-solves the exact prepared field " - "provider from the perturbed state on level zero and every refined level, then " - "restores the frozen primal publication transactionally; the proved execution " - "envelope is host single-process, with no multi-rank MPI route claimed" + "provider from the perturbed state on both levels of the proved 2D ratio-2 L0/L1 " + "hierarchy, then restores the frozen primal publication transactionally; a " + "two-rank native consensus/numerical oracle exists, but the generated-Program " + "route has no installed MPI end-to-end proof and therefore advertises only host " + "single-process execution" ), source=source, ), @@ -594,14 +596,16 @@ def _python_contract_rows(flags: Any, source: str) -> list[Any]: platform="host", mpi=False, gpu=False, - status="partial", + status=composite_boundary_status, limitation=( - "a fully refined hierarchy passes the exact finest-level logical time, state " - "dependencies and nonlinear/JVP context to its dynamic field boundary; a " - "partially refined CompositeFAC hierarchy is refused because its coarse-fine " - "correction lacks a level-qualified homogeneous/JVP boundary operator" + "the proved fully refined 2D ratio-2 L0/L1 hierarchy passes the exact finest-level " + "logical time, state dependencies and nonlinear/JVP context to its dynamic field " + "boundary; a partially refined CompositeFAC hierarchy is refused because its " + "coarse-fine correction lacks a level-qualified homogeneous/JVP boundary operator" + ), + available_route=( + "fully refined 2D ratio-2 L0/L1 host single-process CompositeFAC hierarchy" ), - available_route="fully refined host single-process CompositeFAC hierarchy", alternative=( "use a fully refined hierarchy or implement the level-qualified homogeneous/JVP " "coarse-fine correction boundary" diff --git a/tests/python/unit/codegen/test_fail_closed_reports.py b/tests/python/unit/codegen/test_fail_closed_reports.py index 3335972c8..e01c2b7cb 100644 --- a/tests/python/unit/codegen/test_fail_closed_reports.py +++ b/tests/python/unit/codegen/test_fail_closed_reports.py @@ -97,10 +97,13 @@ def test_mpi_world_route_reports_only_proved_native_availability(supports_mpi, e assert field_jacvec.backend == "production" assert field_jacvec.mpi is False assert field_jacvec.gpu is False - assert "level zero and every refined level" in field_jacvec.limitation + assert "proved 2D ratio-2 L0/L1 hierarchy" in field_jacvec.limitation assert "restores the frozen primal publication transactionally" in field_jacvec.limitation - assert "host single-process" in field_jacvec.limitation - assert "no multi-rank MPI route claimed" in field_jacvec.limitation + assert "two-rank native consensus/numerical oracle exists" in field_jacvec.limitation + assert ( + "generated-Program route has no installed MPI end-to-end proof" in field_jacvec.limitation + ) + assert "host single-process execution" in field_jacvec.limitation assert field_jacvec.available_route == "" assert field_jacvec.alternative == "" composite_boundary = routes["amr:composite_dynamic_boundary"] @@ -109,15 +112,31 @@ def test_mpi_world_route_reports_only_proved_native_availability(supports_mpi, e assert composite_boundary.backend == "production" assert composite_boundary.mpi is False assert composite_boundary.gpu is False - assert "fully refined hierarchy" in composite_boundary.limitation + assert "fully refined 2D ratio-2 L0/L1 hierarchy" in composite_boundary.limitation assert "partially refined CompositeFAC hierarchy is refused" in composite_boundary.limitation assert "level-qualified homogeneous/JVP boundary operator" in composite_boundary.limitation assert composite_boundary.available_route == ( - "fully refined host single-process CompositeFAC hierarchy" + "fully refined 2D ratio-2 L0/L1 host single-process CompositeFAC hierarchy" ) assert "coarse-fine correction boundary" in composite_boundary.alternative +def test_amr_field_jacvec_routes_follow_the_artifact_amr_flag(): + report = capability_reports.native_capability_report( + flags={"supports_mpi": True, "supports_gpu": False, "supports_amr": False}, + source="uniform-test-manifest", + ) + routes = {row.feature: row for row in report.routes} + + field_jacvec = routes["amr:field_coupled_rhs_jacvec"] + assert field_jacvec.status == "unavailable" + assert field_jacvec.error_message + + composite_boundary = routes["amr:composite_dynamic_boundary"] + assert composite_boundary.status == "unavailable" + assert composite_boundary.error_message + + def test_transport_boundary_routes_report_exact_supported_envelope_and_missing_kernels(): report = capability_reports.native_capability_report( flags={"supports_mpi": True, "supports_gpu": False, "supports_amr": True}, @@ -177,9 +196,7 @@ def test_transport_boundary_routes_report_exact_supported_envelope_and_missing_k flags={"supports_mpi": True, "supports_gpu": True, "supports_amr": True}, source="test-gpu-manifest", ) - gpu_post_riemann = { - row.feature: row for row in gpu_report.routes - }["boundary:post_riemann_flux"] + gpu_post_riemann = {row.feature: row for row in gpu_report.routes}["boundary:post_riemann_flux"] assert gpu_post_riemann.gpu is False