@mmnto/totem 1.16.0 → 1.17.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.
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/recurrence-stats.d.ts +19 -0
- package/dist/recurrence-stats.d.ts.map +1 -1
- package/dist/recurrence-stats.js +49 -0
- package/dist/recurrence-stats.js.map +1 -1
- package/dist/retrospect.d.ts +1022 -0
- package/dist/retrospect.d.ts.map +1 -0
- package/dist/retrospect.js +368 -0
- package/dist/retrospect.js.map +1 -0
- package/dist/retrospect.test.d.ts +2 -0
- package/dist/retrospect.test.d.ts.map +1 -0
- package/dist/retrospect.test.js +572 -0
- package/dist/retrospect.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1022 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrospect schemas + pure helpers for `totem retrospect <pr>`
|
|
3
|
+
* (mmnto-ai/totem#1713).
|
|
4
|
+
*
|
|
5
|
+
* Substrate of the bot-tax cluster — the deterministic circuit-breaker
|
|
6
|
+
* that fires when a PR has accumulated enough bot-review rounds to
|
|
7
|
+
* suggest the loop has stalled. Reuses `recurrence-stats.ts` primitives
|
|
8
|
+
* (`computeSignature`, `normalizeFindingBody`, `toSeverityBucket`) so
|
|
9
|
+
* the bot-tax cluster (#1715 / #1714 / #1713) has a single severity +
|
|
10
|
+
* signature vocabulary.
|
|
11
|
+
*
|
|
12
|
+
* Everything in this file is pure: Zod schemas + deterministic helpers.
|
|
13
|
+
* No I/O, no command logic. No LLM. No GitHub API writes.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
/** A push-grouped review round on the target PR. */
|
|
17
|
+
export declare const RetrospectRoundSchema: z.ZodObject<{
|
|
18
|
+
/** 1-based, monotonically increasing in submission order. */
|
|
19
|
+
roundNumber: z.ZodNumber;
|
|
20
|
+
/** ISO 8601 timestamp of the earliest review submission for this round. */
|
|
21
|
+
submittedAt: z.ZodString;
|
|
22
|
+
/** PR head SHA at review time; absent when the upstream review record lacks `commit_id`. */
|
|
23
|
+
headSha: z.ZodOptional<z.ZodString>;
|
|
24
|
+
/** Number of bot findings tied to this round. */
|
|
25
|
+
findingCount: z.ZodNumber;
|
|
26
|
+
}, "strip", z.ZodTypeAny, {
|
|
27
|
+
roundNumber: number;
|
|
28
|
+
submittedAt: string;
|
|
29
|
+
findingCount: number;
|
|
30
|
+
headSha?: string | undefined;
|
|
31
|
+
}, {
|
|
32
|
+
roundNumber: number;
|
|
33
|
+
submittedAt: string;
|
|
34
|
+
findingCount: number;
|
|
35
|
+
headSha?: string | undefined;
|
|
36
|
+
}>;
|
|
37
|
+
export type RetrospectRound = z.infer<typeof RetrospectRoundSchema>;
|
|
38
|
+
/**
|
|
39
|
+
* Classification verdict for a single bot finding.
|
|
40
|
+
*
|
|
41
|
+
* - `route-out` — finding is better tracked as a follow-up issue than blocking the current PR.
|
|
42
|
+
* - `in-pr-fix` — finding should be addressed before merge.
|
|
43
|
+
* - `undetermined` — no heuristic signal fired; contributor judgment.
|
|
44
|
+
*/
|
|
45
|
+
export declare const RetrospectClassificationSchema: z.ZodEnum<["route-out", "in-pr-fix", "undetermined"]>;
|
|
46
|
+
export type RetrospectClassification = z.infer<typeof RetrospectClassificationSchema>;
|
|
47
|
+
/**
|
|
48
|
+
* Closed catalog of `route-out` reasons. The Zod-side mirror of
|
|
49
|
+
* `RETROSPECT_ROUTE_OUT_REASONS` (defined later in the file). Used by the
|
|
50
|
+
* discriminated `RetrospectFindingSchema` to enforce the deterministic
|
|
51
|
+
* contract: every `route-out` finding carries a reason from this enum, and
|
|
52
|
+
* non-route-out findings forbid the field entirely. Per CR mmnto-ai/totem#1734
|
|
53
|
+
* round-2.
|
|
54
|
+
*/
|
|
55
|
+
export declare const RetrospectRouteOutReasonSchema: z.ZodEnum<["covered by existing compiled rule", "rule-covered class flagged late — retroactive shouldn’t block ship", "frequent across other PRs — file follow-up to compile into a rule", "low/nit severity flagged late in the bot-review loop"]>;
|
|
56
|
+
/**
|
|
57
|
+
* Discriminated union on `classification`: `route-out` requires a reason from
|
|
58
|
+
* the closed catalog; `in-pr-fix` and `undetermined` forbid the field entirely.
|
|
59
|
+
* Per CR mmnto-ai/totem#1734 round-2 — the prior `routeOutReason: z.string().optional()`
|
|
60
|
+
* leaked the deterministic contract.
|
|
61
|
+
*/
|
|
62
|
+
export declare const RetrospectFindingSchema: z.ZodDiscriminatedUnion<"classification", [z.ZodObject<{
|
|
63
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
64
|
+
signature: z.ZodString;
|
|
65
|
+
/** Source bot/tool. */
|
|
66
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
67
|
+
/** Normalized severity bucket. */
|
|
68
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
69
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
70
|
+
bodyExcerpt: z.ZodString;
|
|
71
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
72
|
+
file: z.ZodString;
|
|
73
|
+
/** Best-effort line number. */
|
|
74
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
75
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
76
|
+
roundNumber: z.ZodNumber;
|
|
77
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
78
|
+
crossPrRecurrence: z.ZodNumber;
|
|
79
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
80
|
+
coveredByRule: z.ZodBoolean;
|
|
81
|
+
} & {
|
|
82
|
+
classification: z.ZodLiteral<"route-out">;
|
|
83
|
+
/** Reason from the closed catalog (`RETROSPECT_ROUTE_OUT_REASONS`). */
|
|
84
|
+
routeOutReason: z.ZodEnum<["covered by existing compiled rule", "rule-covered class flagged late — retroactive shouldn’t block ship", "frequent across other PRs — file follow-up to compile into a rule", "low/nit severity flagged late in the bot-review loop"]>;
|
|
85
|
+
}, "strip", z.ZodTypeAny, {
|
|
86
|
+
file: string;
|
|
87
|
+
signature: string;
|
|
88
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
89
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
90
|
+
coveredByRule: boolean;
|
|
91
|
+
roundNumber: number;
|
|
92
|
+
bodyExcerpt: string;
|
|
93
|
+
crossPrRecurrence: number;
|
|
94
|
+
classification: "route-out";
|
|
95
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
96
|
+
line?: number | undefined;
|
|
97
|
+
}, {
|
|
98
|
+
file: string;
|
|
99
|
+
signature: string;
|
|
100
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
101
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
102
|
+
coveredByRule: boolean;
|
|
103
|
+
roundNumber: number;
|
|
104
|
+
bodyExcerpt: string;
|
|
105
|
+
crossPrRecurrence: number;
|
|
106
|
+
classification: "route-out";
|
|
107
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
108
|
+
line?: number | undefined;
|
|
109
|
+
}>, z.ZodObject<{
|
|
110
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
111
|
+
signature: z.ZodString;
|
|
112
|
+
/** Source bot/tool. */
|
|
113
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
114
|
+
/** Normalized severity bucket. */
|
|
115
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
116
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
117
|
+
bodyExcerpt: z.ZodString;
|
|
118
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
119
|
+
file: z.ZodString;
|
|
120
|
+
/** Best-effort line number. */
|
|
121
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
122
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
123
|
+
roundNumber: z.ZodNumber;
|
|
124
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
125
|
+
crossPrRecurrence: z.ZodNumber;
|
|
126
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
127
|
+
coveredByRule: z.ZodBoolean;
|
|
128
|
+
} & {
|
|
129
|
+
classification: z.ZodLiteral<"in-pr-fix">;
|
|
130
|
+
}, "strict", z.ZodTypeAny, {
|
|
131
|
+
file: string;
|
|
132
|
+
signature: string;
|
|
133
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
134
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
135
|
+
coveredByRule: boolean;
|
|
136
|
+
roundNumber: number;
|
|
137
|
+
bodyExcerpt: string;
|
|
138
|
+
crossPrRecurrence: number;
|
|
139
|
+
classification: "in-pr-fix";
|
|
140
|
+
line?: number | undefined;
|
|
141
|
+
}, {
|
|
142
|
+
file: string;
|
|
143
|
+
signature: string;
|
|
144
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
145
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
146
|
+
coveredByRule: boolean;
|
|
147
|
+
roundNumber: number;
|
|
148
|
+
bodyExcerpt: string;
|
|
149
|
+
crossPrRecurrence: number;
|
|
150
|
+
classification: "in-pr-fix";
|
|
151
|
+
line?: number | undefined;
|
|
152
|
+
}>, z.ZodObject<{
|
|
153
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
154
|
+
signature: z.ZodString;
|
|
155
|
+
/** Source bot/tool. */
|
|
156
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
157
|
+
/** Normalized severity bucket. */
|
|
158
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
159
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
160
|
+
bodyExcerpt: z.ZodString;
|
|
161
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
162
|
+
file: z.ZodString;
|
|
163
|
+
/** Best-effort line number. */
|
|
164
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
165
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
166
|
+
roundNumber: z.ZodNumber;
|
|
167
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
168
|
+
crossPrRecurrence: z.ZodNumber;
|
|
169
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
170
|
+
coveredByRule: z.ZodBoolean;
|
|
171
|
+
} & {
|
|
172
|
+
classification: z.ZodLiteral<"undetermined">;
|
|
173
|
+
}, "strict", z.ZodTypeAny, {
|
|
174
|
+
file: string;
|
|
175
|
+
signature: string;
|
|
176
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
177
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
178
|
+
coveredByRule: boolean;
|
|
179
|
+
roundNumber: number;
|
|
180
|
+
bodyExcerpt: string;
|
|
181
|
+
crossPrRecurrence: number;
|
|
182
|
+
classification: "undetermined";
|
|
183
|
+
line?: number | undefined;
|
|
184
|
+
}, {
|
|
185
|
+
file: string;
|
|
186
|
+
signature: string;
|
|
187
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
188
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
189
|
+
coveredByRule: boolean;
|
|
190
|
+
roundNumber: number;
|
|
191
|
+
bodyExcerpt: string;
|
|
192
|
+
crossPrRecurrence: number;
|
|
193
|
+
classification: "undetermined";
|
|
194
|
+
line?: number | undefined;
|
|
195
|
+
}>]>;
|
|
196
|
+
export type RetrospectFinding = z.infer<typeof RetrospectFindingSchema>;
|
|
197
|
+
/** Top-level shape emitted by `runRetrospect` and optionally written via `--out`. */
|
|
198
|
+
export declare const RetrospectReportSchema: z.ZodObject<{
|
|
199
|
+
/** Schema version for forward-compat. */
|
|
200
|
+
version: z.ZodLiteral<1>;
|
|
201
|
+
/** Target PR number (string for parity with recurrence-stats prsScanned). */
|
|
202
|
+
prNumber: z.ZodString;
|
|
203
|
+
/** Open / closed / merged at fetch time. */
|
|
204
|
+
prState: z.ZodString;
|
|
205
|
+
/** ISO 8601 generation timestamp. */
|
|
206
|
+
generatedAt: z.ZodString;
|
|
207
|
+
/** Resolved threshold (after option clamping). */
|
|
208
|
+
threshold: z.ZodNumber;
|
|
209
|
+
/** True iff `.totem/recurrence-stats.json` was loaded successfully. */
|
|
210
|
+
substrateAvailable: z.ZodBoolean;
|
|
211
|
+
/** True iff `compiled-rules.json` was loaded successfully. */
|
|
212
|
+
compiledRulesAvailable: z.ZodBoolean;
|
|
213
|
+
/** Push-grouped rounds (ordered by earliest submittedAt per head_sha). */
|
|
214
|
+
rounds: z.ZodArray<z.ZodObject<{
|
|
215
|
+
/** 1-based, monotonically increasing in submission order. */
|
|
216
|
+
roundNumber: z.ZodNumber;
|
|
217
|
+
/** ISO 8601 timestamp of the earliest review submission for this round. */
|
|
218
|
+
submittedAt: z.ZodString;
|
|
219
|
+
/** PR head SHA at review time; absent when the upstream review record lacks `commit_id`. */
|
|
220
|
+
headSha: z.ZodOptional<z.ZodString>;
|
|
221
|
+
/** Number of bot findings tied to this round. */
|
|
222
|
+
findingCount: z.ZodNumber;
|
|
223
|
+
}, "strip", z.ZodTypeAny, {
|
|
224
|
+
roundNumber: number;
|
|
225
|
+
submittedAt: string;
|
|
226
|
+
findingCount: number;
|
|
227
|
+
headSha?: string | undefined;
|
|
228
|
+
}, {
|
|
229
|
+
roundNumber: number;
|
|
230
|
+
submittedAt: string;
|
|
231
|
+
findingCount: number;
|
|
232
|
+
headSha?: string | undefined;
|
|
233
|
+
}>, "many">;
|
|
234
|
+
/** Total bot findings (inline + review-body). */
|
|
235
|
+
totalFindings: z.ZodNumber;
|
|
236
|
+
/** `1 - uniqueSignatures/totalFindings`, clamped to [0,1]; 0 when totalFindings == 0. */
|
|
237
|
+
dedupRate: z.ZodNumber;
|
|
238
|
+
/** Distribution counts. */
|
|
239
|
+
findingDistribution: z.ZodObject<{
|
|
240
|
+
byTool: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
241
|
+
bySeverity: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
242
|
+
byClassification: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
243
|
+
}, "strip", z.ZodTypeAny, {
|
|
244
|
+
byTool: Record<string, number>;
|
|
245
|
+
bySeverity: Record<string, number>;
|
|
246
|
+
byClassification: Record<string, number>;
|
|
247
|
+
}, {
|
|
248
|
+
byTool: Record<string, number>;
|
|
249
|
+
bySeverity: Record<string, number>;
|
|
250
|
+
byClassification: Record<string, number>;
|
|
251
|
+
}>;
|
|
252
|
+
/** Findings classified as `route-out`. */
|
|
253
|
+
routeOutCandidates: z.ZodArray<z.ZodDiscriminatedUnion<"classification", [z.ZodObject<{
|
|
254
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
255
|
+
signature: z.ZodString;
|
|
256
|
+
/** Source bot/tool. */
|
|
257
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
258
|
+
/** Normalized severity bucket. */
|
|
259
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
260
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
261
|
+
bodyExcerpt: z.ZodString;
|
|
262
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
263
|
+
file: z.ZodString;
|
|
264
|
+
/** Best-effort line number. */
|
|
265
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
266
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
267
|
+
roundNumber: z.ZodNumber;
|
|
268
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
269
|
+
crossPrRecurrence: z.ZodNumber;
|
|
270
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
271
|
+
coveredByRule: z.ZodBoolean;
|
|
272
|
+
} & {
|
|
273
|
+
classification: z.ZodLiteral<"route-out">;
|
|
274
|
+
/** Reason from the closed catalog (`RETROSPECT_ROUTE_OUT_REASONS`). */
|
|
275
|
+
routeOutReason: z.ZodEnum<["covered by existing compiled rule", "rule-covered class flagged late — retroactive shouldn’t block ship", "frequent across other PRs — file follow-up to compile into a rule", "low/nit severity flagged late in the bot-review loop"]>;
|
|
276
|
+
}, "strip", z.ZodTypeAny, {
|
|
277
|
+
file: string;
|
|
278
|
+
signature: string;
|
|
279
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
280
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
281
|
+
coveredByRule: boolean;
|
|
282
|
+
roundNumber: number;
|
|
283
|
+
bodyExcerpt: string;
|
|
284
|
+
crossPrRecurrence: number;
|
|
285
|
+
classification: "route-out";
|
|
286
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
287
|
+
line?: number | undefined;
|
|
288
|
+
}, {
|
|
289
|
+
file: string;
|
|
290
|
+
signature: string;
|
|
291
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
292
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
293
|
+
coveredByRule: boolean;
|
|
294
|
+
roundNumber: number;
|
|
295
|
+
bodyExcerpt: string;
|
|
296
|
+
crossPrRecurrence: number;
|
|
297
|
+
classification: "route-out";
|
|
298
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
299
|
+
line?: number | undefined;
|
|
300
|
+
}>, z.ZodObject<{
|
|
301
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
302
|
+
signature: z.ZodString;
|
|
303
|
+
/** Source bot/tool. */
|
|
304
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
305
|
+
/** Normalized severity bucket. */
|
|
306
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
307
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
308
|
+
bodyExcerpt: z.ZodString;
|
|
309
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
310
|
+
file: z.ZodString;
|
|
311
|
+
/** Best-effort line number. */
|
|
312
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
313
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
314
|
+
roundNumber: z.ZodNumber;
|
|
315
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
316
|
+
crossPrRecurrence: z.ZodNumber;
|
|
317
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
318
|
+
coveredByRule: z.ZodBoolean;
|
|
319
|
+
} & {
|
|
320
|
+
classification: z.ZodLiteral<"in-pr-fix">;
|
|
321
|
+
}, "strict", z.ZodTypeAny, {
|
|
322
|
+
file: string;
|
|
323
|
+
signature: string;
|
|
324
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
325
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
326
|
+
coveredByRule: boolean;
|
|
327
|
+
roundNumber: number;
|
|
328
|
+
bodyExcerpt: string;
|
|
329
|
+
crossPrRecurrence: number;
|
|
330
|
+
classification: "in-pr-fix";
|
|
331
|
+
line?: number | undefined;
|
|
332
|
+
}, {
|
|
333
|
+
file: string;
|
|
334
|
+
signature: string;
|
|
335
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
336
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
337
|
+
coveredByRule: boolean;
|
|
338
|
+
roundNumber: number;
|
|
339
|
+
bodyExcerpt: string;
|
|
340
|
+
crossPrRecurrence: number;
|
|
341
|
+
classification: "in-pr-fix";
|
|
342
|
+
line?: number | undefined;
|
|
343
|
+
}>, z.ZodObject<{
|
|
344
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
345
|
+
signature: z.ZodString;
|
|
346
|
+
/** Source bot/tool. */
|
|
347
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
348
|
+
/** Normalized severity bucket. */
|
|
349
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
350
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
351
|
+
bodyExcerpt: z.ZodString;
|
|
352
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
353
|
+
file: z.ZodString;
|
|
354
|
+
/** Best-effort line number. */
|
|
355
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
356
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
357
|
+
roundNumber: z.ZodNumber;
|
|
358
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
359
|
+
crossPrRecurrence: z.ZodNumber;
|
|
360
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
361
|
+
coveredByRule: z.ZodBoolean;
|
|
362
|
+
} & {
|
|
363
|
+
classification: z.ZodLiteral<"undetermined">;
|
|
364
|
+
}, "strict", z.ZodTypeAny, {
|
|
365
|
+
file: string;
|
|
366
|
+
signature: string;
|
|
367
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
368
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
369
|
+
coveredByRule: boolean;
|
|
370
|
+
roundNumber: number;
|
|
371
|
+
bodyExcerpt: string;
|
|
372
|
+
crossPrRecurrence: number;
|
|
373
|
+
classification: "undetermined";
|
|
374
|
+
line?: number | undefined;
|
|
375
|
+
}, {
|
|
376
|
+
file: string;
|
|
377
|
+
signature: string;
|
|
378
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
379
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
380
|
+
coveredByRule: boolean;
|
|
381
|
+
roundNumber: number;
|
|
382
|
+
bodyExcerpt: string;
|
|
383
|
+
crossPrRecurrence: number;
|
|
384
|
+
classification: "undetermined";
|
|
385
|
+
line?: number | undefined;
|
|
386
|
+
}>]>, "many">;
|
|
387
|
+
/** Findings classified as `in-pr-fix`. */
|
|
388
|
+
inPrFixes: z.ZodArray<z.ZodDiscriminatedUnion<"classification", [z.ZodObject<{
|
|
389
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
390
|
+
signature: z.ZodString;
|
|
391
|
+
/** Source bot/tool. */
|
|
392
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
393
|
+
/** Normalized severity bucket. */
|
|
394
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
395
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
396
|
+
bodyExcerpt: z.ZodString;
|
|
397
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
398
|
+
file: z.ZodString;
|
|
399
|
+
/** Best-effort line number. */
|
|
400
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
401
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
402
|
+
roundNumber: z.ZodNumber;
|
|
403
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
404
|
+
crossPrRecurrence: z.ZodNumber;
|
|
405
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
406
|
+
coveredByRule: z.ZodBoolean;
|
|
407
|
+
} & {
|
|
408
|
+
classification: z.ZodLiteral<"route-out">;
|
|
409
|
+
/** Reason from the closed catalog (`RETROSPECT_ROUTE_OUT_REASONS`). */
|
|
410
|
+
routeOutReason: z.ZodEnum<["covered by existing compiled rule", "rule-covered class flagged late — retroactive shouldn’t block ship", "frequent across other PRs — file follow-up to compile into a rule", "low/nit severity flagged late in the bot-review loop"]>;
|
|
411
|
+
}, "strip", z.ZodTypeAny, {
|
|
412
|
+
file: string;
|
|
413
|
+
signature: string;
|
|
414
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
415
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
416
|
+
coveredByRule: boolean;
|
|
417
|
+
roundNumber: number;
|
|
418
|
+
bodyExcerpt: string;
|
|
419
|
+
crossPrRecurrence: number;
|
|
420
|
+
classification: "route-out";
|
|
421
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
422
|
+
line?: number | undefined;
|
|
423
|
+
}, {
|
|
424
|
+
file: string;
|
|
425
|
+
signature: string;
|
|
426
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
427
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
428
|
+
coveredByRule: boolean;
|
|
429
|
+
roundNumber: number;
|
|
430
|
+
bodyExcerpt: string;
|
|
431
|
+
crossPrRecurrence: number;
|
|
432
|
+
classification: "route-out";
|
|
433
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
434
|
+
line?: number | undefined;
|
|
435
|
+
}>, z.ZodObject<{
|
|
436
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
437
|
+
signature: z.ZodString;
|
|
438
|
+
/** Source bot/tool. */
|
|
439
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
440
|
+
/** Normalized severity bucket. */
|
|
441
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
442
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
443
|
+
bodyExcerpt: z.ZodString;
|
|
444
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
445
|
+
file: z.ZodString;
|
|
446
|
+
/** Best-effort line number. */
|
|
447
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
448
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
449
|
+
roundNumber: z.ZodNumber;
|
|
450
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
451
|
+
crossPrRecurrence: z.ZodNumber;
|
|
452
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
453
|
+
coveredByRule: z.ZodBoolean;
|
|
454
|
+
} & {
|
|
455
|
+
classification: z.ZodLiteral<"in-pr-fix">;
|
|
456
|
+
}, "strict", z.ZodTypeAny, {
|
|
457
|
+
file: string;
|
|
458
|
+
signature: string;
|
|
459
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
460
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
461
|
+
coveredByRule: boolean;
|
|
462
|
+
roundNumber: number;
|
|
463
|
+
bodyExcerpt: string;
|
|
464
|
+
crossPrRecurrence: number;
|
|
465
|
+
classification: "in-pr-fix";
|
|
466
|
+
line?: number | undefined;
|
|
467
|
+
}, {
|
|
468
|
+
file: string;
|
|
469
|
+
signature: string;
|
|
470
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
471
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
472
|
+
coveredByRule: boolean;
|
|
473
|
+
roundNumber: number;
|
|
474
|
+
bodyExcerpt: string;
|
|
475
|
+
crossPrRecurrence: number;
|
|
476
|
+
classification: "in-pr-fix";
|
|
477
|
+
line?: number | undefined;
|
|
478
|
+
}>, z.ZodObject<{
|
|
479
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
480
|
+
signature: z.ZodString;
|
|
481
|
+
/** Source bot/tool. */
|
|
482
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
483
|
+
/** Normalized severity bucket. */
|
|
484
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
485
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
486
|
+
bodyExcerpt: z.ZodString;
|
|
487
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
488
|
+
file: z.ZodString;
|
|
489
|
+
/** Best-effort line number. */
|
|
490
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
491
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
492
|
+
roundNumber: z.ZodNumber;
|
|
493
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
494
|
+
crossPrRecurrence: z.ZodNumber;
|
|
495
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
496
|
+
coveredByRule: z.ZodBoolean;
|
|
497
|
+
} & {
|
|
498
|
+
classification: z.ZodLiteral<"undetermined">;
|
|
499
|
+
}, "strict", z.ZodTypeAny, {
|
|
500
|
+
file: string;
|
|
501
|
+
signature: string;
|
|
502
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
503
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
504
|
+
coveredByRule: boolean;
|
|
505
|
+
roundNumber: number;
|
|
506
|
+
bodyExcerpt: string;
|
|
507
|
+
crossPrRecurrence: number;
|
|
508
|
+
classification: "undetermined";
|
|
509
|
+
line?: number | undefined;
|
|
510
|
+
}, {
|
|
511
|
+
file: string;
|
|
512
|
+
signature: string;
|
|
513
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
514
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
515
|
+
coveredByRule: boolean;
|
|
516
|
+
roundNumber: number;
|
|
517
|
+
bodyExcerpt: string;
|
|
518
|
+
crossPrRecurrence: number;
|
|
519
|
+
classification: "undetermined";
|
|
520
|
+
line?: number | undefined;
|
|
521
|
+
}>]>, "many">;
|
|
522
|
+
/** Findings classified as `undetermined`. */
|
|
523
|
+
undetermined: z.ZodArray<z.ZodDiscriminatedUnion<"classification", [z.ZodObject<{
|
|
524
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
525
|
+
signature: z.ZodString;
|
|
526
|
+
/** Source bot/tool. */
|
|
527
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
528
|
+
/** Normalized severity bucket. */
|
|
529
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
530
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
531
|
+
bodyExcerpt: z.ZodString;
|
|
532
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
533
|
+
file: z.ZodString;
|
|
534
|
+
/** Best-effort line number. */
|
|
535
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
536
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
537
|
+
roundNumber: z.ZodNumber;
|
|
538
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
539
|
+
crossPrRecurrence: z.ZodNumber;
|
|
540
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
541
|
+
coveredByRule: z.ZodBoolean;
|
|
542
|
+
} & {
|
|
543
|
+
classification: z.ZodLiteral<"route-out">;
|
|
544
|
+
/** Reason from the closed catalog (`RETROSPECT_ROUTE_OUT_REASONS`). */
|
|
545
|
+
routeOutReason: z.ZodEnum<["covered by existing compiled rule", "rule-covered class flagged late — retroactive shouldn’t block ship", "frequent across other PRs — file follow-up to compile into a rule", "low/nit severity flagged late in the bot-review loop"]>;
|
|
546
|
+
}, "strip", z.ZodTypeAny, {
|
|
547
|
+
file: string;
|
|
548
|
+
signature: string;
|
|
549
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
550
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
551
|
+
coveredByRule: boolean;
|
|
552
|
+
roundNumber: number;
|
|
553
|
+
bodyExcerpt: string;
|
|
554
|
+
crossPrRecurrence: number;
|
|
555
|
+
classification: "route-out";
|
|
556
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
557
|
+
line?: number | undefined;
|
|
558
|
+
}, {
|
|
559
|
+
file: string;
|
|
560
|
+
signature: string;
|
|
561
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
562
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
563
|
+
coveredByRule: boolean;
|
|
564
|
+
roundNumber: number;
|
|
565
|
+
bodyExcerpt: string;
|
|
566
|
+
crossPrRecurrence: number;
|
|
567
|
+
classification: "route-out";
|
|
568
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
569
|
+
line?: number | undefined;
|
|
570
|
+
}>, z.ZodObject<{
|
|
571
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
572
|
+
signature: z.ZodString;
|
|
573
|
+
/** Source bot/tool. */
|
|
574
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
575
|
+
/** Normalized severity bucket. */
|
|
576
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
577
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
578
|
+
bodyExcerpt: z.ZodString;
|
|
579
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
580
|
+
file: z.ZodString;
|
|
581
|
+
/** Best-effort line number. */
|
|
582
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
583
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
584
|
+
roundNumber: z.ZodNumber;
|
|
585
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
586
|
+
crossPrRecurrence: z.ZodNumber;
|
|
587
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
588
|
+
coveredByRule: z.ZodBoolean;
|
|
589
|
+
} & {
|
|
590
|
+
classification: z.ZodLiteral<"in-pr-fix">;
|
|
591
|
+
}, "strict", z.ZodTypeAny, {
|
|
592
|
+
file: string;
|
|
593
|
+
signature: string;
|
|
594
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
595
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
596
|
+
coveredByRule: boolean;
|
|
597
|
+
roundNumber: number;
|
|
598
|
+
bodyExcerpt: string;
|
|
599
|
+
crossPrRecurrence: number;
|
|
600
|
+
classification: "in-pr-fix";
|
|
601
|
+
line?: number | undefined;
|
|
602
|
+
}, {
|
|
603
|
+
file: string;
|
|
604
|
+
signature: string;
|
|
605
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
606
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
607
|
+
coveredByRule: boolean;
|
|
608
|
+
roundNumber: number;
|
|
609
|
+
bodyExcerpt: string;
|
|
610
|
+
crossPrRecurrence: number;
|
|
611
|
+
classification: "in-pr-fix";
|
|
612
|
+
line?: number | undefined;
|
|
613
|
+
}>, z.ZodObject<{
|
|
614
|
+
/** Stable signature hash (16-char) — matches the recurrence-stats vocabulary. */
|
|
615
|
+
signature: z.ZodString;
|
|
616
|
+
/** Source bot/tool. */
|
|
617
|
+
tool: z.ZodEnum<["coderabbit", "gca", "sarif", "override", "unknown"]>;
|
|
618
|
+
/** Normalized severity bucket. */
|
|
619
|
+
severityBucket: z.ZodEnum<["critical", "high", "medium", "low", "nit"]>;
|
|
620
|
+
/** First 280 chars of the raw body (for human triage). */
|
|
621
|
+
bodyExcerpt: z.ZodString;
|
|
622
|
+
/** File path attached to the finding (`(review body)` for CR outside-diff/nits). */
|
|
623
|
+
file: z.ZodString;
|
|
624
|
+
/** Best-effort line number. */
|
|
625
|
+
line: z.ZodOptional<z.ZodNumber>;
|
|
626
|
+
/** Round number assigned by `groupFindingsByRound`. */
|
|
627
|
+
roundNumber: z.ZodNumber;
|
|
628
|
+
/** Count of OTHER PRs sharing this signature (target PR excluded). */
|
|
629
|
+
crossPrRecurrence: z.ZodNumber;
|
|
630
|
+
/** True if the signature heuristically maps to an existing compiled rule (Jaccard ≥ 0.6). */
|
|
631
|
+
coveredByRule: z.ZodBoolean;
|
|
632
|
+
} & {
|
|
633
|
+
classification: z.ZodLiteral<"undetermined">;
|
|
634
|
+
}, "strict", z.ZodTypeAny, {
|
|
635
|
+
file: string;
|
|
636
|
+
signature: string;
|
|
637
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
638
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
639
|
+
coveredByRule: boolean;
|
|
640
|
+
roundNumber: number;
|
|
641
|
+
bodyExcerpt: string;
|
|
642
|
+
crossPrRecurrence: number;
|
|
643
|
+
classification: "undetermined";
|
|
644
|
+
line?: number | undefined;
|
|
645
|
+
}, {
|
|
646
|
+
file: string;
|
|
647
|
+
signature: string;
|
|
648
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
649
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
650
|
+
coveredByRule: boolean;
|
|
651
|
+
roundNumber: number;
|
|
652
|
+
bodyExcerpt: string;
|
|
653
|
+
crossPrRecurrence: number;
|
|
654
|
+
classification: "undetermined";
|
|
655
|
+
line?: number | undefined;
|
|
656
|
+
}>]>, "many">;
|
|
657
|
+
/** Deterministic stop-condition templates (no prose generation). */
|
|
658
|
+
stopConditions: z.ZodArray<z.ZodString, "many">;
|
|
659
|
+
/** Trap-ledger override events read for this PR (read-only count). */
|
|
660
|
+
overrideEventsObserved: z.ZodNumber;
|
|
661
|
+
}, "strip", z.ZodTypeAny, {
|
|
662
|
+
version: 1;
|
|
663
|
+
undetermined: ({
|
|
664
|
+
file: string;
|
|
665
|
+
signature: string;
|
|
666
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
667
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
668
|
+
coveredByRule: boolean;
|
|
669
|
+
roundNumber: number;
|
|
670
|
+
bodyExcerpt: string;
|
|
671
|
+
crossPrRecurrence: number;
|
|
672
|
+
classification: "route-out";
|
|
673
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
674
|
+
line?: number | undefined;
|
|
675
|
+
} | {
|
|
676
|
+
file: string;
|
|
677
|
+
signature: string;
|
|
678
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
679
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
680
|
+
coveredByRule: boolean;
|
|
681
|
+
roundNumber: number;
|
|
682
|
+
bodyExcerpt: string;
|
|
683
|
+
crossPrRecurrence: number;
|
|
684
|
+
classification: "in-pr-fix";
|
|
685
|
+
line?: number | undefined;
|
|
686
|
+
} | {
|
|
687
|
+
file: string;
|
|
688
|
+
signature: string;
|
|
689
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
690
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
691
|
+
coveredByRule: boolean;
|
|
692
|
+
roundNumber: number;
|
|
693
|
+
bodyExcerpt: string;
|
|
694
|
+
crossPrRecurrence: number;
|
|
695
|
+
classification: "undetermined";
|
|
696
|
+
line?: number | undefined;
|
|
697
|
+
})[];
|
|
698
|
+
prNumber: string;
|
|
699
|
+
prState: string;
|
|
700
|
+
generatedAt: string;
|
|
701
|
+
threshold: number;
|
|
702
|
+
substrateAvailable: boolean;
|
|
703
|
+
compiledRulesAvailable: boolean;
|
|
704
|
+
rounds: {
|
|
705
|
+
roundNumber: number;
|
|
706
|
+
submittedAt: string;
|
|
707
|
+
findingCount: number;
|
|
708
|
+
headSha?: string | undefined;
|
|
709
|
+
}[];
|
|
710
|
+
totalFindings: number;
|
|
711
|
+
dedupRate: number;
|
|
712
|
+
findingDistribution: {
|
|
713
|
+
byTool: Record<string, number>;
|
|
714
|
+
bySeverity: Record<string, number>;
|
|
715
|
+
byClassification: Record<string, number>;
|
|
716
|
+
};
|
|
717
|
+
routeOutCandidates: ({
|
|
718
|
+
file: string;
|
|
719
|
+
signature: string;
|
|
720
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
721
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
722
|
+
coveredByRule: boolean;
|
|
723
|
+
roundNumber: number;
|
|
724
|
+
bodyExcerpt: string;
|
|
725
|
+
crossPrRecurrence: number;
|
|
726
|
+
classification: "route-out";
|
|
727
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
728
|
+
line?: number | undefined;
|
|
729
|
+
} | {
|
|
730
|
+
file: string;
|
|
731
|
+
signature: string;
|
|
732
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
733
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
734
|
+
coveredByRule: boolean;
|
|
735
|
+
roundNumber: number;
|
|
736
|
+
bodyExcerpt: string;
|
|
737
|
+
crossPrRecurrence: number;
|
|
738
|
+
classification: "in-pr-fix";
|
|
739
|
+
line?: number | undefined;
|
|
740
|
+
} | {
|
|
741
|
+
file: string;
|
|
742
|
+
signature: string;
|
|
743
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
744
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
745
|
+
coveredByRule: boolean;
|
|
746
|
+
roundNumber: number;
|
|
747
|
+
bodyExcerpt: string;
|
|
748
|
+
crossPrRecurrence: number;
|
|
749
|
+
classification: "undetermined";
|
|
750
|
+
line?: number | undefined;
|
|
751
|
+
})[];
|
|
752
|
+
inPrFixes: ({
|
|
753
|
+
file: string;
|
|
754
|
+
signature: string;
|
|
755
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
756
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
757
|
+
coveredByRule: boolean;
|
|
758
|
+
roundNumber: number;
|
|
759
|
+
bodyExcerpt: string;
|
|
760
|
+
crossPrRecurrence: number;
|
|
761
|
+
classification: "route-out";
|
|
762
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
763
|
+
line?: number | undefined;
|
|
764
|
+
} | {
|
|
765
|
+
file: string;
|
|
766
|
+
signature: string;
|
|
767
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
768
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
769
|
+
coveredByRule: boolean;
|
|
770
|
+
roundNumber: number;
|
|
771
|
+
bodyExcerpt: string;
|
|
772
|
+
crossPrRecurrence: number;
|
|
773
|
+
classification: "in-pr-fix";
|
|
774
|
+
line?: number | undefined;
|
|
775
|
+
} | {
|
|
776
|
+
file: string;
|
|
777
|
+
signature: string;
|
|
778
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
779
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
780
|
+
coveredByRule: boolean;
|
|
781
|
+
roundNumber: number;
|
|
782
|
+
bodyExcerpt: string;
|
|
783
|
+
crossPrRecurrence: number;
|
|
784
|
+
classification: "undetermined";
|
|
785
|
+
line?: number | undefined;
|
|
786
|
+
})[];
|
|
787
|
+
stopConditions: string[];
|
|
788
|
+
overrideEventsObserved: number;
|
|
789
|
+
}, {
|
|
790
|
+
version: 1;
|
|
791
|
+
undetermined: ({
|
|
792
|
+
file: string;
|
|
793
|
+
signature: string;
|
|
794
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
795
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
796
|
+
coveredByRule: boolean;
|
|
797
|
+
roundNumber: number;
|
|
798
|
+
bodyExcerpt: string;
|
|
799
|
+
crossPrRecurrence: number;
|
|
800
|
+
classification: "route-out";
|
|
801
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
802
|
+
line?: number | undefined;
|
|
803
|
+
} | {
|
|
804
|
+
file: string;
|
|
805
|
+
signature: string;
|
|
806
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
807
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
808
|
+
coveredByRule: boolean;
|
|
809
|
+
roundNumber: number;
|
|
810
|
+
bodyExcerpt: string;
|
|
811
|
+
crossPrRecurrence: number;
|
|
812
|
+
classification: "in-pr-fix";
|
|
813
|
+
line?: number | undefined;
|
|
814
|
+
} | {
|
|
815
|
+
file: string;
|
|
816
|
+
signature: string;
|
|
817
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
818
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
819
|
+
coveredByRule: boolean;
|
|
820
|
+
roundNumber: number;
|
|
821
|
+
bodyExcerpt: string;
|
|
822
|
+
crossPrRecurrence: number;
|
|
823
|
+
classification: "undetermined";
|
|
824
|
+
line?: number | undefined;
|
|
825
|
+
})[];
|
|
826
|
+
prNumber: string;
|
|
827
|
+
prState: string;
|
|
828
|
+
generatedAt: string;
|
|
829
|
+
threshold: number;
|
|
830
|
+
substrateAvailable: boolean;
|
|
831
|
+
compiledRulesAvailable: boolean;
|
|
832
|
+
rounds: {
|
|
833
|
+
roundNumber: number;
|
|
834
|
+
submittedAt: string;
|
|
835
|
+
findingCount: number;
|
|
836
|
+
headSha?: string | undefined;
|
|
837
|
+
}[];
|
|
838
|
+
totalFindings: number;
|
|
839
|
+
dedupRate: number;
|
|
840
|
+
findingDistribution: {
|
|
841
|
+
byTool: Record<string, number>;
|
|
842
|
+
bySeverity: Record<string, number>;
|
|
843
|
+
byClassification: Record<string, number>;
|
|
844
|
+
};
|
|
845
|
+
routeOutCandidates: ({
|
|
846
|
+
file: string;
|
|
847
|
+
signature: string;
|
|
848
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
849
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
850
|
+
coveredByRule: boolean;
|
|
851
|
+
roundNumber: number;
|
|
852
|
+
bodyExcerpt: string;
|
|
853
|
+
crossPrRecurrence: number;
|
|
854
|
+
classification: "route-out";
|
|
855
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
856
|
+
line?: number | undefined;
|
|
857
|
+
} | {
|
|
858
|
+
file: string;
|
|
859
|
+
signature: string;
|
|
860
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
861
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
862
|
+
coveredByRule: boolean;
|
|
863
|
+
roundNumber: number;
|
|
864
|
+
bodyExcerpt: string;
|
|
865
|
+
crossPrRecurrence: number;
|
|
866
|
+
classification: "in-pr-fix";
|
|
867
|
+
line?: number | undefined;
|
|
868
|
+
} | {
|
|
869
|
+
file: string;
|
|
870
|
+
signature: string;
|
|
871
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
872
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
873
|
+
coveredByRule: boolean;
|
|
874
|
+
roundNumber: number;
|
|
875
|
+
bodyExcerpt: string;
|
|
876
|
+
crossPrRecurrence: number;
|
|
877
|
+
classification: "undetermined";
|
|
878
|
+
line?: number | undefined;
|
|
879
|
+
})[];
|
|
880
|
+
inPrFixes: ({
|
|
881
|
+
file: string;
|
|
882
|
+
signature: string;
|
|
883
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
884
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
885
|
+
coveredByRule: boolean;
|
|
886
|
+
roundNumber: number;
|
|
887
|
+
bodyExcerpt: string;
|
|
888
|
+
crossPrRecurrence: number;
|
|
889
|
+
classification: "route-out";
|
|
890
|
+
routeOutReason: "covered by existing compiled rule" | "rule-covered class flagged late — retroactive shouldn’t block ship" | "frequent across other PRs — file follow-up to compile into a rule" | "low/nit severity flagged late in the bot-review loop";
|
|
891
|
+
line?: number | undefined;
|
|
892
|
+
} | {
|
|
893
|
+
file: string;
|
|
894
|
+
signature: string;
|
|
895
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
896
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
897
|
+
coveredByRule: boolean;
|
|
898
|
+
roundNumber: number;
|
|
899
|
+
bodyExcerpt: string;
|
|
900
|
+
crossPrRecurrence: number;
|
|
901
|
+
classification: "in-pr-fix";
|
|
902
|
+
line?: number | undefined;
|
|
903
|
+
} | {
|
|
904
|
+
file: string;
|
|
905
|
+
signature: string;
|
|
906
|
+
tool: "unknown" | "override" | "coderabbit" | "gca" | "sarif";
|
|
907
|
+
severityBucket: "critical" | "high" | "medium" | "low" | "nit";
|
|
908
|
+
coveredByRule: boolean;
|
|
909
|
+
roundNumber: number;
|
|
910
|
+
bodyExcerpt: string;
|
|
911
|
+
crossPrRecurrence: number;
|
|
912
|
+
classification: "undetermined";
|
|
913
|
+
line?: number | undefined;
|
|
914
|
+
})[];
|
|
915
|
+
stopConditions: string[];
|
|
916
|
+
overrideEventsObserved: number;
|
|
917
|
+
}>;
|
|
918
|
+
export type RetrospectReport = z.infer<typeof RetrospectReportSchema>;
|
|
919
|
+
/** Minimal review-submission shape (subset of GitHub's `pulls/N/reviews`). */
|
|
920
|
+
export interface RetrospectReviewSubmission {
|
|
921
|
+
id: number;
|
|
922
|
+
/** PR head SHA at review submission time; may be absent for some review states. */
|
|
923
|
+
commit_id?: string | null;
|
|
924
|
+
/** ISO 8601 timestamp. */
|
|
925
|
+
submitted_at?: string | null;
|
|
926
|
+
/** Bot login. */
|
|
927
|
+
user_login: string;
|
|
928
|
+
}
|
|
929
|
+
/** Minimal review-comment shape (subset of `StandardReviewComment`). */
|
|
930
|
+
export interface RetrospectReviewComment {
|
|
931
|
+
id: number;
|
|
932
|
+
author: string;
|
|
933
|
+
createdAt?: string;
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Group bot review submissions by `commit_id` (head SHA).
|
|
937
|
+
*
|
|
938
|
+
* - Two reviews on the same `commit_id` → same round.
|
|
939
|
+
* - Reviews missing `commit_id` are bucketed into a single synthetic
|
|
940
|
+
* round (head SHA `undefined`) so they don't double-count as N rounds.
|
|
941
|
+
* - Round ordering is by EARLIEST `submitted_at` within each SHA bucket.
|
|
942
|
+
* - Round numbers are 1-based.
|
|
943
|
+
*
|
|
944
|
+
* `findingCount` requires `groupFindingsByRound` to receive the corresponding
|
|
945
|
+
* inline-comment list keyed by SHA via `findingShaBySubmissionId`. The mapping
|
|
946
|
+
* is computed by the caller because `pulls/N/comments` and `pulls/N/reviews`
|
|
947
|
+
* are separate GH endpoints and the join is push-based, not in-memory native.
|
|
948
|
+
*
|
|
949
|
+
* To keep the helper pure, this function returns the round index ONLY.
|
|
950
|
+
* Callers walk findings + assign each to a round by submission timestamp.
|
|
951
|
+
*/
|
|
952
|
+
export declare function groupFindingsByRound(reviewSubmissions: ReadonlyArray<RetrospectReviewSubmission>, findingsPerRoundCount: ReadonlyMap<string, number>): RetrospectRound[];
|
|
953
|
+
/**
|
|
954
|
+
* Coarse round-position bucket. The exact thresholds are a v0.1 heuristic
|
|
955
|
+
* documented in `.totem/specs/1713.md` — early ≤ 3, mid 4-9, late ≥ 10.
|
|
956
|
+
*/
|
|
957
|
+
export type RetrospectRoundPosition = 'early' | 'mid' | 'late';
|
|
958
|
+
export declare function toRoundPosition(roundNumber: number): RetrospectRoundPosition;
|
|
959
|
+
/** Coarse cross-PR recurrence bucket. */
|
|
960
|
+
export type RetrospectCrossPrBucket = 'none' | 'some' | 'frequent';
|
|
961
|
+
export declare function toCrossPrBucket(crossPrRecurrence: number): RetrospectCrossPrBucket;
|
|
962
|
+
/**
|
|
963
|
+
* Fixed catalog of route-out reasons. Keep deterministic — every reason
|
|
964
|
+
* a classifier emits MUST come from this catalog so the report doesn't
|
|
965
|
+
* accumulate a long-tail of one-off prose strings.
|
|
966
|
+
*/
|
|
967
|
+
export declare const RETROSPECT_ROUTE_OUT_REASONS: {
|
|
968
|
+
readonly COVERED_BY_RULE: "covered by existing compiled rule";
|
|
969
|
+
readonly RULE_COVERED_LATE: "rule-covered class flagged late — retroactive shouldn’t block ship";
|
|
970
|
+
readonly FREQUENT_CROSS_PR: "frequent across other PRs — file follow-up to compile into a rule";
|
|
971
|
+
readonly LOW_NIT_LATE: "low/nit severity flagged late in the bot-review loop";
|
|
972
|
+
};
|
|
973
|
+
export type RetrospectRouteOutReason = (typeof RETROSPECT_ROUTE_OUT_REASONS)[keyof typeof RETROSPECT_ROUTE_OUT_REASONS];
|
|
974
|
+
/** Input to the deterministic classifier. */
|
|
975
|
+
export interface ClassifyFindingInput {
|
|
976
|
+
severityBucket: 'critical' | 'high' | 'medium' | 'low' | 'nit';
|
|
977
|
+
roundNumber: number;
|
|
978
|
+
crossPrRecurrence: number;
|
|
979
|
+
coveredByRule: boolean;
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* Deterministic, table-driven classifier. Same inputs → same outputs across
|
|
983
|
+
* invocations. Reason strings are drawn exclusively from
|
|
984
|
+
* `RETROSPECT_ROUTE_OUT_REASONS` so consumers can treat them as a closed set.
|
|
985
|
+
*
|
|
986
|
+
* Heuristic intent (v0.1):
|
|
987
|
+
* - `critical` or `high` at any round → `in-pr-fix` (regardless of recurrence/coverage)
|
|
988
|
+
* - `low`/`nit` late + (`coveredByRule` OR `crossPrRecurrence frequent`) → `route-out`
|
|
989
|
+
* - `medium` late + `coveredByRule` → `route-out`
|
|
990
|
+
* - `medium` early/mid → `in-pr-fix`
|
|
991
|
+
* - `nit` early/mid → `in-pr-fix`
|
|
992
|
+
* - else → `undetermined`
|
|
993
|
+
*/
|
|
994
|
+
export declare function classifyFinding(input: ClassifyFindingInput): {
|
|
995
|
+
classification: RetrospectClassification;
|
|
996
|
+
routeOutReason?: RetrospectRouteOutReason;
|
|
997
|
+
};
|
|
998
|
+
/**
|
|
999
|
+
* Deterministic stop-condition templates keyed off the report shape. No
|
|
1000
|
+
* prose generation; only integer substitution. Returns the catalog
|
|
1001
|
+
* filtered to entries whose triggering condition fires for the given
|
|
1002
|
+
* report.
|
|
1003
|
+
*/
|
|
1004
|
+
export declare function buildStopConditions(report: Pick<RetrospectReport, 'rounds' | 'routeOutCandidates' | 'inPrFixes' | 'undetermined' | 'dedupRate' | 'findingDistribution'>): string[];
|
|
1005
|
+
/**
|
|
1006
|
+
* Compute `1 - uniqueSignatures / totalFindings`, clamped to [0, 1].
|
|
1007
|
+
*
|
|
1008
|
+
* - 0 findings → 0 (no findings, no dedup pressure).
|
|
1009
|
+
* - All unique → 0.
|
|
1010
|
+
* - All duplicates of one signature → close to 1 (`1 - 1/N`).
|
|
1011
|
+
*/
|
|
1012
|
+
export declare function computeDedupRate(findings: ReadonlyArray<{
|
|
1013
|
+
signature: string;
|
|
1014
|
+
}>): number;
|
|
1015
|
+
/**
|
|
1016
|
+
* Compute a stable signature for a finding body using the
|
|
1017
|
+
* recurrence-stats normalization pipeline. Re-exported here so callers
|
|
1018
|
+
* outside the cli package don't need to call `normalizeFindingBody +
|
|
1019
|
+
* computeSignature` separately.
|
|
1020
|
+
*/
|
|
1021
|
+
export declare function signatureOfBody(body: string): string;
|
|
1022
|
+
//# sourceMappingURL=retrospect.d.ts.map
|