Skip to content

Commit 17a1ea9

Browse files
authored
chore(miner): migrate batch 4.2 foundational lib modules to TypeScript (#7393)
Convert opportunity-ranker, store-db-adapter, claim-conflict-resolver, harness-submission-trigger, portfolio-queue-manager, pr-disposition-poller, ranked-candidates, and tenant-client from hand-maintained .js + .d.ts to real TypeScript, compiled in place via the package's existing tsc pipeline (#7290 Phase 4, batch 4.2). Public API is preserved exactly and the compiled .js output is behavior-identical; only type annotations, identity row-cast helpers, and tsc formatting differ. Adds tests for the pre-existing branches the migration newly tracks so all eight files reach 100% line + branch + function coverage. Closes #7310
1 parent 7760fc9 commit 17a1ea9

28 files changed

Lines changed: 2634 additions & 981 deletions
Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,73 @@
11
import type { LiveIssueSnapshot } from "./submission-freshness-check.js";
22
import type { ObservedClaim } from "./claim-adjudication.js";
33
import type { LocalWriteActionSpec } from "@loopover/engine";
4-
5-
export function assembleCompetingClaims(
6-
snapshot: LiveIssueSnapshot | null | undefined,
7-
selfPrNumber: number,
8-
minerLogin: string,
9-
): ObservedClaim[];
10-
4+
/**
5+
* Assemble the real competing-claims set from a fetched LiveIssueSnapshot: every OTHER open PR referencing
6+
* the issue, excluding `selfPrNumber` and any PR authored by `minerLogin` itself (case-insensitive, mirrors
7+
* checkSubmissionFreshness's own author comparison -- a login can be echoed back with different casing).
8+
* Excluding same-author PRs is deliberate, not an edge case slipping through: a miner never competes against
9+
* its own work, so if this login somehow has ANOTHER open PR on the same issue (e.g. a retry after a crash
10+
* left a stale one behind), that PR is never treated as a competing claim to lose against -- only a genuinely
11+
* different claimant's PR can trigger a real close.
12+
* Pure given its inputs.
13+
*
14+
* @param {import("./submission-freshness-check.js").LiveIssueSnapshot | null | undefined} snapshot
15+
* @param {number} selfPrNumber
16+
* @param {string} minerLogin
17+
* @returns {import("./claim-adjudication.js").ObservedClaim[]}
18+
*/
19+
export declare function assembleCompetingClaims(snapshot: LiveIssueSnapshot | null | undefined, selfPrNumber: number, minerLogin: string): ObservedClaim[];
1120
export type ClaimConflictInput = {
12-
repoFullName: string;
13-
issueNumber: number;
14-
selfPrNumber: number;
15-
selfClaimedAt: string | null;
16-
minerLogin: string;
21+
repoFullName: string;
22+
issueNumber: number;
23+
selfPrNumber: number;
24+
selfClaimedAt: string | null;
25+
minerLogin: string;
1726
};
18-
1927
export type ClaimConflictDeps = {
20-
fetchLiveIssueSnapshot: (repoFullName: string, issueNumber: number) => Promise<LiveIssueSnapshot | null>;
21-
executeLocalWrite: (spec: LocalWriteActionSpec) => Promise<unknown>;
28+
fetchLiveIssueSnapshot: (repoFullName: string, issueNumber: number) => Promise<LiveIssueSnapshot | null>;
29+
executeLocalWrite: (spec: LocalWriteActionSpec) => Promise<unknown>;
30+
};
31+
export type ClaimConflictResult = {
32+
checked: false;
33+
reason: "live_state_unavailable";
34+
} | {
35+
checked: true;
36+
isWinner: true;
37+
winnerNumber: number | null;
38+
competingCount: number;
39+
} | {
40+
checked: true;
41+
isWinner: false;
42+
winnerNumber: number | null;
43+
competingCount: number;
44+
closeResult: unknown;
2245
};
23-
24-
export type ClaimConflictResult =
25-
| { checked: false; reason: "live_state_unavailable" }
26-
| { checked: true; isWinner: true; winnerNumber: number | null; competingCount: number }
27-
| { checked: true; isWinner: false; winnerNumber: number | null; competingCount: number; closeResult: unknown };
28-
2946
export type ClaimConflictRetryOptions = {
30-
maxAttempts?: number;
31-
sleepFn?: (ms: number) => Promise<unknown>;
32-
backoffMs?: (attempt: number) => number;
47+
maxAttempts?: number;
48+
sleepFn?: (ms: number) => Promise<unknown>;
49+
backoffMs?: (attempt: number) => number;
3350
};
34-
35-
export function resolveClaimConflict(
36-
input: ClaimConflictInput,
37-
deps: ClaimConflictDeps,
38-
options?: ClaimConflictRetryOptions,
39-
): Promise<ClaimConflictResult>;
51+
/**
52+
* Resolve a real claim conflict for an already-submitted PR. Fails OPEN (never closes anything) when the live
53+
* snapshot can't be fetched -- an unavailable check is not evidence of a lost claim.
54+
*
55+
* @param {{ repoFullName: string, issueNumber: number, selfPrNumber: number, selfClaimedAt: string | null, minerLogin: string }} input
56+
* @param {{
57+
* fetchLiveIssueSnapshot: (repoFullName: string, issueNumber: number) => Promise<import("./submission-freshness-check.js").LiveIssueSnapshot | null>,
58+
* executeLocalWrite: (spec: import("@loopover/engine").LocalWriteActionSpec) => Promise<unknown>,
59+
* }} deps
60+
* @param {{ maxAttempts?: number, sleepFn?: (ms: number) => Promise<unknown>, backoffMs?: (attempt: number) => number }} [options]
61+
* Bounded retry for the live-state snapshot fetch (#6058): up to `maxAttempts` (default 3) attempts with
62+
* `backoffMs(attempt)` backoff between them, returning as soon as a competing claim is observed. Pure over
63+
* the injected `sleepFn`/`backoffMs` -- no real timers in tests.
64+
* @returns {Promise<{
65+
* checked: boolean,
66+
* reason?: "live_state_unavailable",
67+
* isWinner?: boolean,
68+
* winnerNumber?: number | null,
69+
* competingCount?: number,
70+
* closeResult?: unknown,
71+
* }>}
72+
*/
73+
export declare function resolveClaimConflict(input: ClaimConflictInput, deps: ClaimConflictDeps, options?: ClaimConflictRetryOptions): Promise<ClaimConflictResult>;

packages/loopover-miner/lib/claim-conflict-resolver.js

Lines changed: 50 additions & 54 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)