Context
packages/loopover-engine/src/signals/predicted-gate-engine.ts defines buildCollisionReport (around line 114), used by the miner's local predicted-gate preview (predicted-gate.ts) to warn about possible duplicate/overlapping work before a PR exists. This function has a canonical twin of the same name in packages/loopover-engine/src/signals/engine.ts (around line 823) — the maintainer-side signal stack the live ORB gate actually runs. Both functions take the same parameters and are otherwise line-for-line identical (confirmed by diffing both full function bodies), except for the risk computation on the issue/linked-PR cluster:
predicted-gate-engine.ts (line 137):
risk: linkedPrs.length > 1 || issue.linkedPrs.length > 1 ? "high" : "medium",
engine.ts, the canonical version (line 847):
risk: linkedPrs.length > 1 ? "high" : "medium",
predicted-gate-engine.ts's version has an extra || issue.linkedPrs.length > 1 clause the canonical engine.ts version does not have. issue.linkedPrs is a separate field from the locally-computed linkedPrs (the PRs that reference issue.number, computed a few lines above from pullRequestsByLinkedIssue) — it is whatever pre-populated/possibly-stale value the caller supplied on the IssueRecord itself. This means the miner's local preview can classify a cluster as "high" risk purely because of a cached/stale issue.linkedPrs count, in a case where the live gate (which only looks at the freshly-computed linkedPrs from the actual open-PR list it was given) would classify the identical cluster as "medium" risk — another break of predicted-gate.ts's documented "the verdict a miner sees pre-submission is therefore the same verdict the gate would compute post-submission" parity contract, this time inflating the miner-facing risk assessment relative to what the live gate would actually report.
Requirements
- In
packages/loopover-engine/src/signals/predicted-gate-engine.ts's buildCollisionReport, remove the || issue.linkedPrs.length > 1 clause from the cluster risk computation so it reads risk: linkedPrs.length > 1 ? "high" : "medium",, matching engine.ts's canonical version exactly.
- Do not change any other part of
buildCollisionReport, and do not modify packages/loopover-engine/src/signals/engine.ts (that file is the canonical, already-correct version this issue is bringing predicted-gate-engine.ts into parity with).
- After this fix, a cluster where exactly one PR (
linkedPrs.length === 1) references the issue, and that issue's own linkedPrs field independently reports more than one, must resolve to "medium" risk, not "high".
Deliverables
Test Coverage Requirements
This repo's Codecov patch gate is 99%+ for src/**/packages/**. The changed branch must be covered by a new or updated test in the suite covering predicted-gate-engine.ts's buildCollisionReport (check test/contract/predicted-gate-engine-collision-parity.test.ts, which already exists specifically to test parity between the two buildCollisionReport implementations, for the pattern to extend).
Expected Outcome
buildCollisionReport's risk classification in the miner-facing predicted-gate preview is byte-identical to the live gate's classification for the same inputs, removing a source of miner-facing risk-assessment inflation that the live gate does not actually apply.
Links & Resources
packages/loopover-engine/src/signals/predicted-gate-engine.ts (buildCollisionReport, ~line 114)
packages/loopover-engine/src/signals/engine.ts (canonical buildCollisionReport, ~line 823)
test/contract/predicted-gate-engine-collision-parity.test.ts (existing parity test suite for this exact pair of functions)
Context
packages/loopover-engine/src/signals/predicted-gate-engine.tsdefinesbuildCollisionReport(around line 114), used by the miner's local predicted-gate preview (predicted-gate.ts) to warn about possible duplicate/overlapping work before a PR exists. This function has a canonical twin of the same name inpackages/loopover-engine/src/signals/engine.ts(around line 823) — the maintainer-side signal stack the live ORB gate actually runs. Both functions take the same parameters and are otherwise line-for-line identical (confirmed by diffing both full function bodies), except for the risk computation on the issue/linked-PR cluster:predicted-gate-engine.ts(line 137):engine.ts, the canonical version (line 847):predicted-gate-engine.ts's version has an extra|| issue.linkedPrs.length > 1clause the canonicalengine.tsversion does not have.issue.linkedPrsis a separate field from the locally-computedlinkedPrs(the PRs that referenceissue.number, computed a few lines above frompullRequestsByLinkedIssue) — it is whatever pre-populated/possibly-stale value the caller supplied on theIssueRecorditself. This means the miner's local preview can classify a cluster as"high"risk purely because of a cached/staleissue.linkedPrscount, in a case where the live gate (which only looks at the freshly-computedlinkedPrsfrom the actual open-PR list it was given) would classify the identical cluster as"medium"risk — another break ofpredicted-gate.ts's documented "the verdict a miner sees pre-submission is therefore the same verdict the gate would compute post-submission" parity contract, this time inflating the miner-facing risk assessment relative to what the live gate would actually report.Requirements
packages/loopover-engine/src/signals/predicted-gate-engine.ts'sbuildCollisionReport, remove the|| issue.linkedPrs.length > 1clause from the clusterriskcomputation so it readsrisk: linkedPrs.length > 1 ? "high" : "medium",, matchingengine.ts's canonical version exactly.buildCollisionReport, and do not modifypackages/loopover-engine/src/signals/engine.ts(that file is the canonical, already-correct version this issue is bringingpredicted-gate-engine.tsinto parity with).linkedPrs.length === 1) references the issue, and that issue's ownlinkedPrsfield independently reports more than one, must resolve to"medium"risk, not"high".Deliverables
buildCollisionReportinpackages/loopover-engine/src/signals/predicted-gate-engine.tsno longer referencesissue.linkedPrs.lengthin its risk computation."medium"risk even when the issue's ownlinkedPrsfield reports more than one.Test Coverage Requirements
This repo's Codecov patch gate is 99%+ for
src/**/packages/**. The changed branch must be covered by a new or updated test in the suite coveringpredicted-gate-engine.ts'sbuildCollisionReport(checktest/contract/predicted-gate-engine-collision-parity.test.ts, which already exists specifically to test parity between the twobuildCollisionReportimplementations, for the pattern to extend).Expected Outcome
buildCollisionReport's risk classification in the miner-facing predicted-gate preview is byte-identical to the live gate's classification for the same inputs, removing a source of miner-facing risk-assessment inflation that the live gate does not actually apply.Links & Resources
packages/loopover-engine/src/signals/predicted-gate-engine.ts(buildCollisionReport, ~line 114)packages/loopover-engine/src/signals/engine.ts(canonicalbuildCollisionReport, ~line 823)test/contract/predicted-gate-engine-collision-parity.test.ts(existing parity test suite for this exact pair of functions)