@cat-factory/orchestration 0.136.1 → 0.138.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/container.d.ts +21 -3
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js.map +1 -1
- package/dist/modules/environments/EnvironmentTestService.d.ts.map +1 -1
- package/dist/modules/environments/EnvironmentTestService.js +7 -1
- package/dist/modules/environments/EnvironmentTestService.js.map +1 -1
- package/dist/modules/execution/ExecutionService.d.ts +7 -371
- package/dist/modules/execution/ExecutionService.d.ts.map +1 -1
- package/dist/modules/execution/ExecutionService.js +32 -35
- package/dist/modules/execution/ExecutionService.js.map +1 -1
- package/dist/modules/execution/ExecutionServiceDependencies.d.ts +381 -0
- package/dist/modules/execution/ExecutionServiceDependencies.d.ts.map +1 -0
- package/dist/modules/execution/ExecutionServiceDependencies.js +2 -0
- package/dist/modules/execution/ExecutionServiceDependencies.js.map +1 -0
- package/dist/modules/execution/PrVerificationReportController.d.ts +106 -0
- package/dist/modules/execution/PrVerificationReportController.d.ts.map +1 -0
- package/dist/modules/execution/PrVerificationReportController.js +134 -0
- package/dist/modules/execution/PrVerificationReportController.js.map +1 -0
- package/dist/modules/execution/RunDispatcher.d.ts +4 -0
- package/dist/modules/execution/RunDispatcher.d.ts.map +1 -1
- package/dist/modules/execution/RunDispatcher.js +13 -0
- package/dist/modules/execution/RunDispatcher.js.map +1 -1
- package/dist/modules/execution/prReport.logic.d.ts +25 -0
- package/dist/modules/execution/prReport.logic.d.ts.map +1 -0
- package/dist/modules/execution/prReport.logic.js +436 -0
- package/dist/modules/execution/prReport.logic.js.map +1 -0
- package/dist/modules/execution/prReportText.logic.d.ts +46 -0
- package/dist/modules/execution/prReportText.logic.d.ts.map +1 -0
- package/dist/modules/execution/prReportText.logic.js +188 -0
- package/dist/modules/execution/prReportText.logic.js.map +1 -0
- package/dist/modules/execution/retry.logic.d.ts +28 -1
- package/dist/modules/execution/retry.logic.d.ts.map +1 -1
- package/dist/modules/execution/retry.logic.js +36 -0
- package/dist/modules/execution/retry.logic.js.map +1 -1
- package/dist/modules/execution/runStartOptions.d.ts +12 -0
- package/dist/modules/execution/runStartOptions.d.ts.map +1 -1
- package/dist/modules/settings/WorkspaceSettingsService.d.ts.map +1 -1
- package/dist/modules/settings/WorkspaceSettingsService.js +1 -0
- package/dist/modules/settings/WorkspaceSettingsService.js.map +1 -1
- package/package.json +11 -11
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
import { redactSecrets } from '@cat-factory/kernel';
|
|
2
|
+
import { PR_VERIFICATION_REPORT_VERSION } from '@cat-factory/contracts';
|
|
3
|
+
import { DEPLOYER_AGENT_KIND } from '@cat-factory/integrations';
|
|
4
|
+
import { CI_AGENT_KIND, MERGER_AGENT_KIND, isTesterKind } from './ci.logic.js';
|
|
5
|
+
import { capList, cell, inline, MAX_SECTION_CHARS, prose } from './prReportText.logic.js';
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// The PR verification report's PURE half: compose it from a run's already-loaded state, and
|
|
8
|
+
// render it as markdown + a fenced JSON block.
|
|
9
|
+
//
|
|
10
|
+
// Everything here reads the `ExecutionInstance` the engine already holds in memory — the CI
|
|
11
|
+
// gate's recorded verdict (`step.gate`), the tester's last report (`step.test`), the
|
|
12
|
+
// deployer's per-frame outcomes (`step.deployEnvs`) and the merger's resolved decision
|
|
13
|
+
// (`step.custom`). Nothing re-probes a provider: a re-probe costs a round trip AND can
|
|
14
|
+
// disagree with the verdict the gate actually acted on, which would make the report a
|
|
15
|
+
// worse record than the run it describes.
|
|
16
|
+
//
|
|
17
|
+
// Sections whose producing step did not run are emitted with `status: 'absent'` and a `note`
|
|
18
|
+
// that SAYS so. A silently missing section is indistinguishable from a clean one, which is
|
|
19
|
+
// exactly the false reassurance this feature exists to remove.
|
|
20
|
+
//
|
|
21
|
+
// Every free-text value the run produced (a tester summary, a merge rationale, a provisioner's
|
|
22
|
+
// stderr) is SCRUBBED here with the same `redactSecrets` the telemetry store uses. A PR body
|
|
23
|
+
// is a strictly more exposed surface than the private telemetry DB — it may be a public repo —
|
|
24
|
+
// so anything worth scrubbing before it reaches our own database is worth scrubbing before it
|
|
25
|
+
// reaches the host. Scrubbing at COMPOSE time (rather than over the rendered markdown) keeps
|
|
26
|
+
// the human prose and the machine-readable JSON block consistent: both are produced from this
|
|
27
|
+
// one already-scrubbed object. Rendering-level hazards (auto-linked mentions and issue
|
|
28
|
+
// references, table-breaking newlines, unbalanced code fences) are handled at the interpolation
|
|
29
|
+
// boundary — see `prReportText.logic.ts`.
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
/** Scrub credentials out of an optional free-text value, preserving `null`/`undefined`. */
|
|
32
|
+
function scrub(value) {
|
|
33
|
+
return value == null ? null : (redactSecrets(value) ?? null);
|
|
34
|
+
}
|
|
35
|
+
/** Scrub a required free-text value. */
|
|
36
|
+
function scrubbed(value) {
|
|
37
|
+
return redactSecrets(value) ?? '';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Cap a list, recording what was dropped in the report's own `truncations` log.
|
|
41
|
+
*
|
|
42
|
+
* A silently shortened list is the same failure this feature exists to remove: 50 of 112
|
|
43
|
+
* failing checks reads exactly like "112 checks, 50 failed". The report SAYS what it left out.
|
|
44
|
+
*/
|
|
45
|
+
function cap(items, label, truncations) {
|
|
46
|
+
const { items: kept, dropped } = capList(items);
|
|
47
|
+
if (dropped > 0)
|
|
48
|
+
truncations.push(`${label}: showing ${kept.length} of ${items.length}`);
|
|
49
|
+
return kept;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The step a section should report on: the LAST matching step that carries evidence, else the
|
|
53
|
+
* first matching step (so a pipeline that has the step but hasn't reached it still gets the
|
|
54
|
+
* "not run yet" note rather than nothing).
|
|
55
|
+
*
|
|
56
|
+
* Last-with-evidence, not first-match: a pipeline may legitimately carry the same kind twice —
|
|
57
|
+
* a `ci` gate after the coder and another after the tester, say — and the later run is the one
|
|
58
|
+
* that describes the PR head as it stands now. Reporting the first would pin the section to a
|
|
59
|
+
* verdict two steps of work out of date.
|
|
60
|
+
*/
|
|
61
|
+
function findStep(instance, matches, hasEvidence) {
|
|
62
|
+
const matching = instance.steps.filter(matches);
|
|
63
|
+
for (let i = matching.length - 1; i >= 0; i--) {
|
|
64
|
+
if (hasEvidence(matching[i]))
|
|
65
|
+
return matching[i];
|
|
66
|
+
}
|
|
67
|
+
return matching[0];
|
|
68
|
+
}
|
|
69
|
+
/** A step is "settled" once it finished — a pending step has no evidence to report yet. */
|
|
70
|
+
function settled(step) {
|
|
71
|
+
return !!step && (step.state === 'done' || step.progress >= 1);
|
|
72
|
+
}
|
|
73
|
+
function composeCi(instance, truncations) {
|
|
74
|
+
const step = findStep(instance, (s) => s.agentKind === CI_AGENT_KIND, (s) => s.gate != null);
|
|
75
|
+
if (!step) {
|
|
76
|
+
return {
|
|
77
|
+
status: 'absent',
|
|
78
|
+
note: 'No CI gate in this pipeline — no continuous-integration verdict was captured.',
|
|
79
|
+
failingChecks: [],
|
|
80
|
+
fixerAttempts: 0,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const gate = step.gate;
|
|
84
|
+
if (!gate) {
|
|
85
|
+
return {
|
|
86
|
+
status: 'absent',
|
|
87
|
+
note: 'The CI gate has not run yet, so no verdict was captured.',
|
|
88
|
+
failingChecks: [],
|
|
89
|
+
fixerAttempts: 0,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const failingChecks = cap(gate.failingChecks ?? [], 'ci.failingChecks', truncations).map((check) => ({
|
|
93
|
+
name: scrubbed(check.name),
|
|
94
|
+
conclusion: scrub(check.conclusion),
|
|
95
|
+
url: check.url ?? null,
|
|
96
|
+
repo: check.repo ?? null,
|
|
97
|
+
}));
|
|
98
|
+
return {
|
|
99
|
+
status: 'reported',
|
|
100
|
+
verdict: gate.lastVerdict ?? null,
|
|
101
|
+
headSha: gate.headSha ?? null,
|
|
102
|
+
failingChecks,
|
|
103
|
+
fixerAttempts: gate.attempts,
|
|
104
|
+
maxFixerAttempts: gate.maxAttempts,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function composeTests(instance, truncations) {
|
|
108
|
+
const step = findStep(instance, (s) => isTesterKind(s.agentKind), (s) => s.test?.lastReport != null);
|
|
109
|
+
if (!step) {
|
|
110
|
+
return {
|
|
111
|
+
status: 'absent',
|
|
112
|
+
note: 'No tester step in this pipeline — no test run was performed by the platform.',
|
|
113
|
+
tested: [],
|
|
114
|
+
outcomes: [],
|
|
115
|
+
concerns: [],
|
|
116
|
+
fixerAttempts: 0,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const report = step.test?.lastReport;
|
|
120
|
+
if (!report) {
|
|
121
|
+
return {
|
|
122
|
+
status: 'absent',
|
|
123
|
+
note: 'The tester step produced no report (it did not run to completion).',
|
|
124
|
+
tested: [],
|
|
125
|
+
outcomes: [],
|
|
126
|
+
concerns: [],
|
|
127
|
+
fixerAttempts: step.test?.attempts ?? 0,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
status: 'reported',
|
|
132
|
+
greenlight: report.greenlight,
|
|
133
|
+
summary: scrubbed(report.summary),
|
|
134
|
+
environment: report.environment ?? null,
|
|
135
|
+
tested: cap(report.tested, 'tests.tested', truncations).map(scrubbed),
|
|
136
|
+
outcomes: cap(report.outcomes, 'tests.outcomes', truncations).map((o) => ({
|
|
137
|
+
name: scrubbed(o.name),
|
|
138
|
+
status: o.status,
|
|
139
|
+
detail: scrub(o.detail),
|
|
140
|
+
})),
|
|
141
|
+
concerns: cap(report.concerns, 'tests.concerns', truncations).map((c) => ({
|
|
142
|
+
title: scrubbed(c.title),
|
|
143
|
+
severity: c.severity,
|
|
144
|
+
})),
|
|
145
|
+
fixerAttempts: step.test?.attempts ?? 0,
|
|
146
|
+
maxFixerAttempts: step.test?.maxAttempts ?? null,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Whether the ephemeral environments a run stood up are gone again. Read off the live
|
|
151
|
+
* per-step environment projections rather than the terminal `deployEnvs` outcomes, because
|
|
152
|
+
* only the projection carries the CURRENT lifecycle state (`torn_down` / `expired`).
|
|
153
|
+
*/
|
|
154
|
+
function teardownState(instance, entries) {
|
|
155
|
+
if (!entries.some((e) => e.status === 'ready'))
|
|
156
|
+
return 'not_applicable';
|
|
157
|
+
const live = instance.steps.some((s) => s.environment != null &&
|
|
158
|
+
s.environment.status !== 'torn_down' &&
|
|
159
|
+
s.environment.status !== 'expired' &&
|
|
160
|
+
s.environment.status !== 'failed');
|
|
161
|
+
return live ? 'pending' : 'confirmed';
|
|
162
|
+
}
|
|
163
|
+
function composeEnvironments(instance, truncations) {
|
|
164
|
+
const step = findStep(instance, (s) => s.agentKind === DEPLOYER_AGENT_KIND, (s) => Object.keys(s.deployEnvs ?? {}).length > 0);
|
|
165
|
+
if (!step) {
|
|
166
|
+
return {
|
|
167
|
+
status: 'absent',
|
|
168
|
+
note: 'No deployer step in this pipeline — no ephemeral environment was provisioned.',
|
|
169
|
+
entries: [],
|
|
170
|
+
teardown: 'not_applicable',
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const entries = cap(Object.entries(step.deployEnvs ?? {}), 'environments.entries', truncations).map(([frameId, state]) => ({
|
|
174
|
+
frameId,
|
|
175
|
+
status: state.status,
|
|
176
|
+
url: state.url ?? null,
|
|
177
|
+
error: scrub(state.error),
|
|
178
|
+
}));
|
|
179
|
+
if (entries.length === 0) {
|
|
180
|
+
return {
|
|
181
|
+
status: 'absent',
|
|
182
|
+
note: 'The deployer step recorded no environment outcomes (it did not run to completion).',
|
|
183
|
+
entries: [],
|
|
184
|
+
teardown: 'not_applicable',
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return { status: 'reported', entries, teardown: teardownState(instance, entries) };
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* The merger's structured verdict. `step.custom` carries the engine's {@link MergeDecision}
|
|
191
|
+
* once the merge resolver has run, and the agent's raw {@link MergeAssessment} in the window
|
|
192
|
+
* before that — both are read, so a report composed at either moment is truthful.
|
|
193
|
+
*/
|
|
194
|
+
function composeMerge(instance) {
|
|
195
|
+
const step = findStep(instance, (s) => s.agentKind === MERGER_AGENT_KIND, (s) => s.custom != null);
|
|
196
|
+
if (!step) {
|
|
197
|
+
return {
|
|
198
|
+
status: 'absent',
|
|
199
|
+
note: 'No merger step in this pipeline — the merge decision is a human one.',
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
const custom = step.custom;
|
|
203
|
+
if (!settled(step) || !custom) {
|
|
204
|
+
return { status: 'absent', note: 'The merger step has not produced an assessment yet.' };
|
|
205
|
+
}
|
|
206
|
+
const assessment = custom.assessment ??
|
|
207
|
+
(typeof custom.complexity === 'number' &&
|
|
208
|
+
typeof custom.risk === 'number' &&
|
|
209
|
+
typeof custom.impact === 'number'
|
|
210
|
+
? {
|
|
211
|
+
complexity: custom.complexity,
|
|
212
|
+
risk: custom.risk,
|
|
213
|
+
impact: custom.impact,
|
|
214
|
+
rationale: custom.rationale ?? '',
|
|
215
|
+
}
|
|
216
|
+
: null);
|
|
217
|
+
if (!assessment && !custom.outcome) {
|
|
218
|
+
return { status: 'absent', note: 'The merger step produced no parseable assessment.' };
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
status: 'reported',
|
|
222
|
+
assessment: assessment
|
|
223
|
+
? { ...assessment, rationale: scrubbed(assessment.rationale) }
|
|
224
|
+
: assessment,
|
|
225
|
+
outcome: custom.outcome ?? null,
|
|
226
|
+
reason: custom.reason ?? null,
|
|
227
|
+
presetName: custom.thresholds?.presetName ?? null,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/** Compose the report from a run's in-memory state plus the few resolved inputs. */
|
|
231
|
+
export function composePrVerificationReport(instance, inputs) {
|
|
232
|
+
const truncations = [];
|
|
233
|
+
const steps = instance.steps.map((step, index) => ({
|
|
234
|
+
index,
|
|
235
|
+
agentKind: step.agentKind,
|
|
236
|
+
state: step.state,
|
|
237
|
+
model: step.model ?? null,
|
|
238
|
+
}));
|
|
239
|
+
return {
|
|
240
|
+
version: PR_VERIFICATION_REPORT_VERSION,
|
|
241
|
+
generatedAt: inputs.now,
|
|
242
|
+
run: {
|
|
243
|
+
executionId: instance.id,
|
|
244
|
+
blockId: instance.blockId,
|
|
245
|
+
blockTitle: scrubbed(inputs.block.title),
|
|
246
|
+
pipelineId: instance.pipelineId,
|
|
247
|
+
pipelineName: scrubbed(instance.pipelineName),
|
|
248
|
+
repo: inputs.repo ?? null,
|
|
249
|
+
provider: inputs.provider ?? null,
|
|
250
|
+
startedAt: instance.createdAt ?? null,
|
|
251
|
+
steps: cap(steps, 'run.steps', truncations),
|
|
252
|
+
issues: cap(inputs.issues, 'run.issues', truncations).map((issue) => ({
|
|
253
|
+
...issue,
|
|
254
|
+
title: scrubbed(issue.title),
|
|
255
|
+
})),
|
|
256
|
+
},
|
|
257
|
+
ci: composeCi(instance, truncations),
|
|
258
|
+
tests: composeTests(instance, truncations),
|
|
259
|
+
environments: composeEnvironments(instance, truncations),
|
|
260
|
+
merge: composeMerge(instance),
|
|
261
|
+
observability: { runUrl: inputs.runUrl },
|
|
262
|
+
truncations,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
// ---------------------------------------------------------------------------
|
|
266
|
+
// Rendering.
|
|
267
|
+
// ---------------------------------------------------------------------------
|
|
268
|
+
/** A 0..1 score as a rounded percentage, matching how the merge notifications phrase them. */
|
|
269
|
+
function pct(score) {
|
|
270
|
+
return `${Math.round(score * 100)}%`;
|
|
271
|
+
}
|
|
272
|
+
// Interpolation of untrusted text goes through `cell` / `inline` / `prose`
|
|
273
|
+
// (`prReportText.logic.ts`) — never a bare template hole. See that module's header for what a
|
|
274
|
+
// PR body does to raw text.
|
|
275
|
+
function renderCi(ci) {
|
|
276
|
+
const out = ['### Continuous integration', ''];
|
|
277
|
+
if (ci.status === 'absent')
|
|
278
|
+
return [...out, `_${ci.note}_`, ''];
|
|
279
|
+
const verdict = ci.verdict === 'pass'
|
|
280
|
+
? '✅ green'
|
|
281
|
+
: ci.verdict === 'fail'
|
|
282
|
+
? '❌ failing'
|
|
283
|
+
: ci.verdict === 'pending'
|
|
284
|
+
? '⏳ still running'
|
|
285
|
+
: 'not reported';
|
|
286
|
+
out.push(`**Verdict:** ${verdict}` + (ci.headSha ? ` (head \`${ci.headSha}\`)` : ''));
|
|
287
|
+
out.push(`**Fixer attempts:** ${ci.fixerAttempts}` +
|
|
288
|
+
(ci.maxFixerAttempts != null ? ` of ${ci.maxFixerAttempts}` : ''));
|
|
289
|
+
if (ci.failingChecks.length) {
|
|
290
|
+
out.push('', '| Check | Conclusion |', '| --- | --- |');
|
|
291
|
+
for (const check of ci.failingChecks) {
|
|
292
|
+
const name = check.url ? `[${cell(check.name)}](${check.url})` : cell(check.name);
|
|
293
|
+
out.push(`| ${name} | ${cell(check.conclusion ?? 'unknown')} |`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return [...out, ''];
|
|
297
|
+
}
|
|
298
|
+
function renderTests(tests) {
|
|
299
|
+
const out = ['### Test verification', ''];
|
|
300
|
+
if (tests.status === 'absent')
|
|
301
|
+
return [...out, `_${tests.note}_`, ''];
|
|
302
|
+
out.push(`**Greenlight:** ${tests.greenlight ? '✅ yes' : '❌ withheld'}`);
|
|
303
|
+
if (tests.environment)
|
|
304
|
+
out.push(`**Environment:** ${tests.environment}`);
|
|
305
|
+
out.push(`**Fixer attempts:** ${tests.fixerAttempts}` +
|
|
306
|
+
(tests.maxFixerAttempts != null ? ` of ${tests.maxFixerAttempts}` : ''));
|
|
307
|
+
if (tests.summary)
|
|
308
|
+
out.push('', prose(tests.summary));
|
|
309
|
+
if (tests.tested.length) {
|
|
310
|
+
out.push('', '**Exercised:**', ...tests.tested.map((t) => `- ${t}`));
|
|
311
|
+
}
|
|
312
|
+
if (tests.outcomes.length) {
|
|
313
|
+
out.push('', '| Area | Result | Detail |', '| --- | --- | --- |');
|
|
314
|
+
for (const outcome of tests.outcomes) {
|
|
315
|
+
out.push(`| ${cell(outcome.name)} | ${cell(outcome.status)} | ${cell(outcome.detail ?? '')} |`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (tests.concerns.length) {
|
|
319
|
+
out.push('', '**Outstanding concerns:**', ...tests.concerns.map((c) => `- \`${c.severity}\` ${c.title}`));
|
|
320
|
+
}
|
|
321
|
+
return [...out, ''];
|
|
322
|
+
}
|
|
323
|
+
function renderEnvironments(envs) {
|
|
324
|
+
const out = ['### Ephemeral environment', ''];
|
|
325
|
+
if (envs.status === 'absent')
|
|
326
|
+
return [...out, `_${envs.note}_`, ''];
|
|
327
|
+
out.push('| Service frame | State | URL | Error |', '| --- | --- | --- | --- |');
|
|
328
|
+
for (const entry of envs.entries) {
|
|
329
|
+
out.push(`| \`${cell(entry.frameId)}\` | ${entry.status} | ${cell(entry.url ?? '')} | ${cell(entry.error ?? '')} |`);
|
|
330
|
+
}
|
|
331
|
+
const teardown = envs.teardown === 'confirmed'
|
|
332
|
+
? '✅ torn down'
|
|
333
|
+
: envs.teardown === 'pending'
|
|
334
|
+
? '⏳ still live'
|
|
335
|
+
: 'nothing to tear down';
|
|
336
|
+
return [...out, '', `**Teardown:** ${teardown}`, ''];
|
|
337
|
+
}
|
|
338
|
+
function renderMerge(merge) {
|
|
339
|
+
const out = ['### Merge assessment', ''];
|
|
340
|
+
if (merge.status === 'absent')
|
|
341
|
+
return [...out, `_${merge.note}_`, ''];
|
|
342
|
+
if (merge.assessment) {
|
|
343
|
+
out.push(`**Complexity** ${pct(merge.assessment.complexity)} · ` +
|
|
344
|
+
`**Risk** ${pct(merge.assessment.risk)} · ` +
|
|
345
|
+
`**Impact** ${pct(merge.assessment.impact)}` +
|
|
346
|
+
(merge.presetName ? ` (preset: ${merge.presetName})` : ''));
|
|
347
|
+
if (merge.assessment.rationale)
|
|
348
|
+
out.push('', prose(merge.assessment.rationale));
|
|
349
|
+
}
|
|
350
|
+
if (merge.outcome) {
|
|
351
|
+
out.push('', `**Engine decision:** ${merge.outcome}` + (merge.reason ? ` — ${merge.reason}` : ''));
|
|
352
|
+
}
|
|
353
|
+
return [...out, ''];
|
|
354
|
+
}
|
|
355
|
+
function renderRun(run, runUrl) {
|
|
356
|
+
const out = [
|
|
357
|
+
'### Run',
|
|
358
|
+
'',
|
|
359
|
+
`**Task:** ${inline(run.blockTitle)} (\`${run.blockId}\`)`,
|
|
360
|
+
`**Pipeline:** ${inline(run.pipelineName)} (\`${run.pipelineId}\`)`,
|
|
361
|
+
`**Execution:** \`${run.executionId}\``,
|
|
362
|
+
];
|
|
363
|
+
if (run.repo)
|
|
364
|
+
out.push(`**Repository:** ${run.repo}${run.provider ? ` (${run.provider})` : ''}`);
|
|
365
|
+
if (run.issues.length) {
|
|
366
|
+
out.push(`**Tracker issues:** ${run.issues.map((i) => `[${inline(i.title)}](${i.url})`).join(', ')}`);
|
|
367
|
+
}
|
|
368
|
+
if (runUrl)
|
|
369
|
+
out.push(`**Observability:** [Model activity / Provided context](${runUrl})`);
|
|
370
|
+
out.push('', '| # | Step | State | Model |', '| --- | --- | --- | --- |');
|
|
371
|
+
for (const step of run.steps) {
|
|
372
|
+
out.push(`| ${step.index + 1} | ${cell(step.agentKind)} | ${cell(step.state)} | ${step.model ? cell(step.model) : '—'} |`);
|
|
373
|
+
}
|
|
374
|
+
return [...out, ''];
|
|
375
|
+
}
|
|
376
|
+
/** Name whatever the report had to leave out, so a capped list never reads as a complete one. */
|
|
377
|
+
function renderTruncations(truncations) {
|
|
378
|
+
if (!truncations.length)
|
|
379
|
+
return [];
|
|
380
|
+
return [
|
|
381
|
+
'### Omitted for length',
|
|
382
|
+
'',
|
|
383
|
+
...truncations.map((note) => `- ${cell(note)}`),
|
|
384
|
+
'',
|
|
385
|
+
'_The full values are in the run’s observability panel._',
|
|
386
|
+
'',
|
|
387
|
+
];
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Render the report as the managed PR-body section: human-readable markdown followed by a
|
|
391
|
+
* fenced JSON block carrying the exact {@link PrVerificationReport} shape, so external
|
|
392
|
+
* tooling can ingest it without scraping prose. The caller splices the result into the PR
|
|
393
|
+
* body between the kernel's markers — this function emits the section CONTENTS only.
|
|
394
|
+
*/
|
|
395
|
+
export function renderPrVerificationReport(report) {
|
|
396
|
+
const body = [
|
|
397
|
+
'## 🐈 Verification report',
|
|
398
|
+
'',
|
|
399
|
+
'_Maintained by cat-factory. These are captured facts from the run that produced this PR,',
|
|
400
|
+
"not the agent's own claims. It is rewritten in place as the run progresses._",
|
|
401
|
+
'',
|
|
402
|
+
...renderRun(report.run, report.observability.runUrl),
|
|
403
|
+
...renderCi(report.ci),
|
|
404
|
+
...renderTests(report.tests),
|
|
405
|
+
...renderEnvironments(report.environments),
|
|
406
|
+
...renderMerge(report.merge),
|
|
407
|
+
...renderTruncations(report.truncations),
|
|
408
|
+
].join('\n');
|
|
409
|
+
const json = [
|
|
410
|
+
'<details><summary>Machine-readable report (JSON)</summary>',
|
|
411
|
+
'',
|
|
412
|
+
'```json',
|
|
413
|
+
JSON.stringify(report, null, 2),
|
|
414
|
+
'```',
|
|
415
|
+
'',
|
|
416
|
+
'</details>',
|
|
417
|
+
].join('\n');
|
|
418
|
+
// The machine-readable half is the droppable one: a reviewer reads the prose above, while the
|
|
419
|
+
// JSON block is bulk an external consumer can re-fetch from the API. So when the section would
|
|
420
|
+
// blow the host's body limit — only reachable with pathological data, since every field is
|
|
421
|
+
// capped at compose time — the JSON goes and a note SAYS it went. Failing the publish instead
|
|
422
|
+
// would leave the PR with no report at all, and silently forever (publishing is best-effort
|
|
423
|
+
// by design), which is the outcome this budget exists to avoid.
|
|
424
|
+
const full = `${body}\n${json}`;
|
|
425
|
+
if (full.length <= MAX_SECTION_CHARS)
|
|
426
|
+
return full;
|
|
427
|
+
const dropped = `${body}\n_The machine-readable JSON block was omitted: this report exceeds the ${MAX_SECTION_CHARS}-character budget for a pull-request description._`;
|
|
428
|
+
if (dropped.length <= MAX_SECTION_CHARS)
|
|
429
|
+
return dropped;
|
|
430
|
+
// Absolute backstop: the prose alone is over budget. Cut it rather than let the host reject
|
|
431
|
+
// the whole write.
|
|
432
|
+
return `${dropped.slice(0, MAX_SECTION_CHARS - TRUNCATED_SECTION_NOTE.length)}${TRUNCATED_SECTION_NOTE}`;
|
|
433
|
+
}
|
|
434
|
+
/** Closes a section that had to be cut at {@link MAX_SECTION_CHARS}. */
|
|
435
|
+
const TRUNCATED_SECTION_NOTE = '\n\n_… report truncated to fit the pull-request body limit._';
|
|
436
|
+
//# sourceMappingURL=prReport.logic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prReport.logic.js","sourceRoot":"","sources":["../../../src/modules/execution/prReport.logic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Free-text prose (a tester summary, a merge rationale) is capped at this many characters. */
|
|
2
|
+
export declare const MAX_PROSE_CHARS = 4000;
|
|
3
|
+
/** A single markdown table cell is capped at this many characters. */
|
|
4
|
+
export declare const MAX_CELL_CHARS = 300;
|
|
5
|
+
/** Any rendered list/table in the report is capped at this many rows. */
|
|
6
|
+
export declare const MAX_LIST_ITEMS = 50;
|
|
7
|
+
/**
|
|
8
|
+
* Hard ceiling for the whole rendered section. GitHub rejects a PR body over 65,536
|
|
9
|
+
* characters with a 422, and the body also has to hold the agent's own description, so the
|
|
10
|
+
* managed region keeps well clear of the limit. With the per-field caps above this is
|
|
11
|
+
* unreachable for realistic runs; it exists so that pathological data degrades visibly
|
|
12
|
+
* instead of making every publish fail silently forever.
|
|
13
|
+
*/
|
|
14
|
+
export declare const MAX_SECTION_CHARS = 50000;
|
|
15
|
+
/**
|
|
16
|
+
* Close any code fence the text leaves open.
|
|
17
|
+
*
|
|
18
|
+
* An unbalanced fence in agent prose — an interrupted transcript, a truncated tool dump — would
|
|
19
|
+
* otherwise swallow every section rendered after it, including the fenced JSON block that is
|
|
20
|
+
* the report's machine-readable contract. Balancing preserves the agent's own formatting
|
|
21
|
+
* (unlike escaping the fences) while guaranteeing the enclosing document stays well-formed.
|
|
22
|
+
*/
|
|
23
|
+
export declare function balanceFences(text: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Render untrusted multi-line prose as a safe markdown block: auto-link triggers defused,
|
|
26
|
+
* length capped, and any code fence the value leaves open closed again.
|
|
27
|
+
*/
|
|
28
|
+
export declare function prose(value: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Render untrusted text as ONE markdown table cell: newlines folded to `<br>` (a raw newline
|
|
31
|
+
* ends the row and spills the rest of the value into the document as loose prose), pipes
|
|
32
|
+
* escaped so a value cannot open a new column, auto-link triggers defused, and the whole thing
|
|
33
|
+
* capped so a stack trace cannot dominate the table.
|
|
34
|
+
*/
|
|
35
|
+
export declare function cell(value: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Render untrusted text INLINE (a title, a label — not a table cell, so pipes are harmless).
|
|
38
|
+
* Newlines are folded to spaces because the surrounding line has its own meaning.
|
|
39
|
+
*/
|
|
40
|
+
export declare function inline(value: string): string;
|
|
41
|
+
/** Cap a list at {@link MAX_LIST_ITEMS}, returning the kept rows plus how many were dropped. */
|
|
42
|
+
export declare function capList<T>(items: readonly T[]): {
|
|
43
|
+
items: T[];
|
|
44
|
+
dropped: number;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=prReportText.logic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prReportText.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/prReportText.logic.ts"],"names":[],"mappings":"AAmBA,+FAA+F;AAC/F,eAAO,MAAM,eAAe,OAAQ,CAAA;AACpC,sEAAsE;AACtE,eAAO,MAAM,cAAc,MAAM,CAAA;AACjC,yEAAyE;AACzE,eAAO,MAAM,cAAc,KAAK,CAAA;AAChC;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,QAAS,CAAA;AA8GvC;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGlD;AAWD;;;GAGG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ3C;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAK1C;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,gGAAgG;AAChG,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG;IAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAG/E"}
|