Skip to content

deriveEligibilityPlan's eligible boolean is always false when no linked issue was required, contradicting its own publicSummary text #7809

Description

@JSONbored

Context

deriveEligibilityPlan's eligible boolean (src/services/eligibility-plan.ts:115) is wrong whenever no linked-issue multiplier was requested — the common case for any ordinary contribution that doesn't reference a linked issue:

const branchConfirmed = branchEligibilityStatus === "eligible" || branchEligibilityStatus === "not_required";
const eligible = result.linkedIssueMultiplier.eligible && branchConfirmed;

ScorePreviewInput.linkedIssueMode defaults to "none" (packages/loopover-engine/src/scoring/preview.ts:408). For that mode, decideLinkedIssueMultiplier (same file, :975-987) unconditionally returns { status: "not_required", eligible: false }. So branchConfirmed is true, but eligible = false && true = false — always, regardless of whether the branch itself is fine.

This contradicts the field's own doc comment (eligibility-plan.ts:13-18): "branch eligible AND linked issue validated when standard mode is requested." The file's own eligibilityStatusKey helper already special-cases this correctly (line 64: if (linkedIssueStatus === "not_required" && branchEligibilityStatus === "not_required") return "not_required"), producing a correct human-readable publicSummary ("...not required for this contribution type") — but the separate structured eligible: boolean field is never given the same special case, so it silently reads false in the same payload where the text reads "not required."

Verified empirically by extracting the exact logic paths and running them — confirmed eligible === false for the mode="none" case. Coverage gap confirmed: test/unit/eligibility-plan.test.ts:119-123's "no linked issue + non-required branch" test is the one case exercising this path, and — unlike every sibling test in the same describe block — never asserts plan.eligible, only publicSummary/linkedIssueProjection.

Consequences are real: EligibilityPlan (including the raw eligible boolean) is returned directly as structured JSON by the loopover_get_eligibility_plan MCP tool (src/mcp/server.ts:4072-4076), the POST API route (src/api/routes.ts:2412), and embedded in buildLocalBranchAnalysis's payload (src/signals/local-branch.ts:361,403) — any client reading the boolean (rather than parsing the prose) is told an otherwise-clean branch/PR is ineligible.

Requirements

Apply the same special case eligibilityStatusKey already uses to the eligible boolean itself: when linkedIssueStatus === "not_required" and branchEligibilityStatus is "eligible" or "not_required", eligible must be true (not gated on linkedIssueMultiplier.eligible, which is meaningless when no linked issue was required in the first place).

Deliverables

  • deriveEligibilityPlan's eligible boolean in src/services/eligibility-plan.ts matches eligibilityStatusKey's existing semantics for the "linked issue not required" case.
  • test/unit/eligibility-plan.test.ts's "no linked issue + non-required branch" test asserts plan.eligible === true, matching its sibling tests in the same describe block.

Test Coverage Requirements

src/services/** is under the top-level 99% patch coverage gate — the fixed branch and its test assertion must both be covered.

Expected Outcome

loopover_get_eligibility_plan (MCP tool, API route, and embedded local-branch-analysis payload) reports eligible: true for an otherwise-clean contribution that simply didn't reference a linked issue, matching its own publicSummary text instead of contradicting it.

Links & Resources

  • src/services/eligibility-plan.ts:13-18 (doc comment), :64 (eligibilityStatusKey's correct existing special case), :115 (the bug)
  • packages/loopover-engine/src/scoring/preview.ts:408,975-987,1128
  • test/unit/eligibility-plan.test.ts:119-123
  • Consumers: src/mcp/server.ts:4072-4076, src/api/routes.ts:2412, src/signals/local-branch.ts:361,403

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions