lastlight-evals 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Multi-round re-review cases (issue #429) — the Node half: the run store a
3
+ * chained case dispatches through, what one round leaves for the next, the
4
+ * artifacts a round is measured on, and the `units` oracle the $0 replay
5
+ * (`scripts/rereview-delta-replay.ts`) and the harness share.
6
+ *
7
+ * ## How round k+1 learns what round k did
8
+ *
9
+ * Exactly as production: through the RUN. `post-review` folds the round's
10
+ * dispositions into the review ledger it was dispatched with
11
+ * (`ctx.prState.reviewLedger`) and writes the result with
12
+ * `store.runs.mergeScratch(workflowId, { reviewLedger, reviewCoverage })`;
13
+ * the next dispatch reads it back through core's `deriveReviewLedger(run,
14
+ * priorState)`. A single-round eval calls `runWorkflow` with no store, so that
15
+ * write is a no-op — a chained case therefore runs every round against the
16
+ * engine's own `InMemoryStateStore` (`lastlight-workflow-engine/test-support`),
17
+ * one workflow id per round, and reads the scratch back off it. Nothing of the
18
+ * fold is re-implemented here.
19
+ *
20
+ * The other three snapshot fields a re-review dispatch resolves from GitHub —
21
+ * `lastBotReview`, `pathsSinceLastBotReview`, `prDiffUnchangedSinceLastReview`
22
+ * — come from the fake's record of what round k posted and from local git, the
23
+ * same reads `resolvePrState` makes against the API.
24
+ */
25
+ import { execFileSync } from "node:child_process";
26
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
27
+ import { tmpdir } from "node:os";
28
+ import { join } from "node:path";
29
+ import { createHash } from "node:crypto";
30
+ import { InMemoryStateStore } from "lastlight-workflow-engine/test-support";
31
+ import { anchorDelta, LINE_HASH_CHARS, locateUnit } from "lastlight-code-facts";
32
+ import { deriveReviewLedger, REVIEW_COVERAGE_SCRATCH_KEY, REVIEW_LEDGER_SCRATCH_KEY } from "lastlight-core/evals";
33
+ import { reviewStateOf } from "./rereview.js";
34
+ function git(cwd, args) {
35
+ return execFileSync("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], maxBuffer: 256 * 1024 * 1024 }).toString();
36
+ }
37
+ // ── the run store ───────────────────────────────────────────────────────────
38
+ /**
39
+ * The store a chained case dispatches every round through. The engine's own
40
+ * in-memory fake, plus `setTraceContext` — the one `StateDb` run method the
41
+ * runner calls outside the engine port (best-effort telemetry bookkeeping).
42
+ */
43
+ export function createRoundStore() {
44
+ const store = new InMemoryStateStore();
45
+ store.runs.setTraceContext = async () => { };
46
+ return store;
47
+ }
48
+ /** A round's run scratch, as the next dispatch reads it. */
49
+ export async function roundScratch(store, workflowId) {
50
+ return ((await store.runs.getRun(workflowId))?.scratch ?? {});
51
+ }
52
+ /** The ledger post-review wrote to a round's scratch, if it wrote one. */
53
+ export function scratchLedger(scratch) {
54
+ return scratch[REVIEW_LEDGER_SCRATCH_KEY];
55
+ }
56
+ /** The coverage record post-review wrote beside it. */
57
+ export function scratchCoverage(scratch) {
58
+ return scratch[REVIEW_COVERAGE_SCRATCH_KEY];
59
+ }
60
+ // ── artifact freshness ─────────────────────────────────────────────────────
61
+ /**
62
+ * The per-PR workspace is reused across rounds (production's semantics), so
63
+ * `.lastlight/pr-review/` still holds the LAST round's files when a round
64
+ * writes none. A round reads an artifact only if it changed during the round:
65
+ * snapshot the mtimes before, compare after.
66
+ */
67
+ export function snapshotMtimes(dir, names) {
68
+ return new Map(names.map((n) => [n, mtimeOf(join(dir, n))]));
69
+ }
70
+ function mtimeOf(path) {
71
+ try {
72
+ return statSync(path).mtimeMs;
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ /** Parsed JSON of `dir/name` when it was (re)written since `before`; else `undefined`. */
79
+ export function readFreshJson(dir, name, before) {
80
+ const now = mtimeOf(join(dir, name));
81
+ if (now === null || now === before.get(name))
82
+ return undefined;
83
+ try {
84
+ return JSON.parse(readFileSync(join(dir, name), "utf8"));
85
+ }
86
+ catch {
87
+ return undefined;
88
+ }
89
+ }
90
+ /** The artifacts a round is measured on. */
91
+ export const ROUND_ARTIFACTS = ["disposition.json", "units.json", "prior-review.json", "review-coverage.json", "findings.json"];
92
+ // ── the next round's snapshot ───────────────────────────────────────────────
93
+ /** Paths changed between two commits (`git diff --name-only a b`); `null` when git cannot say. */
94
+ export function changedPathsBetween(repoDir, from, to) {
95
+ try {
96
+ return git(repoDir, ["diff", "--name-only", from, to]).split("\n").filter(Boolean);
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ }
102
+ /** sha1 of the PR's own three-dot diff at `head` (`base...head`) — the unchanged-diff gate's fingerprint. */
103
+ export function prDiffFingerprint(repoDir, base, head) {
104
+ try {
105
+ return createHash("sha1").update(git(repoDir, ["diff", "--no-color", `${base}...${head}`])).digest("hex");
106
+ }
107
+ catch {
108
+ return null;
109
+ }
110
+ }
111
+ /**
112
+ * The `pr_state` fields round k+1 is dispatched with, from what round k left:
113
+ * the review it posted (the fake's record), the ledger its post-review folded
114
+ * (its run's scratch, read through core's `deriveReviewLedger` exactly as a
115
+ * dispatch reads the prior run), and local git for the two compare reads.
116
+ */
117
+ export function carryForward(input) {
118
+ const posted = input.reviews.at(-1);
119
+ const last = posted
120
+ ? { state: reviewStateOf(posted.event), sha: posted.commitId ?? input.prevHead, body: posted.body ?? null }
121
+ : input.prev.last_bot_review;
122
+ // `deriveReviewLedger(priorRun, priorState)`: the ledger round k FOLDED, else
123
+ // the one it was dispatched with (a round that failed before posting changes
124
+ // nothing). The persisted snapshot only needs the one field.
125
+ const ledger = deriveReviewLedger({ scratch: input.scratch }, (input.prev.review_ledger ? { reviewLedger: input.prev.review_ledger } : null));
126
+ const out = { head_sha: input.nextHead };
127
+ if (last) {
128
+ out.last_bot_review = { state: last.state, sha: last.sha, body: last.body ?? null };
129
+ if (last.sha === input.nextHead) {
130
+ out.bot_review_at_head = { state: last.state, submitted_at: posted?.submittedAt ?? null };
131
+ }
132
+ else {
133
+ const paths = changedPathsBetween(input.repoDir, last.sha, input.nextHead);
134
+ if (paths)
135
+ out.paths_since_last_bot_review = paths;
136
+ const a = prDiffFingerprint(input.repoDir, input.baseCommit, last.sha);
137
+ const b = prDiffFingerprint(input.repoDir, input.baseCommit, input.nextHead);
138
+ if (a !== null && b !== null)
139
+ out.pr_diff_unchanged_since_last_review = a === b;
140
+ }
141
+ }
142
+ if (ledger)
143
+ out.review_ledger = ledger;
144
+ return out;
145
+ }
146
+ // ── thread outdating ────────────────────────────────────────────────────────
147
+ /** A file's text at a commit, or `null`. */
148
+ export function fileAt(repoDir, sha, path) {
149
+ try {
150
+ return git(repoDir, ["show", `${sha}:${path}`]);
151
+ }
152
+ catch {
153
+ return null;
154
+ }
155
+ }
156
+ /**
157
+ * The fake's `isOutdated` for a chained case, best-effort and text-based: a
158
+ * thread raised on an earlier commit is outdated at `head()` when a
159
+ * non-blank line it was anchored on no longer appears in the file there.
160
+ * GitHub's own rule follows the diff hunk, which a fake cannot reproduce;
161
+ * "the code it quoted is gone" is the reading a re-review actually needs.
162
+ */
163
+ export function outdatedResolver(repoDir, head) {
164
+ const cache = new Map();
165
+ const lines = (sha, path) => {
166
+ const key = `${sha}:${path}`;
167
+ if (!cache.has(key))
168
+ cache.set(key, fileAt(repoDir, sha, path)?.split("\n") ?? null);
169
+ return cache.get(key);
170
+ };
171
+ return (a) => {
172
+ const now = head();
173
+ if (!a.commitId || a.commitId === now || a.line === undefined)
174
+ return false;
175
+ const then = lines(a.commitId, a.path);
176
+ if (!then)
177
+ return false;
178
+ const anchored = then.slice((a.start_line ?? a.line) - 1, a.line).map((l) => l.trim()).filter(Boolean);
179
+ if (!anchored.length)
180
+ return false;
181
+ const at = lines(now, a.path);
182
+ if (!at)
183
+ return true;
184
+ const present = new Set(at.map((l) => l.trim()));
185
+ return anchored.some((l) => !present.has(l));
186
+ };
187
+ }
188
+ /**
189
+ * `prior-review.json` from one head's units — what a ledger written at that
190
+ * head would project (`priorReviewOf`): each unit key once, and per file the
191
+ * union of its units' line hashes. The same projection `post-review`'s
192
+ * `readLedgerUnits` makes off `units.json`; kept here so the $0 replay needs no
193
+ * server import.
194
+ */
195
+ export function priorReviewFromUnits(units, head) {
196
+ const keys = new Map();
197
+ const byFile = new Map();
198
+ for (const u of units) {
199
+ if (typeof u.key === "string" && !keys.has(u.key))
200
+ keys.set(u.key, u.contentSha ?? null);
201
+ if (typeof u.file === "string" && typeof u.lineHashes === "string") {
202
+ const set = byFile.get(u.file) ?? byFile.set(u.file, new Set()).get(u.file);
203
+ for (let i = 0; i + LINE_HASH_CHARS <= u.lineHashes.length; i += LINE_HASH_CHARS)
204
+ set.add(u.lineHashes.slice(i, i + LINE_HASH_CHARS));
205
+ }
206
+ }
207
+ return {
208
+ version: 1,
209
+ head,
210
+ units: [...keys].map(([key, contentSha]) => ({ key, contentSha })),
211
+ files: Object.fromEntries([...byFile].map(([f, s]) => [f, [...s].join("")])),
212
+ };
213
+ }
214
+ /**
215
+ * The oracle: run code-facts' `all` then `units [--prior]` over `head`, in a
216
+ * throwaway worktree, exactly as pr-review's `facts` and `units` phases do
217
+ * (merge base, never the base tip). No model is called. `seed` is skipped: an
218
+ * obligation never changes a unit's key, content hash, line hashes or delta.
219
+ */
220
+ export function cutUnits(opts) {
221
+ const dir = opts.outDir ?? mkdtempSync(join(tmpdir(), "rereview-units-"));
222
+ mkdirSync(dir, { recursive: true });
223
+ const wt = mkdtempSync(join(tmpdir(), "rereview-wt-"));
224
+ rmSync(wt, { recursive: true, force: true });
225
+ const timeout = opts.timeoutMs ?? 600_000;
226
+ try {
227
+ git(opts.repoDir, ["worktree", "add", "--quiet", "--detach", wt, opts.head]);
228
+ const mergeBase = git(wt, ["merge-base", opts.base, "HEAD"]).trim();
229
+ execFileSync(opts.factsBin, ["all", "--repo", wt, "--base", mergeBase, "--head", "HEAD", "--out", join(dir, "facts.json"), "--never-fail"], {
230
+ stdio: ["ignore", "ignore", "pipe"],
231
+ timeout,
232
+ maxBuffer: 256 * 1024 * 1024,
233
+ });
234
+ const args = ["units", "--dir", dir, "--repo", wt, "--never-fail"];
235
+ if (opts.prior) {
236
+ writeFileSync(join(dir, "prior-review.json"), `${JSON.stringify(opts.prior)}\n`);
237
+ args.push("--prior", join(dir, "prior-review.json"));
238
+ }
239
+ else {
240
+ rmSync(join(dir, "prior-review.json"), { force: true });
241
+ }
242
+ execFileSync(opts.factsBin, args, { cwd: wt, stdio: ["ignore", "ignore", "pipe"], timeout, maxBuffer: 256 * 1024 * 1024 });
243
+ const doc = JSON.parse(readFileSync(join(dir, "units.json"), "utf8"));
244
+ return {
245
+ units: doc.units ?? [],
246
+ coverage: doc.coverage ?? null,
247
+ degraded: (doc.degraded ?? []).map((d) => `${d.extractor ?? "?"}: ${d.reason ?? "?"}`),
248
+ dir,
249
+ };
250
+ }
251
+ finally {
252
+ try {
253
+ git(opts.repoDir, ["worktree", "remove", "--force", wt]);
254
+ }
255
+ catch {
256
+ rmSync(wt, { recursive: true, force: true });
257
+ try {
258
+ git(opts.repoDir, ["worktree", "prune"]);
259
+ }
260
+ catch {
261
+ /* best-effort */
262
+ }
263
+ }
264
+ }
265
+ }
266
+ /**
267
+ * A chain of oracle cuts over one case's heads, each against the one before
268
+ * — cached per head, so a case with n rounds pays n cuts at most.
269
+ */
270
+ export class UnitsOracle {
271
+ opts;
272
+ cuts = new Map();
273
+ constructor(opts) {
274
+ this.opts = opts;
275
+ }
276
+ /** Units at `heads[i]`, with deltas against `heads[i-1]`'s (none for i = 0). */
277
+ at(heads, i) {
278
+ const head = heads[i];
279
+ const key = `${i}:${head}`;
280
+ const hit = this.cuts.get(key);
281
+ if (hit)
282
+ return hit;
283
+ const prior = i > 0 ? priorReviewFromUnits(this.at(heads, i - 1).units, heads[i - 1]) : null;
284
+ const cut = cutUnits({
285
+ repoDir: this.opts.repoDir,
286
+ base: this.opts.base,
287
+ head,
288
+ prior,
289
+ factsBin: this.opts.factsBin,
290
+ ...(this.opts.root ? { outDir: join(this.opts.root, `round-${i + 1}`) } : {}),
291
+ });
292
+ this.cuts.set(key, cut);
293
+ return cut;
294
+ }
295
+ /** The prior review round `i` is judged against: round i-1's units. */
296
+ priorFor(heads, i) {
297
+ return i > 0 ? priorReviewFromUnits(this.at(heads, i - 1).units, heads[i - 1]) : null;
298
+ }
299
+ }
300
+ /**
301
+ * Judge each comment the way `sites --finalize`'s convergence gate judges a
302
+ * finding: `anchorDelta(prior, path, <anchored lines at head>, <its unit's
303
+ * delta>)`. `unchanged` = every non-trivial anchored line was already in the
304
+ * prior review's lines for that file — a late discovery.
305
+ */
306
+ export function judgeComments(input) {
307
+ const textCache = new Map();
308
+ return input.comments.map((c) => {
309
+ if (c.line === undefined)
310
+ return { ...c, verdict: null, unit: null, anchor: [] };
311
+ if (!textCache.has(c.path))
312
+ textCache.set(c.path, input.fileText(c.path)?.split("\n") ?? null);
313
+ const lines = textCache.get(c.path);
314
+ const anchor = lines ? lines.slice(Math.max(0, (c.start_line ?? c.line) - 1), c.line) : [];
315
+ const unit = locateUnit(input.units, c.path, c.line);
316
+ const verdict = anchorDelta(input.prior, c.path, anchor, unit?.delta);
317
+ return { ...c, verdict, unit: unit ? { ...(unit.key ? { key: unit.key } : {}), ...(unit.delta ? { delta: unit.delta } : {}) } : null, anchor };
318
+ });
319
+ }
320
+ //# sourceMappingURL=rereview-node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rereview-node.js","sourceRoot":"","sources":["../src/rereview-node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,199 @@
1
+ const REAL_SHA = /^[0-9a-f]{40}$/i;
2
+ /**
3
+ * A case's review rounds, validated — or `null` for a case that runs once
4
+ * (no `rounds`, or a single round, which IS the single-round case and must
5
+ * run byte-identically to it). Throws on a malformed declaration: a chained
6
+ * case that silently ran one round would report a re-review it never did.
7
+ */
8
+ export function planRounds(inst) {
9
+ const rounds = inst.rounds;
10
+ if (!rounds || rounds.length <= 1) {
11
+ if (rounds?.length === 1 && inst.pr && rounds[0].head_commit !== inst.pr.head_commit) {
12
+ throw new Error(`${inst.instance_id}: rounds[0].head_commit must equal pr.head_commit (the last round is the scored head)`);
13
+ }
14
+ return null;
15
+ }
16
+ if (!inst.pr)
17
+ throw new Error(`${inst.instance_id}: \`rounds\` is a pr-review field and needs \`pr\``);
18
+ rounds.forEach((r, i) => {
19
+ if (!REAL_SHA.test(r.head_commit ?? "")) {
20
+ throw new Error(`${inst.instance_id}: rounds[${i}].head_commit must be a full 40-hex SHA (got ${JSON.stringify(r.head_commit)})`);
21
+ }
22
+ });
23
+ const last = rounds[rounds.length - 1];
24
+ if (last.head_commit !== inst.pr.head_commit) {
25
+ throw new Error(`${inst.instance_id}: the last round's head_commit (${last.head_commit.slice(0, 12)}) must equal pr.head_commit (${inst.pr.head_commit.slice(0, 12)}) — the last round is the scored head`);
26
+ }
27
+ // A seeded item held for a round the chain never reaches would silently
28
+ // vanish from the scored round's discussion.
29
+ for (const field of ["reviews", "review_comments", "issue_comments"]) {
30
+ (inst.pr[field] ?? []).forEach((item, i) => {
31
+ const r = item.from_round;
32
+ if (r !== undefined && !(Number.isInteger(r) && r >= 1 && r <= rounds.length)) {
33
+ throw new Error(`${inst.instance_id}: pr.${field}[${i}].from_round must be an integer in 1..${rounds.length} (got ${JSON.stringify(r)})`);
34
+ }
35
+ });
36
+ }
37
+ return rounds;
38
+ }
39
+ /** Tier counts and the three #429 reasons, off one round's `disposition.json`. */
40
+ export function dispositionCounts(rows) {
41
+ const tiers = {};
42
+ let converged = 0;
43
+ let alreadyRaised = 0;
44
+ let lateLabelled = 0;
45
+ for (const r of rows) {
46
+ if (r.tier === "inline" || r.tier === "body" || r.tier === "internal")
47
+ tiers[r.tier] = (tiers[r.tier] ?? 0) + 1;
48
+ if (r.reason === "converged")
49
+ converged++;
50
+ if (r.reason === "already-raised")
51
+ alreadyRaised++;
52
+ if (r.finding?.lateDiscovery === true && (r.tier === "inline" || r.tier === "body"))
53
+ lateLabelled++;
54
+ }
55
+ return { tiers, converged, alreadyRaised, lateLabelled };
56
+ }
57
+ /** Units by `delta` — absent when no unit carries one (a first review). */
58
+ export function deltaCounts(units) {
59
+ const out = {};
60
+ let any = false;
61
+ for (const u of units) {
62
+ if (u.delta === "new" || u.delta === "changed" || u.delta === "affected" || u.delta === "unchanged") {
63
+ out[u.delta] = (out[u.delta] ?? 0) + 1;
64
+ any = true;
65
+ }
66
+ }
67
+ return any ? out : undefined;
68
+ }
69
+ /** The ledger's findings by status. */
70
+ export function ledgerCounts(ledger) {
71
+ if (!ledger?.findings)
72
+ return undefined;
73
+ const out = {};
74
+ for (const f of ledger.findings) {
75
+ if (f.status === "open" || f.status === "withheld" || f.status === "addressed" || f.status === "resolved")
76
+ out[f.status] = (out[f.status] ?? 0) + 1;
77
+ }
78
+ return out;
79
+ }
80
+ /**
81
+ * `review-coverage.json` (or post-review's compacted scratch copy of it),
82
+ * compacted again to what a round row shows. `null` for anything that is not
83
+ * a version-1 coverage record.
84
+ */
85
+ export function coverageSummary(raw) {
86
+ if (!raw || typeof raw !== "object")
87
+ return undefined;
88
+ const c = raw;
89
+ if (c.version !== 1)
90
+ return undefined;
91
+ const inScope = (c.inScope ?? {});
92
+ const carried = (c.carried ?? {});
93
+ const num = (v) => (typeof v === "number" ? v : 0);
94
+ const pct = (v) => (typeof v === "number" ? v : null);
95
+ return {
96
+ rereview: c.rereview === true,
97
+ units: num(inScope.units),
98
+ surveyedWeighted: pct(inScope.surveyedWeighted),
99
+ investigatedWeighted: pct(inScope.investigatedWeighted),
100
+ carriedUnits: num(carried.units),
101
+ notInvestigated: Array.isArray(c.notInvestigated) ? c.notInvestigated.length : 0,
102
+ };
103
+ }
104
+ /** The gold indices a grade's trace credits — `null` when the round was not graded. */
105
+ export function goldMatchedOf(trace) {
106
+ if (!trace?.gold)
107
+ return null;
108
+ return trace.gold.flatMap((g, i) => (g.matchedFinding !== null && g.matchedFinding !== undefined ? [i] : []));
109
+ }
110
+ /**
111
+ * Roll a case's rounds up. Late discoveries, convergence and posting are
112
+ * summed over rounds ≥ 2 only — round 1 is a first review and has nothing to
113
+ * be late against. Cumulative recall is the union of every graded round's
114
+ * matched gold, over the case's gold; absent when no round was graded.
115
+ */
116
+ export function rollupRereview(rounds, goldCount) {
117
+ const later = rounds.filter((r) => r.round >= 2);
118
+ const sumOpt = (xs) => xs.some((x) => x !== undefined) ? xs.reduce((a, b) => a + (b ?? 0), 0) : undefined;
119
+ const graded = rounds.filter((r) => r.goldMatched !== undefined);
120
+ const union = new Set(graded.flatMap((r) => r.goldMatched));
121
+ const out = {
122
+ rounds,
123
+ laterInlinePosted: later.reduce((n, r) => n + r.inlinePosted, 0),
124
+ costUsd: rounds.reduce((n, r) => n + r.costUsd, 0),
125
+ };
126
+ const late = sumOpt(later.map((r) => r.lateDiscovery));
127
+ if (late !== undefined) {
128
+ out.lateDiscovery = late;
129
+ out.lateDiscoveryOf = later.reduce((n, r) => n + (r.lateDiscovery !== undefined ? (r.lateDiscoveryOf ?? 0) : 0), 0);
130
+ }
131
+ const conv = sumOpt(later.map((r) => r.converged));
132
+ if (conv !== undefined)
133
+ out.converged = conv;
134
+ const raised = sumOpt(later.map((r) => r.alreadyRaised));
135
+ if (raised !== undefined)
136
+ out.alreadyRaised = raised;
137
+ if (graded.length && goldCount !== undefined) {
138
+ out.cumulativeMatched = union.size;
139
+ out.gold = goldCount;
140
+ out.cumulativeRecall = goldCount > 0 ? union.size / goldCount : 1;
141
+ }
142
+ return out;
143
+ }
144
+ /** Group a tier's results by arm and total their `rereview` blocks; arms with no multi-round case are omitted. */
145
+ export function summarizeRereview(results) {
146
+ const byArm = new Map();
147
+ for (const r of results) {
148
+ const rr = r.rereview;
149
+ if (!rr)
150
+ continue;
151
+ const s = byArm.get(r.model) ??
152
+ byArm
153
+ .set(r.model, {
154
+ model: r.model,
155
+ cases: 0,
156
+ rounds: 0,
157
+ lateDiscovery: null,
158
+ lateDiscoveryOf: 0,
159
+ laterInlinePosted: 0,
160
+ converged: null,
161
+ alreadyRaised: null,
162
+ cumulativeMatched: null,
163
+ gold: 0,
164
+ costUsd: 0,
165
+ })
166
+ .get(r.model);
167
+ s.cases++;
168
+ s.rounds += rr.rounds.length;
169
+ s.laterInlinePosted += rr.laterInlinePosted;
170
+ s.costUsd += rr.costUsd;
171
+ if (rr.lateDiscovery !== undefined) {
172
+ s.lateDiscovery = (s.lateDiscovery ?? 0) + rr.lateDiscovery;
173
+ s.lateDiscoveryOf += rr.lateDiscoveryOf ?? 0;
174
+ }
175
+ if (rr.converged !== undefined)
176
+ s.converged = (s.converged ?? 0) + rr.converged;
177
+ if (rr.alreadyRaised !== undefined)
178
+ s.alreadyRaised = (s.alreadyRaised ?? 0) + rr.alreadyRaised;
179
+ if (rr.cumulativeMatched !== undefined) {
180
+ s.cumulativeMatched = (s.cumulativeMatched ?? 0) + rr.cumulativeMatched;
181
+ s.gold += rr.gold ?? 0;
182
+ }
183
+ }
184
+ return [...byArm.values()];
185
+ }
186
+ /** GitHub's review `state` for a submitted review's `event` — what `lastBotReview.state` carries. */
187
+ export function reviewStateOf(event) {
188
+ switch (event) {
189
+ case "APPROVE":
190
+ return "APPROVED";
191
+ case "REQUEST_CHANGES":
192
+ return "CHANGES_REQUESTED";
193
+ case "COMMENT":
194
+ return "COMMENTED";
195
+ default:
196
+ return "PENDING";
197
+ }
198
+ }
199
+ //# sourceMappingURL=rereview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rereview.js","sourceRoot":"","sources":["../src/rereview.ts"],"names":[],"mappings":"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"}