Context
submission-freshness-check.ts's own header comment states the module's contract explicitly: "FAIL CLOSED: an unreachable/failed live-state fetch is treated as stale (aborts), never as 'no evidence of staleness, so proceed'." But the final author-comparison check (packages/loopover-miner/lib/submission-freshness-check.ts:143-148) does the opposite for a referencing PR whose authorLogin is missing/non-string (e.g. GitHub returns user: null for a deleted account):
const minerLoginKey = minerLogin.toLowerCase();
const addressedByAnotherAuthor = referencingPrs.some(
(pr) => typeof pr.authorLogin === "string" && pr.authorLogin.trim().toLowerCase() !== minerLoginKey && (pr.state === "merged" || pr.state === "open"),
);
If pr.authorLogin isn't a string, the typeof === "string" guard short-circuits the predicate to false — a merged/open PR from an author GitHub can't identify is treated as NOT evidence of "already addressed," so the miner proceeds to open a duplicate PR.
Contrast with claim-conflict-resolver.ts's assembleCompetingClaims (packages/loopover-miner/lib/claim-conflict-resolver.ts:60-64), which handles the identical "is this PR someone else's" question for the identical reason but with the opposite, safer bias:
.filter((pr) => typeof pr.authorLogin !== "string" || pr.authorLogin.trim().toLowerCase() !== minerLoginKey)
Here, a missing authorLogin is treated as "can't rule out it's someone else" and is kept as a competing claim — the correct, fail-closed behavior.
Verified empirically (extracted the exact predicate and ran it in Node): with a merged PR whose authorLogin is missing, addressedByAnotherAuthor evaluates to false, so checkSubmissionFreshness returns {fresh: true} and proceeds to open_pr — directly contradicting the module's own documented guarantee.
Failure scenario: an issue is already fixed and merged by a since-deleted GitHub account. checkSubmissionFreshness — the last gate before open_pr — returns {fresh: true} instead of aborting with already_addressed, so the miner opens a duplicate PR on an already-resolved issue.
Requirements
Align submission-freshness-check.ts's predicate with claim-conflict-resolver.ts's already-correct, safer bias for the identical data shape — a PR with a missing/non-string authorLogin (merged or open) should count as evidence the issue may already be addressed by another author, not be silently excluded from consideration.
Deliverables
Test Coverage Requirements
This file is under src/ via the packages/loopover-miner workspace - confirm current coverage.include scoping before assuming the top-level 99% patch gate applies exactly as src/** does; the new branch and its test must both be covered.
Expected Outcome
A referencing PR whose author GitHub can't identify (e.g. a deleted account) is treated as possible evidence the issue is already addressed, matching this module's own documented fail-closed contract, instead of being silently ignored.
Links & Resources
packages/loopover-miner/lib/submission-freshness-check.ts:143-148 (the bug, and the module's own fail-closed contract in its header comment), packages/loopover-miner/lib/claim-conflict-resolver.ts:60-64 (the correct sibling pattern to mirror)
Context
submission-freshness-check.ts's own header comment states the module's contract explicitly: "FAIL CLOSED: an unreachable/failed live-state fetch is treated as stale (aborts), never as 'no evidence of staleness, so proceed'." But the final author-comparison check (packages/loopover-miner/lib/submission-freshness-check.ts:143-148) does the opposite for a referencing PR whoseauthorLoginis missing/non-string (e.g. GitHub returnsuser: nullfor a deleted account):If
pr.authorLoginisn't a string, thetypeof === "string"guard short-circuits the predicate tofalse— a merged/open PR from an author GitHub can't identify is treated as NOT evidence of "already addressed," so the miner proceeds to open a duplicate PR.Contrast with
claim-conflict-resolver.ts'sassembleCompetingClaims(packages/loopover-miner/lib/claim-conflict-resolver.ts:60-64), which handles the identical "is this PR someone else's" question for the identical reason but with the opposite, safer bias:Here, a missing
authorLoginis treated as "can't rule out it's someone else" and is kept as a competing claim — the correct, fail-closed behavior.Verified empirically (extracted the exact predicate and ran it in Node): with a merged PR whose
authorLoginis missing,addressedByAnotherAuthorevaluates tofalse, socheckSubmissionFreshnessreturns{fresh: true}and proceeds toopen_pr— directly contradicting the module's own documented guarantee.Failure scenario: an issue is already fixed and merged by a since-deleted GitHub account.
checkSubmissionFreshness— the last gate beforeopen_pr— returns{fresh: true}instead of aborting withalready_addressed, so the miner opens a duplicate PR on an already-resolved issue.Requirements
Align
submission-freshness-check.ts's predicate withclaim-conflict-resolver.ts's already-correct, safer bias for the identical data shape — a PR with a missing/non-stringauthorLogin(merged or open) should count as evidence the issue may already be addressed by another author, not be silently excluded from consideration.Deliverables
checkSubmissionFreshnessinpackages/loopover-miner/lib/submission-freshness-check.tstreats a referencing merged/open PR with a missing/non-stringauthorLoginas potential evidence of "addressed by another author," matchingclaim-conflict-resolver.ts's existing bias for the same data shape.authorLogin, assertingcheckSubmissionFreshnessno longer silently treats it as fresh/unaddressed.Test Coverage Requirements
This file is under
src/via thepackages/loopover-minerworkspace - confirm currentcoverage.includescoping before assuming the top-level 99% patch gate applies exactly assrc/**does; the new branch and its test must both be covered.Expected Outcome
A referencing PR whose author GitHub can't identify (e.g. a deleted account) is treated as possible evidence the issue is already addressed, matching this module's own documented fail-closed contract, instead of being silently ignored.
Links & Resources
packages/loopover-miner/lib/submission-freshness-check.ts:143-148(the bug, and the module's own fail-closed contract in its header comment),packages/loopover-miner/lib/claim-conflict-resolver.ts:60-64(the correct sibling pattern to mirror)