@plumloom/cli 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-comment.d.ts","sourceRoot":"","sources":["../../src/github/pr-comment.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAGL,KAAK,yBAAyB,EAC/B,MAAM,yBAAyB,CAAC;AAcjC,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B;IACE,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,yBAAyB,CAAC,aAAa,CAAC,CAAC;CACvD,GACD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GACxD,OAAO,CAGT;AA8CD,wBAAsB,+BAA+B,CAAC,KAAK,EAAE;IAC3D,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC1D,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE,wBAAwB,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA0EnE;AA+ED,wBAAsB,wBAAwB,CAAC,KAAK,EAAE;IACpD,OAAO,EAAE,wBAAwB,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAgEhE;AAED;;;GAGG;AACH,wBAAsB,8BAA8B,CAAC,KAAK,EAAE;IAC1D,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC1D,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA6B/B"}
@@ -0,0 +1,287 @@
1
+ import { open } from 'node:fs/promises';
2
+ import { posix } from 'node:path';
3
+ import { createReliabilityReportMarker, renderReliabilityReport, } from './reliability-report.js';
4
+ const MAX_EVENT_BYTES = 1024 * 1024;
5
+ const MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
6
+ const MAX_COMMENT_CHARS = 65_536;
7
+ const MAX_COMMENT_PAGES = 100;
8
+ const REQUEST_TIMEOUT_MS = 15_000;
9
+ export function githubReliabilityReportingEnabled(environment) {
10
+ const value = environment.AUTOEVAL_PR_RELIABILITY_COMMENT?.trim().toLowerCase();
11
+ return value === '1' || value === 'true';
12
+ }
13
+ async function readBoundedJsonFile(path) {
14
+ const handle = await open(path, 'r');
15
+ try {
16
+ const metadata = await handle.stat();
17
+ if (!metadata.isFile() || metadata.size > MAX_EVENT_BYTES) {
18
+ throw new Error('GitHub event payload is unavailable or too large.');
19
+ }
20
+ const content = await handle.readFile('utf8');
21
+ return JSON.parse(content);
22
+ }
23
+ catch (error) {
24
+ if (error instanceof SyntaxError) {
25
+ throw new Error('GitHub event payload is invalid JSON.', { cause: error });
26
+ }
27
+ throw error;
28
+ }
29
+ finally {
30
+ await handle.close();
31
+ }
32
+ }
33
+ function asObject(input) {
34
+ return input !== null && typeof input === 'object' && !Array.isArray(input)
35
+ ? input
36
+ : undefined;
37
+ }
38
+ function repositoryParts(repository) {
39
+ const match = /^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/u.exec(repository);
40
+ return match?.[1] && match[2] ? { owner: match[1], repo: match[2] } : undefined;
41
+ }
42
+ function normalizedHttpsUrl(input) {
43
+ try {
44
+ const url = new URL(input);
45
+ if (url.protocol !== 'https:')
46
+ return undefined;
47
+ return url.toString().replace(/\/$/u, '');
48
+ }
49
+ catch {
50
+ return undefined;
51
+ }
52
+ }
53
+ function normalizedManifestIdentity(input) {
54
+ return posix.normalize(input.replaceAll('\\', '/'));
55
+ }
56
+ export async function resolveGithubPullRequestContext(input) {
57
+ const environment = input.environment;
58
+ if (!githubReliabilityReportingEnabled(environment)) {
59
+ return { reason: 'reporting is disabled' };
60
+ }
61
+ if (environment.GITHUB_EVENT_NAME !== 'pull_request') {
62
+ return { reason: 'the workflow event is not pull_request' };
63
+ }
64
+ const token = environment.GITHUB_TOKEN?.trim();
65
+ if (!token)
66
+ return { reason: 'GITHUB_TOKEN is unavailable' };
67
+ const repository = environment.GITHUB_REPOSITORY?.trim();
68
+ if (!repository || !repositoryParts(repository)) {
69
+ return { reason: 'GITHUB_REPOSITORY is unavailable or invalid' };
70
+ }
71
+ const eventPath = environment.GITHUB_EVENT_PATH?.trim();
72
+ if (!eventPath)
73
+ return { reason: 'GITHUB_EVENT_PATH is unavailable' };
74
+ let event;
75
+ try {
76
+ event = asObject(await readBoundedJsonFile(eventPath)) ?? {};
77
+ }
78
+ catch {
79
+ return { reason: 'the GitHub pull-request event could not be read' };
80
+ }
81
+ const pullRequest = asObject(event.pull_request);
82
+ const headRepository = asObject(asObject(pullRequest?.head)?.repo)?.full_name;
83
+ if (typeof headRepository !== 'string' ||
84
+ headRepository.toLowerCase() !== repository.toLowerCase()) {
85
+ return { reason: 'fork pull requests are not eligible for comments' };
86
+ }
87
+ const eventNumber = event.number ?? pullRequest?.number;
88
+ if (typeof eventNumber !== 'number' || !Number.isInteger(eventNumber) || eventNumber <= 0) {
89
+ return { reason: 'the pull-request number is unavailable' };
90
+ }
91
+ const apiUrl = normalizedHttpsUrl(environment.GITHUB_API_URL ?? 'https://api.github.com');
92
+ if (!apiUrl)
93
+ return { reason: 'GITHUB_API_URL is unavailable or invalid' };
94
+ const serverUrl = normalizedHttpsUrl(environment.GITHUB_SERVER_URL ?? 'https://github.com');
95
+ const runId = environment.GITHUB_RUN_ID?.trim();
96
+ const actionsRunUrl = serverUrl && runId
97
+ ? `${serverUrl}/${repository}/actions/runs/${encodeURIComponent(runId)}`
98
+ : undefined;
99
+ const jobValue = environment.GITHUB_JOB?.trim();
100
+ const job = jobValue === undefined || jobValue === '' ? 'job' : jobValue;
101
+ const matrixIdentityValue = environment.AUTOEVAL_REPORT_MATRIX_ID?.trim();
102
+ const matrixIdentity = matrixIdentityValue === undefined || matrixIdentityValue === ''
103
+ ? 'default'
104
+ : matrixIdentityValue;
105
+ const expectedAuthorValue = environment.AUTOEVAL_GITHUB_COMMENT_AUTHOR?.trim();
106
+ const expectedAuthorLogin = expectedAuthorValue === undefined || expectedAuthorValue === ''
107
+ ? 'github-actions[bot]'
108
+ : expectedAuthorValue;
109
+ const reportIdentity = [
110
+ repository,
111
+ normalizedManifestIdentity(input.manifestFile),
112
+ job,
113
+ matrixIdentity,
114
+ ].join('\n');
115
+ return {
116
+ context: {
117
+ apiUrl,
118
+ repository,
119
+ pullRequestNumber: eventNumber,
120
+ token,
121
+ expectedAuthorLogin,
122
+ ...(actionsRunUrl ? { actionsRunUrl } : {}),
123
+ reportIdentity,
124
+ },
125
+ };
126
+ }
127
+ async function readBoundedJson(response) {
128
+ const contentLength = Number(response.headers.get('content-length'));
129
+ if (Number.isFinite(contentLength) && contentLength > MAX_RESPONSE_BYTES) {
130
+ throw new Error('GitHub comment response exceeded the allowed size.');
131
+ }
132
+ if (!response.body)
133
+ return undefined;
134
+ const reader = response.body.getReader();
135
+ const chunks = [];
136
+ let totalBytes = 0;
137
+ while (true) {
138
+ const result = await reader.read();
139
+ if (result.done)
140
+ break;
141
+ totalBytes += result.value.byteLength;
142
+ if (totalBytes > MAX_RESPONSE_BYTES) {
143
+ await reader.cancel();
144
+ throw new Error('GitHub comment response exceeded the allowed size.');
145
+ }
146
+ chunks.push(result.value);
147
+ }
148
+ const bytes = new Uint8Array(totalBytes);
149
+ let offset = 0;
150
+ for (const chunk of chunks) {
151
+ bytes.set(chunk, offset);
152
+ offset += chunk.byteLength;
153
+ }
154
+ const text = new TextDecoder().decode(bytes);
155
+ return text === '' ? undefined : JSON.parse(text);
156
+ }
157
+ function requestSignal(signal) {
158
+ const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS);
159
+ return signal ? AbortSignal.any([signal, timeout]) : timeout;
160
+ }
161
+ async function githubRequest(input) {
162
+ const response = await input.fetchImplementation(`${input.context.apiUrl}${input.path}`, {
163
+ method: input.method,
164
+ headers: {
165
+ accept: 'application/vnd.github+json',
166
+ authorization: `Bearer ${input.context.token}`,
167
+ 'x-github-api-version': '2022-11-28',
168
+ ...(input.body ? { 'content-type': 'application/json' } : {}),
169
+ },
170
+ ...(input.body ? { body: JSON.stringify(input.body) } : {}),
171
+ signal: requestSignal(input.signal),
172
+ });
173
+ const payload = await readBoundedJson(response);
174
+ if (!response.ok) {
175
+ throw new Error(`GitHub comment request failed with HTTP ${response.status}.`);
176
+ }
177
+ return payload;
178
+ }
179
+ function parseComments(input) {
180
+ if (!Array.isArray(input))
181
+ throw new Error('GitHub returned an invalid comment list.');
182
+ return input.flatMap((item) => {
183
+ const comment = asObject(item);
184
+ const user = asObject(comment?.user);
185
+ return typeof comment?.id === 'number' && typeof comment.body === 'string'
186
+ ? [
187
+ {
188
+ id: comment.id,
189
+ body: comment.body,
190
+ ...(typeof user?.login === 'string' ? { authorLogin: user.login } : {}),
191
+ },
192
+ ]
193
+ : [];
194
+ });
195
+ }
196
+ export async function upsertPullRequestComment(input) {
197
+ if (input.body.length > MAX_COMMENT_CHARS) {
198
+ throw new Error('Autoeval reliability report exceeded the GitHub comment limit.');
199
+ }
200
+ const repository = repositoryParts(input.context.repository);
201
+ if (!repository)
202
+ throw new Error('GitHub repository identity is invalid.');
203
+ const fetchImplementation = input.fetchImplementation ?? fetch;
204
+ const commentsPath = `/repos/${encodeURIComponent(repository.owner)}/${encodeURIComponent(repository.repo)}/issues/${input.context.pullRequestNumber}/comments`;
205
+ let existing;
206
+ let paginationComplete = false;
207
+ for (let page = 1; page <= MAX_COMMENT_PAGES; page += 1) {
208
+ const payload = await githubRequest({
209
+ context: input.context,
210
+ path: `${commentsPath}?per_page=100&page=${page}`,
211
+ method: 'GET',
212
+ fetchImplementation,
213
+ ...(input.signal ? { signal: input.signal } : {}),
214
+ });
215
+ const comments = parseComments(payload);
216
+ existing = comments.find((comment) => comment.authorLogin === input.context.expectedAuthorLogin &&
217
+ comment.body.includes(input.marker));
218
+ if (existing)
219
+ break;
220
+ if (comments.length < 100) {
221
+ paginationComplete = true;
222
+ break;
223
+ }
224
+ }
225
+ if (!existing && !paginationComplete) {
226
+ throw new Error('GitHub comment pagination exceeded the allowed page limit.');
227
+ }
228
+ if (existing) {
229
+ const payload = asObject(await githubRequest({
230
+ context: input.context,
231
+ path: `/repos/${encodeURIComponent(repository.owner)}/${encodeURIComponent(repository.repo)}/issues/comments/${existing.id}`,
232
+ method: 'PATCH',
233
+ body: { body: input.body },
234
+ fetchImplementation,
235
+ ...(input.signal ? { signal: input.signal } : {}),
236
+ }));
237
+ const commentId = typeof payload?.id === 'number' ? payload.id : existing.id;
238
+ return { status: 'updated', commentId };
239
+ }
240
+ const payload = asObject(await githubRequest({
241
+ context: input.context,
242
+ path: commentsPath,
243
+ method: 'POST',
244
+ body: { body: input.body },
245
+ fetchImplementation,
246
+ ...(input.signal ? { signal: input.signal } : {}),
247
+ }));
248
+ if (typeof payload?.id !== 'number')
249
+ throw new Error('GitHub returned an invalid created comment.');
250
+ return { status: 'created', commentId: payload.id };
251
+ }
252
+ /**
253
+ * Best-effort PR reporting. Every setup, permission, and REST failure becomes a
254
+ * result value so it can never replace the suite gate's verdict or exit code.
255
+ */
256
+ export async function publishGithubReliabilityReport(input) {
257
+ const resolved = await resolveGithubPullRequestContext({
258
+ environment: input.environment,
259
+ manifestFile: input.manifestFile,
260
+ });
261
+ if (!resolved.context)
262
+ return { status: 'skipped', reason: resolved.reason ?? 'not eligible' };
263
+ try {
264
+ const marker = createReliabilityReportMarker(resolved.context.reportIdentity);
265
+ const rendered = renderReliabilityReport({
266
+ gate: input.gate,
267
+ summary: input.summary,
268
+ marker,
269
+ ...(resolved.context.actionsRunUrl ? { actionsRunUrl: resolved.context.actionsRunUrl } : {}),
270
+ });
271
+ const result = await upsertPullRequestComment({
272
+ context: resolved.context,
273
+ marker,
274
+ body: rendered.markdown,
275
+ ...(input.fetchImplementation ? { fetchImplementation: input.fetchImplementation } : {}),
276
+ ...(input.signal ? { signal: input.signal } : {}),
277
+ });
278
+ return { ...result, detailLevel: rendered.detailLevel };
279
+ }
280
+ catch (error) {
281
+ return {
282
+ status: 'failed',
283
+ reason: error instanceof Error ? error.message : 'GitHub reliability comment failed.',
284
+ };
285
+ }
286
+ }
287
+ //# sourceMappingURL=pr-comment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-comment.js","sourceRoot":"","sources":["../../src/github/pr-comment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { SuiteGateResult } from '../actions/suite-gate.js';
2
+ import type { SuiteSummary } from '../actions/suite.js';
3
+ export type ReliabilityReportInput = {
4
+ gate: SuiteGateResult;
5
+ summary: SuiteSummary;
6
+ actionsRunUrl?: string;
7
+ marker: string;
8
+ };
9
+ export type RenderedReliabilityReport = {
10
+ markdown: string;
11
+ detailLevel: 'full' | 'summary' | 'critical' | 'minimal';
12
+ };
13
+ export declare function createReliabilityReportMarker(identity: string): string;
14
+ /** Deterministic, context-aware Markdown over already-sanitized suite evidence. */
15
+ export declare function renderReliabilityReport(input: ReliabilityReportInput): RenderedReliabilityReport;
16
+ //# sourceMappingURL=reliability-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reliability-report.d.ts","sourceRoot":"","sources":["../../src/github/reliability-report.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA6BxD,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;CAC1D,CAAC;AAyVF,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGtE;AAED,mFAAmF;AACnF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,sBAAsB,GAAG,yBAAyB,CAgBhG"}
@@ -0,0 +1,341 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { redactText } from '../auth/redact.js';
3
+ import { extractJudgmentEvidence, extractScenarioRepeatabilityEvidence, } from '../reliability/evidence.js';
4
+ const GITHUB_COMMENT_LIMIT = 65_536;
5
+ const REPORT_LIMIT = 65_000;
6
+ const MAX_CELL_CHARS = 280;
7
+ function sanitizedText(input, maxChars) {
8
+ const withoutControls = Array.from(redactText(input), (character) => {
9
+ const codePoint = character.codePointAt(0) ?? 0;
10
+ return codePoint <= 31 || (codePoint >= 127 && codePoint <= 159) ? ' ' : character;
11
+ }).join('');
12
+ const clipped = withoutControls.length > maxChars
13
+ ? `${withoutControls.slice(0, maxChars - 1)}…`
14
+ : withoutControls;
15
+ return clipped.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
16
+ }
17
+ function clean(input, maxChars = 1_000) {
18
+ return sanitizedText(input, maxChars).replace(/([\\`*_[\]{}()#+.!|])/gu, '\\$1');
19
+ }
20
+ function cell(input) {
21
+ return clean(input.replace(/[\r\n]+/gu, ' '), MAX_CELL_CHARS);
22
+ }
23
+ function number(input) {
24
+ return Number.isInteger(input) ? String(input) : input.toFixed(3).replace(/0+$/u, '');
25
+ }
26
+ function safeRunUrl(input) {
27
+ if (!input)
28
+ return undefined;
29
+ try {
30
+ const url = new URL(input);
31
+ return url.protocol === 'https:' ? url.toString() : undefined;
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ }
37
+ function contextLabel(context) {
38
+ switch (context) {
39
+ case 'scenario':
40
+ return 'Live scenario';
41
+ case 'conversation':
42
+ return 'Frozen conversation';
43
+ case 'agent_trace':
44
+ return 'Frozen agent trace';
45
+ default:
46
+ return 'Unknown';
47
+ }
48
+ }
49
+ function standardSummary(standard) {
50
+ if (!standard?.rubricApplied)
51
+ return 'Not available';
52
+ const parts = ['Rubric'];
53
+ if (standard.judgeModel) {
54
+ parts.push(`judge ${standard.judgeModel}${standard.judgeModelPinned ? ' (pinned)' : ''}`);
55
+ }
56
+ if (standard.qualityStandardStatus === 'not_configured') {
57
+ parts.push('QS: Not configured');
58
+ }
59
+ else if (standard.qualityStandardStatus === 'not_available') {
60
+ parts.push('QS: Not available');
61
+ }
62
+ else {
63
+ const name = standard.qualityStandardName ?? 'applied';
64
+ const version = standard.qualityStandardVersion
65
+ ? `; version ${standard.qualityStandardVersion}`
66
+ : '';
67
+ const anchors = standard.anchorCount === undefined ? '' : `; ${standard.anchorCount} anchors`;
68
+ parts.push(`QS: ${name}${version}${anchors}`);
69
+ }
70
+ return parts.join('; ');
71
+ }
72
+ function judgmentLine(evidence) {
73
+ const count = evidence.assessmentCount;
74
+ if (count === 1)
75
+ return `K=1; Agreement not measured`;
76
+ if (count === undefined)
77
+ return 'K: Not available';
78
+ if (evidence.passVotes !== undefined) {
79
+ return `K=${count}; ${evidence.passVotes}/${count} pass votes`;
80
+ }
81
+ if (evidence.agreedAssessments !== undefined) {
82
+ return `K=${count}; ${evidence.agreedAssessments}/${count} assessments agreed`;
83
+ }
84
+ return `K=${count}; agreement evidence Not available`;
85
+ }
86
+ function judgmentSummary(entries) {
87
+ if (entries.length === 0)
88
+ return 'Not available';
89
+ if (entries.length === 1 && entries[0])
90
+ return judgmentLine(entries[0]);
91
+ return entries.map((entry) => `${entry.scope}: ${judgmentLine(entry)}`).join('; ');
92
+ }
93
+ function repeatabilitySummary(evaluation) {
94
+ if (evaluation.context === 'conversation' || evaluation.context === 'agent_trace') {
95
+ return 'N/A: frozen input; behavioral repeatability not measured';
96
+ }
97
+ if (evaluation.context === 'unknown')
98
+ return 'Not available';
99
+ if (evaluation.decision === 'ERROR' && evaluation.repeatability?.statistics.length === 0) {
100
+ return 'Error';
101
+ }
102
+ const evidence = evaluation.repeatability;
103
+ if (!evidence)
104
+ return 'Not available';
105
+ const trials = evidence.completedTrials;
106
+ const hasStatistics = evidence.statistics.length > 0;
107
+ const insufficient = trials === 1 || evidence.statistics.some((entry) => entry.insufficientEvidence === true);
108
+ if (insufficient) {
109
+ return `${trials === undefined ? 'Trial count Not available' : `${trials} trial`}; Insufficient evidence`;
110
+ }
111
+ if (trials !== undefined) {
112
+ return `${trials} trials; statistics ${hasStatistics ? 'available' : 'Not available'}`;
113
+ }
114
+ return hasStatistics ? 'Trial count Not available; statistics available' : 'Not available';
115
+ }
116
+ function reportEvaluations(input) {
117
+ const summaryByIndex = new Map(input.summary.evals.map((entry) => [entry.index, entry]));
118
+ return [...input.gate.perEvalDecisions]
119
+ .sort((left, right) => left.index - right.index)
120
+ .map((decision) => {
121
+ const summary = summaryByIndex.get(decision.index);
122
+ const executionContext = summary?.execution?.contextType;
123
+ const decisionContext = decision.contextType;
124
+ const context = executionContext && decisionContext && executionContext !== decisionContext
125
+ ? 'unknown'
126
+ : (executionContext ?? decisionContext ?? 'unknown');
127
+ const results = summary?.results;
128
+ const statusRaw = summary?.execution?.statusRaw;
129
+ return {
130
+ index: decision.index,
131
+ name: decision.evaluationName ?? decision.inputFile,
132
+ context,
133
+ decision: decision.decision,
134
+ checks: decision.checks,
135
+ reason: decision.reason,
136
+ ...(summary?.execution?.standard === undefined
137
+ ? {}
138
+ : { standard: summary.execution.standard }),
139
+ judgment: extractJudgmentEvidence(context === 'unknown' ? undefined : context, results, statusRaw),
140
+ ...(context === 'scenario'
141
+ ? { repeatability: extractScenarioRepeatabilityEvidence(results, statusRaw) }
142
+ : {}),
143
+ };
144
+ });
145
+ }
146
+ function contextCounts(evaluations) {
147
+ const counts = {
148
+ scenario: 0,
149
+ conversation: 0,
150
+ agent_trace: 0,
151
+ unknown: 0,
152
+ };
153
+ for (const evaluation of evaluations)
154
+ counts[evaluation.context] += 1;
155
+ return [
156
+ `${counts.scenario} live scenario`,
157
+ `${counts.conversation} frozen conversation`,
158
+ `${counts.agent_trace} frozen agent trace`,
159
+ ...(counts.unknown > 0 ? [`${counts.unknown} unknown`] : []),
160
+ ].join(' · ');
161
+ }
162
+ function header(input, evaluations) {
163
+ const runUrl = safeRunUrl(input.actionsRunUrl);
164
+ return [
165
+ input.marker,
166
+ `## Autoeval Reliability Report — ${input.gate.suiteDecision}`,
167
+ '',
168
+ `${evaluations.length} evaluations · ${contextCounts(evaluations)}${runUrl ? ` · [GitHub Actions run](${runUrl})` : ''}`,
169
+ '',
170
+ ];
171
+ }
172
+ function legend() {
173
+ return [
174
+ '**Standard:** instructions, Quality Standard, and calibration anchors used.',
175
+ '**Judgment:** evidence from multiple judge assessments.',
176
+ '**Repeatability:** performance variation across independent executions of the system being evaluated.',
177
+ '',
178
+ ];
179
+ }
180
+ function table(evaluations) {
181
+ const lines = [
182
+ '| Evaluation | Context | Gate | Standard | Judgment | Repeatability |',
183
+ '| --- | --- | --- | --- | --- | --- |',
184
+ ];
185
+ for (const evaluation of evaluations) {
186
+ lines.push(`| ${cell(evaluation.name)} | ${cell(contextLabel(evaluation.context))} | **${evaluation.decision}** | ${cell(standardSummary(evaluation.standard))} | ${cell(judgmentSummary(evaluation.judgment))} | ${cell(repeatabilitySummary(evaluation))} |`);
187
+ }
188
+ lines.push('');
189
+ return lines;
190
+ }
191
+ function statisticLine(statistic) {
192
+ if (statistic.hasData === false)
193
+ return `${statistic.scope}: Not measured`;
194
+ if (statistic.insufficientEvidence === true) {
195
+ const sample = statistic.sampleSize === undefined ? '' : ` (n=${statistic.sampleSize})`;
196
+ return `${statistic.scope}: Insufficient evidence${sample}`;
197
+ }
198
+ const fields = [];
199
+ if (statistic.mean !== undefined)
200
+ fields.push(`mean ${number(statistic.mean)}`);
201
+ if (statistic.standardDeviation !== undefined) {
202
+ fields.push(`SD ${number(statistic.standardDeviation)}`);
203
+ }
204
+ if (statistic.ci95Lower !== undefined && statistic.ci95Upper !== undefined) {
205
+ fields.push(`95% CI ${number(statistic.ci95Lower)}–${number(statistic.ci95Upper)}`);
206
+ }
207
+ else if (statistic.ci95HalfWidth !== undefined) {
208
+ fields.push(`reported 95% CI half-width ±${number(statistic.ci95HalfWidth)}`);
209
+ }
210
+ if (statistic.sampleSize !== undefined)
211
+ fields.push(`n=${statistic.sampleSize}`);
212
+ return `${statistic.scope}: ${fields.length === 0 ? 'Not available' : fields.join('; ')}`;
213
+ }
214
+ function missingEvidence(evaluation) {
215
+ const missing = [];
216
+ if (!evaluation.standard?.rubricApplied)
217
+ missing.push('Standard metadata: Not available.');
218
+ else if (evaluation.standard.qualityStandardStatus === 'not_available') {
219
+ missing.push('Quality Standard metadata: Not available for this run.');
220
+ }
221
+ if (evaluation.judgment.length === 0)
222
+ missing.push('Judgment evidence: Not available.');
223
+ else if (evaluation.judgment.some((entry) => (entry.assessmentCount ?? 0) > 1 &&
224
+ entry.passVotes === undefined &&
225
+ entry.agreedAssessments === undefined)) {
226
+ missing.push('Judge agreement evidence: Not available at the reported granularity.');
227
+ }
228
+ if (evaluation.context === 'scenario' && evaluation.repeatability?.statistics.length === 0) {
229
+ missing.push('Repeatability statistics: Not available.');
230
+ }
231
+ if (evaluation.context === 'unknown') {
232
+ missing.push('Authoritative context: Not available; repeatability was not inferred.');
233
+ }
234
+ return missing;
235
+ }
236
+ function details(evaluation, actionsRunUrl) {
237
+ const lines = [
238
+ '<details>',
239
+ `<summary>${evaluation.decision} — ${sanitizedText(evaluation.name, 200)} (${contextLabel(evaluation.context)})</summary>`,
240
+ '',
241
+ `- **Standard:** ${clean(standardSummary(evaluation.standard), 500)}`,
242
+ ];
243
+ if (evaluation.judgment.length === 0) {
244
+ lines.push('- **Judgment:** Not available');
245
+ }
246
+ else {
247
+ lines.push('- **Judgment:**');
248
+ for (const entry of evaluation.judgment) {
249
+ lines.push(` - ${clean(entry.scope)}: ${clean(judgmentLine(entry))}`);
250
+ }
251
+ }
252
+ if (evaluation.context === 'scenario') {
253
+ lines.push(`- **Repeatability:** ${clean(repeatabilitySummary(evaluation))}`);
254
+ for (const statistic of evaluation.repeatability?.statistics ?? []) {
255
+ lines.push(` - ${clean(statisticLine(statistic), 700)}`);
256
+ }
257
+ }
258
+ else {
259
+ lines.push(`- **Repeatability:** ${clean(repeatabilitySummary(evaluation))}`);
260
+ }
261
+ if (evaluation.checks.length === 0) {
262
+ lines.push(`- **Gate checks:** ${clean(evaluation.reason, 700)}`);
263
+ }
264
+ else {
265
+ lines.push('- **Gate checks:**');
266
+ for (const check of evaluation.checks) {
267
+ lines.push(` - ${clean(check.label, 200)}: ${clean(check.actual, 200)}; required ${clean(check.threshold, 200)} → **${check.decision}**${check.decision === 'PASS' ? '' : ` — ${clean(check.reason, 500)}`}`);
268
+ }
269
+ }
270
+ const missing = missingEvidence(evaluation);
271
+ if (missing.length > 0) {
272
+ lines.push('- **Missing evidence:**');
273
+ for (const item of missing)
274
+ lines.push(` - ${item}`);
275
+ }
276
+ if (actionsRunUrl)
277
+ lines.push(`- [Full diagnostics in GitHub Actions](${actionsRunUrl})`);
278
+ lines.push('', '</details>', '');
279
+ return lines;
280
+ }
281
+ function renderFull(input, evaluations) {
282
+ const runUrl = safeRunUrl(input.actionsRunUrl);
283
+ const priority = { ERROR: 3, FAIL: 2, INCONCLUSIVE: 1, PASS: 0 };
284
+ const detailOrder = [...evaluations].sort((left, right) => priority[right.decision] - priority[left.decision] || left.index - right.index);
285
+ return [
286
+ ...header(input, evaluations),
287
+ ...legend(),
288
+ ...table(evaluations),
289
+ ...detailOrder.flatMap((evaluation) => details(evaluation, runUrl)),
290
+ ].join('\n');
291
+ }
292
+ function renderSummary(input, evaluations) {
293
+ return [...header(input, evaluations), ...legend(), ...table(evaluations)].join('\n');
294
+ }
295
+ function renderCritical(input, evaluations) {
296
+ const critical = evaluations.filter((evaluation) => evaluation.decision !== 'PASS');
297
+ return [
298
+ ...header(input, evaluations),
299
+ 'Detailed evidence was omitted to stay within the GitHub comment size limit.',
300
+ '',
301
+ ...(critical.length === 0
302
+ ? ['All evaluations passed. See the Actions run for full diagnostics.', '']
303
+ : table(critical)),
304
+ ].join('\n');
305
+ }
306
+ function renderMinimal(input, evaluations) {
307
+ const runUrl = safeRunUrl(input.actionsRunUrl);
308
+ return [
309
+ input.marker,
310
+ `## Autoeval Reliability Report — ${input.gate.suiteDecision}`,
311
+ '',
312
+ `${evaluations.length} evaluations · ${contextCounts(evaluations)}`,
313
+ ...(runUrl ? ['', `[Full diagnostics in GitHub Actions](${runUrl})`] : []),
314
+ '',
315
+ 'Evaluation details were omitted to stay within the GitHub comment size limit.',
316
+ ].join('\n');
317
+ }
318
+ export function createReliabilityReportMarker(identity) {
319
+ const digest = createHash('sha256').update(identity).digest('hex').slice(0, 24);
320
+ return `<!-- autoeval-reliability-report:${digest} -->`;
321
+ }
322
+ /** Deterministic, context-aware Markdown over already-sanitized suite evidence. */
323
+ export function renderReliabilityReport(input) {
324
+ const evaluations = reportEvaluations(input);
325
+ const candidates = [
326
+ ['full', renderFull(input, evaluations)],
327
+ ['summary', renderSummary(input, evaluations)],
328
+ ['critical', renderCritical(input, evaluations)],
329
+ ['minimal', renderMinimal(input, evaluations)],
330
+ ];
331
+ for (const [detailLevel, markdown] of candidates) {
332
+ if (markdown.length <= REPORT_LIMIT)
333
+ return { markdown, detailLevel };
334
+ }
335
+ const fallback = renderMinimal(input, []);
336
+ if (fallback.length > GITHUB_COMMENT_LIMIT) {
337
+ throw new Error('Autoeval reliability report could not fit within the GitHub comment limit.');
338
+ }
339
+ return { markdown: fallback, detailLevel: 'minimal' };
340
+ }
341
+ //# sourceMappingURL=reliability-report.js.map