@mmnto/cli 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/adapters/github-cli-pr.d.ts +13 -1
- package/dist/adapters/github-cli-pr.d.ts.map +1 -1
- package/dist/adapters/github-cli-pr.js +60 -2
- package/dist/adapters/github-cli-pr.js.map +1 -1
- package/dist/adapters/github-cli-pr.test.js +67 -0
- package/dist/adapters/github-cli-pr.test.js.map +1 -1
- package/dist/adapters/pr-adapter.d.ts +25 -0
- package/dist/adapters/pr-adapter.d.ts.map +1 -1
- package/dist/commands/retrospect.d.ts +37 -0
- package/dist/commands/retrospect.d.ts.map +1 -0
- package/dist/commands/retrospect.js +472 -0
- package/dist/commands/retrospect.js.map +1 -0
- package/dist/commands/retrospect.test.d.ts +2 -0
- package/dist/commands/retrospect.test.d.ts.map +1 -0
- package/dist/commands/retrospect.test.js +696 -0
- package/dist/commands/retrospect.test.js.map +1 -0
- package/dist/commands/shield-estimate.d.ts +24 -0
- package/dist/commands/shield-estimate.d.ts.map +1 -0
- package/dist/commands/shield-estimate.js +55 -0
- package/dist/commands/shield-estimate.js.map +1 -0
- package/dist/commands/shield-estimate.test.d.ts +2 -0
- package/dist/commands/shield-estimate.test.d.ts.map +1 -0
- package/dist/commands/shield-estimate.test.js +309 -0
- package/dist/commands/shield-estimate.test.js.map +1 -0
- package/dist/commands/shield-templates.d.ts +9 -0
- package/dist/commands/shield-templates.d.ts.map +1 -1
- package/dist/commands/shield-templates.js +9 -0
- package/dist/commands/shield-templates.js.map +1 -1
- package/dist/commands/shield.d.ts +13 -0
- package/dist/commands/shield.d.ts.map +1 -1
- package/dist/commands/shield.js +33 -0
- package/dist/commands/shield.js.map +1 -1
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `totem retrospect <pr>` — bot-tax circuit-breaker (mmnto-ai/totem#1713).
|
|
3
|
+
*
|
|
4
|
+
* Reads a PR's bot-review history live, groups findings into push-based
|
|
5
|
+
* rounds via the per-submission `commit_id` field, enriches each finding
|
|
6
|
+
* with cross-PR-recurrence flags from `.totem/recurrence-stats.json`
|
|
7
|
+
* (read-only) plus rule-coverage flags from `compiled-rules.json`, and
|
|
8
|
+
* emits a console report classifying findings as `route-out`,
|
|
9
|
+
* `in-pr-fix`, or `undetermined` via a deterministic table-driven
|
|
10
|
+
* heuristic.
|
|
11
|
+
*
|
|
12
|
+
* Substrate of the bot-tax cluster (#1715 + #1714 + #1713). Reuses the
|
|
13
|
+
* `recurrence-stats.ts` signature + severity vocabulary so the cluster
|
|
14
|
+
* has a single source of truth.
|
|
15
|
+
*
|
|
16
|
+
* No LLM. No GitHub API writes. Read-only outside the optional
|
|
17
|
+
* `--out <path>` JSON write.
|
|
18
|
+
*
|
|
19
|
+
* NOTE on `--auto-file`: the auto-spec proposed shelling out to
|
|
20
|
+
* `gh issue create` for every route-out candidate. The locked design
|
|
21
|
+
* (see `.totem/specs/1713.md` Q2) defers `--auto-file` to a follow-up
|
|
22
|
+
* ticket because mass-filing issues is irreversible and the v0.1
|
|
23
|
+
* surface emits suggested titles + bodies that the human can copy-paste.
|
|
24
|
+
*/
|
|
25
|
+
// totem-context: type-only imports above are erased at compile time and don't
|
|
26
|
+
// violate the lazy-import command policy (mmnto-ai/totem#1729 CR R1). All
|
|
27
|
+
// runtime imports (node:fs, node:path, zod, @mmnto/totem, helpers, adapters)
|
|
28
|
+
// are dynamic — see runRetrospect body.
|
|
29
|
+
// ─── Constants ───────────────────────────────────────
|
|
30
|
+
export const RETROSPECT_DISPLAY_TAG = 'Retrospect';
|
|
31
|
+
const TAG = RETROSPECT_DISPLAY_TAG;
|
|
32
|
+
const DEFAULT_THRESHOLD = 5;
|
|
33
|
+
const BODY_EXCERPT_MAX = 280;
|
|
34
|
+
/** Jaccard similarity above which a finding signature is treated as covered by an existing compiled rule. Mirrors `recurrence-stats.ts` `COVERAGE_JACCARD_THRESHOLD`. */
|
|
35
|
+
const RULE_COVERAGE_JACCARD_THRESHOLD = 0.6;
|
|
36
|
+
/** Max chars rendered for a finding's body excerpt in the console report. */
|
|
37
|
+
const RENDER_SNIPPET_MAX = 80;
|
|
38
|
+
/**
|
|
39
|
+
* Strip ANSI/control bytes from text that originated in untrusted GitHub
|
|
40
|
+
* review content before it lands in `log.dim()`. Per CR mmnto-ai/totem#1734
|
|
41
|
+
* round-2: raw `bodyExcerpt` printed without sanitization is a terminal-
|
|
42
|
+
* injection vector (a hostile reviewer can plant CSI sequences that spoof
|
|
43
|
+
* cursor moves or color resets).
|
|
44
|
+
*
|
|
45
|
+
* Removes:
|
|
46
|
+
* - CSI sequences (ESC `[` … final byte): the standard ANSI escape form.
|
|
47
|
+
* - C0/C1 control bytes other than `\n` and `\t` (which `replace(/\s+/g, ' ')`
|
|
48
|
+
* downstream collapses anyway, but pre-replacing makes the surface stable
|
|
49
|
+
* regardless of caller order).
|
|
50
|
+
*/
|
|
51
|
+
function sanitizeForTerminal(value) {
|
|
52
|
+
return value
|
|
53
|
+
.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, '')
|
|
54
|
+
.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, ' ');
|
|
55
|
+
}
|
|
56
|
+
// ─── Main entrypoint ────────────────────────────────
|
|
57
|
+
export async function runRetrospect(options) {
|
|
58
|
+
// Dynamic imports per `packages/cli/src/commands/**` lazy-import policy
|
|
59
|
+
// (mmnto-ai/totem#1729 CR R1).
|
|
60
|
+
const fs = await import('node:fs');
|
|
61
|
+
const path = await import('node:path');
|
|
62
|
+
const { z } = await import('zod');
|
|
63
|
+
const { GitHubCliPrAdapter } = await import('../adapters/github-cli-pr.js');
|
|
64
|
+
const { log } = await import('../ui.js');
|
|
65
|
+
const { isBotComment, detectBot, parseCRSeverity, parseGCASeverity, stripHtmlWrappers, extractReviewBodyFindings, } = await import('../parsers/bot-review-parser.js');
|
|
66
|
+
const { buildStopConditions, classifyFinding, computeDedupRate, computeSignature, groupFindingsByRound, jaccard, loadCompiledRules, normalizeFindingBody, readLedgerEvents, RetrospectReportSchema, toSeverityBucket, tokenizeForJaccard, } = await import('@mmnto/totem');
|
|
67
|
+
const { loadConfig, resolveConfigPath } = await import('../utils.js');
|
|
68
|
+
// Local schema — the recurrence-stats file shape is defined in core,
|
|
69
|
+
// but reading it here keeps the zod import lazy.
|
|
70
|
+
const RecurrenceStatsFileSchema = z.object({
|
|
71
|
+
version: z.literal(1),
|
|
72
|
+
patterns: z.array(z.object({
|
|
73
|
+
signature: z.string(),
|
|
74
|
+
prs: z.array(z.string()),
|
|
75
|
+
})),
|
|
76
|
+
coveredPatterns: z
|
|
77
|
+
.array(z.object({
|
|
78
|
+
signature: z.string(),
|
|
79
|
+
prs: z.array(z.string()),
|
|
80
|
+
}))
|
|
81
|
+
.optional(),
|
|
82
|
+
});
|
|
83
|
+
const cwd = process.cwd();
|
|
84
|
+
const threshold = clampThreshold(options.threshold);
|
|
85
|
+
const prNumber = options.prNumber;
|
|
86
|
+
// Strict integer parse (reject "5foo", "5.2", " 5 ") — `Number.parseInt`
|
|
87
|
+
// silently accepts trailing non-numerics; per CR/GCA mmnto-ai/totem#1734
|
|
88
|
+
// review-1 we use `Number()` + `Number.isInteger` for CLI inputs.
|
|
89
|
+
const prNumberInt = Number(prNumber);
|
|
90
|
+
if (!Number.isInteger(prNumberInt) || prNumberInt <= 0) {
|
|
91
|
+
const { TotemConfigError } = await import('@mmnto/totem');
|
|
92
|
+
throw new TotemConfigError(`Invalid PR number: ${prNumber}`, "Pass a positive integer (e.g. 'totem retrospect 1734').", 'CONFIG_INVALID');
|
|
93
|
+
}
|
|
94
|
+
log.info(TAG, `Retrospect on PR #${prNumber} (threshold=${threshold}).`);
|
|
95
|
+
// 1. Live-fetch PR + reviews + comments.
|
|
96
|
+
const adapter = new GitHubCliPrAdapter(cwd);
|
|
97
|
+
const prData = adapter.fetchPr(prNumberInt);
|
|
98
|
+
const reviewSubmissions = adapter.fetchReviews(prNumberInt);
|
|
99
|
+
const reviewComments = adapter.fetchReviewComments(prNumberInt);
|
|
100
|
+
// 2. Round-grouping. Build a SHA → finding-count map by joining inline
|
|
101
|
+
// comments back to the closest preceding review submission via
|
|
102
|
+
// timestamp. We only consider BOT submissions because the round
|
|
103
|
+
// count is a measure of bot-driven feedback waves.
|
|
104
|
+
// Null-guard before isBotComment — GitHub API permits null `user`
|
|
105
|
+
// (deleted/ghost accounts). Without the guard, `isBotComment(null)`
|
|
106
|
+
// would silently exclude bot rounds. Per CR mmnto-ai/totem#1734 review-1.
|
|
107
|
+
const botSubmissions = reviewSubmissions
|
|
108
|
+
.filter((r) => r.user_login !== null && isBotComment(r.user_login))
|
|
109
|
+
.map((r) => ({
|
|
110
|
+
id: r.id,
|
|
111
|
+
commit_id: r.commit_id ?? null,
|
|
112
|
+
submitted_at: r.submitted_at ?? null,
|
|
113
|
+
user_login: r.user_login,
|
|
114
|
+
}));
|
|
115
|
+
// Bucket each finding by the parent review submission's commit_id.
|
|
116
|
+
// Per CR mmnto-ai/totem#1734 round-2: `created_at` can predate
|
|
117
|
+
// `submitted_at` for pending/draft reviews, so a timestamp join
|
|
118
|
+
// mis-attributes the head SHA. The GitHub API exposes
|
|
119
|
+
// `pull_request_review_id` on each review comment as the stable
|
|
120
|
+
// foreign key back to its parent submission — we use that.
|
|
121
|
+
const sortedSubs = [...botSubmissions].sort((a, b) => {
|
|
122
|
+
const at = a.submitted_at ?? '';
|
|
123
|
+
const bt = b.submitted_at ?? '';
|
|
124
|
+
if (at < bt)
|
|
125
|
+
return -1;
|
|
126
|
+
if (at > bt)
|
|
127
|
+
return 1;
|
|
128
|
+
return 0;
|
|
129
|
+
});
|
|
130
|
+
/** review_id → commit_id lookup over bot-authored submissions only. */
|
|
131
|
+
const reviewIdToSha = new Map();
|
|
132
|
+
for (const s of botSubmissions) {
|
|
133
|
+
if (typeof s.commit_id === 'string')
|
|
134
|
+
reviewIdToSha.set(s.id, s.commit_id);
|
|
135
|
+
}
|
|
136
|
+
function shaForInlineComment(reviewId) {
|
|
137
|
+
if (typeof reviewId !== 'number')
|
|
138
|
+
return '';
|
|
139
|
+
return reviewIdToSha.get(reviewId) ?? '';
|
|
140
|
+
}
|
|
141
|
+
// 3. Inline + review-body bot finding extraction.
|
|
142
|
+
const inlineBotComments = reviewComments.filter((c) => isBotComment(c.author));
|
|
143
|
+
const inlineFindings = [];
|
|
144
|
+
for (const c of inlineBotComments) {
|
|
145
|
+
const tool = detectBot(c.author);
|
|
146
|
+
const severity = tool === 'coderabbit'
|
|
147
|
+
? parseCRSeverity(c.body)
|
|
148
|
+
: tool === 'gca'
|
|
149
|
+
? parseGCASeverity(c.body)
|
|
150
|
+
: 'info';
|
|
151
|
+
const body = stripHtmlWrappers(c.body);
|
|
152
|
+
const hunkMatch = c.diffHunk.match(/@@ .+?\+(\d+)/);
|
|
153
|
+
const line = hunkMatch ? Number.parseInt(hunkMatch[1], 10) : undefined;
|
|
154
|
+
inlineFindings.push({
|
|
155
|
+
finding: {
|
|
156
|
+
tool,
|
|
157
|
+
severity,
|
|
158
|
+
file: c.path,
|
|
159
|
+
line,
|
|
160
|
+
body,
|
|
161
|
+
resolutionSignal: 'none',
|
|
162
|
+
rootCommentId: c.id,
|
|
163
|
+
},
|
|
164
|
+
sha: shaForInlineComment(c.pullRequestReviewId),
|
|
165
|
+
observedAt: c.createdAt ?? '',
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
// CR review-body findings (outside-diff + nits) — bucket into the SHA
|
|
169
|
+
// of the review submission that carried them.
|
|
170
|
+
const reviewBodyFindings = [];
|
|
171
|
+
for (const r of reviewSubmissions) {
|
|
172
|
+
// Null-guard: deleted/ghost accounts skip this branch — same rationale as the bot-submissions filter above.
|
|
173
|
+
if (r.user_login === null || !isBotComment(r.user_login))
|
|
174
|
+
continue;
|
|
175
|
+
const synthesized = extractReviewBodyFindings([{ author: r.user_login, body: r.body ?? '' }]);
|
|
176
|
+
const sha = typeof r.commit_id === 'string' ? r.commit_id : '';
|
|
177
|
+
const observedAt = r.submitted_at ?? '';
|
|
178
|
+
for (const f of synthesized) {
|
|
179
|
+
reviewBodyFindings.push({ finding: f, sha, observedAt });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const allFindings = [...inlineFindings, ...reviewBodyFindings];
|
|
183
|
+
// SHA → finding count.
|
|
184
|
+
const findingsPerSha = new Map();
|
|
185
|
+
for (const f of allFindings) {
|
|
186
|
+
findingsPerSha.set(f.sha, (findingsPerSha.get(f.sha) ?? 0) + 1);
|
|
187
|
+
}
|
|
188
|
+
// Compute rounds via the pure helper.
|
|
189
|
+
const rounds = groupFindingsByRound(sortedSubs, findingsPerSha);
|
|
190
|
+
// SHA → roundNumber lookup so we can stamp each finding.
|
|
191
|
+
const shaToRoundNumber = new Map();
|
|
192
|
+
for (const r of rounds) {
|
|
193
|
+
shaToRoundNumber.set(r.headSha ?? '', r.roundNumber);
|
|
194
|
+
}
|
|
195
|
+
// 4. Substrate read — recurrence-stats (graceful degrade if missing).
|
|
196
|
+
const config = await loadConfig(resolveConfigPath(cwd));
|
|
197
|
+
const totemDir = path.join(cwd, config.totemDir);
|
|
198
|
+
const substratePath = path.join(totemDir, 'recurrence-stats.json');
|
|
199
|
+
let substrateAvailable = false;
|
|
200
|
+
/** signature → list of OTHER PRs sharing this signature (target excluded). */
|
|
201
|
+
const crossPrIndex = new Map();
|
|
202
|
+
if (fs.existsSync(substratePath)) {
|
|
203
|
+
try {
|
|
204
|
+
const raw = fs.readFileSync(substratePath, 'utf-8');
|
|
205
|
+
const parsed = JSON.parse(raw);
|
|
206
|
+
const validated = RecurrenceStatsFileSchema.parse(parsed);
|
|
207
|
+
substrateAvailable = true;
|
|
208
|
+
const allEntries = [...(validated.patterns ?? []), ...(validated.coveredPatterns ?? [])];
|
|
209
|
+
for (const entry of allEntries) {
|
|
210
|
+
const others = entry.prs.filter((p) => p !== prNumber);
|
|
211
|
+
const set = crossPrIndex.get(entry.signature) ?? new Set();
|
|
212
|
+
for (const pr of others)
|
|
213
|
+
set.add(pr);
|
|
214
|
+
crossPrIndex.set(entry.signature, set);
|
|
215
|
+
}
|
|
216
|
+
// totem-context: malformed substrate is a graceful-degrade path per the mmnto-ai/totem#1713 failure-mode table — log + continue with `crossPrRecurrence: 0` for every finding; `substrateAvailable: false` surfaces the degradation in the report so the consumer can see it explicitly. Hard-erroring would block the circuit-breaker the user invoked retrospect to run.
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
220
|
+
log.warn(TAG, `Could not parse ${substratePath}: ${msg} — running without cross-PR recurrence enrichment.`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
log.warn(TAG, `${substratePath} not found — run 'totem stats --pattern-recurrence' first to enable cross-PR enrichment.`);
|
|
225
|
+
}
|
|
226
|
+
// 5. Compiled-rules read — graceful degrade if missing.
|
|
227
|
+
// `loadCompiledRules` is intentionally `[]`-returning on ENOENT so a
|
|
228
|
+
// sync-after-fresh-clone doesn't crash; we can't tell "missing" from
|
|
229
|
+
// "empty manifest" by return value alone. Gate on file existence
|
|
230
|
+
// first so the report's `compiledRulesAvailable` flag matches the
|
|
231
|
+
// user's mental model: if the file isn't there, the coverage check
|
|
232
|
+
// is structurally unavailable.
|
|
233
|
+
const rulesPath = path.join(totemDir, 'compiled-rules.json');
|
|
234
|
+
let compiledRulesAvailable = false;
|
|
235
|
+
let ruleTokenSets = [];
|
|
236
|
+
if (fs.existsSync(rulesPath)) {
|
|
237
|
+
try {
|
|
238
|
+
const compiledRules = loadCompiledRules(rulesPath);
|
|
239
|
+
compiledRulesAvailable = true;
|
|
240
|
+
ruleTokenSets = compiledRules.map((r) => tokenizeForJaccard(r.message ?? ''));
|
|
241
|
+
// totem-context: malformed compiled-rules.json is a graceful-degrade path per the mmnto-ai/totem#1713 failure-mode table — log + continue with `coveredByRule: false` for every finding; `compiledRulesAvailable: false` surfaces the degradation. Mirrors the pattern in `runRecurrenceStats` step 6 ("missing/malformed compiled-rules.json disables coverage routing only").
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
245
|
+
log.warn(TAG, `Could not load compiled rules: ${msg} — coverage check disabled.`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
log.warn(TAG, `${rulesPath} not found — run 'totem lesson compile' first to enable rule-coverage enrichment.`);
|
|
250
|
+
}
|
|
251
|
+
// 6. Trap-ledger override events (read-only, count only). Today the
|
|
252
|
+
// LedgerEventSchema does NOT carry a `prNumber` field, so we cannot
|
|
253
|
+
// actually scope the count to the target PR — every event passes
|
|
254
|
+
// the predicate. The cast-based predicate below is a forward-compat
|
|
255
|
+
// scaffold: when a future ticket adds `prNumber` to LedgerEvent
|
|
256
|
+
// (filed as the mmnto-ai/totem#1734-CR-7 follow-up), the predicate
|
|
257
|
+
// will start filtering automatically with no command-side change.
|
|
258
|
+
// Per CR mmnto-ai/totem#1734 review-1.
|
|
259
|
+
const ledgerEvents = readLedgerEvents(totemDir, (msg) => log.warn(TAG, msg));
|
|
260
|
+
const overrideEventsObserved = ledgerEvents.filter((e) => {
|
|
261
|
+
if (e.type !== 'override')
|
|
262
|
+
return false;
|
|
263
|
+
const eventPr = e.prNumber;
|
|
264
|
+
return eventPr === undefined || String(eventPr) === prNumber;
|
|
265
|
+
}).length;
|
|
266
|
+
// 7. Annotate every finding: signature, classification, recurrence, coverage.
|
|
267
|
+
const annotated = allFindings.map((f) => ({
|
|
268
|
+
finding: f.finding,
|
|
269
|
+
roundNumber: shaToRoundNumber.get(f.sha) ?? 0,
|
|
270
|
+
observedAt: f.observedAt,
|
|
271
|
+
}));
|
|
272
|
+
// Per discriminated union (CR mmnto-ai/totem#1734 round-2): `routeOutReason`
|
|
273
|
+
// is present iff `classification === 'route-out'`; the schema infers
|
|
274
|
+
// `RetrospectFinding` accordingly.
|
|
275
|
+
const enriched = [];
|
|
276
|
+
for (const a of annotated) {
|
|
277
|
+
const normalized = normalizeFindingBody(a.finding.body);
|
|
278
|
+
if (normalized.length === 0)
|
|
279
|
+
continue;
|
|
280
|
+
const signature = computeSignature(normalized);
|
|
281
|
+
const tool = a.finding.tool === 'coderabbit' ? 'coderabbit' : a.finding.tool === 'gca' ? 'gca' : 'unknown';
|
|
282
|
+
const severityBucket = toSeverityBucket(tool, a.finding.severity);
|
|
283
|
+
// Cross-PR recurrence — count of OTHER PRs (target excluded by construction).
|
|
284
|
+
const crossPrRecurrence = crossPrIndex.get(signature)?.size ?? 0;
|
|
285
|
+
// Coverage check — Jaccard 0.6 against any rule message.
|
|
286
|
+
let coveredByRule = false;
|
|
287
|
+
if (compiledRulesAvailable && ruleTokenSets.length > 0) {
|
|
288
|
+
const findingTokens = tokenizeForJaccard(normalized);
|
|
289
|
+
let maxJ = 0;
|
|
290
|
+
for (const ruleTokens of ruleTokenSets) {
|
|
291
|
+
const v = jaccard(findingTokens, ruleTokens);
|
|
292
|
+
if (v > maxJ)
|
|
293
|
+
maxJ = v;
|
|
294
|
+
}
|
|
295
|
+
coveredByRule = maxJ >= RULE_COVERAGE_JACCARD_THRESHOLD;
|
|
296
|
+
}
|
|
297
|
+
const verdict = classifyFinding({
|
|
298
|
+
severityBucket,
|
|
299
|
+
roundNumber: a.roundNumber > 0 ? a.roundNumber : 1,
|
|
300
|
+
crossPrRecurrence,
|
|
301
|
+
coveredByRule,
|
|
302
|
+
});
|
|
303
|
+
const base = {
|
|
304
|
+
signature,
|
|
305
|
+
tool,
|
|
306
|
+
severityBucket,
|
|
307
|
+
bodyExcerpt: a.finding.body.slice(0, BODY_EXCERPT_MAX),
|
|
308
|
+
file: a.finding.file,
|
|
309
|
+
line: a.finding.line,
|
|
310
|
+
roundNumber: a.roundNumber > 0 ? a.roundNumber : 1,
|
|
311
|
+
crossPrRecurrence,
|
|
312
|
+
coveredByRule,
|
|
313
|
+
};
|
|
314
|
+
if (verdict.classification === 'route-out' && verdict.routeOutReason !== undefined) {
|
|
315
|
+
enriched.push({
|
|
316
|
+
...base,
|
|
317
|
+
classification: 'route-out',
|
|
318
|
+
routeOutReason: verdict.routeOutReason,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
else if (verdict.classification === 'route-out') {
|
|
322
|
+
// Defensive: classifier returned 'route-out' without a reason — should
|
|
323
|
+
// be unreachable per the table. Fail loud (Tenet 4) so the missing
|
|
324
|
+
// catalog entry surfaces immediately.
|
|
325
|
+
throw new Error(`[Totem Error] classifier returned route-out without routeOutReason for signature ${signature}`);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
enriched.push({ ...base, classification: verdict.classification });
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// 8. Distribution counts.
|
|
332
|
+
const byTool = {};
|
|
333
|
+
const bySeverity = {};
|
|
334
|
+
const byClassification = {};
|
|
335
|
+
for (const f of enriched) {
|
|
336
|
+
byTool[f.tool] = (byTool[f.tool] ?? 0) + 1;
|
|
337
|
+
bySeverity[f.severityBucket] = (bySeverity[f.severityBucket] ?? 0) + 1;
|
|
338
|
+
byClassification[f.classification] = (byClassification[f.classification] ?? 0) + 1;
|
|
339
|
+
}
|
|
340
|
+
// Sort buckets — primary by roundNumber asc; tie-break: numeric PR
|
|
341
|
+
// sort is on `prs[]` arrays (lesson-26935d32 applies in
|
|
342
|
+
// `recurrence-stats`); here we stay deterministic via signature.
|
|
343
|
+
const sortByRoundThenSig = (a, b) => {
|
|
344
|
+
if (a.roundNumber !== b.roundNumber)
|
|
345
|
+
return a.roundNumber - b.roundNumber;
|
|
346
|
+
return a.signature.localeCompare(b.signature);
|
|
347
|
+
};
|
|
348
|
+
const routeOutCandidates = enriched
|
|
349
|
+
.filter((f) => f.classification === 'route-out')
|
|
350
|
+
.sort(sortByRoundThenSig);
|
|
351
|
+
const inPrFixes = enriched
|
|
352
|
+
.filter((f) => f.classification === 'in-pr-fix')
|
|
353
|
+
.sort(sortByRoundThenSig);
|
|
354
|
+
const undetermined = enriched
|
|
355
|
+
.filter((f) => f.classification === 'undetermined')
|
|
356
|
+
.sort(sortByRoundThenSig);
|
|
357
|
+
const dedupRate = computeDedupRate(enriched);
|
|
358
|
+
// 9. Build report.
|
|
359
|
+
const report = {
|
|
360
|
+
version: 1,
|
|
361
|
+
prNumber,
|
|
362
|
+
prState: prData.state,
|
|
363
|
+
generatedAt: new Date().toISOString(),
|
|
364
|
+
threshold,
|
|
365
|
+
substrateAvailable,
|
|
366
|
+
compiledRulesAvailable,
|
|
367
|
+
rounds,
|
|
368
|
+
totalFindings: enriched.length,
|
|
369
|
+
dedupRate,
|
|
370
|
+
findingDistribution: { byTool, bySeverity, byClassification },
|
|
371
|
+
routeOutCandidates,
|
|
372
|
+
inPrFixes,
|
|
373
|
+
undetermined,
|
|
374
|
+
stopConditions: [],
|
|
375
|
+
overrideEventsObserved,
|
|
376
|
+
};
|
|
377
|
+
report.stopConditions = buildStopConditions(report);
|
|
378
|
+
// Validate the assembled report shape — fail-loud on schema drift.
|
|
379
|
+
RetrospectReportSchema.parse(report);
|
|
380
|
+
// 10. Threshold gate.
|
|
381
|
+
if (rounds.length < threshold && !options.force) {
|
|
382
|
+
log.info(TAG, `PR #${prNumber} has ${rounds.length} bot-review round(s); below threshold ${threshold}. Skipping (pass --force to inspect anyway).`);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
// 11. Render console report.
|
|
386
|
+
renderReport(report, log);
|
|
387
|
+
// 12. Optional --out write (deterministic two-space JSON).
|
|
388
|
+
if (options.out) {
|
|
389
|
+
const outPath = path.isAbsolute(options.out) ? options.out : path.join(cwd, options.out);
|
|
390
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
391
|
+
fs.writeFileSync(outPath, JSON.stringify(report, null, 2) + '\n', 'utf-8');
|
|
392
|
+
log.info(TAG, `Wrote report → ${outPath}`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
function renderReport(report, log) {
|
|
396
|
+
log.info(TAG, `PR #${report.prNumber} (${report.prState}) — ${report.rounds.length} round(s), ${report.totalFindings} bot finding(s).`);
|
|
397
|
+
log.dim(TAG, ` substrate=${report.substrateAvailable ? 'available' : 'absent'}, compiled-rules=${report.compiledRulesAvailable ? 'available' : 'absent'}, dedup-rate=${(report.dedupRate * 100).toFixed(0)}%`);
|
|
398
|
+
// Distribution
|
|
399
|
+
const tools = Object.entries(report.findingDistribution.byTool)
|
|
400
|
+
.sort((a, b) => b[1] - a[1])
|
|
401
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
402
|
+
.join(' ');
|
|
403
|
+
const severities = Object.entries(report.findingDistribution.bySeverity)
|
|
404
|
+
.sort((a, b) => b[1] - a[1])
|
|
405
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
406
|
+
.join(' ');
|
|
407
|
+
const classifications = Object.entries(report.findingDistribution.byClassification)
|
|
408
|
+
.sort((a, b) => b[1] - a[1])
|
|
409
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
410
|
+
.join(' ');
|
|
411
|
+
if (tools)
|
|
412
|
+
log.dim(TAG, ` tool: ${tools}`);
|
|
413
|
+
if (severities)
|
|
414
|
+
log.dim(TAG, ` severity: ${severities}`);
|
|
415
|
+
if (classifications)
|
|
416
|
+
log.dim(TAG, ` classification: ${classifications}`);
|
|
417
|
+
// Route-out candidates.
|
|
418
|
+
if (report.routeOutCandidates.length > 0) {
|
|
419
|
+
log.info(TAG, `Route-out candidates (${report.routeOutCandidates.length}):`);
|
|
420
|
+
for (const f of report.routeOutCandidates) {
|
|
421
|
+
const snippet = sanitizeForTerminal(f.bodyExcerpt)
|
|
422
|
+
.replace(/\s+/g, ' ')
|
|
423
|
+
.slice(0, RENDER_SNIPPET_MAX);
|
|
424
|
+
// Schema discriminates: `f.classification === 'route-out'` guarantees `routeOutReason`.
|
|
425
|
+
const reason = f.routeOutReason;
|
|
426
|
+
log.dim(TAG, ` [r${f.roundNumber}] ${f.severityBucket} ${f.signature} — ${snippet} (${reason})`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
log.dim(TAG, 'Route-out candidates: (none)');
|
|
431
|
+
}
|
|
432
|
+
// In-PR fixes.
|
|
433
|
+
if (report.inPrFixes.length > 0) {
|
|
434
|
+
log.info(TAG, `In-PR fixes (${report.inPrFixes.length}):`);
|
|
435
|
+
for (const f of report.inPrFixes) {
|
|
436
|
+
const snippet = sanitizeForTerminal(f.bodyExcerpt)
|
|
437
|
+
.replace(/\s+/g, ' ')
|
|
438
|
+
.slice(0, RENDER_SNIPPET_MAX);
|
|
439
|
+
log.dim(TAG, ` [r${f.roundNumber}] ${f.severityBucket} ${f.signature} — ${snippet}`);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
log.dim(TAG, 'In-PR fixes: (none)');
|
|
444
|
+
}
|
|
445
|
+
// Undetermined.
|
|
446
|
+
if (report.undetermined.length > 0) {
|
|
447
|
+
log.info(TAG, `Undetermined (${report.undetermined.length}):`);
|
|
448
|
+
for (const f of report.undetermined) {
|
|
449
|
+
const snippet = sanitizeForTerminal(f.bodyExcerpt)
|
|
450
|
+
.replace(/\s+/g, ' ')
|
|
451
|
+
.slice(0, RENDER_SNIPPET_MAX);
|
|
452
|
+
log.dim(TAG, ` [r${f.roundNumber}] ${f.severityBucket} ${f.signature} — ${snippet}`);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
// Stop conditions.
|
|
456
|
+
if (report.stopConditions.length > 0) {
|
|
457
|
+
log.info(TAG, 'Stop conditions:');
|
|
458
|
+
for (const cond of report.stopConditions) {
|
|
459
|
+
log.dim(TAG, ` • ${cond}`);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
if (report.overrideEventsObserved > 0) {
|
|
463
|
+
log.dim(TAG, `Trap ledger: ${report.overrideEventsObserved} override event(s) observed.`);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
// ─── Helpers ────────────────────────────────────────
|
|
467
|
+
function clampThreshold(input) {
|
|
468
|
+
if (input === undefined || !Number.isFinite(input) || input < 1)
|
|
469
|
+
return DEFAULT_THRESHOLD;
|
|
470
|
+
return Math.floor(input);
|
|
471
|
+
}
|
|
472
|
+
//# sourceMappingURL=retrospect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retrospect.js","sourceRoot":"","sources":["../../src/commands/retrospect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retrospect.test.d.ts","sourceRoot":"","sources":["../../src/commands/retrospect.test.ts"],"names":[],"mappings":""}
|