@open-cr-agent/core 0.1.2 → 0.3.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/anchor/relocate.d.ts +1 -0
- package/dist/anchor/relocate.js +2 -2
- package/dist/bundle/grouping.d.ts +1 -0
- package/dist/bundle/grouping.js +2 -2
- package/dist/contracts.d.ts +9 -0
- package/dist/domain.d.ts +26 -3
- package/dist/domain.js +8 -0
- package/dist/errors.d.ts +13 -2
- package/dist/errors.js +41 -3
- package/dist/index.d.ts +24 -17
- package/dist/index.js +16 -17
- package/dist/internal.d.ts +21 -0
- package/dist/internal.js +24 -0
- package/dist/judge/judge.js +2 -2
- package/dist/judge/prompt.d.ts +1 -0
- package/dist/judge/prompt.js +2 -2
- package/dist/memory/memory.js +3 -2
- package/dist/net/proxied-fetch.d.ts +10 -0
- package/dist/net/proxied-fetch.js +33 -0
- package/dist/pipeline/budget.d.ts +2 -1
- package/dist/pipeline/budget.js +3 -2
- package/dist/pipeline/context.d.ts +3 -1
- package/dist/pipeline/context.js +6 -1
- package/dist/pipeline/execute.js +6 -3
- package/dist/pipeline/findings.d.ts +2 -2
- package/dist/pipeline/findings.js +2 -1
- package/dist/pipeline/helpers.js +2 -2
- package/dist/pipeline/imports.d.ts +12 -0
- package/dist/pipeline/imports.js +126 -0
- package/dist/pipeline/matrix.d.ts +9 -1
- package/dist/pipeline/matrix.js +8 -0
- package/dist/pipeline/output-schema.d.ts +326 -0
- package/dist/pipeline/output-schema.js +173 -0
- package/dist/pipeline/output.d.ts +8 -0
- package/dist/pipeline/output.js +9 -0
- package/dist/pipeline/plan.d.ts +3 -2
- package/dist/pipeline/plan.js +2 -1
- package/dist/pipeline/provenance.d.ts +23 -0
- package/dist/pipeline/provenance.js +67 -0
- package/dist/pipeline/report.d.ts +21 -2
- package/dist/pipeline/report.js +8 -3
- package/dist/pipeline/run-id.d.ts +2 -0
- package/dist/pipeline/run-id.js +13 -0
- package/dist/pipeline/run.d.ts +13 -5
- package/dist/pipeline/run.js +75 -22
- package/dist/pipeline/task.d.ts +6 -1
- package/dist/pipeline/task.js +5 -2
- package/dist/pipeline/usage.d.ts +1 -0
- package/dist/pipeline/usage.js +6 -0
- package/dist/plugin/registry.d.ts +5 -1
- package/dist/plugin/registry.js +6 -2
- package/dist/plugin/types.d.ts +13 -1
- package/dist/review/plan-phase.d.ts +1 -0
- package/dist/review/plan-phase.js +2 -2
- package/dist/rules/repo-rules.js +3 -2
- package/dist/runtime/attempt.d.ts +22 -0
- package/dist/runtime/attempt.js +37 -0
- package/dist/runtime/failback.d.ts +30 -0
- package/dist/runtime/failback.js +160 -0
- package/dist/runtime/models.d.ts +30 -0
- package/dist/runtime/models.js +89 -0
- package/dist/runtime/quota.d.ts +9 -0
- package/dist/runtime/quota.js +38 -0
- package/dist/runtime/tools.d.ts +21 -0
- package/dist/runtime/tools.js +113 -0
- package/dist/sarif/candidates.d.ts +27 -0
- package/dist/sarif/candidates.js +102 -0
- package/dist/sarif/schema.d.ts +144 -0
- package/dist/sarif/schema.js +71 -0
- package/dist/select/select.d.ts +11 -1
- package/dist/select/select.js +10 -0
- package/dist/session/jsonl.d.ts +0 -1
- package/dist/session/jsonl.js +4 -10
- package/dist/verify/prompt.d.ts +1 -0
- package/dist/verify/prompt.js +2 -2
- package/dist/verify/verify.js +2 -2
- package/package.json +11 -2
- package/dist/anchor/index.d.ts +0 -3
- package/dist/anchor/index.js +0 -3
- package/dist/bundle/index.d.ts +0 -3
- package/dist/bundle/index.js +0 -3
- package/dist/diff/index.d.ts +0 -3
- package/dist/diff/index.js +0 -3
- package/dist/judge/index.d.ts +0 -4
- package/dist/judge/index.js +0 -4
- package/dist/memory/index.d.ts +0 -2
- package/dist/memory/index.js +0 -2
- package/dist/pipeline/index.d.ts +0 -9
- package/dist/pipeline/index.js +0 -9
- package/dist/plugin/index.d.ts +0 -5
- package/dist/plugin/index.js +0 -5
- package/dist/rereview/index.d.ts +0 -4
- package/dist/rereview/index.js +0 -4
- package/dist/review/index.d.ts +0 -10
- package/dist/review/index.js +0 -10
- package/dist/rules/index.d.ts +0 -5
- package/dist/rules/index.js +0 -5
- package/dist/select/index.d.ts +0 -2
- package/dist/select/index.js +0 -2
- package/dist/session/index.d.ts +0 -2
- package/dist/session/index.js +0 -2
- package/dist/verify/index.d.ts +0 -3
- package/dist/verify/index.js +0 -3
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { anchorFinding } from "../anchor/anchor.js";
|
|
2
|
+
import { sarifCandidates } from "../sarif/candidates.js";
|
|
3
|
+
import { toFinding } from "./findings.js";
|
|
4
|
+
import { boundFinding } from "./task.js";
|
|
5
|
+
import { emptyUsage } from "./usage.js";
|
|
6
|
+
// A hostile log could carry thousands of results on the change.
|
|
7
|
+
export const MAX_IMPORTED_PER_RUN = 200;
|
|
8
|
+
export async function importSarif(logs, plan, emit) {
|
|
9
|
+
const windows = changedLines(plan.selected);
|
|
10
|
+
const imported = { findings: [], outcomes: [], warnings: [] };
|
|
11
|
+
const counts = new Map();
|
|
12
|
+
for (const log of logs) {
|
|
13
|
+
for (const run of log.runs) {
|
|
14
|
+
const { tool, candidates, skipped } = sarifCandidates(run);
|
|
15
|
+
const n = (counts.get(tool.slug) ?? 0) + 1;
|
|
16
|
+
counts.set(tool.slug, n);
|
|
17
|
+
const taskId = `sarif-${tool.slug}-${n}`;
|
|
18
|
+
const started = Date.now();
|
|
19
|
+
const onChange = candidates.filter((c) => touches(windows, c));
|
|
20
|
+
const kept = onChange.slice(0, MAX_IMPORTED_PER_RUN);
|
|
21
|
+
const files = [...new Set(kept.map((c) => c.file))];
|
|
22
|
+
emit({ type: "task_started", taskId, reviewer: tool.slug, bundle: "sarif", files });
|
|
23
|
+
let noCode = 0;
|
|
24
|
+
const findings = [];
|
|
25
|
+
for (const candidate of kept) {
|
|
26
|
+
const finding = await toImportedFinding(candidate, tool.slug, taskId, plan);
|
|
27
|
+
if (!finding) {
|
|
28
|
+
noCode += 1;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
findings.push(finding);
|
|
32
|
+
emit({ type: "finding", taskId, finding });
|
|
33
|
+
}
|
|
34
|
+
const outcome = {
|
|
35
|
+
taskId,
|
|
36
|
+
reviewer: tool.slug,
|
|
37
|
+
bundle: "sarif",
|
|
38
|
+
files,
|
|
39
|
+
status: "completed",
|
|
40
|
+
findings: findings.length,
|
|
41
|
+
durationMs: Date.now() - started,
|
|
42
|
+
usage: emptyUsage(),
|
|
43
|
+
};
|
|
44
|
+
emit({ type: "task_finished", outcome });
|
|
45
|
+
imported.findings.push(...findings);
|
|
46
|
+
imported.outcomes.push(outcome);
|
|
47
|
+
imported.warnings.push(...importWarnings(tool.name, {
|
|
48
|
+
imported: findings.length,
|
|
49
|
+
outside: candidates.length - onChange.length,
|
|
50
|
+
overLimit: onChange.length - kept.length,
|
|
51
|
+
noCode,
|
|
52
|
+
...skipped,
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return imported;
|
|
57
|
+
}
|
|
58
|
+
async function toImportedFinding(candidate, reviewer, taskId, plan) {
|
|
59
|
+
const content = await plan.context.readFile(candidate.file).catch(() => undefined);
|
|
60
|
+
const existingCode = candidate.snippet ?? quoteFrom(content, candidate.lines);
|
|
61
|
+
if (!existingCode)
|
|
62
|
+
return undefined;
|
|
63
|
+
const reported = boundFinding({
|
|
64
|
+
category: reviewer,
|
|
65
|
+
severity: candidate.severity,
|
|
66
|
+
file: candidate.file,
|
|
67
|
+
existingCode,
|
|
68
|
+
title: candidate.title,
|
|
69
|
+
body: candidate.body,
|
|
70
|
+
evidence: [],
|
|
71
|
+
});
|
|
72
|
+
// The tool's lines are not trusted over the quote: the same anchoring as
|
|
73
|
+
// for a model's finding decides where the comment lands.
|
|
74
|
+
const anchor = await anchorFinding(reported, {
|
|
75
|
+
diffs: plan.selected,
|
|
76
|
+
readNewFile: plan.context.readFile,
|
|
77
|
+
});
|
|
78
|
+
return toFinding(reported, reviewer, { task: taskId }, anchor, content);
|
|
79
|
+
}
|
|
80
|
+
function quoteFrom(content, lines) {
|
|
81
|
+
if (content === undefined)
|
|
82
|
+
return undefined;
|
|
83
|
+
const quote = content
|
|
84
|
+
.split("\n")
|
|
85
|
+
.slice(lines.start - 1, lines.end)
|
|
86
|
+
.join("\n")
|
|
87
|
+
.trim();
|
|
88
|
+
return quote || undefined;
|
|
89
|
+
}
|
|
90
|
+
// The new-side lines each hunk covers, context included.
|
|
91
|
+
function changedLines(diffs) {
|
|
92
|
+
const windows = new Map();
|
|
93
|
+
for (const diff of diffs) {
|
|
94
|
+
const ranges = diff.hunks
|
|
95
|
+
.filter((h) => h.newLines > 0)
|
|
96
|
+
.map((h) => ({ start: h.newStart, end: h.newStart + h.newLines - 1 }));
|
|
97
|
+
if (ranges.length > 0)
|
|
98
|
+
windows.set(diff.newPath, ranges);
|
|
99
|
+
}
|
|
100
|
+
return windows;
|
|
101
|
+
}
|
|
102
|
+
function touches(windows, candidate) {
|
|
103
|
+
const ranges = windows.get(candidate.file);
|
|
104
|
+
if (!ranges)
|
|
105
|
+
return false;
|
|
106
|
+
return ranges.some((r) => candidate.lines.start <= r.end && candidate.lines.end >= r.start);
|
|
107
|
+
}
|
|
108
|
+
function importWarnings(tool, c) {
|
|
109
|
+
const left = [];
|
|
110
|
+
if (c.outside > 0)
|
|
111
|
+
left.push(`${c.outside} outside the change`);
|
|
112
|
+
if (c.overLimit > 0)
|
|
113
|
+
left.push(`${c.overLimit} over the limit of ${MAX_IMPORTED_PER_RUN} per run`);
|
|
114
|
+
if (c.noCode > 0)
|
|
115
|
+
left.push(`${c.noCode} on lines that could not be read`);
|
|
116
|
+
if (c.noLocation > 0)
|
|
117
|
+
left.push(`${c.noLocation} without a file and lines`);
|
|
118
|
+
if (c.unsupportedUri > 0)
|
|
119
|
+
left.push(`${c.unsupportedUri} on paths outside the repository`);
|
|
120
|
+
if (c.noMessage > 0)
|
|
121
|
+
left.push(`${c.noMessage} without a message`);
|
|
122
|
+
if (left.length === 0)
|
|
123
|
+
return [];
|
|
124
|
+
return [`${tool}: imported ${c.imported} result(s); left out ${left.join(", ")}`];
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=imports.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
1
2
|
import type { Bundle } from "../bundle/bundle.js";
|
|
2
3
|
import type { RiskTier } from "../domain.js";
|
|
3
4
|
import type { ReviewerDefinition } from "../review/reviewer.js";
|
|
@@ -12,7 +13,14 @@ export interface MatrixCell {
|
|
|
12
13
|
reviewer: ReviewerDefinition;
|
|
13
14
|
bundle: Bundle;
|
|
14
15
|
}
|
|
15
|
-
export
|
|
16
|
+
export declare const skipReasonSchema: z.ZodEnum<{
|
|
17
|
+
below_tier: "below_tier";
|
|
18
|
+
disabled: "disabled";
|
|
19
|
+
no_guidelines: "no_guidelines";
|
|
20
|
+
no_matching_files: "no_matching_files";
|
|
21
|
+
task_limit: "task_limit";
|
|
22
|
+
}>;
|
|
23
|
+
export type SkipReason = z.infer<typeof skipReasonSchema>;
|
|
16
24
|
export interface SkippedCell {
|
|
17
25
|
reviewer: string;
|
|
18
26
|
bundle: string;
|
package/dist/pipeline/matrix.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import picomatch from "picomatch";
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
export const RISK_TIERS = ["trivial", "lite", "full"];
|
|
4
|
+
export const skipReasonSchema = z.enum([
|
|
5
|
+
"disabled",
|
|
6
|
+
"below_tier",
|
|
7
|
+
"no_matching_files",
|
|
8
|
+
"no_guidelines",
|
|
9
|
+
"task_limit",
|
|
10
|
+
]);
|
|
3
11
|
// Deterministic: which reviewer runs on which bundle, so cost grows with the
|
|
4
12
|
// risk of the change instead of bundles × reviewers.
|
|
5
13
|
export function planMatrix(bundles, reviewers, tier, overrides = {}, options = {}) {
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type ReportOutput } from "./output.js";
|
|
3
|
+
export declare const outputFindingSchema: z.ZodObject<{
|
|
4
|
+
fingerprint: z.ZodString;
|
|
5
|
+
reviewer: z.ZodString;
|
|
6
|
+
category: z.ZodString;
|
|
7
|
+
severity: z.ZodEnum<{
|
|
8
|
+
critical: "critical";
|
|
9
|
+
suggestion: "suggestion";
|
|
10
|
+
warning: "warning";
|
|
11
|
+
}>;
|
|
12
|
+
verification: z.ZodEnum<{
|
|
13
|
+
confirmed: "confirmed";
|
|
14
|
+
uncertain: "uncertain";
|
|
15
|
+
unchecked: "unchecked";
|
|
16
|
+
}>;
|
|
17
|
+
file: z.ZodString;
|
|
18
|
+
lines: z.ZodOptional<z.ZodObject<{
|
|
19
|
+
start: z.ZodInt;
|
|
20
|
+
end: z.ZodInt;
|
|
21
|
+
}, z.core.$strict>>;
|
|
22
|
+
inDiff: z.ZodBoolean;
|
|
23
|
+
status: z.ZodEnum<{
|
|
24
|
+
new: "new";
|
|
25
|
+
unfixed: "unfixed";
|
|
26
|
+
}>;
|
|
27
|
+
title: z.ZodString;
|
|
28
|
+
body: z.ZodString;
|
|
29
|
+
suggestion: z.ZodOptional<z.ZodString>;
|
|
30
|
+
evidence: z.ZodArray<z.ZodString>;
|
|
31
|
+
code: z.ZodString;
|
|
32
|
+
lowConfidence: z.ZodOptional<z.ZodLiteral<true>>;
|
|
33
|
+
provenance: z.ZodOptional<z.ZodObject<{
|
|
34
|
+
task: z.ZodString;
|
|
35
|
+
model: z.ZodOptional<z.ZodString>;
|
|
36
|
+
}, z.core.$strict>>;
|
|
37
|
+
}, z.core.$strict>;
|
|
38
|
+
export declare const reportOutputSchema: z.ZodObject<{
|
|
39
|
+
version: z.ZodLiteral<1>;
|
|
40
|
+
runId: z.ZodOptional<z.ZodString>;
|
|
41
|
+
changeRequest: z.ZodObject<{
|
|
42
|
+
id: z.ZodString;
|
|
43
|
+
title: z.ZodString;
|
|
44
|
+
description: z.ZodString;
|
|
45
|
+
baseSha: z.ZodString;
|
|
46
|
+
headSha: z.ZodString;
|
|
47
|
+
override: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
by: z.ZodString;
|
|
49
|
+
reason: z.ZodString;
|
|
50
|
+
}, z.core.$strict>>;
|
|
51
|
+
}, z.core.$strict>;
|
|
52
|
+
tier: z.ZodEnum<{
|
|
53
|
+
full: "full";
|
|
54
|
+
lite: "lite";
|
|
55
|
+
trivial: "trivial";
|
|
56
|
+
}>;
|
|
57
|
+
verdict: z.ZodEnum<{
|
|
58
|
+
approved: "approved";
|
|
59
|
+
approved_with_comments: "approved_with_comments";
|
|
60
|
+
minor_issues: "minor_issues";
|
|
61
|
+
significant_concerns: "significant_concerns";
|
|
62
|
+
}>;
|
|
63
|
+
summary: z.ZodString;
|
|
64
|
+
scope: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
65
|
+
mode: z.ZodLiteral<"incremental">;
|
|
66
|
+
since: z.ZodString;
|
|
67
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
68
|
+
mode: z.ZodLiteral<"full">;
|
|
69
|
+
reason: z.ZodString;
|
|
70
|
+
}, z.core.$strict>], "mode">>;
|
|
71
|
+
coverage: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
72
|
+
path: z.ZodString;
|
|
73
|
+
status: z.ZodEnum<{
|
|
74
|
+
failed: "failed";
|
|
75
|
+
reviewed: "reviewed";
|
|
76
|
+
unchanged: "unchanged";
|
|
77
|
+
unreviewed: "unreviewed";
|
|
78
|
+
}>;
|
|
79
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
80
|
+
path: z.ZodString;
|
|
81
|
+
status: z.ZodLiteral<"excluded">;
|
|
82
|
+
reason: z.ZodEnum<{
|
|
83
|
+
binary: "binary";
|
|
84
|
+
deleted: "deleted";
|
|
85
|
+
extension: "extension";
|
|
86
|
+
generated: "generated";
|
|
87
|
+
secret: "secret";
|
|
88
|
+
too_large: "too_large";
|
|
89
|
+
user_exclude: "user_exclude";
|
|
90
|
+
}>;
|
|
91
|
+
}, z.core.$strict>], "status">>;
|
|
92
|
+
findings: z.ZodArray<z.ZodObject<{
|
|
93
|
+
fingerprint: z.ZodString;
|
|
94
|
+
reviewer: z.ZodString;
|
|
95
|
+
category: z.ZodString;
|
|
96
|
+
severity: z.ZodEnum<{
|
|
97
|
+
critical: "critical";
|
|
98
|
+
suggestion: "suggestion";
|
|
99
|
+
warning: "warning";
|
|
100
|
+
}>;
|
|
101
|
+
verification: z.ZodEnum<{
|
|
102
|
+
confirmed: "confirmed";
|
|
103
|
+
uncertain: "uncertain";
|
|
104
|
+
unchecked: "unchecked";
|
|
105
|
+
}>;
|
|
106
|
+
file: z.ZodString;
|
|
107
|
+
lines: z.ZodOptional<z.ZodObject<{
|
|
108
|
+
start: z.ZodInt;
|
|
109
|
+
end: z.ZodInt;
|
|
110
|
+
}, z.core.$strict>>;
|
|
111
|
+
inDiff: z.ZodBoolean;
|
|
112
|
+
status: z.ZodEnum<{
|
|
113
|
+
new: "new";
|
|
114
|
+
unfixed: "unfixed";
|
|
115
|
+
}>;
|
|
116
|
+
title: z.ZodString;
|
|
117
|
+
body: z.ZodString;
|
|
118
|
+
suggestion: z.ZodOptional<z.ZodString>;
|
|
119
|
+
evidence: z.ZodArray<z.ZodString>;
|
|
120
|
+
code: z.ZodString;
|
|
121
|
+
lowConfidence: z.ZodOptional<z.ZodLiteral<true>>;
|
|
122
|
+
provenance: z.ZodOptional<z.ZodObject<{
|
|
123
|
+
task: z.ZodString;
|
|
124
|
+
model: z.ZodOptional<z.ZodString>;
|
|
125
|
+
}, z.core.$strict>>;
|
|
126
|
+
}, z.core.$strict>>;
|
|
127
|
+
unverifiedCriticals: z.ZodInt;
|
|
128
|
+
refuted: z.ZodArray<z.ZodObject<{
|
|
129
|
+
fingerprint: z.ZodString;
|
|
130
|
+
file: z.ZodString;
|
|
131
|
+
title: z.ZodString;
|
|
132
|
+
reason: z.ZodString;
|
|
133
|
+
}, z.core.$strict>>;
|
|
134
|
+
remembered: z.ZodArray<z.ZodObject<{
|
|
135
|
+
fingerprint: z.ZodString;
|
|
136
|
+
file: z.ZodString;
|
|
137
|
+
title: z.ZodString;
|
|
138
|
+
reason: z.ZodString;
|
|
139
|
+
added: z.ZodOptional<z.ZodString>;
|
|
140
|
+
}, z.core.$strip>>;
|
|
141
|
+
judgement: z.ZodOptional<z.ZodObject<{
|
|
142
|
+
merged: z.ZodArray<z.ZodObject<{
|
|
143
|
+
kept: z.ZodString;
|
|
144
|
+
merged: z.ZodArray<z.ZodString>;
|
|
145
|
+
}, z.core.$strict>>;
|
|
146
|
+
dropped: z.ZodArray<z.ZodObject<{
|
|
147
|
+
fingerprint: z.ZodString;
|
|
148
|
+
file: z.ZodString;
|
|
149
|
+
title: z.ZodString;
|
|
150
|
+
reason: z.ZodString;
|
|
151
|
+
}, z.core.$strict>>;
|
|
152
|
+
recalibrated: z.ZodArray<z.ZodObject<{
|
|
153
|
+
fingerprint: z.ZodString;
|
|
154
|
+
from: z.ZodEnum<{
|
|
155
|
+
critical: "critical";
|
|
156
|
+
suggestion: "suggestion";
|
|
157
|
+
warning: "warning";
|
|
158
|
+
}>;
|
|
159
|
+
to: z.ZodEnum<{
|
|
160
|
+
critical: "critical";
|
|
161
|
+
suggestion: "suggestion";
|
|
162
|
+
warning: "warning";
|
|
163
|
+
}>;
|
|
164
|
+
reason: z.ZodString;
|
|
165
|
+
}, z.core.$strict>>;
|
|
166
|
+
}, z.core.$strict>>;
|
|
167
|
+
rereview: z.ZodOptional<z.ZodObject<{
|
|
168
|
+
fixed: z.ZodArray<z.ZodObject<{
|
|
169
|
+
fingerprint: z.ZodString;
|
|
170
|
+
title: z.ZodString;
|
|
171
|
+
file: z.ZodString;
|
|
172
|
+
severity: z.ZodEnum<{
|
|
173
|
+
critical: "critical";
|
|
174
|
+
suggestion: "suggestion";
|
|
175
|
+
warning: "warning";
|
|
176
|
+
}>;
|
|
177
|
+
verification: z.ZodEnum<{
|
|
178
|
+
confirmed: "confirmed";
|
|
179
|
+
uncertain: "uncertain";
|
|
180
|
+
unchecked: "unchecked";
|
|
181
|
+
}>;
|
|
182
|
+
}, z.core.$strict>>;
|
|
183
|
+
notReproduced: z.ZodArray<z.ZodObject<{
|
|
184
|
+
fingerprint: z.ZodString;
|
|
185
|
+
title: z.ZodString;
|
|
186
|
+
file: z.ZodString;
|
|
187
|
+
severity: z.ZodEnum<{
|
|
188
|
+
critical: "critical";
|
|
189
|
+
suggestion: "suggestion";
|
|
190
|
+
warning: "warning";
|
|
191
|
+
}>;
|
|
192
|
+
verification: z.ZodEnum<{
|
|
193
|
+
confirmed: "confirmed";
|
|
194
|
+
uncertain: "uncertain";
|
|
195
|
+
unchecked: "unchecked";
|
|
196
|
+
}>;
|
|
197
|
+
}, z.core.$strict>>;
|
|
198
|
+
notRechecked: z.ZodArray<z.ZodObject<{
|
|
199
|
+
fingerprint: z.ZodString;
|
|
200
|
+
title: z.ZodString;
|
|
201
|
+
file: z.ZodString;
|
|
202
|
+
severity: z.ZodEnum<{
|
|
203
|
+
critical: "critical";
|
|
204
|
+
suggestion: "suggestion";
|
|
205
|
+
warning: "warning";
|
|
206
|
+
}>;
|
|
207
|
+
verification: z.ZodEnum<{
|
|
208
|
+
confirmed: "confirmed";
|
|
209
|
+
uncertain: "uncertain";
|
|
210
|
+
unchecked: "unchecked";
|
|
211
|
+
}>;
|
|
212
|
+
}, z.core.$strict>>;
|
|
213
|
+
unchanged: z.ZodArray<z.ZodObject<{
|
|
214
|
+
fingerprint: z.ZodString;
|
|
215
|
+
title: z.ZodString;
|
|
216
|
+
file: z.ZodString;
|
|
217
|
+
severity: z.ZodEnum<{
|
|
218
|
+
critical: "critical";
|
|
219
|
+
suggestion: "suggestion";
|
|
220
|
+
warning: "warning";
|
|
221
|
+
}>;
|
|
222
|
+
verification: z.ZodEnum<{
|
|
223
|
+
confirmed: "confirmed";
|
|
224
|
+
uncertain: "uncertain";
|
|
225
|
+
unchecked: "unchecked";
|
|
226
|
+
}>;
|
|
227
|
+
}, z.core.$strict>>;
|
|
228
|
+
dismissed: z.ZodArray<z.ZodObject<{
|
|
229
|
+
fingerprint: z.ZodString;
|
|
230
|
+
title: z.ZodString;
|
|
231
|
+
file: z.ZodString;
|
|
232
|
+
severity: z.ZodEnum<{
|
|
233
|
+
critical: "critical";
|
|
234
|
+
suggestion: "suggestion";
|
|
235
|
+
warning: "warning";
|
|
236
|
+
}>;
|
|
237
|
+
verification: z.ZodEnum<{
|
|
238
|
+
confirmed: "confirmed";
|
|
239
|
+
uncertain: "uncertain";
|
|
240
|
+
unchecked: "unchecked";
|
|
241
|
+
}>;
|
|
242
|
+
}, z.core.$strict>>;
|
|
243
|
+
}, z.core.$strict>>;
|
|
244
|
+
tasks: z.ZodArray<z.ZodObject<{
|
|
245
|
+
taskId: z.ZodString;
|
|
246
|
+
reviewer: z.ZodString;
|
|
247
|
+
bundle: z.ZodString;
|
|
248
|
+
files: z.ZodArray<z.ZodString>;
|
|
249
|
+
status: z.ZodEnum<{
|
|
250
|
+
cancelled: "cancelled";
|
|
251
|
+
completed: "completed";
|
|
252
|
+
failed: "failed";
|
|
253
|
+
timed_out: "timed_out";
|
|
254
|
+
}>;
|
|
255
|
+
error: z.ZodOptional<z.ZodString>;
|
|
256
|
+
findings: z.ZodInt;
|
|
257
|
+
durationMs: z.ZodNumber;
|
|
258
|
+
usage: z.ZodObject<{
|
|
259
|
+
inputTokens: z.ZodNumber;
|
|
260
|
+
outputTokens: z.ZodNumber;
|
|
261
|
+
reasoningTokens: z.ZodNumber;
|
|
262
|
+
cachedTokens: z.ZodNumber;
|
|
263
|
+
costUsd: z.ZodNumber;
|
|
264
|
+
}, z.core.$strict>;
|
|
265
|
+
}, z.core.$strict>>;
|
|
266
|
+
skipped: z.ZodArray<z.ZodObject<{
|
|
267
|
+
reviewer: z.ZodString;
|
|
268
|
+
bundle: z.ZodString;
|
|
269
|
+
reason: z.ZodEnum<{
|
|
270
|
+
below_tier: "below_tier";
|
|
271
|
+
disabled: "disabled";
|
|
272
|
+
no_guidelines: "no_guidelines";
|
|
273
|
+
no_matching_files: "no_matching_files";
|
|
274
|
+
task_limit: "task_limit";
|
|
275
|
+
}>;
|
|
276
|
+
}, z.core.$strict>>;
|
|
277
|
+
bundles: z.ZodArray<z.ZodObject<{
|
|
278
|
+
label: z.ZodString;
|
|
279
|
+
files: z.ZodArray<z.ZodString>;
|
|
280
|
+
}, z.core.$strict>>;
|
|
281
|
+
anchoring: z.ZodOptional<z.ZodObject<{
|
|
282
|
+
byMethod: z.ZodRecord<z.ZodEnum<{
|
|
283
|
+
cross_file: "cross_file";
|
|
284
|
+
file: "file";
|
|
285
|
+
file_level: "file_level";
|
|
286
|
+
hunk: "hunk";
|
|
287
|
+
relocated: "relocated";
|
|
288
|
+
}>, z.ZodInt>;
|
|
289
|
+
ambiguous: z.ZodInt;
|
|
290
|
+
relocationCalls: z.ZodInt;
|
|
291
|
+
}, z.core.$strict>>;
|
|
292
|
+
spendLimit: z.ZodOptional<z.ZodObject<{
|
|
293
|
+
usd: z.ZodNumber;
|
|
294
|
+
reached: z.ZodOptional<z.ZodEnum<{
|
|
295
|
+
review: "review";
|
|
296
|
+
total: "total";
|
|
297
|
+
}>>;
|
|
298
|
+
}, z.core.$strict>>;
|
|
299
|
+
provenance: z.ZodOptional<z.ZodObject<{
|
|
300
|
+
ocraVersion: z.ZodString;
|
|
301
|
+
promptHash: z.ZodString;
|
|
302
|
+
configHash: z.ZodString;
|
|
303
|
+
sampling: z.ZodObject<{
|
|
304
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
305
|
+
seed: z.ZodOptional<z.ZodInt>;
|
|
306
|
+
notApplied: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
307
|
+
seed: "seed";
|
|
308
|
+
temperature: "temperature";
|
|
309
|
+
}>>>;
|
|
310
|
+
}, z.core.$strict>;
|
|
311
|
+
}, z.core.$strict>>;
|
|
312
|
+
usage: z.ZodObject<{
|
|
313
|
+
inputTokens: z.ZodNumber;
|
|
314
|
+
outputTokens: z.ZodNumber;
|
|
315
|
+
reasoningTokens: z.ZodNumber;
|
|
316
|
+
cachedTokens: z.ZodNumber;
|
|
317
|
+
costUsd: z.ZodNumber;
|
|
318
|
+
}, z.core.$strict>;
|
|
319
|
+
warnings: z.ZodArray<z.ZodString>;
|
|
320
|
+
}, z.core.$strict>;
|
|
321
|
+
type OutputFromSchema = z.output<typeof reportOutputSchema>;
|
|
322
|
+
export declare function asSchemaOutput(output: ReportOutput): OutputFromSchema;
|
|
323
|
+
export declare const REPORT_SCHEMA_ID = "https://ocra.majincheng.com/schema/report.v1.json";
|
|
324
|
+
export declare function reportJsonSchema(): Record<string, unknown>;
|
|
325
|
+
export {};
|
|
326
|
+
//# sourceMappingURL=output-schema.d.ts.map
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { anchorMethodSchema, riskTierSchema, severitySchema, verdictSchema, verificationSchema, } from "../domain.js";
|
|
3
|
+
import { memoryEntrySchema } from "../memory/memory.js";
|
|
4
|
+
import { exclusionReasonSchema } from "../select/select.js";
|
|
5
|
+
import { skipReasonSchema } from "./matrix.js";
|
|
6
|
+
import { REPORT_VERSION } from "./output.js";
|
|
7
|
+
import { taskStatusSchema } from "./report.js";
|
|
8
|
+
// The JSON report as a schema: what `toReportOutput` writes, no more. Every
|
|
9
|
+
// object is strict, so a field added to the output without a schema change
|
|
10
|
+
// fails the tests, and the published JSON Schema (docs/schema/report.v1.json)
|
|
11
|
+
// is generated from here, never written by hand.
|
|
12
|
+
const usageSchema = z.strictObject({
|
|
13
|
+
inputTokens: z.number(),
|
|
14
|
+
outputTokens: z.number(),
|
|
15
|
+
reasoningTokens: z.number(),
|
|
16
|
+
cachedTokens: z.number(),
|
|
17
|
+
costUsd: z.number(),
|
|
18
|
+
});
|
|
19
|
+
const changeRequestSchema = z.strictObject({
|
|
20
|
+
id: z.string(),
|
|
21
|
+
title: z.string(),
|
|
22
|
+
description: z.string(),
|
|
23
|
+
baseSha: z.string(),
|
|
24
|
+
headSha: z.string(),
|
|
25
|
+
override: z.strictObject({ by: z.string(), reason: z.string() }).optional(),
|
|
26
|
+
});
|
|
27
|
+
const coverageEntrySchema = z.discriminatedUnion("status", [
|
|
28
|
+
z.strictObject({
|
|
29
|
+
path: z.string(),
|
|
30
|
+
status: z.enum(["reviewed", "failed", "unreviewed", "unchanged"]),
|
|
31
|
+
}),
|
|
32
|
+
z.strictObject({
|
|
33
|
+
path: z.string(),
|
|
34
|
+
status: z.literal("excluded"),
|
|
35
|
+
reason: exclusionReasonSchema,
|
|
36
|
+
}),
|
|
37
|
+
]);
|
|
38
|
+
const linesSchema = z.strictObject({ start: z.int().positive(), end: z.int().positive() });
|
|
39
|
+
export const outputFindingSchema = z.strictObject({
|
|
40
|
+
fingerprint: z.string(),
|
|
41
|
+
reviewer: z.string(),
|
|
42
|
+
category: z.string(),
|
|
43
|
+
severity: severitySchema,
|
|
44
|
+
verification: verificationSchema,
|
|
45
|
+
file: z.string(),
|
|
46
|
+
lines: linesSchema.optional(),
|
|
47
|
+
inDiff: z.boolean(),
|
|
48
|
+
status: z.enum(["new", "unfixed"]),
|
|
49
|
+
title: z.string(),
|
|
50
|
+
body: z.string(),
|
|
51
|
+
suggestion: z.string().optional(),
|
|
52
|
+
evidence: z.array(z.string()),
|
|
53
|
+
code: z.string(),
|
|
54
|
+
lowConfidence: z.literal(true).optional(),
|
|
55
|
+
provenance: z.strictObject({ task: z.string(), model: z.string().optional() }).optional(),
|
|
56
|
+
});
|
|
57
|
+
const outputPriorFindingSchema = z.strictObject({
|
|
58
|
+
fingerprint: z.string(),
|
|
59
|
+
title: z.string(),
|
|
60
|
+
file: z.string(),
|
|
61
|
+
severity: severitySchema,
|
|
62
|
+
verification: verificationSchema,
|
|
63
|
+
});
|
|
64
|
+
const refutedFindingSchema = z.strictObject({
|
|
65
|
+
fingerprint: z.string(),
|
|
66
|
+
file: z.string(),
|
|
67
|
+
title: z.string(),
|
|
68
|
+
reason: z.string(),
|
|
69
|
+
});
|
|
70
|
+
const judgeDecisionsSchema = z.strictObject({
|
|
71
|
+
merged: z.array(z.strictObject({ kept: z.string(), merged: z.array(z.string()) })),
|
|
72
|
+
dropped: z.array(z.strictObject({
|
|
73
|
+
fingerprint: z.string(),
|
|
74
|
+
file: z.string(),
|
|
75
|
+
title: z.string(),
|
|
76
|
+
reason: z.string(),
|
|
77
|
+
})),
|
|
78
|
+
recalibrated: z.array(z.strictObject({
|
|
79
|
+
fingerprint: z.string(),
|
|
80
|
+
from: severitySchema,
|
|
81
|
+
to: severitySchema,
|
|
82
|
+
reason: z.string(),
|
|
83
|
+
})),
|
|
84
|
+
});
|
|
85
|
+
const taskOutcomeSchema = z.strictObject({
|
|
86
|
+
taskId: z.string(),
|
|
87
|
+
reviewer: z.string(),
|
|
88
|
+
bundle: z.string(),
|
|
89
|
+
files: z.array(z.string()),
|
|
90
|
+
status: taskStatusSchema,
|
|
91
|
+
error: z.string().optional(),
|
|
92
|
+
findings: z.int().nonnegative(),
|
|
93
|
+
durationMs: z.number(),
|
|
94
|
+
usage: usageSchema,
|
|
95
|
+
});
|
|
96
|
+
const skippedCellSchema = z.strictObject({
|
|
97
|
+
reviewer: z.string(),
|
|
98
|
+
bundle: z.string(),
|
|
99
|
+
reason: skipReasonSchema,
|
|
100
|
+
});
|
|
101
|
+
const anchoringSummarySchema = z.strictObject({
|
|
102
|
+
byMethod: z.record(anchorMethodSchema, z.int().nonnegative()),
|
|
103
|
+
ambiguous: z.int().nonnegative(),
|
|
104
|
+
relocationCalls: z.int().nonnegative(),
|
|
105
|
+
});
|
|
106
|
+
const scopeSchema = z.discriminatedUnion("mode", [
|
|
107
|
+
z.strictObject({ mode: z.literal("incremental"), since: z.string() }),
|
|
108
|
+
z.strictObject({ mode: z.literal("full"), reason: z.string() }),
|
|
109
|
+
]);
|
|
110
|
+
const priorList = z.array(outputPriorFindingSchema);
|
|
111
|
+
const samplingSchema = z.strictObject({
|
|
112
|
+
temperature: z.number().optional(),
|
|
113
|
+
seed: z.int().optional(),
|
|
114
|
+
notApplied: z.array(z.enum(["temperature", "seed"])).optional(),
|
|
115
|
+
});
|
|
116
|
+
const provenanceSchema = z.strictObject({
|
|
117
|
+
ocraVersion: z.string(),
|
|
118
|
+
promptHash: z.string(),
|
|
119
|
+
configHash: z.string(),
|
|
120
|
+
sampling: samplingSchema,
|
|
121
|
+
});
|
|
122
|
+
export const reportOutputSchema = z.strictObject({
|
|
123
|
+
version: z.literal(REPORT_VERSION),
|
|
124
|
+
runId: z.string().optional(),
|
|
125
|
+
changeRequest: changeRequestSchema,
|
|
126
|
+
tier: riskTierSchema,
|
|
127
|
+
verdict: verdictSchema,
|
|
128
|
+
summary: z.string(),
|
|
129
|
+
scope: scopeSchema.optional(),
|
|
130
|
+
coverage: z.array(coverageEntrySchema),
|
|
131
|
+
findings: z.array(outputFindingSchema),
|
|
132
|
+
unverifiedCriticals: z.int().nonnegative(),
|
|
133
|
+
refuted: z.array(refutedFindingSchema),
|
|
134
|
+
remembered: z.array(memoryEntrySchema),
|
|
135
|
+
judgement: judgeDecisionsSchema.optional(),
|
|
136
|
+
rereview: z
|
|
137
|
+
.strictObject({
|
|
138
|
+
fixed: priorList,
|
|
139
|
+
notReproduced: priorList,
|
|
140
|
+
notRechecked: priorList,
|
|
141
|
+
unchanged: priorList,
|
|
142
|
+
dismissed: priorList,
|
|
143
|
+
})
|
|
144
|
+
.optional(),
|
|
145
|
+
tasks: z.array(taskOutcomeSchema),
|
|
146
|
+
skipped: z.array(skippedCellSchema),
|
|
147
|
+
bundles: z.array(z.strictObject({ label: z.string(), files: z.array(z.string()) })),
|
|
148
|
+
anchoring: anchoringSummarySchema.optional(),
|
|
149
|
+
spendLimit: z
|
|
150
|
+
.strictObject({ usd: z.number(), reached: z.enum(["review", "total"]).optional() })
|
|
151
|
+
.optional(),
|
|
152
|
+
provenance: provenanceSchema.optional(),
|
|
153
|
+
usage: usageSchema,
|
|
154
|
+
warnings: z.array(z.string()),
|
|
155
|
+
});
|
|
156
|
+
export function asSchemaOutput(output) {
|
|
157
|
+
return output;
|
|
158
|
+
}
|
|
159
|
+
export const REPORT_SCHEMA_ID = "https://ocra.majincheng.com/schema/report.v1.json";
|
|
160
|
+
// JSON Schema (draft 2020-12) for `--format json` and a session's
|
|
161
|
+
// report.json, for validators and code generators outside this codebase.
|
|
162
|
+
export function reportJsonSchema() {
|
|
163
|
+
const generated = z.toJSONSchema(reportOutputSchema, { target: "draft-2020-12", io: "output" });
|
|
164
|
+
const { $schema, ...rest } = generated;
|
|
165
|
+
return {
|
|
166
|
+
$schema,
|
|
167
|
+
$id: REPORT_SCHEMA_ID,
|
|
168
|
+
title: "ocra review report",
|
|
169
|
+
description: `The report ocra writes with --format json and as a session's report.json (version ${REPORT_VERSION}). A version only gains optional fields; anything else is a new version.`,
|
|
170
|
+
...rest,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=output-schema.js.map
|
|
@@ -5,6 +5,7 @@ import type { MemoryEntry } from "../memory/memory.js";
|
|
|
5
5
|
import type { RefutedFinding } from "../verify/verify.js";
|
|
6
6
|
import type { SkippedCell } from "./matrix.js";
|
|
7
7
|
import type { ReviewPreview } from "./preview.js";
|
|
8
|
+
import type { RunProvenance } from "./provenance.js";
|
|
8
9
|
import type { AnchoringSummary, CoverageEntry, ReviewReport, TaskOutcome } from "./report.js";
|
|
9
10
|
export declare const REPORT_VERSION = 1;
|
|
10
11
|
export interface OutputFinding {
|
|
@@ -26,6 +27,10 @@ export interface OutputFinding {
|
|
|
26
27
|
evidence: string[];
|
|
27
28
|
code: string;
|
|
28
29
|
lowConfidence?: true;
|
|
30
|
+
provenance?: {
|
|
31
|
+
task: string;
|
|
32
|
+
model?: string;
|
|
33
|
+
};
|
|
29
34
|
}
|
|
30
35
|
export interface OutputPriorFinding {
|
|
31
36
|
fingerprint: string;
|
|
@@ -36,6 +41,7 @@ export interface OutputPriorFinding {
|
|
|
36
41
|
}
|
|
37
42
|
export interface ReportOutput {
|
|
38
43
|
version: typeof REPORT_VERSION;
|
|
44
|
+
runId?: string;
|
|
39
45
|
changeRequest: ChangeRequest;
|
|
40
46
|
tier: RiskTier;
|
|
41
47
|
verdict: Verdict;
|
|
@@ -55,6 +61,8 @@ export interface ReportOutput {
|
|
|
55
61
|
files: string[];
|
|
56
62
|
}[];
|
|
57
63
|
anchoring?: AnchoringSummary;
|
|
64
|
+
spendLimit?: ReviewReport["spendLimit"];
|
|
65
|
+
provenance?: RunProvenance;
|
|
58
66
|
usage: Usage;
|
|
59
67
|
warnings: string[];
|
|
60
68
|
}
|