argus-reviewer-e2e 0.1.3 → 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/README.md +86 -49
- package/action/action.yml +155 -61
- package/action/approval-review.mjs +393 -0
- package/action/bootstrap.mjs +102 -0
- package/action/cli.mjs +36 -0
- package/action/emit-review.mjs +336 -0
- package/action/runtime.mjs +154 -0
- package/action/sticky-comment.cjs +870 -0
- package/dist/api.d.ts +2 -0
- package/dist/api.js +4 -0
- package/dist/cache/store.d.ts +2 -0
- package/dist/cache/store.js +10 -3
- package/dist/cli.d.ts +137 -0
- package/dist/cli.js +677 -60
- package/dist/config.d.ts +67 -2
- package/dist/config.js +138 -7
- package/dist/debug.d.ts +1 -0
- package/dist/debug.js +9 -3
- package/dist/engine/loop.d.ts +12 -0
- package/dist/engine/loop.js +55 -6
- package/dist/evidence/ci.d.ts +3 -0
- package/dist/evidence/ci.js +3 -1
- package/dist/pipeline/budget.d.ts +11 -0
- package/dist/pipeline/budget.js +48 -0
- package/dist/pipeline/contracts.d.ts +12 -0
- package/dist/pipeline/contracts.js +16 -0
- package/dist/pipeline/verify.d.ts +27 -0
- package/dist/pipeline/verify.js +197 -0
- package/dist/probe/queue.d.ts +4 -1
- package/dist/probe/queue.js +46 -8
- package/dist/report/manifest.d.ts +87 -0
- package/dist/report/manifest.js +143 -0
- package/dist/report/run.d.ts +9 -0
- package/dist/report/run.js +6 -0
- package/dist/review/adjudicate.d.ts +63 -0
- package/dist/review/adjudicate.js +111 -0
- package/dist/review/secrets.d.ts +90 -0
- package/dist/review/secrets.js +224 -0
- package/dist/review/triage.d.ts +76 -0
- package/dist/review/triage.js +163 -0
- package/dist/trust.d.ts +50 -0
- package/dist/trust.js +103 -0
- package/dist/vision/cost.d.ts +14 -1
- package/dist/vision/cost.js +13 -0
- package/dist/vision/decisions.d.ts +95 -0
- package/dist/vision/decisions.js +232 -0
- package/package.json +9 -8
- package/action/sticky-comment.mjs +0 -404
package/dist/api.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { Config, defineConfig } from './config.js';
|
|
|
7
7
|
import { ErrorRecord } from './journal/schema.js';
|
|
8
8
|
import { Logger } from './log.js';
|
|
9
9
|
export { defineConfig };
|
|
10
|
+
export { DecisionClient, DecisionError, JEV_DEFAULT_MODEL, type DecisionAnswer, type DecisionClientOptions, type DecisionErrorKind, type DecisionQuestion, } from './vision/decisions.js';
|
|
10
11
|
/**
|
|
11
12
|
* Test-facing API (R13). Test files are plain TypeScript using a `td` object:
|
|
12
13
|
*
|
|
@@ -91,6 +92,7 @@ export declare class TdSession {
|
|
|
91
92
|
private constructor();
|
|
92
93
|
static create(opts: TdSessionOptions): Promise<TdSession>;
|
|
93
94
|
get visionCalls(): number;
|
|
95
|
+
get cacheStats(): import("./engine/loop.js").CacheStats;
|
|
94
96
|
/** Non-fatal anomalies observed by the engine — journaled as evidence. */
|
|
95
97
|
get errorRecords(): ErrorRecord[];
|
|
96
98
|
get failed(): boolean;
|
package/dist/api.js
CHANGED
|
@@ -4,6 +4,7 @@ import { loadFlow, saveFlow } from './cache/store.js';
|
|
|
4
4
|
import { Ledger } from './vision/ledger.js';
|
|
5
5
|
import { defineConfig } from './config.js';
|
|
6
6
|
export { defineConfig };
|
|
7
|
+
export { DecisionClient, DecisionError, JEV_DEFAULT_MODEL, } from './vision/decisions.js';
|
|
7
8
|
const KEY_ALIASES = {
|
|
8
9
|
tab: 'Tab',
|
|
9
10
|
enter: 'Enter',
|
|
@@ -89,6 +90,9 @@ export class TdSession {
|
|
|
89
90
|
get visionCalls() {
|
|
90
91
|
return this.engine.visionCalls;
|
|
91
92
|
}
|
|
93
|
+
get cacheStats() {
|
|
94
|
+
return this.engine.cacheStats;
|
|
95
|
+
}
|
|
92
96
|
/** Non-fatal anomalies observed by the engine — journaled as evidence. */
|
|
93
97
|
get errorRecords() {
|
|
94
98
|
return this.engine.errorRecords;
|
package/dist/cache/store.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FingerprintRecord } from './fingerprint.js';
|
|
2
|
+
export declare const FLOW_CACHE_SCHEMA_VERSION: 1;
|
|
2
3
|
/** A cached assertion verdict, keyed on (question, page-state hash). */
|
|
3
4
|
export interface CachedAssert {
|
|
4
5
|
question: string;
|
|
@@ -9,6 +10,7 @@ export interface CachedAssert {
|
|
|
9
10
|
model: string | undefined;
|
|
10
11
|
}
|
|
11
12
|
export interface FlowCache {
|
|
13
|
+
schemaVersion?: typeof FLOW_CACHE_SCHEMA_VERSION;
|
|
12
14
|
steps: FingerprintRecord[];
|
|
13
15
|
asserts?: CachedAssert[];
|
|
14
16
|
}
|
package/dist/cache/store.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { writeAtomicJson } from '../fsutil.js';
|
|
4
|
+
export const FLOW_CACHE_SCHEMA_VERSION = 1;
|
|
4
5
|
function sortKeys(_, value) {
|
|
5
6
|
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
6
7
|
const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
|
|
@@ -19,11 +20,17 @@ export async function loadFlow(cacheDir, flowName) {
|
|
|
19
20
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
20
21
|
return undefined;
|
|
21
22
|
}
|
|
22
|
-
const { steps, asserts } = parsed;
|
|
23
|
+
const { schemaVersion, steps, asserts } = parsed;
|
|
23
24
|
if (!Array.isArray(steps)) {
|
|
24
25
|
return undefined;
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
+
if (schemaVersion !== undefined && schemaVersion !== FLOW_CACHE_SCHEMA_VERSION) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const out = {
|
|
31
|
+
...(schemaVersion === FLOW_CACHE_SCHEMA_VERSION ? { schemaVersion } : {}),
|
|
32
|
+
steps: steps,
|
|
33
|
+
};
|
|
27
34
|
if (Array.isArray(asserts))
|
|
28
35
|
out.asserts = asserts;
|
|
29
36
|
return out;
|
|
@@ -37,5 +44,5 @@ export async function loadFlow(cacheDir, flowName) {
|
|
|
37
44
|
}
|
|
38
45
|
}
|
|
39
46
|
export async function saveFlow(cacheDir, flowName, steps, asserts) {
|
|
40
|
-
await writeAtomicJson(flowPath(cacheDir, flowName), { steps, asserts: asserts ?? [] }, sortKeys);
|
|
47
|
+
await writeAtomicJson(flowPath(cacheDir, flowName), { schemaVersion: FLOW_CACHE_SCHEMA_VERSION, steps, asserts: asserts ?? [] }, sortKeys);
|
|
41
48
|
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -3,6 +3,14 @@ import { Config } from './config.js';
|
|
|
3
3
|
import { type ExecFn } from './detect.js';
|
|
4
4
|
import { BrowserDriver } from './driver/browser.js';
|
|
5
5
|
import { VisionClient } from './engine/loop.js';
|
|
6
|
+
import { type PrMeta } from './evidence/ci.js';
|
|
7
|
+
import { type Evidence } from './evidence/link.js';
|
|
8
|
+
import { type SecretsScanResult } from './review/secrets.js';
|
|
9
|
+
import { type TriageRecord } from './review/triage.js';
|
|
10
|
+
import { type FindingAdjudicationAudit } from './review/adjudicate.js';
|
|
11
|
+
import { type ProbeRecord } from './probe/queue.js';
|
|
12
|
+
import { type HeadBinding } from './report/manifest.js';
|
|
13
|
+
import { CallCost } from './vision/cost.js';
|
|
6
14
|
export interface CliDeps {
|
|
7
15
|
cwd?: string;
|
|
8
16
|
env?: NodeJS.ProcessEnv;
|
|
@@ -21,5 +29,134 @@ interface PrFile {
|
|
|
21
29
|
previous_filename?: string;
|
|
22
30
|
patch?: string;
|
|
23
31
|
}
|
|
32
|
+
export interface ReviewFinding {
|
|
33
|
+
file: string;
|
|
34
|
+
line?: number;
|
|
35
|
+
severity: string;
|
|
36
|
+
category?: string;
|
|
37
|
+
message: string;
|
|
38
|
+
/** U8 — Jev true-positive probability (absent = unadjudicated). */
|
|
39
|
+
p?: number;
|
|
40
|
+
/** R1 — committable replacement lines for the commented range (parse-bounded). */
|
|
41
|
+
suggestion?: string;
|
|
42
|
+
/** R1 — first line of the replaced range; absent = single-line fix at `line`. */
|
|
43
|
+
startLine?: number;
|
|
44
|
+
evidence?: Evidence;
|
|
45
|
+
}
|
|
46
|
+
/** KTD3 — one pre-rendered inline review comment; posters POST it verbatim. */
|
|
47
|
+
export interface ReviewComment {
|
|
48
|
+
path: string;
|
|
49
|
+
line: number;
|
|
50
|
+
start_line?: number;
|
|
51
|
+
start_side?: 'RIGHT';
|
|
52
|
+
side: 'RIGHT';
|
|
53
|
+
body: string;
|
|
54
|
+
/** R10 — path:line:bodyFirstLine:hash8(suggestion); a corrected suggestion re-posts. */
|
|
55
|
+
dedupKey: string;
|
|
56
|
+
}
|
|
57
|
+
interface CodeReviewReport {
|
|
58
|
+
ok: boolean;
|
|
59
|
+
skipped: boolean;
|
|
60
|
+
summary: string;
|
|
61
|
+
verdict: 'pass' | 'needs_changes' | 'approve';
|
|
62
|
+
findings: ReviewFinding[];
|
|
63
|
+
/** Inline-comment cap consumed by the sticky poster (Tencent max_comments pull). */
|
|
64
|
+
maxComments?: number;
|
|
65
|
+
/** R3/KTD2 — poster gate: 'request_changes' only for proven blockers. */
|
|
66
|
+
reviewEvent: 'comment' | 'request_changes';
|
|
67
|
+
/** Blocker-severity findings a sandbox probe reproduced. */
|
|
68
|
+
provenBlockers: number;
|
|
69
|
+
/** Blocker-severity findings at/above the Jev P(true-positive) gate. */
|
|
70
|
+
highConfidenceBlockers: number;
|
|
71
|
+
/** KTD3 — eligibility-filtered, severity-sorted, sanitized, capped. */
|
|
72
|
+
reviewComments: ReviewComment[];
|
|
73
|
+
/** Eligible findings dropped by the maxComments cap. */
|
|
74
|
+
commentsOverflow: number;
|
|
75
|
+
/** B.2 probe audit records — present only when the sandbox lane ran. */
|
|
76
|
+
probes?: ProbeRecord[];
|
|
77
|
+
/** Why an enabled lane bowed out (fork gate, no docker, no harness…). */
|
|
78
|
+
probeLaneSkipped?: string;
|
|
79
|
+
/** Secrets-lane audit — masked candidates, adjudication verdicts, skip reason. */
|
|
80
|
+
secretsScan?: SecretsScanResult | {
|
|
81
|
+
skipped: string;
|
|
82
|
+
};
|
|
83
|
+
/** U7 triage record — Jev pre-review signals (annotate/route, never gates). */
|
|
84
|
+
triage?: TriageRecord;
|
|
85
|
+
/** U8 adjudication audit — per-finding p + suppressed records. */
|
|
86
|
+
findingAdjudication?: FindingAdjudicationAudit;
|
|
87
|
+
calls: CallCost[];
|
|
88
|
+
visionCostUsd: number;
|
|
89
|
+
tokens: number;
|
|
90
|
+
model: string;
|
|
91
|
+
budgetExceeded: boolean;
|
|
92
|
+
/** Identity relationship between the report source and checkout. */
|
|
93
|
+
headBinding?: HeadBinding;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Split `git diff` text into per-file PrFile entries — the local-diff
|
|
97
|
+
* equivalent of the PR-files API response (which also reports `patch`
|
|
98
|
+
* per file). `+++ b/` names new/copied files; `--- a/` covers deletions.
|
|
99
|
+
*/
|
|
100
|
+
export declare function filesFromUnifiedDiff(diff: string): PrFile[];
|
|
101
|
+
/**
|
|
102
|
+
* `--fixture <dir>` seam: the dir is a real git repo with an
|
|
103
|
+
* `argus-fixture-base` ref (the merge base) and HEAD at the PR head —
|
|
104
|
+
* scripts/demo.mjs materializes it. Returns the same diff/files/meta
|
|
105
|
+
* the GitHub paths would produce, so every downstream lane (chunking,
|
|
106
|
+
* secrets scan, evidence linkage) runs its real code path.
|
|
107
|
+
*/
|
|
108
|
+
export declare function loadFixture(dir: string, exec?: ExecFn): Promise<{
|
|
109
|
+
files: PrFile[];
|
|
110
|
+
meta: PrMeta;
|
|
111
|
+
diff: string;
|
|
112
|
+
} | {
|
|
113
|
+
skipped: string;
|
|
114
|
+
}>;
|
|
24
115
|
export declare function buildPatchChunks(files: PrFile[], contexts?: Record<string, string>): string[];
|
|
116
|
+
export declare function parseCodeReview(content: string): {
|
|
117
|
+
summary: string;
|
|
118
|
+
verdict: 'pass' | 'needs_changes' | 'approve';
|
|
119
|
+
findings: CodeReviewReport['findings'];
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* KTD1 — a surviving synthesized finding's suggestion is restored verbatim
|
|
123
|
+
* from its pre-synthesis original, matched on file + line + whitespace-
|
|
124
|
+
* normalized message. With no pre-image the synthesized copy is dropped:
|
|
125
|
+
* synthesis output is ungrounded model text, never committable code.
|
|
126
|
+
*/
|
|
127
|
+
export declare function carryForwardSuggestions(findings: CodeReviewReport['findings'], originals: CodeReviewReport['findings']): CodeReviewReport['findings'];
|
|
128
|
+
/**
|
|
129
|
+
* R3/KTD2 — Jev P(true-positive) at/above which a blocker-severity finding
|
|
130
|
+
* counts as proven for the REQUEST_CHANGES gate. This is a different axis
|
|
131
|
+
* from `review.findingThreshold` (P(false-positive) for nit/q suppression)
|
|
132
|
+
* — never reuse that knob. 0.7: high-confidence without demanding
|
|
133
|
+
* near-certainty from a calibrated scorer.
|
|
134
|
+
*/
|
|
135
|
+
export declare const P_TRUE_POSITIVE_THRESHOLD = 0.7;
|
|
136
|
+
/**
|
|
137
|
+
* KTD2 — the poster-facing review gate, computed once at report assembly
|
|
138
|
+
* on linkedFindings (post-adjudication `p`, post-probe `evidence`,
|
|
139
|
+
* secrets-lane `pLive` already carried as `p`) and serialized into
|
|
140
|
+
* code-review.json; posters read `reviewEvent`, never recompute.
|
|
141
|
+
* Unadjudicated blockers (no p, not reproduced) never escalate —
|
|
142
|
+
* degrade-open by design. The two counts overlap deliberately: a
|
|
143
|
+
* reproduced AND Jev-confident finding is reported under both.
|
|
144
|
+
*/
|
|
145
|
+
export declare function computeReviewEvent(findings: ReviewFinding[], blockSeverities: string[], allowRequestChanges: boolean): {
|
|
146
|
+
reviewEvent: 'comment' | 'request_changes';
|
|
147
|
+
provenBlockers: number;
|
|
148
|
+
highConfidenceBlockers: number;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* KTD3 — pre-render the inline review surface: eligibility-filtered
|
|
152
|
+
* (R8's static half — real path, positive integer line), severity-sorted
|
|
153
|
+
* before the maxComments cap so nits can't crowd out bugs (R2), sanitized
|
|
154
|
+
* (R5), suggestion-fenced, each carrying a dedupKey (R10). Posters consume
|
|
155
|
+
* `comments` verbatim — dedup + live-diff validation + POST, no render
|
|
156
|
+
* policy. `overflow` is the count of eligible findings past the cap.
|
|
157
|
+
*/
|
|
158
|
+
export declare function renderReviewComments(findings: ReviewFinding[], maxComments?: number): {
|
|
159
|
+
comments: ReviewComment[];
|
|
160
|
+
overflow: number;
|
|
161
|
+
};
|
|
25
162
|
export {};
|