Skip to content

Expose complete convergence trunk control recipes including trunk flanks #1751

Description

@pinin4fjords

Parent: #1745

Predecessor: #1750 and its stacked draft PR.

Prototype evidence: draft PR #1743 and checkpoint 3f11f175, especially the provisional scalar recipe records in corridor_cohort_integration.py and request/grant tests in test_convergence_corridor_grants.py.

Direct partial-work links: _convergence_corridor_target, convergence_corridor_requests, _validate_control_recipe and recipe records, and test_convergence_corridor_grants.py.

Retrieving the prototype: git fetch origin refs/pull/1743/head:pr-1743-checkpoint, then read files with git show 3f11f1758f16341ace6b1409eff53a36a36ec715:<path>. Never check that branch out into your worktree.

Outcome

Expose every pre-freeze mutable convergence trunk as one owner-typed scalar request with an explicit affine control recipe. Do not solve or apply the request in this issue.

Estimate: budget generously; the dependant-set enumeration below is the crux of the whole programme and is net-new work the checkpoint never completed. If it exceeds one day, stop and split with a documented boundary rather than shipping a partial enumeration.

Starting reproduction

python -c "from nf_metro.layout.routing.convergences import convergence_corridor_requests"  # ImportError
pytest -q -n 0 tests/test_convergence_corridor_grants.py                                    # ERROR: file not found

Scope

  • convergences.py: derive unique plan/trunk owner identity, axis, source frame, legal domain, controlled landing joins, opening endpoints, continuation starts, feeder ownership endpoints, offsets, and directed runway invariants.
  • Expose ALL FIVE _trunk_segments runs as footprints, not just the central run [0]. At the checkpoint, segments [1] and [3] run from the moving lateral coordinate to the static flank coordinates and segments [2] and [4] are the flank runs; the flank connector segments change geometry on every grant yet were never exposed, which is the recorded stacked-collector failure ("a planned trunk flank was absent from the emitted member"). Name the flank connector point-axes as controlled footprints in the recipe.
  • The enumeration standard: the recipe must name every point main's _move_trunk_axis, _move_trunk_flank, _move_landing_opening, _reseat_landing_opening, and _reseat_landing_cross currently move or re-derive, including the runway (_reseated_runway) as a carried invariant rather than a re-derivation. _move_trunk_axis (on main at src/nf_metro/layout/routing/convergences.py:1636) stays live through this issue and is retired by Apply convergence grants mechanically and complete Seed 77 #1754; do not touch it here.
  • corridor_cohort_integration.py: validate/serialize the recipe records and expose their footprints to the witness compiler.
  • test_convergence_corridor_grants.py (new file): contract and completeness tests.

Reuse guidance

The checkpoint's CorridorScalarControlledPoint, CorridorScalarDirectedRunway, CorridorScalarControlRecipe, request recipe, grant recipe, and coordinate_delta fields are shape-only prototypes: at the checkpoint no production producer ever set control_recipe, so the recipe branch was dead and coordinate_delta measured against the requested coordinate rather than a persisted owner frame. Complete the record rather than blessing that state. The live checkpoint request exposes only a synthetic two-point central run while _move_trunk_axis moves hidden dependants; treat _move_trunk_axis(... preserve_lane_offsets=True) as negative evidence only.

Start at _convergence_corridor_target, _convergence_corridor_preference, _convergence_corridor_region, convergence_corridor_requests, build_corridor_footprint_witnesses, and _validate_control_recipe. Re-establish test_adapter_exposes_every_planned_trunk_without_replacing_members and test_convergence_refuses_partial_or_extra_grant_sets.

Non-goals

  • No scalar solver call, cohort component integration, grant application, or route mutation.
  • Do not use point_to_polyline_distance or tolerance-based ownership.

Code expected to become obsolete

None in this issue; the setters the recipes will displace are deleted by #1754 when grants take over.

Acceptance

  • Establish the complete eligible plan population before extracting recipes; no eligible plan may disappear through a None return.
  • Every PLANNED + owns_geometry mutable trunk is represented exactly once; immutable trunks are explicitly typed.
  • Request exposure includes every footprint later moved by a grant, including all five trunk-segment runs and the flank connector point-axes.
  • Typed plan/member/edge/role fields define identity; no consumer decodes a synthetic string prefix.
  • Every controlled point-axis has exactly one role, including points outside the old proximity tolerance.
  • Duplicate plan owners, incomplete identities, invalid runways, nonfinite coordinates, and missing/extra controlled points fail closed.
  • Explicitly controlled points outside the old proximity tolerance remain controlled; nearby unrelated points do not.
  • Intentional convergence-owned crossings and exit-owned doglegs are distinguished per segment.
  • A recipe can be translated without changing approach direction, runway meaning, or ownership.
  • Opposite-running trunks and members remain direction-qualified and unbundled.

Verification

pytest -q -n 0 tests/test_convergence_corridor_grants.py
ruff check src/nf_metro/layout/routing/convergences.py src/nf_metro/layout/routing/corridor_cohort_integration.py tests/test_convergence_corridor_grants.py
ruff format --check src/nf_metro/layout/routing/convergences.py src/nf_metro/layout/routing/corridor_cohort_integration.py tests/test_convergence_corridor_grants.py
mypy

CI and render expectations

This issue edits convergences.py, which is production routing code, but exposes requests without solving or applying them, so the render diff must still be empty. If a render changes, ownership has leaked into the exposure step; stop. Open the PR as a draft based on the predecessor's branch and never merge it to main alone. Mark work-in-progress commits [skip ci]; push the final commit without a skip marker so CI runs.

#1653 guardrail and stop condition

This issue records semantic ownership only. If complete control requires searching current geometry, changing approach direction, or introducing a convergence-only solve, stop and revise the plan identity.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions