@effect-agent/pr-review 0.1.0-beta.21 → 0.1.0-beta.23
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 +63 -46
- package/dist/action.d.mts +13 -13
- package/dist/action.mjs +33 -25
- package/dist/action.mjs.map +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/{fan-out-D5xrmadQ.d.mts → fan-out-BJBTAYuh.d.mts} +278 -303
- package/dist/{github-DSqZp3Ce.mjs → github-BbwYzNrC.mjs} +588 -243
- package/dist/github-BbwYzNrC.mjs.map +1 -0
- package/dist/index.d.mts +72 -116
- package/dist/index.mjs +11 -11
- package/dist/index.mjs.map +1 -1
- package/dist/{providers-CblG1G9b.mjs → providers-NyP-4rS6.mjs} +162 -578
- package/dist/providers-NyP-4rS6.mjs.map +1 -0
- package/dist/testing.d.mts +4 -15
- package/dist/testing.mjs +12 -41
- package/dist/testing.mjs.map +1 -1
- package/package.json +2 -2
- package/src/action.ts +40 -34
- package/src/internal/action-entry.ts +0 -1
- package/src/internal/coverage.ts +147 -532
- package/src/internal/factory.ts +29 -50
- package/src/internal/fan-out-scripted.ts +26 -80
- package/src/internal/fan-out.ts +577 -426
- package/src/internal/profiles.ts +8 -8
- package/src/internal/render.ts +34 -45
- package/src/internal/retirement.ts +3 -1
- package/src/internal/review-agent.ts +6 -1
- package/src/internal/review-state.ts +43 -19
- package/src/internal/review-units.ts +25 -0
- package/src/internal/run.ts +211 -174
- package/src/internal/source.ts +1 -1
- package/dist/github-DSqZp3Ce.mjs.map +0 -1
- package/dist/providers-CblG1G9b.mjs.map +0 -1
package/src/action.ts
CHANGED
|
@@ -51,10 +51,6 @@ import {
|
|
|
51
51
|
// nothing.
|
|
52
52
|
// ---------------------------------------------------------------------------
|
|
53
53
|
|
|
54
|
-
/** Deprecated compatibility input; host-derived conclusions are unconditional. */
|
|
55
|
-
export const FailOnPolicy = Schema.Literals(["never", "request-changes"]);
|
|
56
|
-
export type FailOnPolicy = typeof FailOnPolicy.Type;
|
|
57
|
-
|
|
58
54
|
export const ReviewCheckConclusion = Schema.Literals(["success", "blocking", "incomplete"]);
|
|
59
55
|
export type ReviewCheckConclusion = typeof ReviewCheckConclusion.Type;
|
|
60
56
|
|
|
@@ -96,8 +92,6 @@ export interface ResolvedActionInputs {
|
|
|
96
92
|
readonly maxFindings: number | undefined;
|
|
97
93
|
readonly maxDurationMinutes: number | undefined;
|
|
98
94
|
readonly reviewMode: ReviewMode;
|
|
99
|
-
/** Deprecated compatibility input; conclusions are always conservative. */
|
|
100
|
-
readonly failOn: FailOnPolicy;
|
|
101
95
|
readonly skipUnchanged: boolean;
|
|
102
96
|
readonly retireStaleReviews: boolean;
|
|
103
97
|
readonly progressComment: boolean;
|
|
@@ -135,9 +129,6 @@ export const resolveActionInputs = Effect.fn("resolveActionInputs")(function* ()
|
|
|
135
129
|
const reviewMode = yield* Config.literals(["incremental", "final"], "PR_REVIEW_MODE").pipe(
|
|
136
130
|
Config.withDefault<ReviewMode>("incremental"),
|
|
137
131
|
);
|
|
138
|
-
const failOn = yield* Config.literals(["never", "request-changes"], "PR_REVIEW_FAIL_ON").pipe(
|
|
139
|
-
Config.withDefault<FailOnPolicy>("never"),
|
|
140
|
-
);
|
|
141
132
|
const skipUnchanged = yield* Config.boolean("PR_REVIEW_SKIP_UNCHANGED").pipe(
|
|
142
133
|
Config.withDefault(true),
|
|
143
134
|
);
|
|
@@ -163,7 +154,6 @@ export const resolveActionInputs = Effect.fn("resolveActionInputs")(function* ()
|
|
|
163
154
|
maxFindings: Option.getOrUndefined(maxFindings),
|
|
164
155
|
maxDurationMinutes,
|
|
165
156
|
reviewMode,
|
|
166
|
-
failOn,
|
|
167
157
|
skipUnchanged,
|
|
168
158
|
retireStaleReviews,
|
|
169
159
|
progressComment,
|
|
@@ -276,6 +266,7 @@ const outcomeOutputs = (
|
|
|
276
266
|
["inline-comments", String(outcome.plan.comments.length)],
|
|
277
267
|
["demoted-findings", String(outcome.plan.demoted.length)],
|
|
278
268
|
["concerns", String(outcome.review.concerns?.length ?? 0)],
|
|
269
|
+
["unreviewed-paths", String(outcome.unreviewedPaths.length)],
|
|
279
270
|
...(outcome.usage === undefined
|
|
280
271
|
? []
|
|
281
272
|
: ([
|
|
@@ -296,14 +287,15 @@ const outcomeSummary = (
|
|
|
296
287
|
`- Input coverage: **${outcome.inputCoverage.status}** · scope: ${outcome.reviewMode ?? "full"}`,
|
|
297
288
|
`- Review assurance: **${outcome.assurance.status}** · general discovery ${outcome.assurance.completedGeneralDiscoveryPasses}/${outcome.assurance.requiredGeneralDiscoveryPasses} · specialist ${outcome.assurance.completedSpecialistPasses}/${outcome.assurance.requiredSpecialistPasses} · verification ${outcome.assurance.completedVerificationPasses}/${outcome.assurance.requiredVerificationPasses}`,
|
|
298
289
|
`- Inline comments: ${outcome.plan.comments.length} · demoted findings: ${outcome.plan.demoted.length} · concerns: ${outcome.review.concerns?.length ?? 0}`,
|
|
299
|
-
...(
|
|
300
|
-
...(outcome.usage === undefined
|
|
290
|
+
...(outcome.unreviewedPaths.length === 0
|
|
301
291
|
? []
|
|
302
292
|
: [
|
|
303
|
-
`-
|
|
304
|
-
outcome.usageScope === "coordinator" ? " (coordinator)" : ""
|
|
305
|
-
}`,
|
|
293
|
+
`- Carried forward: ${outcome.unreviewedPaths.length} unreviewed path(s) retried automatically on the next run (reviewer-side gap, not a code defect)`,
|
|
306
294
|
]),
|
|
295
|
+
...(modelLabel === undefined ? [] : [`- Model: \`${modelLabel}\``]),
|
|
296
|
+
...(outcome.usage === undefined
|
|
297
|
+
? []
|
|
298
|
+
: [`- Tokens: ${outcome.usage.inputTokens} in / ${outcome.usage.outputTokens} out`]),
|
|
307
299
|
...(outcome.published === undefined
|
|
308
300
|
? ["- Dry run: nothing posted"]
|
|
309
301
|
: [`- Posted: ${outcome.published.url}`]),
|
|
@@ -376,32 +368,44 @@ const blockingReasons = (input: {
|
|
|
376
368
|
.map((concern) => `blocking concern: ${concern.title}`),
|
|
377
369
|
];
|
|
378
370
|
|
|
379
|
-
/**
|
|
371
|
+
/**
|
|
372
|
+
* Host-derived check conclusion; model verdict prose cannot weaken it.
|
|
373
|
+
*
|
|
374
|
+
* Blocking code findings outrank machinery gaps — they are the actionable
|
|
375
|
+
* signal. A machinery gap (incomplete input, unsettled passes) concludes
|
|
376
|
+
* `incomplete` with reasons that explicitly say the failure is reviewer-side
|
|
377
|
+
* uncertainty carried forward for retry, never an invitation to change code.
|
|
378
|
+
* The flat reviewer's constant `unverified` assurance is not a gap.
|
|
379
|
+
*/
|
|
380
380
|
export const concludeReviewOutcome = (
|
|
381
381
|
outcome: ReviewRunOutcome,
|
|
382
382
|
): {
|
|
383
383
|
readonly conclusion: ReviewCheckConclusion;
|
|
384
384
|
readonly reasons: ReadonlyArray<string>;
|
|
385
385
|
} => {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
386
|
+
const machinery: Array<string> = [];
|
|
387
|
+
if (outcome.inputCoverage.status === "incomplete" || outcome.assurance.status === "incomplete") {
|
|
388
|
+
machinery.push(
|
|
389
|
+
outcome.unreviewedPaths.length > 0
|
|
390
|
+
? `review infrastructure did not settle — a reviewer-side gap, not a code defect; ${outcome.unreviewedPaths.length} path(s) are carried forward and retried automatically on the next run`
|
|
391
|
+
: "review infrastructure did not settle — a reviewer-side gap, not a code defect",
|
|
392
|
+
);
|
|
393
|
+
if (outcome.inputCoverage.status === "incomplete") {
|
|
394
|
+
machinery.push(...outcome.inputCoverage.reasons);
|
|
395
|
+
}
|
|
396
|
+
if (outcome.assurance.status === "incomplete") {
|
|
397
|
+
machinery.push(...outcome.assurance.reasons);
|
|
398
|
+
}
|
|
397
399
|
}
|
|
398
|
-
const
|
|
400
|
+
const blocking = blockingReasons({
|
|
399
401
|
findings: outcome.activeFindings,
|
|
400
402
|
concerns: outcome.activeConcerns,
|
|
401
403
|
});
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
404
|
+
if (blocking.length > 0) {
|
|
405
|
+
return { conclusion: "blocking", reasons: [...blocking, ...machinery] };
|
|
406
|
+
}
|
|
407
|
+
if (machinery.length > 0) return { conclusion: "incomplete", reasons: machinery };
|
|
408
|
+
return { conclusion: "success", reasons: [] };
|
|
405
409
|
};
|
|
406
410
|
|
|
407
411
|
const concludeReviewState = (state: ReviewState) => {
|
|
@@ -462,7 +466,6 @@ export const runReviewAction = <E, R, FingerprintE = never, FingerprintR = never
|
|
|
462
466
|
reviewer: HarnessedReviewer<E, R, FingerprintE, FingerprintR>,
|
|
463
467
|
options: {
|
|
464
468
|
readonly post?: boolean | undefined;
|
|
465
|
-
readonly failOn?: FailOnPolicy | undefined;
|
|
466
469
|
/** Skip model execution when the current head already has complete stored coverage. */
|
|
467
470
|
readonly skipUnchanged?: boolean | undefined;
|
|
468
471
|
/** Incremental by default; `final` deliberately re-reviews the full PR diff. */
|
|
@@ -533,6 +536,9 @@ export const runReviewAction = <E, R, FingerprintE = never, FingerprintR = never
|
|
|
533
536
|
(options.reviewMode ?? "incremental") === "incremental" &&
|
|
534
537
|
options.skipUnchanged !== false &&
|
|
535
538
|
recovered.state !== undefined &&
|
|
539
|
+
// Only a fully settled run may be skipped over: an unsettled state
|
|
540
|
+
// carries retryable scope the next run must actually retry.
|
|
541
|
+
recovered.state.settled &&
|
|
536
542
|
currentFingerprint !== undefined &&
|
|
537
543
|
validateReviewState(recovered.state, metadata, profileFingerprint) === undefined &&
|
|
538
544
|
recovered.state.acceptedScopeFingerprint === currentFingerprint
|
|
@@ -605,7 +611,8 @@ export const runReviewAction = <E, R, FingerprintE = never, FingerprintR = never
|
|
|
605
611
|
options.skipUnchanged !== false &&
|
|
606
612
|
selection.mode === "incremental" &&
|
|
607
613
|
selection.files.length === 0 &&
|
|
608
|
-
selection.priorState !== undefined
|
|
614
|
+
selection.priorState !== undefined &&
|
|
615
|
+
selection.priorState.settled
|
|
609
616
|
) {
|
|
610
617
|
const reason = "no changed review scope since the last settled review head";
|
|
611
618
|
return yield* skipCoveredReview({
|
|
@@ -747,7 +754,6 @@ export const reviewActionProgram = Effect.gen(function* () {
|
|
|
747
754
|
};
|
|
748
755
|
const harness = {
|
|
749
756
|
post: inputs.post,
|
|
750
|
-
failOn: inputs.failOn,
|
|
751
757
|
skipUnchanged: inputs.skipUnchanged,
|
|
752
758
|
reviewMode: inputs.reviewMode,
|
|
753
759
|
retireStaleReviews: inputs.retireStaleReviews,
|
|
@@ -23,7 +23,6 @@ const INPUT_TO_ENV: ReadonlyArray<readonly [input: string, env: string]> = [
|
|
|
23
23
|
["INPUT_IGNORE", "PR_REVIEW_IGNORE"],
|
|
24
24
|
["INPUT_MAX-FINDINGS", "PR_REVIEW_MAX_FINDINGS"],
|
|
25
25
|
["INPUT_REVIEW-MODE", "PR_REVIEW_MODE"],
|
|
26
|
-
["INPUT_FAIL-ON", "PR_REVIEW_FAIL_ON"],
|
|
27
26
|
["INPUT_SKIP-UNCHANGED", "PR_REVIEW_SKIP_UNCHANGED"],
|
|
28
27
|
["INPUT_RETIRE-STALE-REVIEWS", "PR_REVIEW_RETIRE_STALE_REVIEWS"],
|
|
29
28
|
["INPUT_PROGRESS-COMMENT", "PR_REVIEW_PROGRESS_COMMENT"],
|