Skip to content

fix(review): derive linked-issue fact-fetch from the same fresh body parse as the overflow check - #8477

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
cleanjunc:feat/8354-linked-issue-hardrule-fresh-parse
Jul 24, 2026
Merged

fix(review): derive linked-issue fact-fetch from the same fresh body parse as the overflow check#8477
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
cleanjunc:feat/8354-linked-issue-hardrule-fresh-parse

Conversation

@cleanjunc

Copy link
Copy Markdown
Contributor

Closes #8354

Summary

src/review/linked-issue-hard-rules.ts's resolveLinkedIssueHardRule computed the overflow check from a fresh parse of the PR's current body (extractLinkedIssueNumbersWithOverflow(args.body ?? "", …).overflow) but ran its per-issue fact-fetch loop against a separate, caller-supplied args.linkedIssues array — a field populated by an earlier body parse. The two could disagree: if a contributor edits their PR description to add a new closing reference between the last pr.linkedIssues sync and this evaluation, the overflow check (fresh body) passes while the fact-fetch loop (stale list) never sees — and so never evaluates — the newly-added issue against the configured hard rules until a later re-sync. That's a genuine edit-driven detection-bypass window for a module whose whole job is "evaluate every currently-linked issue's facts against the hard rules."

Fix: parse the body once and drive both the overflow check and the fact-fetch loop (and the numbers.length === 0 early-out) from that single result, so they can never disagree about which issues are currently linked.

Direction chosen — the issue's second option: keep the linkedIssues parameter for call-site compatibility but stop reading it, deriving the fetch list from the fresh parse instead. This keeps the change surgical (src/queue/processors.ts's sole call site is untouched); the parameter is documented in-code as retained-but-not-the-source-of-truth so it can't be mistaken for live input.

Regression test: a body linking #9 with a stale linkedIssues: [1] now evaluates #9's facts and blocks on its ineligibility — whereas before the fix it fetched only #1, 404'd, and reported a "could not be found" violation for the wrong issue. This test fails on the old code and passes on the new.

Existing tests that relied on linkedIssues driving the fetch were updated to place the same references in body (their intent is unchanged); all pass.

Closes #8354

Scope

  • The PR title follows type(scope): short summary Conventional Commit format.
  • Focused: one behavior fix in linked-issue-hard-rules.ts plus its unit test; no unrelated backend/UI/MCP/docs/dep changes.
  • Follows CONTRIBUTING.md; does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked a currently open issue this PR resolves — Closes #8354.

Validation

  • git diff --check — clean.
  • npm run actionlint — N/A: no workflow / composite-action changes.
  • npm run typecheck — green.
  • npm run test:coverage locally — test/unit/linked-issue-hard-rules.test.ts (70 tests, incl. the new regression) and the end-to-end test/unit/queue.test.ts + test/unit/agent-approval-queue.test.ts (260 tests) all pass. codecov/patch: the changed lines/branches in linked-issue-hard-rules.ts are 100% covered (verified via lcov — the only uncovered branch in the file is at line 134, pre-existing and outside this diff); both arms of the overflow check and the empty early-out are exercised.
  • npm run test:workers — N/A: no worker code changed.
  • npm run build:mcp / npm run test:mcp-pack — N/A: no MCP changes.
  • npm run ui:openapi:check / npm run ui:lint / npm run ui:typecheck / npm run ui:build — N/A: no UI, API, or OpenAPI surface changed.
  • npm audit --audit-level=moderate — not run locally (sandbox audit endpoint returns a lockfile 400); no dependency changes, so it cannot affect the audit. CI runs it against a clean install.
  • New or changed behavior has unit tests — the regression test plus updated existing coverage.

If any required check was skipped, explain why:

  • Skipped checks are N/A for a focused backend fix with no UI/MCP/API/workflow/dependency changes.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, PATs, private keys, trust scores, private rankings, or maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and implies no compensation or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests — N/A: none changed. (The linked-issue hard rule's own fail-open / not-found / transient-error negative paths remain covered.)
  • API/OpenAPI/MCP behavior is updated and tested where needed — N/A: none changed.
  • UI changes use live API data / real empty/error/loading states — N/A: no UI changes.
  • Public docs/changelogs updated where needed; CHANGELOG.md not edited (not a release-prep PR).

Notes

  • Behavior is unchanged whenever body and linkedIssues already agree (the common case) — the fix only changes the outcome in the divergence window the issue describes, which is exactly what the regression test pins. The full end-to-end queue/processor suites confirm no other behavior shifted.

…parse as the overflow check

`resolveLinkedIssueHardRule` computed the overflow check from a fresh parse of the
PR's current `body` (`extractLinkedIssueNumbersWithOverflow`) but ran its per-issue
fact-fetch loop against a SEPARATE, caller-supplied `args.linkedIssues` array — a
field synced by an earlier body parse. If a contributor edits their PR description
to add a new closing reference between that sync and this evaluation, the overflow
check (fresh body) and the fact-fetch loop (stale list) disagree about which issues
are "currently linked", and the newly-added issue is silently never evaluated
against the configured hard rules until a later re-sync. That is a real
edit-driven detection-bypass window for a module whose whole purpose is "evaluate
every currently-linked issue's facts against the hard rules."

Fix: parse the body once and drive BOTH the overflow check and the fact-fetch loop
(and the empty early-out) from that single `extractLinkedIssueNumbersWithOverflow`
result, so the two can never disagree. Direction chosen (per the issue's second
option): keep the `linkedIssues` parameter for call-site compatibility but stop
reading it — a surgical change that leaves `src/queue/processors.ts` untouched; the
parameter is documented as retained-but-not-the-source-of-truth.

Add a regression test: a body linking JSONbored#9 with a stale `linkedIssues: [1]` now
evaluates JSONbored#9's facts (previously it fetched only JSONbored#1, 404'd, and reported the wrong
issue). Existing tests that relied on `linkedIssues` driving the fetch were updated
to put the same references in `body` (their intent is unchanged); all still pass.

Closes JSONbored#8354
@cleanjunc
cleanjunc requested a review from JSONbored as a code owner July 24, 2026 14:53
@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.60%. Comparing base (c2190cd) to head (4c60f1e).
⚠️ Report is 17 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8477      +/-   ##
==========================================
- Coverage   92.50%   89.60%   -2.90%     
==========================================
  Files         791       98     -693     
  Lines       79328    22764   -56564     
  Branches    23959     3896   -20063     
==========================================
- Hits        73379    20398   -52981     
+ Misses       4810     2187    -2623     
+ Partials     1139      179     -960     
Flag Coverage Δ
shard-1 55.17% <25.00%> (-0.24%) ⬇️
shard-2 13.79% <25.00%> (-35.19%) ⬇️
shard-3 98.27% <100.00%> (+41.60%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/review/linked-issue-hard-rules.ts 98.27% <100.00%> (+0.03%) ⬆️

... and 693 files with indirect coverage changes

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 24, 2026
@loopover-orb

loopover-orb Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-24 15:23:19 UTC

2 files · 1 AI reviewer · no blockers · readiness 93/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This PR fixes a genuine consistency bug: `resolveLinkedIssueHardRule` previously computed its overflow check from a fresh `body` parse but drove the per-issue fact-fetch loop from a separate, potentially stale `args.linkedIssues` array. The fix parses `body` once via `extractLinkedIssueNumbersWithOverflow` and uses that single result for both the overflow check and the fetch list, closing the edit-driven detection-bypass window described in #8354. The regression test at the end of the diff correctly demonstrates the fixed behavior (evaluating #9 from the fresh body instead of the stale `linkedIssues: [1]`), and existing tests were updated consistently to supply matching `body` text. The retained-but-unread `linkedIssues` parameter is clearly documented in-code so future readers won't mistake it for live input.

Nits — 4 non-blocking
  • src/review/linked-issue-hard-rules.ts:196-199 — since `args.linkedIssues` is now provably dead as an input (only kept for call-site compatibility), consider whether the sole call site in src/queue/processors.ts could stop computing/passing it at all, or at least add a short note there pointing back to this comment so a future reader doesn't try to 'fix' the seemingly-unused param.
  • The PR touches only the one call path exercised by tests; worth confirming (not visible in this diff) that no other caller of resolveLinkedIssueHardRule relies on linkedIssues being read — the search here only saw src/queue/processors.ts referenced in the description.
  • Consider a follow-up (or note in this PR) to drop the `linkedIssues` parameter entirely in a later PR once all callers are confirmed not to depend on it, rather than carrying a permanently-unread field.
  • The inline comment block on the parameter and above the parse call is quite long (source: linked-issue-hard-rules.ts:196-199 and :207-212) — could be trimmed to the essential 'why', but this is purely stylistic.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #8354
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 60 registered-repo PR(s), 25 merged, 37 issue(s).
Contributor context ✅ Confirmed Gittensor contributor cleanjunc; Gittensor profile; 60 PR(s), 37 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Addressed
The diff derives both the overflow check and fact-fetch loop from a single fresh parse of args.body, preserves the numbers.length===0 early-out semantics, explicitly documents the chosen direction (retain linkedIssues param but stop reading it, no call-site change needed), and adds a regression test matching the issue's spec.

Review context
  • Author: cleanjunc
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, TypeScript, JavaScript, Scala
  • Official Gittensor activity: 60 PR(s), 37 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Triage stale or unlinked PRs.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit df753da into JSONbored:main Jul 24, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant