Context
computeMetadataDupRisk in packages/loopover-engine/src/opportunity-metadata.ts scans a peer-issue list to estimate duplicate risk, and its own self-row exclusion is inconsistent with the same-repo check two lines below it in the same loop body:
- Self-skip guard (
opportunity-metadata.ts:184): peer.issueNumber === issue.issueNumber && peer.repoFullName === issue.repoFullName — exact, case-sensitive string comparison.
- Same-repo guard (
opportunity-metadata.ts:186): peer.repoFullName.trim().toLowerCase() !== issue.repoFullName.trim().toLowerCase() — normalized.
This file already knows repo/login casing isn't guaranteed consistent across API responses — there's a dedicated test ("applies repo-specific goal specs case-insensitively") and sibling modules in this codebase (submission-freshness-check.ts, claim-conflict-resolver.ts) deliberately lowercase logins/repo names for the same documented reason. Line 184 is the one place in this function that didn't get the same treatment.
Requirements
- Normalize the self-skip comparison at
opportunity-metadata.ts:184 to match the same casing/whitespace normalization already used at line 186 (.trim().toLowerCase()), so a peer entry that is the source issue itself — but with differently-cased repoFullName — is correctly excluded rather than counted as a duplicate of itself.
- No other logic in
computeMetadataDupRisk changes — this is a one-line normalization fix, not a rewrite of the dup-risk algorithm.
Deliverables
Test Coverage Requirements
This file is under src/ via the packages/loopover-engine workspace — confirm current coverage.include scoping for this package before assuming the top-level 99% patch gate applies exactly as src/** does; match whatever this package's existing test file already does for its coverage target. The new test must cover the normalized comparison.
Expected Outcome
computeMetadataDupRisk never counts the source issue as a duplicate of itself due to a casing mismatch in repoFullName between the source and its own echoed-back peer entry.
Links & Resources
packages/loopover-engine/src/opportunity-metadata.ts:184 (the bug), :186 (the correct pattern to mirror)
test/unit/opportunity-metadata-signals.test.ts (existing self-skip test to extend)
Context
computeMetadataDupRiskinpackages/loopover-engine/src/opportunity-metadata.tsscans a peer-issue list to estimate duplicate risk, and its own self-row exclusion is inconsistent with the same-repo check two lines below it in the same loop body:opportunity-metadata.ts:184):peer.issueNumber === issue.issueNumber && peer.repoFullName === issue.repoFullName— exact, case-sensitive string comparison.opportunity-metadata.ts:186):peer.repoFullName.trim().toLowerCase() !== issue.repoFullName.trim().toLowerCase()— normalized.This file already knows repo/login casing isn't guaranteed consistent across API responses — there's a dedicated test ("applies repo-specific goal specs case-insensitively") and sibling modules in this codebase (
submission-freshness-check.ts,claim-conflict-resolver.ts) deliberately lowercase logins/repo names for the same documented reason. Line 184 is the one place in this function that didn't get the same treatment.Requirements
opportunity-metadata.ts:184to match the same casing/whitespace normalization already used at line 186 (.trim().toLowerCase()), so a peer entry that is the source issue itself — but with differently-casedrepoFullName— is correctly excluded rather than counted as a duplicate of itself.computeMetadataDupRiskchanges — this is a one-line normalization fix, not a rewrite of the dup-risk algorithm.Deliverables
opportunity-metadata.ts:184's self-skip guard normalized the same way as line 186.test/unit/opportunity-metadata-signals.test.ts(alongside the existing "computeMetadataDupRisk skips the source issue when scanning peers" test) covering a peer list containing the source issue with a differently-casedrepoFullName, assertingdupRiskis unaffected (not inflated).Test Coverage Requirements
This file is under
src/via thepackages/loopover-engineworkspace — confirm currentcoverage.includescoping for this package before assuming the top-level 99% patch gate applies exactly assrc/**does; match whatever this package's existing test file already does for its coverage target. The new test must cover the normalized comparison.Expected Outcome
computeMetadataDupRisknever counts the source issue as a duplicate of itself due to a casing mismatch inrepoFullNamebetween the source and its own echoed-back peer entry.Links & Resources
packages/loopover-engine/src/opportunity-metadata.ts:184(the bug),:186(the correct pattern to mirror)test/unit/opportunity-metadata-signals.test.ts(existing self-skip test to extend)