@effect-agent/pr-review 0.1.0-beta.11 → 0.1.0-beta.111

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 (59) hide show
  1. package/NOTICE +26 -0
  2. package/README.md +181 -172
  3. package/dist/Review.d.mts +294 -0
  4. package/dist/Review.mjs +738 -0
  5. package/dist/Review.mjs.map +1 -0
  6. package/dist/ReviewRepository-Wd_4qCaO.d.mts +71 -0
  7. package/dist/ReviewRepository.d.mts +2 -0
  8. package/dist/ReviewRepository.mjs +15 -0
  9. package/dist/ReviewRepository.mjs.map +1 -0
  10. package/dist/index.d.mts +3 -718
  11. package/dist/index.mjs +3 -66
  12. package/dist/repository-D7NN3225.mjs +101 -0
  13. package/dist/repository-D7NN3225.mjs.map +1 -0
  14. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  15. package/package.json +1 -54
  16. package/src/Review.ts +1111 -0
  17. package/src/ReviewRepository.ts +9 -0
  18. package/src/index.ts +2 -21
  19. package/src/internal/repository.ts +156 -0
  20. package/dist/action.d.mts +0 -190
  21. package/dist/action.mjs +0 -423
  22. package/dist/action.mjs.map +0 -1
  23. package/dist/cli.d.mts +0 -1
  24. package/dist/cli.mjs +0 -103
  25. package/dist/cli.mjs.map +0 -1
  26. package/dist/fan-out-TrA9EUCr.d.mts +0 -1085
  27. package/dist/github-5TCFrxfX.mjs +0 -1676
  28. package/dist/github-5TCFrxfX.mjs.map +0 -1
  29. package/dist/index.mjs.map +0 -1
  30. package/dist/providers-DobNWMUn.mjs +0 -990
  31. package/dist/providers-DobNWMUn.mjs.map +0 -1
  32. package/dist/testing.d.mts +0 -131
  33. package/dist/testing.mjs +0 -230
  34. package/dist/testing.mjs.map +0 -1
  35. package/src/action.ts +0 -697
  36. package/src/cli.ts +0 -214
  37. package/src/internal/action-entry.ts +0 -43
  38. package/src/internal/coverage.ts +0 -245
  39. package/src/internal/diff.ts +0 -134
  40. package/src/internal/effort.ts +0 -86
  41. package/src/internal/factory.ts +0 -374
  42. package/src/internal/fan-out-scripted.ts +0 -164
  43. package/src/internal/fan-out.ts +0 -450
  44. package/src/internal/fingerprint.ts +0 -74
  45. package/src/internal/fixtures.ts +0 -131
  46. package/src/internal/github-env.ts +0 -148
  47. package/src/internal/github.ts +0 -774
  48. package/src/internal/ignore.ts +0 -88
  49. package/src/internal/profiles.ts +0 -79
  50. package/src/internal/providers.ts +0 -94
  51. package/src/internal/render.ts +0 -428
  52. package/src/internal/retirement.ts +0 -332
  53. package/src/internal/review-agent.ts +0 -385
  54. package/src/internal/review-state.ts +0 -488
  55. package/src/internal/review-units.ts +0 -167
  56. package/src/internal/run.ts +0 -397
  57. package/src/internal/scripted.ts +0 -108
  58. package/src/internal/source.ts +0 -110
  59. package/src/testing.ts +0 -8
package/NOTICE ADDED
@@ -0,0 +1,26 @@
1
+ This package includes adaptations of the review instructions from PR-Agent:
2
+
3
+ https://github.com/The-PR-Agent/pr-agent
4
+ Pinned source: 9e6d6a5b40f9ce90bcc085466ba7a42c0837c37a
5
+
6
+ MIT License
7
+
8
+ Copyright (c) 2026 The PR Agent
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
package/README.md CHANGED
@@ -1,178 +1,187 @@
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. One read-only Agent reviews a pull request through typed
5
- ports; the host validates every finding anchor against the real diff and
6
- posts one review after the run settles.
7
-
8
- **Deployment class E (ephemeral).** One `AgentRuntime.run` per invocation, no
9
- durability claim, and review posting is never exactly-once: a failed or
10
- truncated run posts nothing.
11
-
12
- ## Use
13
-
14
- ```ts
15
- import { Effect, Layer } from "effect";
16
- import {
17
- PrReview,
18
- gitHubReviewLayers,
19
- resolveReviewTarget,
20
- makeOpenAiReviewModel,
21
- openAiClientLayer,
22
- } from "@effect-agent/pr-review";
23
-
24
- const reviewer = PrReview.make({ model: makeOpenAiReviewModel() });
25
-
26
- const program = Effect.gen(function* () {
27
- const target = yield* resolveReviewTarget({ repository: "acme/api", number: 123 });
28
- return yield* reviewer
29
- .run({ post: true })
30
- .pipe(Effect.provide(Layer.merge(gitHubReviewLayers(target), openAiClientLayer)));
31
- });
32
- ```
33
-
34
- 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
37
- (`makeAnthropicReviewModel`, `anthropicClientLayer`), and the factory accepts
38
- any Effect AI Model.
39
-
40
- ## Adapt
41
-
42
- ```ts
43
- const reviewer = PrReview.make({
44
- model: makeAnthropicReviewModel("claude-sonnet-5"),
45
- guidance: (mission) => [
46
- "This is an Effect codebase. Flag naked Promises in public APIs.",
47
- mission.changedFileCount > 50 ? "Large PR: prioritize breadth over nit depth." : "",
48
- ],
49
- ignore: ["**/*.lock", "dist/**"],
50
- maxFindings: 10,
51
- policy: { maxTurns: 20, maxToolCalls: 40, maxDuration: "10 minutes", toolConcurrency: 2 },
52
- extraTools: [MyReadonlyTool], // must be annotated ToolExecutionClass "readonly"
53
- });
54
- ```
55
-
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
62
- the delegating variant bounded per-unit child reviewers (S1 attached
63
- ephemeral delegation) merged under the same output contract and the same
64
- publication path; the shared `guidance` and `maxFindings` shape the
65
- coordinator's merge as well as the children.
66
-
67
- ## What a posted review looks like
68
-
69
- The body opens with a host-derived callout tier `[!CAUTION]` when any
70
- finding is blocking, `[!IMPORTANT]` for important findings, an ℹ️ blockquote
71
- for nits, `✅` for a clean approval computed from the validated severities,
72
- never from model prose. Below the summary, non-anchored `concerns` (deletion
73
- plans, rollout sequencing, coverage gaps, scope questions things with no
74
- diff line to point at) render as severity-tagged sections. The footer names
75
- the model binding, the observed token usage, and links to the workflow run;
76
- an invisible metadata comment pins the reviewed head commit so later readers
77
- know when line callouts have gone stale.
78
-
79
- ## Swap a port
80
-
81
- Tools observe the pull request only through `PullRequestSource`; publication
82
- happens only through `ReviewPublisher`. Provide your own Layers to review
83
- anything diff-shaped or publish anywhere else — the GitHub REST adapters are
84
- one implementation, not the contract.
85
-
86
- ## Test what you adapted
3
+ A provider-neutral agent that reviews an exact base-to-head change using a complete change
4
+ index, paged diffs, and immutable source tools. One conversation follows related behavior across
5
+ files. There are no separate patch batches, candidate pipeline, voting, or repository execution.
6
+
7
+ ## Evidence and findings
8
+
9
+ The initial prompt includes every admitted path and its character range in one literal diff
10
+ artifact. Changes up to 32,000 characters are included directly. Larger changes use `read_diff`:
11
+ start at offset zero and follow `nextOffset`, or select a file's start offset from the index.
12
+ Pages contain at most 32,000 UTF-16 characters and can cross file boundaries or split lines.
13
+ Original unified patches, hunk coordinates, deletions, renames, and mode metadata remain intact.
14
+
15
+ `read_file` reads up to 200 lines and 20,000 characters at the exact base or head.
16
+ `find_files` searches filenames. `search_code` searches literal, case-sensitive source text to
17
+ find definitions, callers, consumers, and tests, including unchanged code. Its path filter is a
18
+ filename substring; cursor zero starts the search. Each page scans twenty authorized files,
19
+ returns up to five matching lines per file, and provides `nextCursor` for more files.
20
+ `truncated` identifies omitted matching lines and `unreadablePaths` identifies failed reads.
21
+ A partial or failed search cannot establish that a caller is absent.
22
+
23
+ The reviewer starts with the promised consumer outcome and traces supported execution paths,
24
+ including unchanged callers and consumers. It distinguishes missing promised behavior from
25
+ optional feature expansion. Before recording a defect, it checks the
26
+ strongest relevant guard, documented exception, or alternative interpretation and establishes
27
+ why the supported trigger still causes concrete impact. It checks base/head causation, boundary
28
+ values, cleanup, concurrency, and whether changed tests would detect the claimed failure.
29
+ New features must satisfy their stated contracts, including validation, limits, isolation,
30
+ and aggregation; a bypass can be a defect even when the old code also accepted that input.
31
+ Unrelated old bugs, speculation, style, compiler diagnostics, and generic test requests are
32
+ excluded. Incremental reviews limit new findings to their exact delta.
33
+
34
+ The shared finding rubric, parent review procedure, and host-supplied repository policy are
35
+ separate instructions. Policy findings identify the specific rule and applicable exceptions,
36
+ citing instruction paths and lines when available. An explicitly reviewable architecture
37
+ contract can warrant a finding without a runtime failure; its supplied severity takes precedence.
38
+
39
+ `record_finding` is the only way to add findings to the report. The model is instructed to record
40
+ each distinct root cause once and recover the saved ledger with `review_status` after `new_context`,
41
+ without re-recording an issue with revised wording or severity. Counterevidence must be checked
42
+ before recording because the ledger has no retraction or revision operation. `submit_review` is the
43
+ required native completion tool and accepts only `blockedOn` and `resolutions` metadata.
44
+ The host builds the final report directly from the ledger, so completion never rewrites or merges
45
+ findings. Extra completion fields fail validation.
46
+
47
+ The host validates changed paths and RIGHT-side line anchors, demotes invalid anchors to
48
+ top-level findings, and removes only exact repeated records. Distinct defects at the same path
49
+ and line remain separate. Up to 24 findings are retained, prioritizing blocking over important
50
+ over minor findings. Overflow always marks the result incomplete, regardless of later completion.
51
+ Finding paths, titles, and bodies retain their 512, 200, and 2,000-character bounds.
52
+
53
+ ## Coverage and limits
54
+
55
+ Requests admit up to 1,000 distinct changed paths, 2,000,000 characters per patch, and 8,000,000
56
+ patch characters overall. These are host input limits, separate from the model's working context.
57
+ Source hosts can apply additional authorization and admission bounds.
58
+
59
+ The host tracks diff ranges available to completed model requests. Merely issuing a read, repeating
60
+ a page, skipping ahead, or failing a tool does not establish complete coverage. `pendingPaths`
61
+ includes partially read files. `review_status` recovers saved findings and outstanding ranges;
62
+ its optional cursor pages through the current pending list. While a range remains unread,
63
+ `submit_review` returns a recoverable error with the next unread offset. The same run continues
64
+ under its original budgets. A native budget stop preserves the pending paths and findings as
65
+ incomplete; repeated completion refusals cannot restart the run or reset its allowance.
66
+ Reading all ranges is necessary, but it does not prove that the model assessed every behavior.
67
+
68
+ `review_status` also keeps a bounded investigation notebook for the lifetime of the review.
69
+ Replace it with `notes: { text, expectedRevision }`; text is limited to 4,000 characters and
70
+ stale revisions fail without overwriting newer notes. The response supplies the current text and
71
+ revision. Notes preserve unresolved questions, exact evidence references, and next checks across
72
+ rollover. They are model-authored context, never proof of coverage or a source of findings.
73
+ Only the accepted-update count (`notesUpdates`) leaves the review; note text is not persisted in
74
+ the outcome. Children cannot update the parent's notebook.
75
+
76
+ Completion means a source-based assessment of the admitted changes and material supported
77
+ hypotheses, not proof of correctness or an exhaustive audit of every dependency. The model can
78
+ report `blockedOn` only for specific unavailable evidence, naming the affected behavior and its
79
+ attempts to retrieve that evidence. It must still review the remaining patches. The bounded
80
+ reason is retained in the outcome and summary, forces incompleteness, and prevents resolutions.
81
+ Excluded artifacts, lack of live execution, and hypothetical uncertainty do not themselves
82
+ block assessment of the admitted change.
83
+
84
+ Every parent conversation has 128 model turns, 512 tool calls, four concurrent tools, and a five-minute deadline.
85
+ The default `compaction: "rollover"` strategy uses a 48,000-token working context to bound
86
+ context growth during large reviews. Hosts can select `compaction: "prune"`
87
+ and an integer `contextTokenLimit` from 16,000 to 128,000. These settings do not widen host input
88
+ admission or create new spending, turn, or tool allowances. Invalid options fail before model work.
89
+
90
+ Native rollover starts a fresh window without a summarizer call. Its bounded recovery excerpt
91
+ may omit unseen tool results, so undelivered diff pages remain unread and must be fetched again.
92
+ Already delivered ranges and saved findings survive. Both strategies support calling `new_context`
93
+ alone with a handoff; original instructions and the complete change index remain available.
94
+ After rollover, the reviewer resumes unread offsets from `review_status`. Once every range has
95
+ been delivered, it follows the remaining investigation notes with targeted reads instead of
96
+ starting another complete diff sweep.
97
+
98
+ Logs identify each successful diff read by character offsets, the first unread offset, and
99
+ whether the whole page had already been delivered. Rollover logs count queued reads discarded
100
+ before delivery. Navigation totals include successful reads, fully repeated reads, status calls,
101
+ accepted note updates, pending paths, and emitted compactions. They contain no source or note text;
102
+ repeated reads can be legitimate evidence checks and do not themselves establish wasted work.
103
+ Failure logs retain the typed error category and specific policy limit. A duration stop is also
104
+ identified as the five-minute deadline in the review summary.
105
+
106
+ Every measured outcome includes `compactions`, an array of emitted native `CompactionPerformed`
107
+ events containing only `kind`, `turn`, `tokensBeforeEstimate`, and `tokensAfterEstimate`.
108
+ An empty array means no event was emitted; absence means the outcome supplied no measurement.
109
+ The array is bounded to 512 entries and includes events retained before a typed failure. It does
110
+ not expose source or handoff text, and events alone do not distinguish automatic from requested
111
+ rollovers. Boundaries that fail before event emission are not counted.
112
+
113
+ Without `costControl`, the engine applies a cumulative 416,000-token policy with a 160,000-token
114
+ completion reserve. A host cost estimator alone does not disable it. With `costControl`, the
115
+ host reserves the full possible charge before each provider call, replacing that token quota.
116
+ The [GitHub Action](../../action/README.md) supplies spending admission for supported OpenAI models.
117
+ Recorded findings survive a cost stop without requiring another paid call. `reservedCostMicrousd`
118
+ reports maximum additional charges for sent requests whose usage remains unknown.
119
+
120
+ Token, turn, tool, or cost exhaustion is incomplete. Expected failures preserve recorded findings
121
+ and completed model attempts, including their accounting when no finding was recorded. Context/input-token
122
+ refusals return an incomplete token-exhausted outcome before paid inference when possible.
123
+ Failures before any model attempt, finding, or budget refusal remain typed. Defects and interruption propagate, and every
124
+ resource belongs to the review's Scope. Excluded host `unreviewedPaths` remain separately disclosed.
125
+ An empty result never proves that the repository is defect-free.
126
+
127
+ ## Optional research children
128
+
129
+ The default reviewer runs alone. Experiments can provide `research: { model, concurrency: 2 }`
130
+ to expose native `delegate_research`. Concurrency is either one or two (default two), with at
131
+ most two children established per review. Each child has six ordinary model turns, twelve tool
132
+ calls, a 60-second deadline, and a 32,000-token context using native pruning. The runtime can
133
+ reserve a final completion response after structural exhaustion. The host configures the child
134
+ model's output limit; the eval uses 4,000 tokens.
135
+
136
+ A delegation supplies one unresolved, falsifiable question whose answer could change a finding,
137
+ and one to three distinct admitted changed paths. Instructions ask neutrally for supporting or
138
+ refuting evidence and discourage generic second reviews; children use the same finding rubric.
139
+ The host selects their exact patches, rejecting more than 32,000 total patch characters.
140
+ Children receive the immutable revisions and current saved findings, and can use only the
141
+ three repository read tools, `record_finding`, and `finish_research`. The completion contains
142
+ an evidence summary and incomplete flag; findings go directly to the same canonical ledger.
143
+ Children cannot delegate further, establish parent diff coverage, or resolve prior reviews.
144
+
145
+ Native reservations and child fibers belong to the review's Scope. Child compaction cannot
146
+ change the parent's unread ranges. Child model requirements remain visible in the review's
147
+ Effect requirements, and usage contributes to the existing accounting. A host supplying
148
+ `costControl` must use the same admission service for both model layers, so all requests draw
149
+ from one spending cap. Without host admission, the parent and child native token policies are
150
+ separate; the parent token quota is not a combined spending cap.
151
+
152
+ Research-enabled runs break equal-severity finding ties by their complete serialized values
153
+ before retaining 24, so child completion order cannot select the survivors. Exact duplicates
154
+ are still the only records removed. A rejected delegation, failed or interrupted child,
155
+ unfinished join, child-reported incomplete result, or child budget exhaustion makes the parent
156
+ incomplete and suppresses resolutions. Defects and external interruption still propagate.
157
+
158
+ Measured outcomes include `research` counters: `delegations` counts declared delegation calls;
159
+ `started`, `completed`, `failed`, and `interrupted` count emitted native child events; `incomplete`
160
+ counts completed child results that report incomplete or exhausted work. Zero counts are measured
161
+ zero, while an absent field means no measurement was supplied. Counts contain no child source,
162
+ summary, or transcript; prestart refusals have a declaration but no child event.
163
+
164
+ ## Follow-ups and hosting
165
+
166
+ Hosts can supply up to eight prior `ReviewFollowUp` values, each up to 32,000 characters. The
167
+ reviewer verifies every blocker in a follow-up against current source before returning its exact
168
+ ID and fixing evidence. Unknown or duplicate resolution IDs fail verification. Incomplete,
169
+ exhausted, pending-path, or excluded-path results return no resolutions. History selection,
170
+ credentials, dismissal authorization, and publication belong to the host.
87
171
 
88
172
  ```ts
89
- import {
90
- fixturePullRequestSourceLayer,
91
- collectingReviewPublisherLayer,
92
- makeOfflineReviewerModel,
93
- makePromptKeyedModel,
94
- } from "@effect-agent/pr-review/testing";
173
+ const reviewer = makeReviewer({ model, guidance, costControl });
174
+ const program = reviewer.review(request).pipe(Effect.provideService(ReviewRepository, repository));
95
175
  ```
96
176
 
97
- Deterministic in-memory adapters for both ports plus prompt-keyed scripted
98
- models that walk the real tool surface no network, no credentials, every
99
- ordinary gate.
100
-
101
- ## Incremental Action reviews
102
-
103
- A completely covered posted Action review carries bounded, versioned,
104
- HMAC-authenticated continuity state:
105
- the exact PR/base/head lineage, profile and accepted-scope fingerprints, and
106
- the still-unresolved findings and concerns. A later Action run validates the
107
- state and reviews the GitHub comparison from that reviewed head to the
108
- current head, not the complete base...HEAD diff. Unchanged accepted scope is
109
- not sent back to the model; unchanged unresolved findings remain active;
110
- changed or reverted paths invalidate their prior findings. Non-anchored
111
- concerns are carried conservatively until a full audit because they cannot be
112
- mapped safely to one path.
113
-
114
- The state marker must be terminal, signed with the configured stable
115
- `PR_REVIEW_STATE_SECRET`, authored by the configured review-posting bot, and
116
- pinned to the reviewed commit. The expected author defaults to
117
- `github-actions[bot]`; set `PR_REVIEW_AUTHOR_LOGIN` (or the Action's
118
- `review-author` input) to `<app-slug>[bot]` when posting with a custom GitHub
119
- App token. State lookup, authentication, schema, identity, ancestry, profile,
120
- and comparison checks are fail-closed for scope selection: missing, stale,
121
- incompatible, or truncated state/comparisons produce a visible full-diff
122
- fallback. An ancestor base advance remains incremental and adds overlapping
123
- PR paths as affected context; a materially changed base lineage falls back to
124
- full. Re-running the same covered head skips model execution by default while
125
- preserving its stored blocking/success conclusion.
126
-
127
- After a new state-bearing Action review posts, prior marker-bearing bot reviews
128
- are retired by default: their bodies become collapsed, superseded history,
129
- resolved findings are struck through, and matching inline comments are
130
- minimized as outdated. Only strictly older reviews from the same GitHub actor
131
- are eligible, so copied markers and newer concurrent reviews are untouched.
132
- The machine-state comments remain byte-identical and terminal, so an edited
133
- body still participates in incremental state recovery.
134
- This cosmetic pass is fail-open and can be disabled with the Action input
135
- `retire-stale-reviews: "false"`.
136
-
137
- Authentication is an explicit Effect service supplied by the Action host;
138
- WebCrypto import/sign/verify failures stay typed. The terminal marker is
139
- schema-branded and capped at 24,000 characters. If signing fails or state
140
- exceeds that bound, the completed review is posted without continuity state
141
- and with a bounded warning, so the next run safely performs a full review.
142
-
143
- `review-mode: final` is the explicit bounded merge-readiness audit. It reviews
144
- the full current PR diff and resets the incremental baseline; normal
145
- `synchronize` events use `incremental` and do not perform this audit.
146
-
147
- ## Hosts
148
-
149
- - **GitHub Actions**: the repository ships a prebuilt node-runtime action
150
- supporting a committed review-profile document via `guidance-file` (this
151
- repository's own profile lives at `.github/review-guidance.md`)
152
- (`action/` at the repo root) — `uses` it with an API-key secret and nothing
153
- else. For custom reviewers in CI, `@effect-agent/pr-review/action` exports
154
- `runReviewAction` (event resolution, typed draft/non-PR skips, bounded range
155
- selection, step outputs, and conservative check gate) to harness your own
156
- `reviewer.run`.
157
- - **CLI**: `bun src/cli.ts --repo owner/name --pr 123 [--post] [--provider anthropic] [--fan-out]`
158
- (also exported as the `./cli` entry).
159
-
160
- Environment: `OPENAI_API_KEY` or `ANTHROPIC_API_KEY` for the model,
161
- `PR_REVIEW_STATE_SECRET` to authenticate incremental state,
162
- `PR_REVIEW_AUTHOR_LOGIN` to match a custom review-posting bot (defaults to
163
- `github-actions[bot]`),
164
- `GITHUB_TOKEN` to post (optional for public-repository reads), and the
165
- standard `GITHUB_REPOSITORY` / `GITHUB_EVENT_PATH` / `GITHUB_API_URL`
166
- variables inside Actions.
167
-
168
- ## Bounds, spelled out
169
-
170
- Finite `AgentPolicy` on every definition plus run-level `UsageBudgetLimits`
171
- (tokens, tool calls, cost, duration). Reading a file head version beyond 200k
172
- characters is refused typed. The changeset surface is bounded at 300 files:
173
- files beyond the bound are not fetched, and the review body reports
174
- `Reviewed N of M changed files` instead of claiming completeness. Fan-out
175
- capacity overflow is reported in the review summary, never dropped. Any
176
- blocking active finding fails the Action check. Any required-file coverage
177
- gap — undiffable/unassigned paths, failed units (including policy exhaustion),
178
- truncation, or coordinator/run failure — is non-success rather than green.
177
+ `ReviewRepository` implementations provide typed Effect operations for `readFile`, `findFiles`,
178
+ and `searchCode`. Hosts authorize source sent to models, pin immutable revisions, enforce read
179
+ bounds, and treat all source and model output as untrusted. The reviewer has no ambient filesystem
180
+ or network access. `ReviewSource.fromText` applies the shared source-range bounds.
181
+
182
+ The navigable diff approach is informed by [Pullfrog's review workflow](https://github.com/pullfrog/pullfrog/blob/0212dedb0f92b8ba4020c17dc30d3eced32415d7/modes.ts)
183
+ and [Codex's review task](https://github.com/openai/codex/blob/588b781ab4924ce7352488394028e63d74cf807f/codex-rs/core/src/tasks/review.rs).
184
+ These designs do not establish accuracy. The [eval bench](../../tooling/pr-review-eval/README.md)
185
+ measures first-trial detection, false positives, and incomplete runs against adjudicated cases.
186
+ Portions of the original review instructions were adapted from
187
+ [PR-Agent](https://github.com/The-PR-Agent/pr-agent); see `NOTICE` for its MIT attribution.