Skip to content

Cross-repo pair gate never resolves a DECLARED Pairs-with: when the diff removes no public surface #7397

Closed

Description

@systemorph-com

Core's Cross-repo pair (public surface) gate never resolves a DECLARED Pairs-with: when the diff removes no public type or member. So a dependency-only removal that a satellite depends on (a PackageReference or PackageVersion leaving core) gets no enforced landing order.

Evidence (core main, 2026-10-26): scripts/check-cross-repo-pair.py returns 0 at if not removed: out.append("No public type or member left src/ in this diff — no cross-repo pair to gate."). That return comes before any Pairs-with: parsing. scripts/check-package-pin-removal.py checks only that a Satellite-pins: declaration is present; its docstring says so on purpose ("WHAT IT CANNOT DO"), so it cannot hold the order either.

Where it surfaced: MeshWeaver#7205 (drops YamlDotNet from core) declares Pairs-with: Systemorph/MeshWeaver.Plugins#4227, and its body claimed the pair gate held it red until #4227 merged. The Copilot review (thread 4371264675) pointed out that no gate held it. In practice the PR was kept in DRAFT and readied by a script only after #4227 merged, so nothing broke this time.

Possible fix (triage's call): when the PR body DECLARES Pairs-with:, resolve it even if the surface diff is empty. A declaration is the author asserting a coupling, so the gate should hold the PR to it whatever the detector found. The gate would still not fire for undeclared dependency-only removals; Satellite-pins: covers those by declaration only.

NOT established: whether any past merge actually landed a dependency-only removal before its counterpart because of this gap. I checked only #7205.


Context (triage): reported from Doc/Architecture/CrossRepoPairGate (the page that documents this gate, its cross-repo-pair job in .github/workflows/dotnet-test.yml, and the Pairs-with: declaration forms). Found while landing the YamlDotNet removal, core#7205 paired with Plugins#4227 (merged as 9142c1c99b). Incidental: it did not block that task. The reporter proposes resolving a declared Pairs-with: even when the public-surface detector reports nothing removed — the same "an author who believes they declared something and a gate that believes they did not is indistinguishable from a skip" principle the gate itself already carries.

Origin: https://control.systemorph.com/Feedback/_Submissions/fb-e7f711c6dd753a9af48a2708204d120d

filed by the triage agent on behalf of someone on control.systemorph.com via systemorph-com


Triage routing: filed in Systemorph/MeshWeaver — agent: Systemorph/MeshWeaver — The feedback names scripts/check-cross-repo-pair.py and scripts/check-package-pin-removal.py; the Doc/Architecture/CrossRepoPairGate page documents these as this repository's own gates (cross-repo-pair job in .github/workflows/dotnet-test.yml, beside the scripts under scripts/), and the incident it cites (MeshWeaver#7205 paired with the private Systemorph/MeshWeaver.Plugins#4227) is a core pull request..

Activity

  1. added
    bugSomething isn't working
    sev:MMedium - secondary path broken, or easy workaround
    on Oct 27, 2026
  2. rbuergi commented on Oct 27, 2026

    @rbuergi
    Contributor

    Unique detail from #7384, now closed as a duplicate of this one. It is the same early return, seen on the pin-removal shape: #7179 dropped GUI PackageVersion pins that MeshWeaver.Plugins consumes versionless via Plugins#4202. Nothing held it to that order, because check-cross-repo-pair.py returns at L342-343 (if not removed:) before reading Pairs-with:. check-package-pin-removal.py only checks that every removed id is named under Satellite-pins:. The cost of landing first is NU1010 in the satellite at its next platform move. The suggested fix there is for check-package-pin-removal.py, when it sees removals, to resolve any Pairs-with: with the pair gate's resolver. Both scripts are unchanged at core main 1fa6e093ca.

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

    bugSomething isn't workingsev:MMedium - secondary path broken, or easy workaround

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions