@effect-agent/pr-review 0.1.0-beta.23 → 0.1.0-beta.25

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.
Files changed (37) hide show
  1. package/README.md +83 -195
  2. package/dist/action.d.mts +27 -18
  3. package/dist/action.mjs +60 -39
  4. package/dist/action.mjs.map +1 -1
  5. package/dist/cli.mjs +3 -3
  6. package/dist/cli.mjs.map +1 -1
  7. package/dist/{fan-out-BJBTAYuh.d.mts → fan-out-CMEsbFLk.d.mts} +455 -177
  8. package/dist/{github-BbwYzNrC.mjs → github-NjgxGqwM.mjs} +2163 -1518
  9. package/dist/github-NjgxGqwM.mjs.map +1 -0
  10. package/dist/index.d.mts +30 -20
  11. package/dist/index.mjs +3 -3
  12. package/dist/{providers-NyP-4rS6.mjs → providers-CODZQCmL.mjs} +202 -80
  13. package/dist/providers-CODZQCmL.mjs.map +1 -0
  14. package/dist/testing.d.mts +3 -1
  15. package/dist/testing.mjs +3 -2
  16. package/dist/testing.mjs.map +1 -1
  17. package/package.json +2 -2
  18. package/src/action.ts +141 -78
  19. package/src/cli.ts +6 -1
  20. package/src/index.ts +1 -0
  21. package/src/internal/adjudication.ts +415 -0
  22. package/src/internal/coverage.ts +41 -60
  23. package/src/internal/factory.ts +4 -4
  24. package/src/internal/fan-out.ts +208 -14
  25. package/src/internal/fingerprint.ts +16 -10
  26. package/src/internal/fixtures.ts +6 -0
  27. package/src/internal/github-env.ts +9 -0
  28. package/src/internal/github.ts +243 -7
  29. package/src/internal/progress.ts +1 -1
  30. package/src/internal/render.ts +186 -42
  31. package/src/internal/retirement.ts +16 -17
  32. package/src/internal/review-agent.ts +39 -4
  33. package/src/internal/review-state.ts +315 -105
  34. package/src/internal/review-units.ts +10 -9
  35. package/src/internal/run.ts +197 -63
  36. package/dist/github-BbwYzNrC.mjs.map +0 -1
  37. package/dist/providers-NyP-4rS6.mjs.map +0 -1
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # @effect-agent/pr-review
2
2
 
3
- A bounded, fail-closed GitHub pull-request reviewer built on the effect-agent
4
- public surface. Read-only Agents review host-partitioned pull-request evidence
3
+ A bounded, fail-closed GitHub pull-request reviewer built on effect-agent's public APIs. Read-only
4
+ Agents review host-partitioned pull-request evidence
5
5
  through typed ports; the host validates every finding anchor against the real
6
6
  diff and posts one review after the run settles.
7
7
 
@@ -15,6 +15,7 @@ truncated run posts nothing.
15
15
  import { Effect, Layer } from "effect";
16
16
  import {
17
17
  PrReview,
18
+ fullReviewExecutionContextLayer,
18
19
  gitHubReviewLayers,
19
20
  resolveReviewTarget,
20
21
  makeOpenAiReviewModel,
@@ -27,13 +28,22 @@ const program = Effect.gen(function* () {
27
28
  const target = yield* resolveReviewTarget({ repository: "acme/api", number: 123 });
28
29
  return yield* reviewer
29
30
  .run({ post: true })
30
- .pipe(Effect.provide(Layer.merge(gitHubReviewLayers(target), openAiClientLayer)));
31
+ .pipe(
32
+ Effect.provide(
33
+ fullReviewExecutionContextLayer("explicit direct full review").pipe(
34
+ Layer.provideMerge(Layer.merge(gitHubReviewLayers(target), openAiClientLayer)),
35
+ ),
36
+ ),
37
+ );
31
38
  });
32
39
  ```
33
40
 
34
41
  The run's requirement channel keeps every real dependency visible: the
35
- `PullRequestSource` and `ReviewPublisher` ports, the provider client, and the
36
- handler Layer of any extra tool you add. Anthropic is equally supported
42
+ `PullRequestSource`, `ReviewPublisher`, `ReviewAdjudicationHost`, and
43
+ `ReviewExecutionContext` ports, the provider client, and the handler Layer of
44
+ any extra tool you add. Direct callers provide an explicit full-review context
45
+ as above; the packaged action supplies its selected incremental or full range.
46
+ Anthropic is equally supported
37
47
  (`makeAnthropicReviewModel`, `anthropicClientLayer`), and the factory accepts
38
48
  any Effect AI Model.
39
49
 
@@ -53,44 +63,20 @@ const reviewer = PrReview.make({
53
63
  });
54
64
  ```
55
65
 
56
- Every knob widens what goes INTO the review. What leaves it is not
57
- configurable: model output is untrusted input, so finding anchors are
58
- re-validated against the parsed unified diff (invalid ones are demoted into
59
- the review body with the reason named, never trusted), the findings bound is
60
- enforced host-side, and publication happens only through the
61
- `ReviewPublisher` port after the run settles. `PrReview.makeFanOut` builds the
62
- assured host-scheduled variant. The host deterministically partitions bounded
63
- evidence, classifies high-risk units, requires a general discovery pass for
64
- every unit, adds a fresh specialist discovery pass for every unit, and uses
65
- deterministic host-classified risk categories as explicit focus labels. A
66
- fresh verifier must confirm or reject every discovered candidate. Every pass
67
- runs as a bounded evidence-only child dispatched directly by host code with
68
- Effect structured concurrency there is no coordinator model and no
69
- delegation tool, so nothing depends on a model copying the plan correctly. A
70
- pass that fails (child fault, malformed or misdirected output) is retried
71
- once; a pass that stays failed is reported and its unit's paths carry forward
72
- as retryable scope. Verifiers receive the exact candidate claims and the
73
- complete bounded unit, including neighboring evidence that can falsify a
74
- locally plausible claim; they do not receive discovery reasoning.
75
- The host builds publishable findings and concerns from exact confirmed
76
- candidate IDs and deduplicates byte-identical cross-pass claims in
77
- deterministic plan order; a discovery claim anchored outside its assigned
78
- evidence is discarded and counted, never published and never pass-fatal. The
79
- summary and verdict are composed deterministically from the confirmed
80
- severities. Shared `guidance` reaches both discovery and verification;
81
- `maxFindings` remains a host-enforced publication cap.
82
-
83
- GitHub may omit the `patch` field for large textual files as well as binary
84
- files. The GitHub source recovers a missing patch by reading bounded, strict
85
- UTF-8 base/head content: additions require the head, deletions require the
86
- base, and other changes require both. Reviewers receive that content through
87
- the ordinary diff-read tool with non-anchorable `B`/`H` line labels and must
88
- report defects as review-body concerns. Invalid UTF-8, binary NUL content,
89
- missing sides, and files beyond the per-side read bound leave a path with no
90
- reviewable textual evidence. Such paths keep input coverage incomplete and are
91
- carried for as long as they are part of the pull request — an unreviewable
92
- change must never authorize a green check; exclude them deliberately with
93
- ignore globs when that is intended.
66
+ Model output is untrusted. The host revalidates anchors, enforces `maxFindings`, and publishes only
67
+ after the run settles. `PrReview.makeFanOut` partitions bounded evidence and schedules general and
68
+ specialist discovery for every unit, followed by independent candidate verification. Verifiers
69
+ receive the exact claims and enough neighboring evidence to reject a plausible mistake, but no
70
+ discovery reasoning.
71
+
72
+ Each failed pass retries once, then carries its unit forward. The host accepts only confirmed
73
+ candidate IDs, discards anchors outside assigned evidence, deduplicates claims in plan order, and
74
+ derives the verdict from validated severities. Shared `guidance` reaches discovery and verification.
75
+
76
+ When GitHub omits a textual patch, the source reads bounded, strict UTF-8 base/head content and
77
+ labels it with non-anchorable `B`/`H` lines. Invalid UTF-8, binary NUL content, missing sides, and
78
+ oversized files remain unreviewable and keep input coverage incomplete. Exclude them with ignore
79
+ globs only when that is intentional.
94
80
 
95
81
  ## Assurance model
96
82
 
@@ -117,51 +103,52 @@ favors redundant work, but it cannot recognize every semantically risky
117
103
  change. The specialist pass is context-independent redundancy, not a claim of
118
104
  provider or model diversity. Running it for every unit prevents classifier
119
105
  silence from suppressing scrutiny; the category labels still cannot prove
120
- that every semantic risk was recognized. The legacy aggregate `coverage` field remains
121
- for compatibility; new hosts and UI use `inputCoverage` and `assurance`.
106
+ that every semantic risk was recognized. Hosts and UI use `inputCoverage` and `assurance`.
122
107
  The flat reviewer has path-input accounting but no independent verifier, so
123
108
  its assurance is `unverified` and the Action check cannot report success from
124
109
  that shape.
125
110
 
111
+ ## Maintainer adjudication
112
+
113
+ A maintainer can settle a finding without changing code, from the pull request itself:
114
+
115
+ - On a finding's inline thread, reply `/adjudicate accepted-risk|refuted|obsolete[: reason]`.
116
+ The thread names the target, so the verb alone suffices.
117
+ - For an unanchored concern, comment
118
+ `/adjudicate <disposition> "<exact concern title>"[: reason]` in the PR conversation. The quoted
119
+ title is required and must match exactly.
120
+
121
+ An adjudicated identity leaves active findings, verdict counts, and the check conclusion; it
122
+ renders in a collapsed "Adjudicated" section instead, and the final audit distinguishes fixed,
123
+ adjudicated, and still-open items. The reviewer prompt names each adjudication so the model does
124
+ not re-raise it without materially new evidence. Identity is exact — path, line range, and title
125
+ for findings, title alone for concerns — so a materially different finding at the same location is
126
+ untouched. Adjudications persist in the signed review state, and the skip-unchanged path re-reads
127
+ them, so an adjudication lifts a blocking check without a new commit.
128
+
129
+ **Authorization is fail-closed**: only comments whose `author_association` is OWNER, MEMBER, or
130
+ COLLABORATOR adjudicate. Anything else — third parties, bots, malformed commands — is ignored
131
+ (logged at debug). Later adjudications of the same identity win by comment creation order, bounded
132
+ at 20 stored entries (oldest dropped with a logged notice). If either GitHub listing surface fails,
133
+ or one thread exceeds the bounded authorized-command history, fresh collection is discarded and
134
+ the stored set stands unchanged.
135
+
136
+ **Rejected alternative — parsing free-text rebuttals** ("this is fine because …" replies): only an
137
+ explicit, authorized verb is auditable and fail-closed. Inferring intent from prose would let model
138
+ output or third-party comments silently suppress findings, and nobody could later say which comment
139
+ dismissed what.
140
+
126
141
  ## What a posted review looks like
127
142
 
128
- The body opens with a host-derived callout tier `[!CAUTION]` when any
129
- finding is blocking, `[!IMPORTANT]` for important findings, an ℹ️ blockquote
130
- for nits, `✅` for a clean approval computed from the validated severities,
131
- never from model prose. Directly under it, one host-derived stats line names
132
- the changeset size (`N files (+adds / −dels)`), the severity tally, and a
133
- deterministic 1–5 review-effort estimate computed from the changeset shape
134
- alone. Fan-out reviews add a second host-derived line naming input assignment,
135
- discovery/specialist/verification settlement, and candidate dispositions.
136
- Below the summary, a collapsed **📝 Walkthrough** table carries the
137
- model's one-sentence per-file change summaries — walkthrough paths are
138
- validated like finding anchors, so entries naming files outside the changeset
139
- are dropped. Under fan-out only summaries a
140
- successfully settled general pass actually reported for its own unit's paths
141
- survive, so a child cannot smuggle or invent entries. Non-anchored `concerns`
142
- (deletion plans, rollout sequencing,
143
- coverage gaps, scope questions — things with no diff line to point at) render
144
- as severity-tagged sections; demoted findings and findings carried from
145
- unchanged scope collapse into counted `<details>` sections.
146
-
147
- Each inline comment is headed by its severity plus an optional model-claimed
148
- category chip (`**[⚠️ important · security] …**`), carries a committable
149
- GitHub `suggestion` fence when independent verification settled the model's
150
- suggestion as committable replacement source, and ends with a
151
- collapsed **🤖 Prompt for AI agents** — a copy-paste instruction derived
152
- host-side from the validated finding, opening with a fixed preamble telling
153
- the receiving agent to treat the finding content as untrusted review data.
154
- The review body repeats every finding — anchored, demoted, and carried — in
155
- one consolidated prompt block so nothing needs to be collected by hand. The
156
- footer names the model binding, the observed token usage, and links to the
157
- workflow run; an invisible metadata comment pins the reviewed head commit so
158
- later readers know when line callouts have gone stale.
143
+ The host derives callouts, statistics, walkthroughs, inline comments, and the final prompt from
144
+ validated findings. Model prose cannot choose the verdict or smuggle paths outside the changeset.
145
+ The [Action guide](../../action/README.md) documents the rendered review and workflow outputs.
159
146
 
160
147
  ## Swap a port
161
148
 
162
149
  Tools observe the pull request only through `PullRequestSource`; publication
163
150
  happens only through `ReviewPublisher`. Provide your own Layers to review
164
- anything diff-shaped or publish anywhere else — the GitHub REST adapters are
151
+ any diff-shaped input or publish elsewhere. The GitHub REST adapters are
165
152
  one implementation, not the contract.
166
153
 
167
154
  ## Test what you adapted
@@ -176,124 +163,25 @@ import {
176
163
  ```
177
164
 
178
165
  Deterministic in-memory adapters for both ports plus prompt-keyed scripted
179
- models that walk the real tool surface no network, no credentials, every
180
- ordinary gate.
181
-
182
- ## Incremental Action reviews
183
-
184
- Every completed Action review that can be signed carries bounded, versioned,
185
- HMAC-authenticated continuity state: the exact PR/base/head lineage, profile
186
- and settled-scope fingerprints, the still-unresolved findings and concerns,
187
- any retryable unreviewed paths, and whether the run fully settled. The
188
- baseline is monotone by design — a flaky or failed pass carries exactly its
189
- own scope forward instead of freezing the baseline and reopening everything
190
- reviewed since (the non-converging loop of issue #131). A later Action run
191
- validates the state and reviews the GitHub comparison from that reviewed head
192
- to the current head plus the carried unreviewed paths, not the complete
193
- base...HEAD diff. Unchanged settled scope is not sent back to the model;
194
- unchanged unresolved findings remain active; changed or reverted paths
195
- invalidate their prior findings and receive fresh discovery and verification.
196
- Whole overflow files are reviewed in bounded installments across pushes
197
- through the same carry; a single file beyond total plan capacity and
198
- undiffable paths stay explicitly incomplete instead — an unreviewable tail
199
- never moves behind a green check. Non-anchored concerns are carried conservatively
200
- until a full audit because they cannot be mapped safely to one path.
201
-
202
- The state marker must be terminal, signed with the configured stable
203
- `PR_REVIEW_STATE_SECRET`, authored by the configured review-posting bot, and
204
- pinned to the reviewed commit. The expected author defaults to
205
- `github-actions[bot]`; set `PR_REVIEW_AUTHOR_LOGIN` (or the Action's
206
- `review-author` input) to `<app-slug>[bot]` when posting with a custom GitHub
207
- App token. State lookup, authentication, schema, identity, ancestry, profile,
208
- and comparison checks are fail-closed for scope selection: missing, stale,
209
- incompatible, or truncated state/comparisons produce a visible full-diff
210
- fallback. An ancestor base advance remains incremental and adds overlapping
211
- PR paths as affected context; a materially changed base lineage falls back to
212
- full unless the authenticated settled-scope fingerprint still matches. The
213
- schema field retains the compatibility name `acceptedScopeFingerprint`. That
214
- fingerprint hashes the ignore-filtered effective diff, patchless base/head
215
- evidence, PR framing, and review-shaping profile while excluding commit IDs,
216
- base ancestry, and unified-diff hunk coordinates. Re-running the same head or a
217
- patch-equivalent rebase skips model execution by default ONLY when the stored
218
- state fully settled — a state carrying unreviewed scope is always retried.
219
- The preserved skip keeps its stored blocking/success conclusion and posts no
220
- duplicate review comments. Missing/corrupt state and any fingerprint or
221
- profile mismatch review conservatively.
222
-
223
- After a new state-bearing Action review posts, prior marker-bearing bot reviews
224
- are retired by default: their bodies become collapsed, superseded history,
225
- resolved findings are struck through, and matching inline comments are
226
- minimized as outdated. Only strictly older reviews from the same GitHub actor
227
- are eligible, so copied markers and newer concurrent reviews are untouched.
228
- The machine-state comments remain byte-identical and terminal, so an edited
229
- body still participates in incremental state recovery.
230
- This cosmetic pass is fail-open and can be disabled with the Action input
231
- `retire-stale-reviews: "false"`.
232
-
233
- Authentication is an explicit Effect service supplied by the Action host;
234
- WebCrypto import/sign/verify failures stay typed. The terminal marker is
235
- schema-branded and capped at 24,000 characters. If signing fails or state
236
- exceeds that bound, the completed review is posted without continuity state
237
- and with a bounded warning, so the next run safely performs a full review.
238
-
239
- `review-mode: final` is the explicit bounded merge-readiness audit. It ignores
240
- prior assurance state, plans fresh discovery over the full current PR
241
- diff, verifies new candidates, and resets the incremental baseline; normal
242
- `synchronize` events use `incremental` and do not perform this audit.
243
- Because equivalence is based on the textual review surface, a base change that
244
- alters runtime meaning without changing the diff/context is not detectable;
245
- request `final` mode (or disable unchanged skipping) for that case.
246
-
247
- ## Hosts
248
-
249
- - **GitHub Actions**: the repository ships a prebuilt node-runtime action
250
- supporting a committed review-profile document via `guidance-file` (this
251
- repository's own profile lives at `.github/review-guidance.md`)
252
- (`action/` at the repo root) — `uses` it with an API-key secret and nothing
253
- else. Fan-out is the Action default because the flat compatibility shape
254
- has no independent verifier and cannot settle review assurance. While a run executes it maintains one sticky, fail-open "review in
255
- progress" comment updated in place with the settled outcome
256
- (`progress-comment` input, default on; at-least-once with generation-fenced
257
- writes and best-effort duplicate cleanup — strict single-comment behavior
258
- comes from a per-PR workflow concurrency group), and its logs render one
259
- compact line per event (`log-level` input, default `Info`). For custom reviewers in
260
- CI, `@effect-agent/pr-review/action` exports `runReviewAction` (event
261
- resolution, typed draft/non-PR skips, bounded range selection, step
262
- outputs, and conservative check gate) to harness your own `reviewer.run`;
263
- pass `progressComment: true` to opt a custom harness into the sticky
264
- progress comment. A custom fingerprint-only harness remains source-compatible
265
- but cannot skip model work: unchanged skipping requires the profile fingerprint
266
- and authenticated state that prove the prior configured work settled.
267
- - **CLI**: `bun src/cli.ts --repo owner/name --pr 123 [--post] [--provider anthropic] [--fan-out]`
268
- (also exported as the `./cli` entry).
269
-
270
- Environment: `OPENAI_API_KEY` or `ANTHROPIC_API_KEY` for the model,
271
- `PR_REVIEW_STATE_SECRET` to authenticate incremental state,
272
- `PR_REVIEW_AUTHOR_LOGIN` to match a custom review-posting bot (defaults to
273
- `github-actions[bot]`),
274
- `GITHUB_TOKEN` to post (optional for public-repository reads), and the
275
- standard `GITHUB_REPOSITORY` / `GITHUB_EVENT_PATH` / `GITHUB_API_URL`
276
- variables inside Actions.
166
+ models that call the real Tools. Tests need no network or credentials and exercise every ordinary
167
+ gate.
168
+
169
+ ## Action and CLI
170
+
171
+ The prebuilt GitHub Action handles signed incremental state, fail-closed scope selection, sticky
172
+ progress, stale-review retirement, and final audits. See its [setup and behavior guide](../../action/README.md)
173
+ and [input reference](../../action/action.yml). Custom hosts can import `runReviewAction` from
174
+ `@effect-agent/pr-review/action`.
175
+
176
+ Run the CLI with
177
+ `bun src/cli.ts --repo owner/name --pr 123 [--post] [--provider anthropic] [--fan-out]`.
277
178
 
278
179
  ## Bounds, spelled out
279
180
 
280
- Finite `AgentPolicy` on every definition plus run-level `UsageBudgetLimits`
281
- (tokens, tool calls, cost, duration). Reading either file version beyond 200k
282
- bytes or characters is refused typed; patchless content is reviewable only
283
- when its complete B/H rendering fits 220k characters. The changeset surface is
284
- bounded at 300 files:
285
- files beyond the bound are not fetched, and the review body reports
286
- `Input exposed N of M changed files` instead of claiming completeness.
287
- Fan-out capacity overflow is reported, never dropped. Every fan-out unit has
288
- at most 12 files, 12 complete evidence shards, and 240,000 evidence characters;
289
- one path may span multiple shards or units when necessary. If the eight-unit
290
- plan capacity is exhausted, every affected path and the exact shard count are
291
- reported, with a deterministic identifier sample bounded to one plan's capacity;
292
- at most eight units produce at most 24 attached children (general and
293
- specialist discovery plus one verification batch per unit), with child
294
- concurrency capped at four. Any blocking active finding fails the Action
295
- check. Any input gap—including an unassigned evidence shard—failed or
296
- exhausted configured pass, mismatched candidate batch, or unsettled
297
- verification is non-success rather than green. A settled
298
- clean result is evidence that these bounded passes completed, not proof that
299
- no defect exists.
181
+ Every definition has a finite `AgentPolicy` and run-level `UsageBudgetLimits`. The reviewer rejects
182
+ file versions beyond 200k bytes or characters and patchless B/H renderings beyond 220k characters.
183
+ It reads at most 300 changed files. Each fan-out unit holds at most 12 files, 12 complete evidence
184
+ shards, and 240,000 evidence characters. At most eight units produce 24 attached children with
185
+ child concurrency capped at four. The result reports every capacity overflow. Any blocking
186
+ finding, input gap, failed pass, exhausted pass, mismatched candidate batch, or unsettled
187
+ verification prevents a green check.
package/dist/action.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { L as PriorReviews, P as GitHubApiFailure, X as ReviewRetirementHost, ar as PullRequestSource, bt as ReviewStateAuthenticator, ht as ReviewMode, ir as PullRequestMetadata, lr as ChangedFile, or as PullRequestSourceFailure, z as ReviewPublisher } from "./fan-out-BJBTAYuh.mjs";
1
+ import { Br as ChangedFile, Cn as ReviewStateAuthenticator, Fr as PullRequestMetadata, Ir as PullRequestSource, L as PriorReviews, Lr as PullRequestSourceFailure, P as GitHubApiFailure, Q as ReviewRetirementHost, Qt as ReviewAdjudicationHost, gn as ReviewExecutionContext, vn as ReviewMode, z as ReviewPublisher } from "./fan-out-CMEsbFLk.mjs";
2
2
  import { EffortPosition, InvalidEffortInput, ReviewProgressReporter, ReviewProvider, ReviewRunOutcome, ReviewTargetUnresolved, RunReviewOptions } from "./index.mjs";
3
3
  import { Config, Effect, FileSystem, Schema } from "effect";
4
4
  import { BudgetExceeded } from "effect-agent";
@@ -92,29 +92,38 @@ type ReviewActionResult = {
92
92
  * The reviewer surface the action harness drives. `PrReview.make` and
93
93
  * `PrReview.makeFanOut` provide the state-selection effects. A fingerprint is
94
94
  * skip authority only when a profile fingerprint and authenticated review
95
- * state bind it to settled assurance; a fingerprint-only custom harness
96
- * remains source-compatible but deliberately runs instead of claiming green
97
- * assurance from unauthenticated prior-review text.
95
+ * state bind it to settled assurance.
98
96
  */
99
- interface HarnessedReviewer<E, R, FingerprintE, FingerprintR> {
100
- readonly run: (runOptions?: RunReviewOptions) => Effect.Effect<ReviewRunOutcome, E, R>;
97
+ interface HarnessedReviewerBase<E, R> {
98
+ /** The action composition root always supplies the selected run context. */
99
+ readonly run: (runOptions?: RunReviewOptions) => Effect.Effect<ReviewRunOutcome, E, R | ReviewExecutionContext>;
100
+ }
101
+ type HarnessedReviewer<E, R, FingerprintE, FingerprintR> = HarnessedReviewerBase<E, R> & ({
102
+ readonly fingerprint?: undefined;
103
+ readonly profileFingerprint?: undefined;
104
+ readonly snapshot?: undefined;
105
+ readonly filterFiles?: undefined;
106
+ } | {
101
107
  /** Current effective changeset fingerprint; not standalone skip authority. */
102
- readonly fingerprint?: Effect.Effect<string, FingerprintE, FingerprintR> | undefined;
103
- readonly profileFingerprint?: Effect.Effect<string, FingerprintE, FingerprintR> | undefined;
104
- readonly snapshot?: Effect.Effect<{
108
+ readonly fingerprint: Effect.Effect<string, FingerprintE, FingerprintR>;
109
+ readonly profileFingerprint: Effect.Effect<string, FingerprintE, FingerprintR>;
110
+ readonly snapshot: Effect.Effect<{
105
111
  readonly metadata: PullRequestMetadata;
106
112
  readonly files: ReadonlyArray<ChangedFile>;
107
- }, FingerprintE, FingerprintR> | undefined;
113
+ }, FingerprintE, FingerprintR>;
108
114
  readonly filterFiles?: ((files: ReadonlyArray<ChangedFile>) => ReadonlyArray<ChangedFile>) | undefined;
109
- }
115
+ });
110
116
  /**
111
117
  * Host-derived check conclusion; model verdict prose cannot weaken it.
112
118
  *
113
119
  * Blocking code findings outrank machinery gaps — they are the actionable
114
- * signal. A machinery gap (incomplete input, unsettled passes) concludes
115
- * `incomplete` with reasons that explicitly say the failure is reviewer-side
116
- * uncertainty carried forward for retry, never an invitation to change code.
117
- * The flat reviewer's constant `unverified` assurance is not a gap.
120
+ * signal. A retryable machinery gap (failed passes, capacity overflow)
121
+ * concludes `incomplete` with reasons that explicitly say the failure is
122
+ * reviewer-side uncertainty carried forward for retry, never an invitation to
123
+ * change code. Undiffable files are the deliberate exception: no retry can
124
+ * settle them, so their reason instructs removal or ignore globs instead of
125
+ * promising an automatic retry. The flat reviewer's constant `unverified`
126
+ * assurance is not a gap.
118
127
  */
119
128
  declare const concludeReviewOutcome: (outcome: ReviewRunOutcome) => {
120
129
  readonly conclusion: ReviewCheckConclusion;
@@ -154,7 +163,7 @@ declare const runReviewAction: <E, R, FingerprintE = never, FingerprintR = never
154
163
  } | {
155
164
  _tag: "Completed";
156
165
  outcome: ReviewRunOutcome;
157
- }, E | FingerprintE | Config.ConfigError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved, FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient | ReviewStateAuthenticator | Exclude<FingerprintR, PriorReviews | PullRequestSource | ReviewProgressReporter | ReviewPublisher | ReviewRetirementHost> | Exclude<R, PriorReviews | PullRequestSource | ReviewProgressReporter | ReviewPublisher | ReviewRetirementHost>>;
166
+ }, E | FingerprintE | Config.ConfigError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved, FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient | ReviewStateAuthenticator | Exclude<FingerprintR, PriorReviews | PullRequestSource | ReviewAdjudicationHost | ReviewProgressReporter | ReviewPublisher | ReviewRetirementHost> | Exclude<Exclude<R, PullRequestSource | ReviewExecutionContext>, PriorReviews | PullRequestSource | ReviewAdjudicationHost | ReviewProgressReporter | ReviewPublisher | ReviewRetirementHost>>;
158
167
  /**
159
168
  * The packaged, environment-driven action program: inputs from PR_REVIEW_*,
160
169
  * reviewer built from the packaged factory, provider client from the
@@ -166,7 +175,7 @@ declare const reviewActionProgram: Effect.Effect<{
166
175
  } | {
167
176
  _tag: "Completed";
168
177
  outcome: ReviewRunOutcome;
169
- }, import("effect-agent").AgentApprovalDenied | import("effect-agent").AgentApprovalPending | import("effect-agent").AgentChildPending | import("effect-agent").AgentInputError | import("effect-agent").AgentOutputError | import("effect-agent").AgentPolicyError | import("effect-agent").AgentToolAuthorizationDenied | import("effect/unstable/ai/AiError").AiError | import("effect-agent").BudgetAdapterError | BudgetExceeded | Config.ConfigError | import("effect-agent").ContextOverflowError | GitHubApiFailure | GuidanceFileUnreadable | InvalidEffortInput | InvalidMaxDurationInput | import("effect-agent").ModelProtocolError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved | Schema.SchemaError, FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient>;
178
+ }, import("effect-agent").AgentApprovalDenied | import("effect-agent").AgentApprovalPending | import("effect-agent").AgentChildPending | import("effect-agent").AgentInputError | import("effect-agent").AgentOutputError | import("effect-agent").AgentPolicyError | import("effect-agent").AgentToolAuthorizationDenied | import("effect/unstable/ai/AiError").AiError | import("effect-agent").BudgetAdapterError | BudgetExceeded | Config.ConfigError | import("effect-agent").ContextOverflowError | GitHubApiFailure | GuidanceFileUnreadable | InvalidEffortInput | InvalidMaxDurationInput | import("effect-agent").ModelProtocolError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved | Schema.SchemaError, import("effect/Crypto").Crypto | FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient>;
170
179
  /** Run the packaged action program on Node; the bundled action entrypoint. */
171
180
  declare const main: () => void;
172
181
  /** The packaged GitHub Actions surface. */
@@ -195,7 +204,7 @@ declare const PrReviewAction: {
195
204
  } | {
196
205
  _tag: "Completed";
197
206
  outcome: ReviewRunOutcome;
198
- }, import("effect-agent").AgentApprovalDenied | import("effect-agent").AgentApprovalPending | import("effect-agent").AgentChildPending | import("effect-agent").AgentInputError | import("effect-agent").AgentOutputError | import("effect-agent").AgentPolicyError | import("effect-agent").AgentToolAuthorizationDenied | import("effect/unstable/ai/AiError").AiError | import("effect-agent").BudgetAdapterError | BudgetExceeded | Config.ConfigError | import("effect-agent").ContextOverflowError | GitHubApiFailure | GuidanceFileUnreadable | InvalidEffortInput | InvalidMaxDurationInput | import("effect-agent").ModelProtocolError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved | Schema.SchemaError, FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient>;
207
+ }, import("effect-agent").AgentApprovalDenied | import("effect-agent").AgentApprovalPending | import("effect-agent").AgentChildPending | import("effect-agent").AgentInputError | import("effect-agent").AgentOutputError | import("effect-agent").AgentPolicyError | import("effect-agent").AgentToolAuthorizationDenied | import("effect/unstable/ai/AiError").AiError | import("effect-agent").BudgetAdapterError | BudgetExceeded | Config.ConfigError | import("effect-agent").ContextOverflowError | GitHubApiFailure | GuidanceFileUnreadable | InvalidEffortInput | InvalidMaxDurationInput | import("effect-agent").ModelProtocolError | import("effect/PlatformError").PlatformError | PullRequestSourceFailure | ReviewGateFailed | ReviewTargetUnresolved | Schema.SchemaError, import("effect/Crypto").Crypto | FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient>;
199
208
  readonly main: typeof main;
200
209
  };
201
210
  //#endregion