Skip to content

fix(review): resolveLinkedIssueHardRule's overflow check and per-issue fact-fetch read from two different sources that can disagree #8354

Description

@JSONbored

Context

src/review/linked-issue-hard-rules.ts's resolveLinkedIssueHardRule (lines ~190-231) orchestrates the linked-issue hard-rule decision. Line 205 computes:

if (extractLinkedIssueNumbersWithOverflow(args.body ?? "", args.repoFullName).overflow) { ... }

— a fresh, authoritative re-parse of the PR's current body, used only for its .overflow boolean (the "too many linked issues to verify safely" check). The freshly-parsed .numbers result is discarded. The function then runs its real per-issue fact-fetch loop (line 214, args.linkedIssues.map(...)) against a separate, caller-supplied args.linkedIssues array instead.

The one production call site (src/queue/processors.ts, ~line 2985-2995) passes body: pr.body, linkedIssues: pr.linkedIssues — both read off the same pr DB row, but pr.linkedIssues is itself a field populated by an earlier parse of the body at some prior sync point, not necessarily a live parse of the exact pr.body value fed into extractLinkedIssueNumbersWithOverflow moments earlier in the same function call. If a contributor edits their PR description to add a new linked-issue reference between the last pr.linkedIssues sync and this evaluation, the overflow check (reading the fresh body) may still pass, but the fact-fetch loop — which never sees the newly-added reference because it trusts the stale args.linkedIssues — silently never evaluates that issue against the configured hard rules until a later pass re-syncs pr.linkedIssues. This is a genuine detection-bypass window: the module's whole purpose is "evaluate every currently-linked issue's facts against the hard rules," and a body edit can currently outrun that evaluation.

Requirements

  • resolveLinkedIssueHardRule must derive the set of issue numbers it fetches facts for from the same extractLinkedIssueNumbersWithOverflow(args.body ?? "", args.repoFullName) call already made for the overflow check (using its .numbers result), rather than trusting the separately-supplied args.linkedIssues parameter — so the overflow check and the fact-fetch loop can never disagree about which issues are "currently linked."
  • Preserve the existing args.linkedIssues.length === 0 → return undefined early-out semantics (line 211) — source the emptiness check from the same fresh parse instead of the separate parameter.
  • Either remove the now-redundant linkedIssues parameter from resolveLinkedIssueHardRule's signature entirely (updating the one call site in src/queue/processors.ts to stop passing it), or keep the parameter for call-site compatibility but stop using it for the fact-fetch loop, deriving from the fresh parse instead. Pick exactly one direction and state which was chosen in the PR description.
  • Every existing test covering resolveLinkedIssueHardRule must keep passing.

Deliverables

  • resolveLinkedIssueHardRule sources its per-issue fetch list from the same body-derived parse used for the overflow check.
  • src/queue/processors.ts's call site updated to match the new/simplified signature if the parameter was removed.
  • New regression test: given a body whose fresh parse yields an issue number that is NOT present in a separately-supplied stale linkedIssues array, assert the hard-rule evaluation now still evaluates that issue (previously it would have silently been skipped).

Test Coverage Requirements

99%+ Codecov patch coverage, branch-counted, on every changed line/branch in linked-issue-hard-rules.ts and any call-site changes in src/queue/processors.ts, per codecov.yml.

Expected Outcome

The linked-issue hard-rule evaluator can no longer disagree with itself about which issues are currently linked to a PR — the overflow check and the per-issue fact evaluation are always computed from the identical, fresh body parse, closing the edit-driven detection-bypass window described above.

Links & Resources

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