Context
packages/loopover-engine/src/predicted-gate.ts's own doc comment states its explicit parity contract: "Parity: it runs the EXACT same engine the maintainer PR pipeline runs ... The verdict a miner sees pre-submission is therefore the same verdict the gate would compute post-submission." predicted-gate.ts calls buildPreflightResult from packages/loopover-engine/src/signals/predicted-gate-engine.ts (the portable, publishable twin used by the miner's local pre-submission preview).
packages/loopover-engine/src/signals/predicted-gate-engine.ts also defines its own hasClearNoIssueRationale (around line 751), which correctly recognizes a docs-only/tests-only/ci-only/refactor-only/"no issue: ..." PR as not needing a linked issue. That function IS used elsewhere in the same file (in buildLaneAdvice's caller context, around line 575), but buildPreflightResult's missing_linked_issue finding (around line 411) does NOT consult it:
if (linkedIssues.length === 0 && lane.lane !== "issue_discovery") {
findings.push({
code: "missing_linked_issue",
...
});
}
Compare this to the canonical, live-gate-used twin of the SAME function in packages/loopover-engine/src/signals/engine.ts (the maintainer-side signal stack the live ORB gate actually runs, imported by src/mcp/server.ts, src/rules/advisory.ts, src/queue/processors.ts, etc.), whose equivalent buildPreflightResult (around line 2588) is:
if (linkedIssues.length === 0 && lane.lane !== "issue_discovery" && !hasClearNoIssueRationale({ title: input.title, body: input.body })) {
findings.push({
code: "missing_linked_issue",
...
});
}
Both functions are named buildPreflightResult, take the same parameters, and are otherwise line-for-line identical in this section apart from this one missing clause (confirmed by diffing the two function bodies — every other shared helper function between engine.ts and predicted-gate-engine.ts is either byte-identical or only stylistically different, except this one and two others filed as separate issues). This means a miner running the local pre-submission preview for a genuinely docs-only/tests-only/no-issue-rationale PR sees a spurious missing_linked_issue warning that the LIVE gate would never raise for the same PR — breaking the documented predicted/live parity contract in the direction of a false negative (miner is warned about something that won't actually be a problem).
Requirements
- In
packages/loopover-engine/src/signals/predicted-gate-engine.ts's buildPreflightResult function, the missing_linked_issue finding's condition must also check !hasClearNoIssueRationale(...), using this file's own local hasClearNoIssueRationale function (already defined in this same file, around line 751) and the same { title: input.title, body: input.body } argument shape the canonical engine.ts version uses — i.e. the condition must become if (linkedIssues.length === 0 && lane.lane !== "issue_discovery" && !hasClearNoIssueRationale({ title: input.title, body: input.body })) { ... }.
- Do not change any other finding in
buildPreflightResult, 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
PreflightInput with linkedIssues: [], a title/body that hasClearNoIssueRationale recognizes (e.g. title: "docs-only: fix typo"), and lane.lane !== "issue_discovery" must NOT produce a missing_linked_issue finding.
Deliverables
Test Coverage Requirements
This repo's Codecov patch gate is 99%+ for src/**/packages/**. The new conditional branch (rationale present → no finding) must be covered by a new or updated test in the test suite covering predicted-gate-engine.ts's buildPreflightResult (check test/unit/predicted-gate-engine-coverage.test.ts, test/unit/predicted-gate-engine-branch-coverage.test.ts, and test/contract/predicted-gate-engine-collision-parity.test.ts for the existing coverage pattern to follow).
Expected Outcome
A miner's local predicted-gate preview no longer raises a missing_linked_issue warning for a PR whose title/body clearly states a no-issue rationale (docs-only, tests-only, ci-only, refactor-only, or an explicit "no issue: ..." statement) — matching the live gate's actual behavior, restoring the documented predicted/live verdict parity for this finding.
Links & Resources
packages/loopover-engine/src/signals/predicted-gate-engine.ts (buildPreflightResult, ~line 354; hasClearNoIssueRationale, ~line 751)
packages/loopover-engine/src/signals/engine.ts (canonical buildPreflightResult, ~line 2537; the hasClearNoIssueRationale call in question, ~line 2588)
packages/loopover-engine/src/predicted-gate.ts (the documented "Parity" contract this fixes a break of)
Context
packages/loopover-engine/src/predicted-gate.ts's own doc comment states its explicit parity contract: "Parity: it runs the EXACT same engine the maintainer PR pipeline runs ... The verdict a miner sees pre-submission is therefore the same verdict the gate would compute post-submission."predicted-gate.tscallsbuildPreflightResultfrompackages/loopover-engine/src/signals/predicted-gate-engine.ts(the portable, publishable twin used by the miner's local pre-submission preview).packages/loopover-engine/src/signals/predicted-gate-engine.tsalso defines its ownhasClearNoIssueRationale(around line 751), which correctly recognizes a docs-only/tests-only/ci-only/refactor-only/"no issue: ..." PR as not needing a linked issue. That function IS used elsewhere in the same file (inbuildLaneAdvice's caller context, around line 575), butbuildPreflightResult'smissing_linked_issuefinding (around line 411) does NOT consult it:Compare this to the canonical, live-gate-used twin of the SAME function in
packages/loopover-engine/src/signals/engine.ts(the maintainer-side signal stack the live ORB gate actually runs, imported bysrc/mcp/server.ts,src/rules/advisory.ts,src/queue/processors.ts, etc.), whose equivalentbuildPreflightResult(around line 2588) is:Both functions are named
buildPreflightResult, take the same parameters, and are otherwise line-for-line identical in this section apart from this one missing clause (confirmed by diffing the two function bodies — every other shared helper function betweenengine.tsandpredicted-gate-engine.tsis either byte-identical or only stylistically different, except this one and two others filed as separate issues). This means a miner running the local pre-submission preview for a genuinely docs-only/tests-only/no-issue-rationale PR sees a spuriousmissing_linked_issuewarning that the LIVE gate would never raise for the same PR — breaking the documented predicted/live parity contract in the direction of a false negative (miner is warned about something that won't actually be a problem).Requirements
packages/loopover-engine/src/signals/predicted-gate-engine.ts'sbuildPreflightResultfunction, themissing_linked_issuefinding's condition must also check!hasClearNoIssueRationale(...), using this file's own localhasClearNoIssueRationalefunction (already defined in this same file, around line 751) and the same{ title: input.title, body: input.body }argument shape the canonicalengine.tsversion uses — i.e. the condition must becomeif (linkedIssues.length === 0 && lane.lane !== "issue_discovery" && !hasClearNoIssueRationale({ title: input.title, body: input.body })) { ... }.buildPreflightResult, 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).PreflightInputwithlinkedIssues: [], a title/body thathasClearNoIssueRationalerecognizes (e.g.title: "docs-only: fix typo"), andlane.lane !== "issue_discovery"must NOT produce amissing_linked_issuefinding.Deliverables
buildPreflightResultinpackages/loopover-engine/src/signals/predicted-gate-engine.tsgains the!hasClearNoIssueRationale(...)exemption on itsmissing_linked_issuefinding, matchingengine.ts's canonical version.missing_linked_issuefinding frombuildPreflightResult.Test Coverage Requirements
This repo's Codecov patch gate is 99%+ for
src/**/packages/**. The new conditional branch (rationale present → no finding) must be covered by a new or updated test in the test suite coveringpredicted-gate-engine.ts'sbuildPreflightResult(checktest/unit/predicted-gate-engine-coverage.test.ts,test/unit/predicted-gate-engine-branch-coverage.test.ts, andtest/contract/predicted-gate-engine-collision-parity.test.tsfor the existing coverage pattern to follow).Expected Outcome
A miner's local predicted-gate preview no longer raises a
missing_linked_issuewarning for a PR whose title/body clearly states a no-issue rationale (docs-only, tests-only, ci-only, refactor-only, or an explicit "no issue: ..." statement) — matching the live gate's actual behavior, restoring the documented predicted/live verdict parity for this finding.Links & Resources
packages/loopover-engine/src/signals/predicted-gate-engine.ts(buildPreflightResult, ~line 354;hasClearNoIssueRationale, ~line 751)packages/loopover-engine/src/signals/engine.ts(canonicalbuildPreflightResult, ~line 2537; thehasClearNoIssueRationalecall in question, ~line 2588)packages/loopover-engine/src/predicted-gate.ts(the documented "Parity" contract this fixes a break of)