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

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 CHANGED
@@ -190,9 +190,14 @@ own scope forward instead of freezing the baseline and reopening everything
190
190
  reviewed since (the non-converging loop of issue #131). A later Action run
191
191
  validates the state and reviews the GitHub comparison from that reviewed head
192
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.
193
+ base...HEAD diff. When that head is not a git ancestor a rebase, amend, or
194
+ force-push the host falls back to a two-dot tree comparison and reviews only
195
+ the current PR paths whose contents actually changed, plus leftovers. Unchanged
196
+ settled scope is not sent back to the model; unchanged unresolved findings
197
+ remain active; changed or reverted paths invalidate their prior findings and
198
+ receive fresh discovery and verification. An unchanged leftover from a failed
199
+ pass retries only that failed stage and keeps its stored findings — it does
200
+ not run a second general discovery.
196
201
  Whole overflow files are reviewed in bounded installments across pushes
197
202
  through the same carry; a single file beyond total plan capacity and
198
203
  undiffable paths stay explicitly incomplete instead — an unreviewable tail
@@ -207,9 +212,11 @@ pinned to the reviewed commit. The expected author defaults to
207
212
  App token. State lookup, authentication, schema, identity, ancestry, profile,
208
213
  and comparison checks are fail-closed for scope selection: missing, stale,
209
214
  incompatible, or truncated state/comparisons produce a visible full-diff
210
- fallback. An ancestor base advance remains incremental and adds overlapping
215
+ fallback unless a two-dot content comparison can still name the changed PR
216
+ paths. An ancestor base advance remains incremental and adds overlapping
211
217
  PR paths as affected context; a materially changed base lineage falls back to
212
- full unless the authenticated settled-scope fingerprint still matches. The
218
+ full unless the authenticated settled-scope fingerprint still matches or the
219
+ content comparison intersects the current PR path set. The
213
220
  schema field retains the compatibility name `acceptedScopeFingerprint`. That
214
221
  fingerprint hashes the ignore-filtered effective diff, patchless base/head
215
222
  evidence, PR framing, and review-shaping profile while excluding commit IDs,
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 { L as PriorReviews, P as GitHubApiFailure, X as ReviewRetirementHost, cr as PullRequestSource, fr as ChangedFile, gt as ReviewMode, lr as PullRequestSourceFailure, sr as PullRequestMetadata, xt as ReviewStateAuthenticator, z as ReviewPublisher } from "./fan-out-Bi1v0VaU.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";
@@ -166,7 +166,7 @@ declare const reviewActionProgram: Effect.Effect<{
166
166
  } | {
167
167
  _tag: "Completed";
168
168
  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>;
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, import("effect/Crypto").Crypto | FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient>;
170
170
  /** Run the packaged action program on Node; the bundled action entrypoint. */
171
171
  declare const main: () => void;
172
172
  /** The packaged GitHub Actions surface. */
@@ -195,7 +195,7 @@ declare const PrReviewAction: {
195
195
  } | {
196
196
  _tag: "Completed";
197
197
  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>;
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, import("effect/Crypto").Crypto | FileSystem.FileSystem | import("effect/unstable/http/HttpClient").HttpClient>;
199
199
  readonly main: typeof main;
200
200
  };
201
201
  //#endregion
package/dist/action.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { B as selectReviewRange, E as ReviewHeadComparison, G as validateReviewState, K as webCryptoReviewStateAuthenticatorLayer, Kn as normalizeRepoRelativePath, T as ReviewExecutionContext, Un as PullRequestSource, V as selectedPullRequestSourceLayer, W as unavailableReviewStateAuthenticatorLayer, a as PriorReviews, j as ReviewStateAuthenticator, x as retireStaleReviews } from "./github-BbwYzNrC.mjs";
2
- import { A as reviewBudgetLimits, C as PrReview, H as InvalidEffortInput, W as parseEffortPosition, a as anthropicClientLayer, c as makeOpenAiReviewModel, f as gitHubReviewLayers, g as ReviewProgressReporter, k as fanOutReviewBudgetLimits, l as openAiClientLayer, m as resolveReviewTarget, n as DEFAULT_PROVIDER, o as describeReviewModel, p as readGitHubEvent, s as makeAnthropicReviewModel } from "./providers-NyP-4rS6.mjs";
1
+ import { D as ReviewHeadComparison, E as ReviewExecutionContext, H as isLineageAncestor, J as validateReviewState, M as ReviewStateAuthenticator, U as selectReviewRange, W as selectedPullRequestSourceLayer, Xn as normalizeRepoRelativePath, Y as webCryptoReviewStateAuthenticatorLayer, a as PriorReviews, q as unavailableReviewStateAuthenticatorLayer, qn as PullRequestSource, x as retireStaleReviews } from "./github-C6jrBLA2.mjs";
2
+ import { A as reviewBudgetLimits, C as PrReview, H as InvalidEffortInput, W as parseEffortPosition, a as anthropicClientLayer, c as makeOpenAiReviewModel, f as gitHubReviewLayers, g as ReviewProgressReporter, k as fanOutReviewBudgetLimits, l as openAiClientLayer, m as resolveReviewTarget, n as DEFAULT_PROVIDER, o as describeReviewModel, p as readGitHubEvent, s as makeAnthropicReviewModel } from "./providers-2Jao2ZAX.mjs";
3
3
  import { n as compactReviewLoggingLayer } from "./logging-Q4j0oub-.mjs";
4
4
  import { Config, Console, Effect, FileSystem, Layer, Option, Redacted, Schema } from "effect";
5
5
  import { BudgetExceeded, UsageBudgetLimits } from "effect-agent";
@@ -293,6 +293,7 @@ const runReviewAction = (reviewer, options = {}) => Effect.gen(function* () {
293
293
  });
294
294
  let comparison;
295
295
  let baseComparison;
296
+ let contentComparison;
296
297
  if ((options.reviewMode ?? "incremental") === "incremental" && recovered.state !== void 0) {
297
298
  if (recovered.state.reviewedHeadSha === metadata.headSha) comparison = ReviewHeadComparison.make({
298
299
  status: "identical",
@@ -316,6 +317,13 @@ const runReviewAction = (reviewer, options = {}) => Effect.gen(function* () {
316
317
  files: reviewer.filterFiles(baseComparison.files)
317
318
  });
318
319
  }
320
+ if (recovered.state.reviewedHeadSha !== metadata.headSha && (comparison === void 0 || !isLineageAncestor(comparison, recovered.state, metadata.headSha))) {
321
+ contentComparison = yield* history.compareTrees(recovered.state.reviewedHeadSha, metadata.headSha).pipe(Effect.orElseSucceed(() => void 0));
322
+ if (contentComparison !== void 0 && reviewer.filterFiles !== void 0) contentComparison = ReviewHeadComparison.make({
323
+ ...contentComparison,
324
+ files: reviewer.filterFiles(contentComparison.files)
325
+ });
326
+ }
319
327
  }
320
328
  selection = {
321
329
  ...selectReviewRange({
@@ -326,6 +334,7 @@ const runReviewAction = (reviewer, options = {}) => Effect.gen(function* () {
326
334
  priorState: recovered.state,
327
335
  comparison,
328
336
  baseComparison,
337
+ contentComparison,
329
338
  lookupFailure: recovered.failure
330
339
  }),
331
340
  stateAuthenticator
@@ -1 +1 @@
1
- {"version":3,"file":"action.mjs","names":[],"sources":["../src/action.ts"],"sourcesContent":["import { NodeRuntime, NodeServices } from \"@effect/platform-node\";\nimport { Config, Console, Effect, FileSystem, Layer, Option, Redacted, Schema } from \"effect\";\nimport { BudgetExceeded, UsageBudgetLimits } from \"effect-agent\";\nimport { FetchHttpClient } from \"effect/unstable/http\";\n\nimport type { ChangedFile } from \"./internal/diff.ts\";\nimport { InvalidEffortInput, parseEffortPosition, type EffortPosition } from \"./internal/effort.ts\";\nimport { PrReview, type RunReviewOptions } from \"./internal/factory.ts\";\nimport { readGitHubEvent, resolveReviewTarget, gitHubReviewLayers } from \"./internal/github-env.ts\";\nimport { PriorReviews } from \"./internal/github.ts\";\nimport { compactReviewLoggingLayer } from \"./internal/logging.ts\";\nimport { ReviewProgressReporter } from \"./internal/progress.ts\";\nimport {\n anthropicClientLayer,\n DEFAULT_PROVIDER,\n describeReviewModel,\n makeAnthropicReviewModel,\n makeOpenAiReviewModel,\n openAiClientLayer,\n type ReviewProvider,\n} from \"./internal/providers.ts\";\nimport { retireStaleReviews } from \"./internal/retirement.ts\";\nimport {\n ReviewExecutionContext,\n ReviewHeadComparison,\n ReviewStateAuthenticator,\n type ReviewMode,\n type ReviewState,\n selectReviewRange,\n selectedPullRequestSourceLayer,\n unavailableReviewStateAuthenticatorLayer,\n validateReviewState,\n webCryptoReviewStateAuthenticatorLayer,\n} from \"./internal/review-state.ts\";\nimport { fanOutReviewBudgetLimits, reviewBudgetLimits } from \"./internal/run.ts\";\nimport type { ReviewRunOutcome } from \"./internal/run.ts\";\nimport {\n normalizeRepoRelativePath,\n PullRequestSource,\n type PullRequestMetadata,\n} from \"./internal/source.ts\";\n\n// ---------------------------------------------------------------------------\n// The GitHub Actions entrypoint (deployment class E: one bounded ephemeral\n// run, no exactly-once posting). Bounded continuity state travels in GitHub\n// review bodies and is validated before reuse. Inputs arrive as\n// PR_REVIEW_* environment variables set by the action manifest; the target\n// pull request comes from the standard Actions event environment. A non-PR\n// or draft event is a typed skip — green job, nothing posted. Publication\n// happens only after the run settles, so a failed or truncated run posts\n// nothing.\n// ---------------------------------------------------------------------------\n\nexport const ReviewCheckConclusion = Schema.Literals([\"success\", \"blocking\", \"incomplete\"]);\nexport type ReviewCheckConclusion = typeof ReviewCheckConclusion.Type;\n\n/** The host-derived blocking or incomplete conclusion failed the check. */\nexport class ReviewGateFailed extends Schema.TaggedError<ReviewGateFailed>()(\"ReviewGateFailed\", {\n conclusion: Schema.Literals([\"blocking\", \"incomplete\"]),\n reasons: Schema.Array(Schema.NonEmptyString.check(Schema.isMaxLength(1_000))).check(\n Schema.isMinLength(1),\n ),\n}) {\n override get message() {\n return `Review check concluded '${this.conclusion}': ${this.reasons.join(\"; \")}`;\n }\n}\n\n/** A configured max-duration that cannot bound a run; configuration faults fail loudly. */\nexport class InvalidMaxDurationInput extends Schema.TaggedError<InvalidMaxDurationInput>()(\n \"InvalidMaxDurationInput\",\n {\n minutes: Schema.Int,\n },\n) {\n override get message() {\n return `Invalid max-duration-minutes '${this.minutes}': expected a positive number of minutes.`;\n }\n}\n\n/** Everything the packaged action reads from its environment. */\nexport interface ResolvedActionInputs {\n readonly provider: ReviewProvider;\n readonly model: string | undefined;\n readonly effort: EffortPosition | undefined;\n readonly post: boolean;\n readonly applyVerdict: boolean;\n readonly fanOut: boolean;\n readonly guidance: string | undefined;\n readonly guidanceFile: string | undefined;\n readonly ignore: ReadonlyArray<string>;\n readonly maxFindings: number | undefined;\n readonly maxDurationMinutes: number | undefined;\n readonly reviewMode: ReviewMode;\n readonly skipUnchanged: boolean;\n readonly retireStaleReviews: boolean;\n readonly progressComment: boolean;\n}\n\n/** Read the PR_REVIEW_* input surface (all optional, all defaulted). */\nexport const resolveActionInputs = Effect.fn(\"resolveActionInputs\")(function* () {\n const provider = yield* Config.literals([\"openai\", \"anthropic\"], \"PR_REVIEW_PROVIDER\").pipe(\n Config.withDefault<ReviewProvider>(DEFAULT_PROVIDER),\n );\n const model = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_MODEL\"));\n const effortRaw = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_EFFORT\"));\n let effort: EffortPosition | undefined;\n if (Option.isSome(effortRaw)) {\n effort = parseEffortPosition(effortRaw.value);\n if (effort === undefined) {\n return yield* InvalidEffortInput.make({ input: effortRaw.value });\n }\n }\n const maxDurationMinutes = Option.getOrUndefined(\n yield* Config.option(Config.int(\"PR_REVIEW_MAX_DURATION_MINUTES\")),\n );\n if (maxDurationMinutes !== undefined && maxDurationMinutes <= 0) {\n return yield* InvalidMaxDurationInput.make({ minutes: maxDurationMinutes });\n }\n const post = yield* Config.boolean(\"PR_REVIEW_POST\").pipe(Config.withDefault(true));\n const applyVerdict = yield* Config.boolean(\"PR_REVIEW_APPLY_VERDICT\").pipe(\n Config.withDefault(false),\n );\n const fanOut = yield* Config.boolean(\"PR_REVIEW_FAN_OUT\").pipe(Config.withDefault(true));\n const guidance = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_GUIDANCE\"));\n const guidanceFile = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_GUIDANCE_FILE\"));\n const ignoreRaw = yield* Config.string(\"PR_REVIEW_IGNORE\").pipe(Config.withDefault(\"\"));\n const maxFindings = yield* Config.option(Config.int(\"PR_REVIEW_MAX_FINDINGS\"));\n const reviewMode = yield* Config.literals([\"incremental\", \"final\"], \"PR_REVIEW_MODE\").pipe(\n Config.withDefault<ReviewMode>(\"incremental\"),\n );\n const skipUnchanged = yield* Config.boolean(\"PR_REVIEW_SKIP_UNCHANGED\").pipe(\n Config.withDefault(true),\n );\n const retireStaleReviews = yield* Config.boolean(\"PR_REVIEW_RETIRE_STALE_REVIEWS\").pipe(\n Config.withDefault(true),\n );\n const progressComment = yield* Config.boolean(\"PR_REVIEW_PROGRESS_COMMENT\").pipe(\n Config.withDefault(true),\n );\n return {\n provider,\n model: Option.getOrUndefined(model),\n effort,\n post,\n applyVerdict,\n fanOut,\n guidance: Option.getOrUndefined(guidance),\n guidanceFile: Option.getOrUndefined(guidanceFile),\n ignore: ignoreRaw\n .split(\",\")\n .map((pattern) => pattern.trim())\n .filter((pattern) => pattern.length > 0),\n maxFindings: Option.getOrUndefined(maxFindings),\n maxDurationMinutes,\n reviewMode,\n skipUnchanged,\n retireStaleReviews,\n progressComment,\n } satisfies ResolvedActionInputs;\n});\n\n/** A guidance file larger than this is refused, never silently truncated. */\nexport const MAX_GUIDANCE_FILE_CHARS = 20_000;\n\n/** A configured guidance file could not be used; configuration faults fail loudly. */\nexport class GuidanceFileUnreadable extends Schema.TaggedError<GuidanceFileUnreadable>()(\n \"GuidanceFileUnreadable\",\n {\n path: Schema.String,\n reason: Schema.String,\n },\n) {\n override get message() {\n return `Cannot use guidance file '${this.path}': ${this.reason}`;\n }\n}\n\n/**\n * Resolve the effective review guidance: the committed guidance file (a\n * repository-owned review profile) first, with any inline guidance appended.\n * A configured-but-unreadable file fails typed — a review silently running\n * without its profile would be worse than a red job.\n */\nexport const resolveGuidance = Effect.fn(\"resolveGuidance\")(function* (inputs: {\n readonly guidance: string | undefined;\n readonly guidanceFile: string | undefined;\n}) {\n const filePath = inputs.guidanceFile;\n if (filePath === undefined) return inputs.guidance;\n // The profile path is operator configuration, but it stays fail-closed\n // like every other path in this package: workspace-relative only, and the\n // size bound is checked before the file is read into memory.\n const relative = yield* normalizeRepoRelativePath(filePath).pipe(\n Effect.mapError((violation) =>\n GuidanceFileUnreadable.make({ path: filePath, reason: violation.reason }),\n ),\n );\n const fs = yield* FileSystem.FileSystem;\n const unreadable = (error: { readonly _tag: string; readonly message: string }) =>\n GuidanceFileUnreadable.make({\n path: relative,\n reason: `${error._tag}: ${error.message}`.slice(0, 2_048),\n });\n const stat = yield* fs.stat(relative).pipe(Effect.mapError(unreadable));\n const oversized = GuidanceFileUnreadable.make({\n path: relative,\n reason: `File is larger than the ${MAX_GUIDANCE_FILE_CHARS}-character guidance bound.`,\n });\n if (stat.size > BigInt(MAX_GUIDANCE_FILE_CHARS) * 4n) {\n return yield* oversized;\n }\n const content = yield* fs.readFileString(relative).pipe(Effect.mapError(unreadable));\n if (content.length > MAX_GUIDANCE_FILE_CHARS) {\n return yield* oversized;\n }\n const combined = [content.trim(), inputs.guidance ?? \"\"]\n .filter((part) => part.length > 0)\n .join(\"\\n\");\n return combined.length > 0 ? combined : undefined;\n});\n\n/** One step-output line; values must be single-line by construction. */\nconst outputLine = (name: string, value: string): string =>\n `${name}=${value.replaceAll(\"\\n\", \" \").slice(0, 1_000)}\\n`;\n\n/** Append step outputs to GITHUB_OUTPUT when present (no-op locally). */\nexport const writeActionOutputs = Effect.fn(\"writeActionOutputs\")(function* (\n entries: ReadonlyArray<readonly [name: string, value: string]>,\n) {\n const outputPath = yield* Config.string(\"GITHUB_OUTPUT\").pipe(Config.withDefault(\"\"));\n if (outputPath === \"\") return;\n const fs = yield* FileSystem.FileSystem;\n yield* fs.writeFileString(\n outputPath,\n entries.map(([name, value]) => outputLine(name, value)).join(\"\"),\n {\n flag: \"a\",\n },\n );\n});\n\n/** Append markdown to the GITHUB_STEP_SUMMARY report when present (no-op locally). */\nexport const writeStepSummary = Effect.fn(\"writeStepSummary\")(function* (\n lines: ReadonlyArray<string>,\n) {\n const summaryPath = yield* Config.string(\"GITHUB_STEP_SUMMARY\").pipe(Config.withDefault(\"\"));\n if (summaryPath === \"\") return;\n const fs = yield* FileSystem.FileSystem;\n yield* fs.writeFileString(summaryPath, `${lines.join(\"\\n\")}\\n`, { flag: \"a\" });\n});\n\nconst outcomeOutputs = (\n outcome: ReviewRunOutcome,\n conclusion: ReviewCheckConclusion,\n): ReadonlyArray<readonly [string, string]> => [\n [\"skipped\", \"false\"],\n [\"conclusion\", conclusion],\n [\"verdict\", outcome.review.verdict],\n [\"input-coverage\", outcome.inputCoverage.status],\n [\"review-assurance\", outcome.assurance.status],\n // Compatibility output: the precise outputs above own new integrations.\n [\"coverage\", outcome.coverage.status],\n [\"review-mode\", outcome.reviewMode ?? \"full\"],\n [\"review-reason\", outcome.reviewReason ?? \"direct full review\"],\n [\"inline-comments\", String(outcome.plan.comments.length)],\n [\"demoted-findings\", String(outcome.plan.demoted.length)],\n [\"concerns\", String(outcome.review.concerns?.length ?? 0)],\n [\"unreviewed-paths\", String(outcome.unreviewedPaths.length)],\n ...(outcome.usage === undefined\n ? []\n : ([\n [\"input-tokens\", String(outcome.usage.inputTokens)],\n [\"output-tokens\", String(outcome.usage.outputTokens)],\n ] as const)),\n [\"review-url\", outcome.published?.url ?? \"\"],\n];\n\nconst outcomeSummary = (\n outcome: ReviewRunOutcome,\n modelLabel: string | undefined,\n conclusion: ReviewCheckConclusion,\n): ReadonlyArray<string> => [\n \"### Pull-request review\",\n `- Check conclusion: **${conclusion}**`,\n `- Verdict: **${outcome.review.verdict}**`,\n `- Input coverage: **${outcome.inputCoverage.status}** · scope: ${outcome.reviewMode ?? \"full\"}`,\n `- 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}`,\n `- Inline comments: ${outcome.plan.comments.length} · demoted findings: ${outcome.plan.demoted.length} · concerns: ${outcome.review.concerns?.length ?? 0}`,\n ...(outcome.unreviewedPaths.length === 0\n ? []\n : [\n `- Carried forward: ${outcome.unreviewedPaths.length} unreviewed path(s) retried automatically on the next run (reviewer-side gap, not a code defect)`,\n ]),\n ...(modelLabel === undefined ? [] : [`- Model: \\`${modelLabel}\\``]),\n ...(outcome.usage === undefined\n ? []\n : [`- Tokens: ${outcome.usage.inputTokens} in / ${outcome.usage.outputTokens} out`]),\n ...(outcome.published === undefined\n ? [\"- Dry run: nothing posted\"]\n : [`- Posted: ${outcome.published.url}`]),\n];\n\n/** The result of one action invocation: a typed skip or a settled review. */\nexport type ReviewActionResult =\n | { readonly _tag: \"Skipped\"; readonly reason: string }\n | { readonly _tag: \"Completed\"; readonly outcome: ReviewRunOutcome };\n\nconst skip = (reason: string) =>\n Effect.gen(function* () {\n yield* Console.log(`Skipping review: ${reason}`);\n yield* writeActionOutputs([\n [\"skipped\", \"true\"],\n [\"skip-reason\", reason],\n ]);\n yield* writeStepSummary([\"### Pull-request review skipped\", `- Reason: ${reason}`]);\n return { _tag: \"Skipped\", reason } satisfies ReviewActionResult;\n });\n\n/** The Actions run URL for the review footer, or undefined outside Actions. */\nconst resolveRunUrl = Effect.fn(\"resolveRunUrl\")(function* () {\n const runId = yield* Config.string(\"GITHUB_RUN_ID\").pipe(Config.withDefault(\"\"));\n const repository = yield* Config.string(\"GITHUB_REPOSITORY\").pipe(Config.withDefault(\"\"));\n if (runId === \"\" || repository === \"\") return undefined;\n const server = yield* Config.string(\"GITHUB_SERVER_URL\").pipe(\n Config.withDefault(\"https://github.com\"),\n );\n return `${server}/${repository}/actions/runs/${runId}`;\n});\n\n/**\n * The reviewer surface the action harness drives. `PrReview.make` and\n * `PrReview.makeFanOut` provide the state-selection effects. A fingerprint is\n * skip authority only when a profile fingerprint and authenticated review\n * state bind it to settled assurance; a fingerprint-only custom harness\n * remains source-compatible but deliberately runs instead of claiming green\n * assurance from unauthenticated prior-review text.\n */\nexport interface HarnessedReviewer<E, R, FingerprintE, FingerprintR> {\n readonly run: (runOptions?: RunReviewOptions) => Effect.Effect<ReviewRunOutcome, E, R>;\n /** Current effective changeset fingerprint; not standalone skip authority. */\n readonly fingerprint?: Effect.Effect<string, FingerprintE, FingerprintR> | undefined;\n readonly profileFingerprint?: Effect.Effect<string, FingerprintE, FingerprintR> | undefined;\n readonly snapshot?:\n | Effect.Effect<\n {\n readonly metadata: PullRequestMetadata;\n readonly files: ReadonlyArray<ChangedFile>;\n },\n FingerprintE,\n FingerprintR\n >\n | undefined;\n readonly filterFiles?:\n | ((files: ReadonlyArray<ChangedFile>) => ReadonlyArray<ChangedFile>)\n | undefined;\n}\n\nconst blockingReasons = (input: {\n readonly findings: ReadonlyArray<{ readonly severity: string; readonly title: string }>;\n readonly concerns: ReadonlyArray<{ readonly severity: string; readonly title: string }>;\n}): ReadonlyArray<string> => [\n ...input.findings\n .filter((finding) => finding.severity === \"blocking\")\n .map((finding) => `blocking finding: ${finding.title}`),\n ...input.concerns\n .filter((concern) => concern.severity === \"blocking\")\n .map((concern) => `blocking concern: ${concern.title}`),\n];\n\n/**\n * Host-derived check conclusion; model verdict prose cannot weaken it.\n *\n * Blocking code findings outrank machinery gaps — they are the actionable\n * signal. A machinery gap (incomplete input, unsettled passes) concludes\n * `incomplete` with reasons that explicitly say the failure is reviewer-side\n * uncertainty carried forward for retry, never an invitation to change code.\n * The flat reviewer's constant `unverified` assurance is not a gap.\n */\nexport const concludeReviewOutcome = (\n outcome: ReviewRunOutcome,\n): {\n readonly conclusion: ReviewCheckConclusion;\n readonly reasons: ReadonlyArray<string>;\n} => {\n const machinery: Array<string> = [];\n if (outcome.inputCoverage.status === \"incomplete\" || outcome.assurance.status === \"incomplete\") {\n machinery.push(\n outcome.unreviewedPaths.length > 0\n ? `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`\n : \"review infrastructure did not settle — a reviewer-side gap, not a code defect\",\n );\n if (outcome.inputCoverage.status === \"incomplete\") {\n machinery.push(...outcome.inputCoverage.reasons);\n }\n if (outcome.assurance.status === \"incomplete\") {\n machinery.push(...outcome.assurance.reasons);\n }\n }\n const blocking = blockingReasons({\n findings: outcome.activeFindings,\n concerns: outcome.activeConcerns,\n });\n if (blocking.length > 0) {\n return { conclusion: \"blocking\", reasons: [...blocking, ...machinery] };\n }\n if (machinery.length > 0) return { conclusion: \"incomplete\", reasons: machinery };\n return { conclusion: \"success\", reasons: [] };\n};\n\nconst concludeReviewState = (state: ReviewState) => {\n const reasons = blockingReasons({\n findings: state.unresolvedFindings,\n concerns: state.unresolvedConcerns,\n });\n return reasons.length > 0\n ? ({ conclusion: \"blocking\", reasons } as const)\n : ({ conclusion: \"success\", reasons: [] } as const);\n};\n\nconst skipCoveredReview = Effect.fn(\"skipCoveredReview\")(function* (input: {\n readonly repository: string;\n readonly pullRequestNumber: number;\n readonly reason: string;\n readonly state: ReviewState;\n readonly fingerprint?: string | undefined;\n}) {\n const result = concludeReviewState(input.state);\n yield* Console.log(\n `Skipping review of ${input.repository}#${input.pullRequestNumber}: ${input.reason}.`,\n );\n yield* writeActionOutputs([\n [\"skipped\", \"true\"],\n [\"skip-reason\", input.reason],\n ...(input.fingerprint === undefined ? [] : ([[\"fingerprint\", input.fingerprint]] as const)),\n [\"conclusion\", result.conclusion],\n [\"input-coverage\", \"complete\"],\n [\"review-assurance\", \"settled\"],\n [\"coverage\", \"complete\"],\n [\"review-mode\", \"incremental\"],\n ]);\n yield* writeStepSummary([\n \"### Pull-request review skipped\",\n `- Reason: ${input.reason}`,\n `- Preserved check conclusion: **${result.conclusion}**`,\n ]);\n if (result.conclusion === \"blocking\") {\n return yield* ReviewGateFailed.make({\n conclusion: \"blocking\",\n reasons: result.reasons,\n });\n }\n return { _tag: \"Skipped\", reason: input.reason } satisfies ReviewActionResult;\n});\n\n/**\n * Harness one already-built reviewer inside the Actions environment: resolve\n * the target from the event, provide the GitHub source/publisher/prior\n * reviews, validate/select bounded continuity scope, write step outputs, and apply\n * the host-derived coverage/blocker gate. Draft and non-PR skips are values;\n * an unchanged reviewed head preserves and enforces its stored conclusion. The reviewer's\n * remaining requirements — its model client, any extra tool handlers — stay\n * visible in `R` for the caller.\n */\nexport const runReviewAction = <E, R, FingerprintE = never, FingerprintR = never>(\n reviewer: HarnessedReviewer<E, R, FingerprintE, FingerprintR>,\n options: {\n readonly post?: boolean | undefined;\n /** Skip model execution when the current head already has complete stored coverage. */\n readonly skipUnchanged?: boolean | undefined;\n /** Incremental by default; `final` deliberately re-reviews the full PR diff. */\n readonly reviewMode?: ReviewMode | undefined;\n /** Model binding descriptor for the Actions step summary. */\n readonly modelLabel?: string | undefined;\n /** Explicit test/custom-host history override; GitHub owns the default adapter. */\n readonly priorReviews?: PriorReviews[\"Service\"] | undefined;\n /** Retire marker-bearing prior reviews after a successful post (default true). */\n readonly retireStaleReviews?: boolean | undefined;\n /**\n * Maintain one sticky \"review in progress\" issue comment, updated in\n * place when the run settles. Default false here for custom-harness\n * compatibility; the packaged action enables it by default. Dry runs\n * (`post: false`) never post progress.\n */\n readonly progressComment?: boolean | undefined;\n } = {},\n) =>\n Effect.gen(function* () {\n const event = yield* readGitHubEvent();\n if (Option.isSome(event)) {\n if (event.value.pull_request === undefined) {\n return yield* skip(\"the triggering event carries no pull request\");\n }\n if (event.value.pull_request.draft === true) {\n return yield* skip(\"the pull request is a draft\");\n }\n }\n const target = yield* resolveReviewTarget({});\n // One layer build for state selection AND the run, so both observe\n // the same cached pull-request snapshot.\n return yield* Effect.gen(function* () {\n let selection: ReturnType<typeof selectReviewRange> | undefined;\n if (reviewer.profileFingerprint !== undefined) {\n const source = yield* PullRequestSource;\n const [snapshot, profileFingerprint, currentFingerprint] = yield* Effect.all([\n reviewer.snapshot ?? Effect.all({ metadata: source.metadata, files: source.anchorFiles }),\n reviewer.profileFingerprint,\n reviewer.fingerprint === undefined\n ? Effect.succeed(undefined)\n : reviewer.fingerprint.pipe(\n Effect.map((fingerprint): string | undefined => fingerprint),\n Effect.orElseSucceed(() => undefined),\n ),\n ]);\n const { metadata, files: fullFiles } = snapshot;\n const history = options.priorReviews ?? (yield* PriorReviews);\n const stateAuthenticator = yield* ReviewStateAuthenticator;\n const recovered =\n stateAuthenticator.status === \"unavailable\"\n ? {\n state: undefined,\n failure:\n stateAuthenticator.unavailableReason ??\n \"an authenticated review-state secret is not configured\",\n }\n : yield* history.latestState.pipe(\n Effect.match({\n onFailure: (failure) => ({ state: undefined, failure: failure.reason }),\n onSuccess: (state) => ({\n state: Option.getOrUndefined(state),\n failure: undefined,\n }),\n }),\n );\n const equivalentPatchState =\n (options.reviewMode ?? \"incremental\") === \"incremental\" &&\n options.skipUnchanged !== false &&\n recovered.state !== undefined &&\n // Only a fully settled run may be skipped over: an unsettled state\n // carries retryable scope the next run must actually retry.\n recovered.state.settled &&\n currentFingerprint !== undefined &&\n validateReviewState(recovered.state, metadata, profileFingerprint) === undefined &&\n recovered.state.acceptedScopeFingerprint === currentFingerprint\n ? recovered.state\n : undefined;\n if (equivalentPatchState !== undefined) {\n return yield* skipCoveredReview({\n repository: target.repository,\n pullRequestNumber: target.number,\n reason:\n equivalentPatchState.reviewedHeadSha === metadata.headSha\n ? \"the current head already has settled stored review assurance\"\n : \"the effective pull-request patch is unchanged since the last settled review\",\n state: equivalentPatchState,\n fingerprint: currentFingerprint,\n });\n }\n let comparison: ReviewHeadComparison | undefined;\n let baseComparison: ReviewHeadComparison | undefined;\n if (\n (options.reviewMode ?? \"incremental\") === \"incremental\" &&\n recovered.state !== undefined\n ) {\n if (recovered.state.reviewedHeadSha === metadata.headSha) {\n comparison = ReviewHeadComparison.make({\n status: \"identical\",\n baseSha: metadata.headSha,\n headSha: metadata.headSha,\n mergeBaseSha: metadata.headSha,\n files: [],\n truncated: false,\n });\n } else {\n comparison = yield* history\n .compareHeads(recovered.state.reviewedHeadSha, metadata.headSha)\n .pipe(Effect.orElseSucceed(() => undefined));\n if (comparison !== undefined && reviewer.filterFiles !== undefined) {\n comparison = ReviewHeadComparison.make({\n ...comparison,\n files: reviewer.filterFiles(comparison.files),\n });\n }\n }\n if (metadata.baseSha !== undefined && recovered.state.baseSha !== metadata.baseSha) {\n baseComparison = yield* history\n .compareHeads(recovered.state.baseSha, metadata.baseSha)\n .pipe(Effect.orElseSucceed(() => undefined));\n if (baseComparison !== undefined && reviewer.filterFiles !== undefined) {\n baseComparison = ReviewHeadComparison.make({\n ...baseComparison,\n files: reviewer.filterFiles(baseComparison.files),\n });\n }\n }\n }\n selection = {\n ...selectReviewRange({\n requestedMode: options.reviewMode ?? \"incremental\",\n current: metadata,\n fullFiles,\n profileFingerprint,\n priorState: recovered.state,\n comparison,\n baseComparison,\n lookupFailure: recovered.failure,\n }),\n stateAuthenticator,\n };\n if (\n options.skipUnchanged !== false &&\n selection.mode === \"incremental\" &&\n selection.files.length === 0 &&\n selection.priorState !== undefined &&\n selection.priorState.settled\n ) {\n const reason = \"no changed review scope since the last settled review head\";\n return yield* skipCoveredReview({\n repository: target.repository,\n pullRequestNumber: target.number,\n reason,\n state: selection.priorState,\n });\n }\n }\n yield* Console.log(\n `Reviewing ${target.repository}#${target.number} (${options.post === false ? \"dry run\" : \"posting\"})...`,\n );\n const runUrl = yield* resolveRunUrl();\n // Progress is a cosmetic, fail-open narration surface: it says a run is\n // working the moment execution starts and is overwritten in place when\n // the run settles. It never gates or delays the review itself.\n const progress =\n options.progressComment === true && options.post !== false\n ? Option.some(yield* ReviewProgressReporter)\n : Option.none<ReviewProgressReporter[\"Service\"]>();\n if (Option.isSome(progress)) {\n const source = yield* PullRequestSource;\n const headMetadata = yield* source.metadata.pipe(Effect.orElseSucceed(() => undefined));\n yield* progress.value.begin({\n headSha: headMetadata?.headSha,\n reviewMode: selection?.mode,\n reviewReason: selection?.reason,\n filesInScope: selection?.files.length,\n modelLabel: options.modelLabel,\n runUrl,\n });\n }\n const runReview = reviewer.run({ post: options.post ?? true, runUrl });\n const reviewEffect = Option.isSome(progress)\n ? runReview.pipe(\n Effect.tapCause(() =>\n progress.value.settle({\n outcome: \"failed\",\n runUrl,\n modelLabel: options.modelLabel,\n }),\n ),\n )\n : runReview;\n const outcome = yield* selection === undefined\n ? reviewEffect\n : reviewEffect.pipe(\n Effect.provide(selectedPullRequestSourceLayer(selection)),\n Effect.provideService(ReviewExecutionContext, selection),\n );\n yield* Console.log(\n `Review finished in ${outcome.turns} turn(s): verdict ${outcome.review.verdict}, ` +\n `${outcome.plan.comments.length} inline comment(s), ${outcome.plan.demoted.length} demoted finding(s).`,\n );\n if (outcome.published !== undefined) {\n yield* Console.log(`Posted ${outcome.published.event} review: ${outcome.published.url}`);\n if (options.retireStaleReviews !== false && outcome.state !== undefined) {\n if (outcome.published.authorNodeId === null || outcome.published.submittedAt === null) {\n yield* Console.warn(\n \"Skipping stale-review retirement because GitHub did not return the posted review's actor and submission time.\",\n );\n } else {\n const report = yield* retireStaleReviews({\n currentReviewId: outcome.published.reviewId,\n currentReviewUrl: outcome.published.url,\n currentAuthorNodeId: outcome.published.authorNodeId,\n currentSubmittedAt: outcome.published.submittedAt,\n currentState: outcome.state,\n });\n yield* Console.log(\n `Review retirement: ${report.reviewsRetired} prior review(s), ` +\n `${report.findingsResolved} resolved finding(s), ` +\n `${report.commentsMinimized} minimized inline comment(s), ` +\n `${report.failures} failure(s).`,\n );\n }\n }\n }\n const check = concludeReviewOutcome(outcome);\n if (Option.isSome(progress)) {\n yield* progress.value.settle({\n outcome: \"reviewed\",\n conclusion: check.conclusion,\n verdict: outcome.review.verdict,\n inlineComments: outcome.plan.comments.length,\n reviewUrl: outcome.published?.url,\n runUrl,\n modelLabel: options.modelLabel,\n });\n }\n yield* writeActionOutputs(outcomeOutputs(outcome, check.conclusion));\n yield* writeStepSummary(outcomeSummary(outcome, options.modelLabel, check.conclusion));\n if (check.conclusion !== \"success\") {\n return yield* ReviewGateFailed.make({\n conclusion: check.conclusion,\n reasons: check.reasons,\n });\n }\n return { _tag: \"Completed\", outcome } satisfies ReviewActionResult;\n }).pipe(Effect.provide(gitHubReviewLayers(target)));\n });\n\n/**\n * The packaged, environment-driven action program: inputs from PR_REVIEW_*,\n * reviewer built from the packaged factory, provider client from the\n * matching credential environment variable.\n */\nexport const reviewActionProgram = Effect.gen(function* () {\n const inputs = yield* resolveActionInputs();\n const stateSecret = Option.map(\n yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_STATE_SECRET\")),\n Redacted.make,\n );\n const stateAuthenticatorLayer = Option.match(stateSecret, {\n onNone: () =>\n unavailableReviewStateAuthenticatorLayer(\n \"an authenticated review-state secret is not configured\",\n ),\n onSome: webCryptoReviewStateAuthenticatorLayer,\n });\n const guidance = yield* resolveGuidance(inputs);\n const modelLabel = describeReviewModel(inputs.provider, inputs.model, inputs.effort);\n const defaults = inputs.fanOut ? fanOutReviewBudgetLimits : reviewBudgetLimits;\n const budget =\n inputs.maxDurationMinutes === undefined\n ? defaults\n : UsageBudgetLimits.make({\n ...defaults,\n maxDurationMillis: inputs.maxDurationMinutes * 60_000,\n });\n const shared = {\n guidance,\n ignore: inputs.ignore,\n maxFindings: inputs.maxFindings,\n applyVerdict: inputs.applyVerdict,\n modelLabel,\n budget,\n };\n const harness = {\n post: inputs.post,\n skipUnchanged: inputs.skipUnchanged,\n reviewMode: inputs.reviewMode,\n retireStaleReviews: inputs.retireStaleReviews,\n progressComment: inputs.progressComment,\n modelLabel,\n };\n if (inputs.provider === \"anthropic\") {\n const model = makeAnthropicReviewModel(inputs.model, inputs.effort);\n const reviewer = inputs.fanOut\n ? PrReview.makeFanOut({ ...shared, model })\n : PrReview.make({ ...shared, model });\n return yield* runReviewAction(reviewer, harness).pipe(\n Effect.provide(Layer.merge(stateAuthenticatorLayer, anthropicClientLayer)),\n );\n }\n const model = makeOpenAiReviewModel(inputs.model, inputs.effort);\n const reviewer = inputs.fanOut\n ? PrReview.makeFanOut({ ...shared, model })\n : PrReview.make({ ...shared, model });\n return yield* runReviewAction(reviewer, harness).pipe(\n Effect.provide(Layer.merge(stateAuthenticatorLayer, openAiClientLayer)),\n );\n});\n\n/** Run the packaged action program on Node; the bundled action entrypoint. */\nexport const main = (): void =>\n NodeRuntime.runMain(\n reviewActionProgram.pipe(\n Effect.tapError((error) =>\n Console.error(\n Schema.is(BudgetExceeded)(error)\n ? `Budget exceeded: ${error.limit} observed ${error.observedValue}, limit ${error.limitValue}.`\n : String(error),\n ),\n ),\n Effect.scoped,\n Effect.provide(\n Layer.mergeAll(NodeServices.layer, FetchHttpClient.layer, compactReviewLoggingLayer),\n ),\n ),\n { disableErrorReporting: true },\n );\n\n/** The packaged GitHub Actions surface. */\nexport const PrReviewAction = {\n inputs: resolveActionInputs,\n run: runReviewAction,\n program: reviewActionProgram,\n main,\n} as const;\n"],"mappings":"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"}
1
+ {"version":3,"file":"action.mjs","names":[],"sources":["../src/action.ts"],"sourcesContent":["import { NodeRuntime, NodeServices } from \"@effect/platform-node\";\nimport { Config, Console, Effect, FileSystem, Layer, Option, Redacted, Schema } from \"effect\";\nimport { BudgetExceeded, UsageBudgetLimits } from \"effect-agent\";\nimport { FetchHttpClient } from \"effect/unstable/http\";\n\nimport type { ChangedFile } from \"./internal/diff.ts\";\nimport { InvalidEffortInput, parseEffortPosition, type EffortPosition } from \"./internal/effort.ts\";\nimport { PrReview, type RunReviewOptions } from \"./internal/factory.ts\";\nimport { readGitHubEvent, resolveReviewTarget, gitHubReviewLayers } from \"./internal/github-env.ts\";\nimport { PriorReviews } from \"./internal/github.ts\";\nimport { compactReviewLoggingLayer } from \"./internal/logging.ts\";\nimport { ReviewProgressReporter } from \"./internal/progress.ts\";\nimport {\n anthropicClientLayer,\n DEFAULT_PROVIDER,\n describeReviewModel,\n makeAnthropicReviewModel,\n makeOpenAiReviewModel,\n openAiClientLayer,\n type ReviewProvider,\n} from \"./internal/providers.ts\";\nimport { retireStaleReviews } from \"./internal/retirement.ts\";\nimport {\n ReviewExecutionContext,\n ReviewHeadComparison,\n ReviewStateAuthenticator,\n isLineageAncestor,\n type ReviewMode,\n type ReviewState,\n selectReviewRange,\n selectedPullRequestSourceLayer,\n unavailableReviewStateAuthenticatorLayer,\n validateReviewState,\n webCryptoReviewStateAuthenticatorLayer,\n} from \"./internal/review-state.ts\";\nimport { fanOutReviewBudgetLimits, reviewBudgetLimits } from \"./internal/run.ts\";\nimport type { ReviewRunOutcome } from \"./internal/run.ts\";\nimport {\n normalizeRepoRelativePath,\n PullRequestSource,\n type PullRequestMetadata,\n} from \"./internal/source.ts\";\n\n// ---------------------------------------------------------------------------\n// The GitHub Actions entrypoint (deployment class E: one bounded ephemeral\n// run, no exactly-once posting). Bounded continuity state travels in GitHub\n// review bodies and is validated before reuse. Inputs arrive as\n// PR_REVIEW_* environment variables set by the action manifest; the target\n// pull request comes from the standard Actions event environment. A non-PR\n// or draft event is a typed skip — green job, nothing posted. Publication\n// happens only after the run settles, so a failed or truncated run posts\n// nothing.\n// ---------------------------------------------------------------------------\n\nexport const ReviewCheckConclusion = Schema.Literals([\"success\", \"blocking\", \"incomplete\"]);\nexport type ReviewCheckConclusion = typeof ReviewCheckConclusion.Type;\n\n/** The host-derived blocking or incomplete conclusion failed the check. */\nexport class ReviewGateFailed extends Schema.TaggedError<ReviewGateFailed>()(\"ReviewGateFailed\", {\n conclusion: Schema.Literals([\"blocking\", \"incomplete\"]),\n reasons: Schema.Array(Schema.NonEmptyString.check(Schema.isMaxLength(1_000))).check(\n Schema.isMinLength(1),\n ),\n}) {\n override get message() {\n return `Review check concluded '${this.conclusion}': ${this.reasons.join(\"; \")}`;\n }\n}\n\n/** A configured max-duration that cannot bound a run; configuration faults fail loudly. */\nexport class InvalidMaxDurationInput extends Schema.TaggedError<InvalidMaxDurationInput>()(\n \"InvalidMaxDurationInput\",\n {\n minutes: Schema.Int,\n },\n) {\n override get message() {\n return `Invalid max-duration-minutes '${this.minutes}': expected a positive number of minutes.`;\n }\n}\n\n/** Everything the packaged action reads from its environment. */\nexport interface ResolvedActionInputs {\n readonly provider: ReviewProvider;\n readonly model: string | undefined;\n readonly effort: EffortPosition | undefined;\n readonly post: boolean;\n readonly applyVerdict: boolean;\n readonly fanOut: boolean;\n readonly guidance: string | undefined;\n readonly guidanceFile: string | undefined;\n readonly ignore: ReadonlyArray<string>;\n readonly maxFindings: number | undefined;\n readonly maxDurationMinutes: number | undefined;\n readonly reviewMode: ReviewMode;\n readonly skipUnchanged: boolean;\n readonly retireStaleReviews: boolean;\n readonly progressComment: boolean;\n}\n\n/** Read the PR_REVIEW_* input surface (all optional, all defaulted). */\nexport const resolveActionInputs = Effect.fn(\"resolveActionInputs\")(function* () {\n const provider = yield* Config.literals([\"openai\", \"anthropic\"], \"PR_REVIEW_PROVIDER\").pipe(\n Config.withDefault<ReviewProvider>(DEFAULT_PROVIDER),\n );\n const model = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_MODEL\"));\n const effortRaw = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_EFFORT\"));\n let effort: EffortPosition | undefined;\n if (Option.isSome(effortRaw)) {\n effort = parseEffortPosition(effortRaw.value);\n if (effort === undefined) {\n return yield* InvalidEffortInput.make({ input: effortRaw.value });\n }\n }\n const maxDurationMinutes = Option.getOrUndefined(\n yield* Config.option(Config.int(\"PR_REVIEW_MAX_DURATION_MINUTES\")),\n );\n if (maxDurationMinutes !== undefined && maxDurationMinutes <= 0) {\n return yield* InvalidMaxDurationInput.make({ minutes: maxDurationMinutes });\n }\n const post = yield* Config.boolean(\"PR_REVIEW_POST\").pipe(Config.withDefault(true));\n const applyVerdict = yield* Config.boolean(\"PR_REVIEW_APPLY_VERDICT\").pipe(\n Config.withDefault(false),\n );\n const fanOut = yield* Config.boolean(\"PR_REVIEW_FAN_OUT\").pipe(Config.withDefault(true));\n const guidance = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_GUIDANCE\"));\n const guidanceFile = yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_GUIDANCE_FILE\"));\n const ignoreRaw = yield* Config.string(\"PR_REVIEW_IGNORE\").pipe(Config.withDefault(\"\"));\n const maxFindings = yield* Config.option(Config.int(\"PR_REVIEW_MAX_FINDINGS\"));\n const reviewMode = yield* Config.literals([\"incremental\", \"final\"], \"PR_REVIEW_MODE\").pipe(\n Config.withDefault<ReviewMode>(\"incremental\"),\n );\n const skipUnchanged = yield* Config.boolean(\"PR_REVIEW_SKIP_UNCHANGED\").pipe(\n Config.withDefault(true),\n );\n const retireStaleReviews = yield* Config.boolean(\"PR_REVIEW_RETIRE_STALE_REVIEWS\").pipe(\n Config.withDefault(true),\n );\n const progressComment = yield* Config.boolean(\"PR_REVIEW_PROGRESS_COMMENT\").pipe(\n Config.withDefault(true),\n );\n return {\n provider,\n model: Option.getOrUndefined(model),\n effort,\n post,\n applyVerdict,\n fanOut,\n guidance: Option.getOrUndefined(guidance),\n guidanceFile: Option.getOrUndefined(guidanceFile),\n ignore: ignoreRaw\n .split(\",\")\n .map((pattern) => pattern.trim())\n .filter((pattern) => pattern.length > 0),\n maxFindings: Option.getOrUndefined(maxFindings),\n maxDurationMinutes,\n reviewMode,\n skipUnchanged,\n retireStaleReviews,\n progressComment,\n } satisfies ResolvedActionInputs;\n});\n\n/** A guidance file larger than this is refused, never silently truncated. */\nexport const MAX_GUIDANCE_FILE_CHARS = 20_000;\n\n/** A configured guidance file could not be used; configuration faults fail loudly. */\nexport class GuidanceFileUnreadable extends Schema.TaggedError<GuidanceFileUnreadable>()(\n \"GuidanceFileUnreadable\",\n {\n path: Schema.String,\n reason: Schema.String,\n },\n) {\n override get message() {\n return `Cannot use guidance file '${this.path}': ${this.reason}`;\n }\n}\n\n/**\n * Resolve the effective review guidance: the committed guidance file (a\n * repository-owned review profile) first, with any inline guidance appended.\n * A configured-but-unreadable file fails typed — a review silently running\n * without its profile would be worse than a red job.\n */\nexport const resolveGuidance = Effect.fn(\"resolveGuidance\")(function* (inputs: {\n readonly guidance: string | undefined;\n readonly guidanceFile: string | undefined;\n}) {\n const filePath = inputs.guidanceFile;\n if (filePath === undefined) return inputs.guidance;\n // The profile path is operator configuration, but it stays fail-closed\n // like every other path in this package: workspace-relative only, and the\n // size bound is checked before the file is read into memory.\n const relative = yield* normalizeRepoRelativePath(filePath).pipe(\n Effect.mapError((violation) =>\n GuidanceFileUnreadable.make({ path: filePath, reason: violation.reason }),\n ),\n );\n const fs = yield* FileSystem.FileSystem;\n const unreadable = (error: { readonly _tag: string; readonly message: string }) =>\n GuidanceFileUnreadable.make({\n path: relative,\n reason: `${error._tag}: ${error.message}`.slice(0, 2_048),\n });\n const stat = yield* fs.stat(relative).pipe(Effect.mapError(unreadable));\n const oversized = GuidanceFileUnreadable.make({\n path: relative,\n reason: `File is larger than the ${MAX_GUIDANCE_FILE_CHARS}-character guidance bound.`,\n });\n if (stat.size > BigInt(MAX_GUIDANCE_FILE_CHARS) * 4n) {\n return yield* oversized;\n }\n const content = yield* fs.readFileString(relative).pipe(Effect.mapError(unreadable));\n if (content.length > MAX_GUIDANCE_FILE_CHARS) {\n return yield* oversized;\n }\n const combined = [content.trim(), inputs.guidance ?? \"\"]\n .filter((part) => part.length > 0)\n .join(\"\\n\");\n return combined.length > 0 ? combined : undefined;\n});\n\n/** One step-output line; values must be single-line by construction. */\nconst outputLine = (name: string, value: string): string =>\n `${name}=${value.replaceAll(\"\\n\", \" \").slice(0, 1_000)}\\n`;\n\n/** Append step outputs to GITHUB_OUTPUT when present (no-op locally). */\nexport const writeActionOutputs = Effect.fn(\"writeActionOutputs\")(function* (\n entries: ReadonlyArray<readonly [name: string, value: string]>,\n) {\n const outputPath = yield* Config.string(\"GITHUB_OUTPUT\").pipe(Config.withDefault(\"\"));\n if (outputPath === \"\") return;\n const fs = yield* FileSystem.FileSystem;\n yield* fs.writeFileString(\n outputPath,\n entries.map(([name, value]) => outputLine(name, value)).join(\"\"),\n {\n flag: \"a\",\n },\n );\n});\n\n/** Append markdown to the GITHUB_STEP_SUMMARY report when present (no-op locally). */\nexport const writeStepSummary = Effect.fn(\"writeStepSummary\")(function* (\n lines: ReadonlyArray<string>,\n) {\n const summaryPath = yield* Config.string(\"GITHUB_STEP_SUMMARY\").pipe(Config.withDefault(\"\"));\n if (summaryPath === \"\") return;\n const fs = yield* FileSystem.FileSystem;\n yield* fs.writeFileString(summaryPath, `${lines.join(\"\\n\")}\\n`, { flag: \"a\" });\n});\n\nconst outcomeOutputs = (\n outcome: ReviewRunOutcome,\n conclusion: ReviewCheckConclusion,\n): ReadonlyArray<readonly [string, string]> => [\n [\"skipped\", \"false\"],\n [\"conclusion\", conclusion],\n [\"verdict\", outcome.review.verdict],\n [\"input-coverage\", outcome.inputCoverage.status],\n [\"review-assurance\", outcome.assurance.status],\n // Compatibility output: the precise outputs above own new integrations.\n [\"coverage\", outcome.coverage.status],\n [\"review-mode\", outcome.reviewMode ?? \"full\"],\n [\"review-reason\", outcome.reviewReason ?? \"direct full review\"],\n [\"inline-comments\", String(outcome.plan.comments.length)],\n [\"demoted-findings\", String(outcome.plan.demoted.length)],\n [\"concerns\", String(outcome.review.concerns?.length ?? 0)],\n [\"unreviewed-paths\", String(outcome.unreviewedPaths.length)],\n ...(outcome.usage === undefined\n ? []\n : ([\n [\"input-tokens\", String(outcome.usage.inputTokens)],\n [\"output-tokens\", String(outcome.usage.outputTokens)],\n ] as const)),\n [\"review-url\", outcome.published?.url ?? \"\"],\n];\n\nconst outcomeSummary = (\n outcome: ReviewRunOutcome,\n modelLabel: string | undefined,\n conclusion: ReviewCheckConclusion,\n): ReadonlyArray<string> => [\n \"### Pull-request review\",\n `- Check conclusion: **${conclusion}**`,\n `- Verdict: **${outcome.review.verdict}**`,\n `- Input coverage: **${outcome.inputCoverage.status}** · scope: ${outcome.reviewMode ?? \"full\"}`,\n `- 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}`,\n `- Inline comments: ${outcome.plan.comments.length} · demoted findings: ${outcome.plan.demoted.length} · concerns: ${outcome.review.concerns?.length ?? 0}`,\n ...(outcome.unreviewedPaths.length === 0\n ? []\n : [\n `- Carried forward: ${outcome.unreviewedPaths.length} unreviewed path(s) retried automatically on the next run (reviewer-side gap, not a code defect)`,\n ]),\n ...(modelLabel === undefined ? [] : [`- Model: \\`${modelLabel}\\``]),\n ...(outcome.usage === undefined\n ? []\n : [`- Tokens: ${outcome.usage.inputTokens} in / ${outcome.usage.outputTokens} out`]),\n ...(outcome.published === undefined\n ? [\"- Dry run: nothing posted\"]\n : [`- Posted: ${outcome.published.url}`]),\n];\n\n/** The result of one action invocation: a typed skip or a settled review. */\nexport type ReviewActionResult =\n | { readonly _tag: \"Skipped\"; readonly reason: string }\n | { readonly _tag: \"Completed\"; readonly outcome: ReviewRunOutcome };\n\nconst skip = (reason: string) =>\n Effect.gen(function* () {\n yield* Console.log(`Skipping review: ${reason}`);\n yield* writeActionOutputs([\n [\"skipped\", \"true\"],\n [\"skip-reason\", reason],\n ]);\n yield* writeStepSummary([\"### Pull-request review skipped\", `- Reason: ${reason}`]);\n return { _tag: \"Skipped\", reason } satisfies ReviewActionResult;\n });\n\n/** The Actions run URL for the review footer, or undefined outside Actions. */\nconst resolveRunUrl = Effect.fn(\"resolveRunUrl\")(function* () {\n const runId = yield* Config.string(\"GITHUB_RUN_ID\").pipe(Config.withDefault(\"\"));\n const repository = yield* Config.string(\"GITHUB_REPOSITORY\").pipe(Config.withDefault(\"\"));\n if (runId === \"\" || repository === \"\") return undefined;\n const server = yield* Config.string(\"GITHUB_SERVER_URL\").pipe(\n Config.withDefault(\"https://github.com\"),\n );\n return `${server}/${repository}/actions/runs/${runId}`;\n});\n\n/**\n * The reviewer surface the action harness drives. `PrReview.make` and\n * `PrReview.makeFanOut` provide the state-selection effects. A fingerprint is\n * skip authority only when a profile fingerprint and authenticated review\n * state bind it to settled assurance; a fingerprint-only custom harness\n * remains source-compatible but deliberately runs instead of claiming green\n * assurance from unauthenticated prior-review text.\n */\nexport interface HarnessedReviewer<E, R, FingerprintE, FingerprintR> {\n readonly run: (runOptions?: RunReviewOptions) => Effect.Effect<ReviewRunOutcome, E, R>;\n /** Current effective changeset fingerprint; not standalone skip authority. */\n readonly fingerprint?: Effect.Effect<string, FingerprintE, FingerprintR> | undefined;\n readonly profileFingerprint?: Effect.Effect<string, FingerprintE, FingerprintR> | undefined;\n readonly snapshot?:\n | Effect.Effect<\n {\n readonly metadata: PullRequestMetadata;\n readonly files: ReadonlyArray<ChangedFile>;\n },\n FingerprintE,\n FingerprintR\n >\n | undefined;\n readonly filterFiles?:\n | ((files: ReadonlyArray<ChangedFile>) => ReadonlyArray<ChangedFile>)\n | undefined;\n}\n\nconst blockingReasons = (input: {\n readonly findings: ReadonlyArray<{ readonly severity: string; readonly title: string }>;\n readonly concerns: ReadonlyArray<{ readonly severity: string; readonly title: string }>;\n}): ReadonlyArray<string> => [\n ...input.findings\n .filter((finding) => finding.severity === \"blocking\")\n .map((finding) => `blocking finding: ${finding.title}`),\n ...input.concerns\n .filter((concern) => concern.severity === \"blocking\")\n .map((concern) => `blocking concern: ${concern.title}`),\n];\n\n/**\n * Host-derived check conclusion; model verdict prose cannot weaken it.\n *\n * Blocking code findings outrank machinery gaps — they are the actionable\n * signal. A machinery gap (incomplete input, unsettled passes) concludes\n * `incomplete` with reasons that explicitly say the failure is reviewer-side\n * uncertainty carried forward for retry, never an invitation to change code.\n * The flat reviewer's constant `unverified` assurance is not a gap.\n */\nexport const concludeReviewOutcome = (\n outcome: ReviewRunOutcome,\n): {\n readonly conclusion: ReviewCheckConclusion;\n readonly reasons: ReadonlyArray<string>;\n} => {\n const machinery: Array<string> = [];\n if (outcome.inputCoverage.status === \"incomplete\" || outcome.assurance.status === \"incomplete\") {\n machinery.push(\n outcome.unreviewedPaths.length > 0\n ? `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`\n : \"review infrastructure did not settle — a reviewer-side gap, not a code defect\",\n );\n if (outcome.inputCoverage.status === \"incomplete\") {\n machinery.push(...outcome.inputCoverage.reasons);\n }\n if (outcome.assurance.status === \"incomplete\") {\n machinery.push(...outcome.assurance.reasons);\n }\n }\n const blocking = blockingReasons({\n findings: outcome.activeFindings,\n concerns: outcome.activeConcerns,\n });\n if (blocking.length > 0) {\n return { conclusion: \"blocking\", reasons: [...blocking, ...machinery] };\n }\n if (machinery.length > 0) return { conclusion: \"incomplete\", reasons: machinery };\n return { conclusion: \"success\", reasons: [] };\n};\n\nconst concludeReviewState = (state: ReviewState) => {\n const reasons = blockingReasons({\n findings: state.unresolvedFindings,\n concerns: state.unresolvedConcerns,\n });\n return reasons.length > 0\n ? ({ conclusion: \"blocking\", reasons } as const)\n : ({ conclusion: \"success\", reasons: [] } as const);\n};\n\nconst skipCoveredReview = Effect.fn(\"skipCoveredReview\")(function* (input: {\n readonly repository: string;\n readonly pullRequestNumber: number;\n readonly reason: string;\n readonly state: ReviewState;\n readonly fingerprint?: string | undefined;\n}) {\n const result = concludeReviewState(input.state);\n yield* Console.log(\n `Skipping review of ${input.repository}#${input.pullRequestNumber}: ${input.reason}.`,\n );\n yield* writeActionOutputs([\n [\"skipped\", \"true\"],\n [\"skip-reason\", input.reason],\n ...(input.fingerprint === undefined ? [] : ([[\"fingerprint\", input.fingerprint]] as const)),\n [\"conclusion\", result.conclusion],\n [\"input-coverage\", \"complete\"],\n [\"review-assurance\", \"settled\"],\n [\"coverage\", \"complete\"],\n [\"review-mode\", \"incremental\"],\n ]);\n yield* writeStepSummary([\n \"### Pull-request review skipped\",\n `- Reason: ${input.reason}`,\n `- Preserved check conclusion: **${result.conclusion}**`,\n ]);\n if (result.conclusion === \"blocking\") {\n return yield* ReviewGateFailed.make({\n conclusion: \"blocking\",\n reasons: result.reasons,\n });\n }\n return { _tag: \"Skipped\", reason: input.reason } satisfies ReviewActionResult;\n});\n\n/**\n * Harness one already-built reviewer inside the Actions environment: resolve\n * the target from the event, provide the GitHub source/publisher/prior\n * reviews, validate/select bounded continuity scope, write step outputs, and apply\n * the host-derived coverage/blocker gate. Draft and non-PR skips are values;\n * an unchanged reviewed head preserves and enforces its stored conclusion. The reviewer's\n * remaining requirements — its model client, any extra tool handlers — stay\n * visible in `R` for the caller.\n */\nexport const runReviewAction = <E, R, FingerprintE = never, FingerprintR = never>(\n reviewer: HarnessedReviewer<E, R, FingerprintE, FingerprintR>,\n options: {\n readonly post?: boolean | undefined;\n /** Skip model execution when the current head already has complete stored coverage. */\n readonly skipUnchanged?: boolean | undefined;\n /** Incremental by default; `final` deliberately re-reviews the full PR diff. */\n readonly reviewMode?: ReviewMode | undefined;\n /** Model binding descriptor for the Actions step summary. */\n readonly modelLabel?: string | undefined;\n /** Explicit test/custom-host history override; GitHub owns the default adapter. */\n readonly priorReviews?: PriorReviews[\"Service\"] | undefined;\n /** Retire marker-bearing prior reviews after a successful post (default true). */\n readonly retireStaleReviews?: boolean | undefined;\n /**\n * Maintain one sticky \"review in progress\" issue comment, updated in\n * place when the run settles. Default false here for custom-harness\n * compatibility; the packaged action enables it by default. Dry runs\n * (`post: false`) never post progress.\n */\n readonly progressComment?: boolean | undefined;\n } = {},\n) =>\n Effect.gen(function* () {\n const event = yield* readGitHubEvent();\n if (Option.isSome(event)) {\n if (event.value.pull_request === undefined) {\n return yield* skip(\"the triggering event carries no pull request\");\n }\n if (event.value.pull_request.draft === true) {\n return yield* skip(\"the pull request is a draft\");\n }\n }\n const target = yield* resolveReviewTarget({});\n // One layer build for state selection AND the run, so both observe\n // the same cached pull-request snapshot.\n return yield* Effect.gen(function* () {\n let selection: ReturnType<typeof selectReviewRange> | undefined;\n if (reviewer.profileFingerprint !== undefined) {\n const source = yield* PullRequestSource;\n const [snapshot, profileFingerprint, currentFingerprint] = yield* Effect.all([\n reviewer.snapshot ?? Effect.all({ metadata: source.metadata, files: source.anchorFiles }),\n reviewer.profileFingerprint,\n reviewer.fingerprint === undefined\n ? Effect.succeed(undefined)\n : reviewer.fingerprint.pipe(\n Effect.map((fingerprint): string | undefined => fingerprint),\n Effect.orElseSucceed(() => undefined),\n ),\n ]);\n const { metadata, files: fullFiles } = snapshot;\n const history = options.priorReviews ?? (yield* PriorReviews);\n const stateAuthenticator = yield* ReviewStateAuthenticator;\n const recovered =\n stateAuthenticator.status === \"unavailable\"\n ? {\n state: undefined,\n failure:\n stateAuthenticator.unavailableReason ??\n \"an authenticated review-state secret is not configured\",\n }\n : yield* history.latestState.pipe(\n Effect.match({\n onFailure: (failure) => ({ state: undefined, failure: failure.reason }),\n onSuccess: (state) => ({\n state: Option.getOrUndefined(state),\n failure: undefined,\n }),\n }),\n );\n const equivalentPatchState =\n (options.reviewMode ?? \"incremental\") === \"incremental\" &&\n options.skipUnchanged !== false &&\n recovered.state !== undefined &&\n // Only a fully settled run may be skipped over: an unsettled state\n // carries retryable scope the next run must actually retry.\n recovered.state.settled &&\n currentFingerprint !== undefined &&\n validateReviewState(recovered.state, metadata, profileFingerprint) === undefined &&\n recovered.state.acceptedScopeFingerprint === currentFingerprint\n ? recovered.state\n : undefined;\n if (equivalentPatchState !== undefined) {\n return yield* skipCoveredReview({\n repository: target.repository,\n pullRequestNumber: target.number,\n reason:\n equivalentPatchState.reviewedHeadSha === metadata.headSha\n ? \"the current head already has settled stored review assurance\"\n : \"the effective pull-request patch is unchanged since the last settled review\",\n state: equivalentPatchState,\n fingerprint: currentFingerprint,\n });\n }\n let comparison: ReviewHeadComparison | undefined;\n let baseComparison: ReviewHeadComparison | undefined;\n let contentComparison: ReviewHeadComparison | undefined;\n if (\n (options.reviewMode ?? \"incremental\") === \"incremental\" &&\n recovered.state !== undefined\n ) {\n if (recovered.state.reviewedHeadSha === metadata.headSha) {\n comparison = ReviewHeadComparison.make({\n status: \"identical\",\n baseSha: metadata.headSha,\n headSha: metadata.headSha,\n mergeBaseSha: metadata.headSha,\n files: [],\n truncated: false,\n });\n } else {\n comparison = yield* history\n .compareHeads(recovered.state.reviewedHeadSha, metadata.headSha)\n .pipe(Effect.orElseSucceed(() => undefined));\n if (comparison !== undefined && reviewer.filterFiles !== undefined) {\n comparison = ReviewHeadComparison.make({\n ...comparison,\n files: reviewer.filterFiles(comparison.files),\n });\n }\n }\n if (metadata.baseSha !== undefined && recovered.state.baseSha !== metadata.baseSha) {\n baseComparison = yield* history\n .compareHeads(recovered.state.baseSha, metadata.baseSha)\n .pipe(Effect.orElseSucceed(() => undefined));\n if (baseComparison !== undefined && reviewer.filterFiles !== undefined) {\n baseComparison = ReviewHeadComparison.make({\n ...baseComparison,\n files: reviewer.filterFiles(baseComparison.files),\n });\n }\n }\n if (\n recovered.state.reviewedHeadSha !== metadata.headSha &&\n (comparison === undefined ||\n !isLineageAncestor(comparison, recovered.state, metadata.headSha))\n ) {\n contentComparison = yield* history\n .compareTrees(recovered.state.reviewedHeadSha, metadata.headSha)\n .pipe(Effect.orElseSucceed(() => undefined));\n if (contentComparison !== undefined && reviewer.filterFiles !== undefined) {\n contentComparison = ReviewHeadComparison.make({\n ...contentComparison,\n files: reviewer.filterFiles(contentComparison.files),\n });\n }\n }\n }\n selection = {\n ...selectReviewRange({\n requestedMode: options.reviewMode ?? \"incremental\",\n current: metadata,\n fullFiles,\n profileFingerprint,\n priorState: recovered.state,\n comparison,\n baseComparison,\n contentComparison,\n lookupFailure: recovered.failure,\n }),\n stateAuthenticator,\n };\n if (\n options.skipUnchanged !== false &&\n selection.mode === \"incremental\" &&\n selection.files.length === 0 &&\n selection.priorState !== undefined &&\n selection.priorState.settled\n ) {\n const reason = \"no changed review scope since the last settled review head\";\n return yield* skipCoveredReview({\n repository: target.repository,\n pullRequestNumber: target.number,\n reason,\n state: selection.priorState,\n });\n }\n }\n yield* Console.log(\n `Reviewing ${target.repository}#${target.number} (${options.post === false ? \"dry run\" : \"posting\"})...`,\n );\n const runUrl = yield* resolveRunUrl();\n // Progress is a cosmetic, fail-open narration surface: it says a run is\n // working the moment execution starts and is overwritten in place when\n // the run settles. It never gates or delays the review itself.\n const progress =\n options.progressComment === true && options.post !== false\n ? Option.some(yield* ReviewProgressReporter)\n : Option.none<ReviewProgressReporter[\"Service\"]>();\n if (Option.isSome(progress)) {\n const source = yield* PullRequestSource;\n const headMetadata = yield* source.metadata.pipe(Effect.orElseSucceed(() => undefined));\n yield* progress.value.begin({\n headSha: headMetadata?.headSha,\n reviewMode: selection?.mode,\n reviewReason: selection?.reason,\n filesInScope: selection?.files.length,\n modelLabel: options.modelLabel,\n runUrl,\n });\n }\n const runReview = reviewer.run({ post: options.post ?? true, runUrl });\n const reviewEffect = Option.isSome(progress)\n ? runReview.pipe(\n Effect.tapCause(() =>\n progress.value.settle({\n outcome: \"failed\",\n runUrl,\n modelLabel: options.modelLabel,\n }),\n ),\n )\n : runReview;\n const outcome = yield* selection === undefined\n ? reviewEffect\n : reviewEffect.pipe(\n Effect.provide(selectedPullRequestSourceLayer(selection)),\n Effect.provideService(ReviewExecutionContext, selection),\n );\n yield* Console.log(\n `Review finished in ${outcome.turns} turn(s): verdict ${outcome.review.verdict}, ` +\n `${outcome.plan.comments.length} inline comment(s), ${outcome.plan.demoted.length} demoted finding(s).`,\n );\n if (outcome.published !== undefined) {\n yield* Console.log(`Posted ${outcome.published.event} review: ${outcome.published.url}`);\n if (options.retireStaleReviews !== false && outcome.state !== undefined) {\n if (outcome.published.authorNodeId === null || outcome.published.submittedAt === null) {\n yield* Console.warn(\n \"Skipping stale-review retirement because GitHub did not return the posted review's actor and submission time.\",\n );\n } else {\n const report = yield* retireStaleReviews({\n currentReviewId: outcome.published.reviewId,\n currentReviewUrl: outcome.published.url,\n currentAuthorNodeId: outcome.published.authorNodeId,\n currentSubmittedAt: outcome.published.submittedAt,\n currentState: outcome.state,\n });\n yield* Console.log(\n `Review retirement: ${report.reviewsRetired} prior review(s), ` +\n `${report.findingsResolved} resolved finding(s), ` +\n `${report.commentsMinimized} minimized inline comment(s), ` +\n `${report.failures} failure(s).`,\n );\n }\n }\n }\n const check = concludeReviewOutcome(outcome);\n if (Option.isSome(progress)) {\n yield* progress.value.settle({\n outcome: \"reviewed\",\n conclusion: check.conclusion,\n verdict: outcome.review.verdict,\n inlineComments: outcome.plan.comments.length,\n reviewUrl: outcome.published?.url,\n runUrl,\n modelLabel: options.modelLabel,\n });\n }\n yield* writeActionOutputs(outcomeOutputs(outcome, check.conclusion));\n yield* writeStepSummary(outcomeSummary(outcome, options.modelLabel, check.conclusion));\n if (check.conclusion !== \"success\") {\n return yield* ReviewGateFailed.make({\n conclusion: check.conclusion,\n reasons: check.reasons,\n });\n }\n return { _tag: \"Completed\", outcome } satisfies ReviewActionResult;\n }).pipe(Effect.provide(gitHubReviewLayers(target)));\n });\n\n/**\n * The packaged, environment-driven action program: inputs from PR_REVIEW_*,\n * reviewer built from the packaged factory, provider client from the\n * matching credential environment variable.\n */\nexport const reviewActionProgram = Effect.gen(function* () {\n const inputs = yield* resolveActionInputs();\n const stateSecret = Option.map(\n yield* Config.option(Config.nonEmptyString(\"PR_REVIEW_STATE_SECRET\")),\n Redacted.make,\n );\n const stateAuthenticatorLayer = Option.match(stateSecret, {\n onNone: () =>\n unavailableReviewStateAuthenticatorLayer(\n \"an authenticated review-state secret is not configured\",\n ),\n onSome: webCryptoReviewStateAuthenticatorLayer,\n });\n const guidance = yield* resolveGuidance(inputs);\n const modelLabel = describeReviewModel(inputs.provider, inputs.model, inputs.effort);\n const defaults = inputs.fanOut ? fanOutReviewBudgetLimits : reviewBudgetLimits;\n const budget =\n inputs.maxDurationMinutes === undefined\n ? defaults\n : UsageBudgetLimits.make({\n ...defaults,\n maxDurationMillis: inputs.maxDurationMinutes * 60_000,\n });\n const shared = {\n guidance,\n ignore: inputs.ignore,\n maxFindings: inputs.maxFindings,\n applyVerdict: inputs.applyVerdict,\n modelLabel,\n budget,\n };\n const harness = {\n post: inputs.post,\n skipUnchanged: inputs.skipUnchanged,\n reviewMode: inputs.reviewMode,\n retireStaleReviews: inputs.retireStaleReviews,\n progressComment: inputs.progressComment,\n modelLabel,\n };\n if (inputs.provider === \"anthropic\") {\n const model = makeAnthropicReviewModel(inputs.model, inputs.effort);\n const reviewer = inputs.fanOut\n ? PrReview.makeFanOut({ ...shared, model })\n : PrReview.make({ ...shared, model });\n return yield* runReviewAction(reviewer, harness).pipe(\n Effect.provide(Layer.merge(stateAuthenticatorLayer, anthropicClientLayer)),\n );\n }\n const model = makeOpenAiReviewModel(inputs.model, inputs.effort);\n const reviewer = inputs.fanOut\n ? PrReview.makeFanOut({ ...shared, model })\n : PrReview.make({ ...shared, model });\n return yield* runReviewAction(reviewer, harness).pipe(\n Effect.provide(Layer.merge(stateAuthenticatorLayer, openAiClientLayer)),\n );\n});\n\n/** Run the packaged action program on Node; the bundled action entrypoint. */\nexport const main = (): void =>\n NodeRuntime.runMain(\n reviewActionProgram.pipe(\n Effect.tapError((error) =>\n Console.error(\n Schema.is(BudgetExceeded)(error)\n ? `Budget exceeded: ${error.limit} observed ${error.observedValue}, limit ${error.limitValue}.`\n : String(error),\n ),\n ),\n Effect.scoped,\n Effect.provide(\n Layer.mergeAll(NodeServices.layer, FetchHttpClient.layer, compactReviewLoggingLayer),\n ),\n ),\n { disableErrorReporting: true },\n );\n\n/** The packaged GitHub Actions surface. */\nexport const PrReviewAction = {\n inputs: resolveActionInputs,\n run: runReviewAction,\n program: reviewActionProgram,\n main,\n} as const;\n"],"mappings":";;;;;;;;AAsDA,MAAa,wBAAwB,OAAO,SAAS;CAAC;CAAW;CAAY;AAAY,CAAC;;AAI1F,IAAa,mBAAb,cAAsC,OAAO,YAA8B,CAAC,CAAC,oBAAoB;CAC/F,YAAY,OAAO,SAAS,CAAC,YAAY,YAAY,CAAC;CACtD,SAAS,OAAO,MAAM,OAAO,eAAe,MAAM,OAAO,YAAY,GAAK,CAAC,CAAC,CAAC,CAAC,MAC5E,OAAO,YAAY,CAAC,CACtB;AACF,CAAC,CAAC,CAAC;CACD,IAAa,UAAU;EACrB,OAAO,2BAA2B,KAAK,WAAW,KAAK,KAAK,QAAQ,KAAK,IAAI;CAC/E;AACF;;AAGA,IAAa,0BAAb,cAA6C,OAAO,YAAqC,CAAC,CACxF,2BACA,EACE,SAAS,OAAO,IAClB,CACF,CAAC,CAAC;CACA,IAAa,UAAU;EACrB,OAAO,iCAAiC,KAAK,QAAQ;CACvD;AACF;;AAsBA,MAAa,sBAAsB,OAAO,GAAG,qBAAqB,CAAC,CAAC,aAAa;CAC/E,MAAM,WAAW,OAAO,OAAO,SAAS,CAAC,UAAU,WAAW,GAAG,oBAAoB,CAAC,CAAC,KACrF,OAAO,YAA4B,gBAAgB,CACrD;CACA,MAAM,QAAQ,OAAO,OAAO,OAAO,OAAO,eAAe,iBAAiB,CAAC;CAC3E,MAAM,YAAY,OAAO,OAAO,OAAO,OAAO,eAAe,kBAAkB,CAAC;CAChF,IAAI;CACJ,IAAI,OAAO,OAAO,SAAS,GAAG;EAC5B,SAAS,oBAAoB,UAAU,KAAK;EAC5C,IAAI,WAAW,KAAA,GACb,OAAO,OAAO,mBAAmB,KAAK,EAAE,OAAO,UAAU,MAAM,CAAC;CAEpE;CACA,MAAM,qBAAqB,OAAO,eAChC,OAAO,OAAO,OAAO,OAAO,IAAI,gCAAgC,CAAC,CACnE;CACA,IAAI,uBAAuB,KAAA,KAAa,sBAAsB,GAC5D,OAAO,OAAO,wBAAwB,KAAK,EAAE,SAAS,mBAAmB,CAAC;CAE5E,MAAM,OAAO,OAAO,OAAO,QAAQ,gBAAgB,CAAC,CAAC,KAAK,OAAO,YAAY,IAAI,CAAC;CAClF,MAAM,eAAe,OAAO,OAAO,QAAQ,yBAAyB,CAAC,CAAC,KACpE,OAAO,YAAY,KAAK,CAC1B;CACA,MAAM,SAAS,OAAO,OAAO,QAAQ,mBAAmB,CAAC,CAAC,KAAK,OAAO,YAAY,IAAI,CAAC;CACvF,MAAM,WAAW,OAAO,OAAO,OAAO,OAAO,eAAe,oBAAoB,CAAC;CACjF,MAAM,eAAe,OAAO,OAAO,OAAO,OAAO,eAAe,yBAAyB,CAAC;CAC1F,MAAM,YAAY,OAAO,OAAO,OAAO,kBAAkB,CAAC,CAAC,KAAK,OAAO,YAAY,EAAE,CAAC;CACtF,MAAM,cAAc,OAAO,OAAO,OAAO,OAAO,IAAI,wBAAwB,CAAC;CAC7E,MAAM,aAAa,OAAO,OAAO,SAAS,CAAC,eAAe,OAAO,GAAG,gBAAgB,CAAC,CAAC,KACpF,OAAO,YAAwB,aAAa,CAC9C;CACA,MAAM,gBAAgB,OAAO,OAAO,QAAQ,0BAA0B,CAAC,CAAC,KACtE,OAAO,YAAY,IAAI,CACzB;CACA,MAAM,qBAAqB,OAAO,OAAO,QAAQ,gCAAgC,CAAC,CAAC,KACjF,OAAO,YAAY,IAAI,CACzB;CACA,MAAM,kBAAkB,OAAO,OAAO,QAAQ,4BAA4B,CAAC,CAAC,KAC1E,OAAO,YAAY,IAAI,CACzB;CACA,OAAO;EACL;EACA,OAAO,OAAO,eAAe,KAAK;EAClC;EACA;EACA;EACA;EACA,UAAU,OAAO,eAAe,QAAQ;EACxC,cAAc,OAAO,eAAe,YAAY;EAChD,QAAQ,UACL,MAAM,GAAG,CAAC,CACV,KAAK,YAAY,QAAQ,KAAK,CAAC,CAAC,CAChC,QAAQ,YAAY,QAAQ,SAAS,CAAC;EACzC,aAAa,OAAO,eAAe,WAAW;EAC9C;EACA;EACA;EACA;EACA;CACF;AACF,CAAC;;AAGD,MAAa,0BAA0B;;AAGvC,IAAa,yBAAb,cAA4C,OAAO,YAAoC,CAAC,CACtF,0BACA;CACE,MAAM,OAAO;CACb,QAAQ,OAAO;AACjB,CACF,CAAC,CAAC;CACA,IAAa,UAAU;EACrB,OAAO,6BAA6B,KAAK,KAAK,KAAK,KAAK;CAC1D;AACF;;;;;;;AAQA,MAAa,kBAAkB,OAAO,GAAG,iBAAiB,CAAC,CAAC,WAAW,QAGpE;CACD,MAAM,WAAW,OAAO;CACxB,IAAI,aAAa,KAAA,GAAW,OAAO,OAAO;CAI1C,MAAM,WAAW,OAAO,0BAA0B,QAAQ,CAAC,CAAC,KAC1D,OAAO,UAAU,cACf,uBAAuB,KAAK;EAAE,MAAM;EAAU,QAAQ,UAAU;CAAO,CAAC,CAC1E,CACF;CACA,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,cAAc,UAClB,uBAAuB,KAAK;EAC1B,MAAM;EACN,QAAQ,GAAG,MAAM,KAAK,IAAI,MAAM,UAAU,MAAM,GAAG,IAAK;CAC1D,CAAC;CACH,MAAM,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,KAAK,OAAO,SAAS,UAAU,CAAC;CACtE,MAAM,YAAY,uBAAuB,KAAK;EAC5C,MAAM;EACN,QAAQ,2BAA2B,wBAAwB;CAC7D,CAAC;CACD,IAAI,KAAK,OAAO,OAAA,GAA8B,IAAI,IAChD,OAAO,OAAO;CAEhB,MAAM,UAAU,OAAO,GAAG,eAAe,QAAQ,CAAC,CAAC,KAAK,OAAO,SAAS,UAAU,CAAC;CACnF,IAAI,QAAQ,SAAA,KACV,OAAO,OAAO;CAEhB,MAAM,WAAW,CAAC,QAAQ,KAAK,GAAG,OAAO,YAAY,EAAE,CAAC,CACrD,QAAQ,SAAS,KAAK,SAAS,CAAC,CAAC,CACjC,KAAK,IAAI;CACZ,OAAO,SAAS,SAAS,IAAI,WAAW,KAAA;AAC1C,CAAC;;AAGD,MAAM,cAAc,MAAc,UAChC,GAAG,KAAK,GAAG,MAAM,WAAW,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,GAAK,EAAE;;AAGzD,MAAa,qBAAqB,OAAO,GAAG,oBAAoB,CAAC,CAAC,WAChE,SACA;CACA,MAAM,aAAa,OAAO,OAAO,OAAO,eAAe,CAAC,CAAC,KAAK,OAAO,YAAY,EAAE,CAAC;CACpF,IAAI,eAAe,IAAI;CAEvB,QAAO,OADW,WAAW,WAAA,CACnB,gBACR,YACA,QAAQ,KAAK,CAAC,MAAM,WAAW,WAAW,MAAM,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,GAC/D,EACE,MAAM,IACR,CACF;AACF,CAAC;;AAGD,MAAa,mBAAmB,OAAO,GAAG,kBAAkB,CAAC,CAAC,WAC5D,OACA;CACA,MAAM,cAAc,OAAO,OAAO,OAAO,qBAAqB,CAAC,CAAC,KAAK,OAAO,YAAY,EAAE,CAAC;CAC3F,IAAI,gBAAgB,IAAI;CAExB,QAAO,OADW,WAAW,WAAA,CACnB,gBAAgB,aAAa,GAAG,MAAM,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,IAAI,CAAC;AAC/E,CAAC;AAED,MAAM,kBACJ,SACA,eAC6C;CAC7C,CAAC,WAAW,OAAO;CACnB,CAAC,cAAc,UAAU;CACzB,CAAC,WAAW,QAAQ,OAAO,OAAO;CAClC,CAAC,kBAAkB,QAAQ,cAAc,MAAM;CAC/C,CAAC,oBAAoB,QAAQ,UAAU,MAAM;CAE7C,CAAC,YAAY,QAAQ,SAAS,MAAM;CACpC,CAAC,eAAe,QAAQ,cAAc,MAAM;CAC5C,CAAC,iBAAiB,QAAQ,gBAAgB,oBAAoB;CAC9D,CAAC,mBAAmB,OAAO,QAAQ,KAAK,SAAS,MAAM,CAAC;CACxD,CAAC,oBAAoB,OAAO,QAAQ,KAAK,QAAQ,MAAM,CAAC;CACxD,CAAC,YAAY,OAAO,QAAQ,OAAO,UAAU,UAAU,CAAC,CAAC;CACzD,CAAC,oBAAoB,OAAO,QAAQ,gBAAgB,MAAM,CAAC;CAC3D,GAAI,QAAQ,UAAU,KAAA,IAClB,CAAC,IACA,CACC,CAAC,gBAAgB,OAAO,QAAQ,MAAM,WAAW,CAAC,GAClD,CAAC,iBAAiB,OAAO,QAAQ,MAAM,YAAY,CAAC,CACtD;CACJ,CAAC,cAAc,QAAQ,WAAW,OAAO,EAAE;AAC7C;AAEA,MAAM,kBACJ,SACA,YACA,eAC0B;CAC1B;CACA,yBAAyB,WAAW;CACpC,gBAAgB,QAAQ,OAAO,QAAQ;CACvC,uBAAuB,QAAQ,cAAc,OAAO,cAAc,QAAQ,cAAc;CACxF,yBAAyB,QAAQ,UAAU,OAAO,yBAAyB,QAAQ,UAAU,gCAAgC,GAAG,QAAQ,UAAU,+BAA+B,gBAAgB,QAAQ,UAAU,0BAA0B,GAAG,QAAQ,UAAU,yBAAyB,kBAAkB,QAAQ,UAAU,4BAA4B,GAAG,QAAQ,UAAU;CAChX,sBAAsB,QAAQ,KAAK,SAAS,OAAO,uBAAuB,QAAQ,KAAK,QAAQ,OAAO,eAAe,QAAQ,OAAO,UAAU,UAAU;CACxJ,GAAI,QAAQ,gBAAgB,WAAW,IACnC,CAAC,IACD,CACE,sBAAsB,QAAQ,gBAAgB,OAAO,iGACvD;CACJ,GAAI,eAAe,KAAA,IAAY,CAAC,IAAI,CAAC,cAAc,WAAW,GAAG;CACjE,GAAI,QAAQ,UAAU,KAAA,IAClB,CAAC,IACD,CAAC,aAAa,QAAQ,MAAM,YAAY,QAAQ,QAAQ,MAAM,aAAa,KAAK;CACpF,GAAI,QAAQ,cAAc,KAAA,IACtB,CAAC,2BAA2B,IAC5B,CAAC,aAAa,QAAQ,UAAU,KAAK;AAC3C;AAOA,MAAM,QAAQ,WACZ,OAAO,IAAI,aAAa;CACtB,OAAO,QAAQ,IAAI,oBAAoB,QAAQ;CAC/C,OAAO,mBAAmB,CACxB,CAAC,WAAW,MAAM,GAClB,CAAC,eAAe,MAAM,CACxB,CAAC;CACD,OAAO,iBAAiB,CAAC,mCAAmC,aAAa,QAAQ,CAAC;CAClF,OAAO;EAAE,MAAM;EAAW;CAAO;AACnC,CAAC;;AAGH,MAAM,gBAAgB,OAAO,GAAG,eAAe,CAAC,CAAC,aAAa;CAC5D,MAAM,QAAQ,OAAO,OAAO,OAAO,eAAe,CAAC,CAAC,KAAK,OAAO,YAAY,EAAE,CAAC;CAC/E,MAAM,aAAa,OAAO,OAAO,OAAO,mBAAmB,CAAC,CAAC,KAAK,OAAO,YAAY,EAAE,CAAC;CACxF,IAAI,UAAU,MAAM,eAAe,IAAI,OAAO,KAAA;CAI9C,OAAO,GAAG,OAHY,OAAO,OAAO,mBAAmB,CAAC,CAAC,KACvD,OAAO,YAAY,oBAAoB,CACzC,EACiB,GAAG,WAAW,gBAAgB;AACjD,CAAC;AA8BD,MAAM,mBAAmB,UAGI,CAC3B,GAAG,MAAM,SACN,QAAQ,YAAY,QAAQ,aAAa,UAAU,CAAC,CACpD,KAAK,YAAY,qBAAqB,QAAQ,OAAO,GACxD,GAAG,MAAM,SACN,QAAQ,YAAY,QAAQ,aAAa,UAAU,CAAC,CACpD,KAAK,YAAY,qBAAqB,QAAQ,OAAO,CAC1D;;;;;;;;;;AAWA,MAAa,yBACX,YAIG;CACH,MAAM,YAA2B,CAAC;CAClC,IAAI,QAAQ,cAAc,WAAW,gBAAgB,QAAQ,UAAU,WAAW,cAAc;EAC9F,UAAU,KACR,QAAQ,gBAAgB,SAAS,IAC7B,kFAAkF,QAAQ,gBAAgB,OAAO,0EACjH,+EACN;EACA,IAAI,QAAQ,cAAc,WAAW,cACnC,UAAU,KAAK,GAAG,QAAQ,cAAc,OAAO;EAEjD,IAAI,QAAQ,UAAU,WAAW,cAC/B,UAAU,KAAK,GAAG,QAAQ,UAAU,OAAO;CAE/C;CACA,MAAM,WAAW,gBAAgB;EAC/B,UAAU,QAAQ;EAClB,UAAU,QAAQ;CACpB,CAAC;CACD,IAAI,SAAS,SAAS,GACpB,OAAO;EAAE,YAAY;EAAY,SAAS,CAAC,GAAG,UAAU,GAAG,SAAS;CAAE;CAExE,IAAI,UAAU,SAAS,GAAG,OAAO;EAAE,YAAY;EAAc,SAAS;CAAU;CAChF,OAAO;EAAE,YAAY;EAAW,SAAS,CAAC;CAAE;AAC9C;AAEA,MAAM,uBAAuB,UAAuB;CAClD,MAAM,UAAU,gBAAgB;EAC9B,UAAU,MAAM;EAChB,UAAU,MAAM;CAClB,CAAC;CACD,OAAO,QAAQ,SAAS,IACnB;EAAE,YAAY;EAAY;CAAQ,IAClC;EAAE,YAAY;EAAW,SAAS,CAAC;CAAE;AAC5C;AAEA,MAAM,oBAAoB,OAAO,GAAG,mBAAmB,CAAC,CAAC,WAAW,OAMjE;CACD,MAAM,SAAS,oBAAoB,MAAM,KAAK;CAC9C,OAAO,QAAQ,IACb,sBAAsB,MAAM,WAAW,GAAG,MAAM,kBAAkB,IAAI,MAAM,OAAO,EACrF;CACA,OAAO,mBAAmB;EACxB,CAAC,WAAW,MAAM;EAClB,CAAC,eAAe,MAAM,MAAM;EAC5B,GAAI,MAAM,gBAAgB,KAAA,IAAY,CAAC,IAAK,CAAC,CAAC,eAAe,MAAM,WAAW,CAAC;EAC/E,CAAC,cAAc,OAAO,UAAU;EAChC,CAAC,kBAAkB,UAAU;EAC7B,CAAC,oBAAoB,SAAS;EAC9B,CAAC,YAAY,UAAU;EACvB,CAAC,eAAe,aAAa;CAC/B,CAAC;CACD,OAAO,iBAAiB;EACtB;EACA,aAAa,MAAM;EACnB,mCAAmC,OAAO,WAAW;CACvD,CAAC;CACD,IAAI,OAAO,eAAe,YACxB,OAAO,OAAO,iBAAiB,KAAK;EAClC,YAAY;EACZ,SAAS,OAAO;CAClB,CAAC;CAEH,OAAO;EAAE,MAAM;EAAW,QAAQ,MAAM;CAAO;AACjD,CAAC;;;;;;;;;;AAWD,MAAa,mBACX,UACA,UAmBI,CAAC,MAEL,OAAO,IAAI,aAAa;CACtB,MAAM,QAAQ,OAAO,gBAAgB;CACrC,IAAI,OAAO,OAAO,KAAK,GAAG;EACxB,IAAI,MAAM,MAAM,iBAAiB,KAAA,GAC/B,OAAO,OAAO,KAAK,8CAA8C;EAEnE,IAAI,MAAM,MAAM,aAAa,UAAU,MACrC,OAAO,OAAO,KAAK,6BAA6B;CAEpD;CACA,MAAM,SAAS,OAAO,oBAAoB,CAAC,CAAC;CAG5C,OAAO,OAAO,OAAO,IAAI,aAAa;EACpC,IAAI;EACJ,IAAI,SAAS,uBAAuB,KAAA,GAAW;GAC7C,MAAM,SAAS,OAAO;GACtB,MAAM,CAAC,UAAU,oBAAoB,sBAAsB,OAAO,OAAO,IAAI;IAC3E,SAAS,YAAY,OAAO,IAAI;KAAE,UAAU,OAAO;KAAU,OAAO,OAAO;IAAY,CAAC;IACxF,SAAS;IACT,SAAS,gBAAgB,KAAA,IACrB,OAAO,QAAQ,KAAA,CAAS,IACxB,SAAS,YAAY,KACnB,OAAO,KAAK,gBAAoC,WAAW,GAC3D,OAAO,oBAAoB,KAAA,CAAS,CACtC;GACN,CAAC;GACD,MAAM,EAAE,UAAU,OAAO,cAAc;GACvC,MAAM,UAAU,QAAQ,iBAAiB,OAAO;GAChD,MAAM,qBAAqB,OAAO;GAClC,MAAM,YACJ,mBAAmB,WAAW,gBAC1B;IACE,OAAO,KAAA;IACP,SACE,mBAAmB,qBACnB;GACJ,IACA,OAAO,QAAQ,YAAY,KACzB,OAAO,MAAM;IACX,YAAY,aAAa;KAAE,OAAO,KAAA;KAAW,SAAS,QAAQ;IAAO;IACrE,YAAY,WAAW;KACrB,OAAO,OAAO,eAAe,KAAK;KAClC,SAAS,KAAA;IACX;GACF,CAAC,CACH;GACN,MAAM,wBACH,QAAQ,cAAc,mBAAmB,iBAC1C,QAAQ,kBAAkB,SAC1B,UAAU,UAAU,KAAA,KAGpB,UAAU,MAAM,WAChB,uBAAuB,KAAA,KACvB,oBAAoB,UAAU,OAAO,UAAU,kBAAkB,MAAM,KAAA,KACvE,UAAU,MAAM,6BAA6B,qBACzC,UAAU,QACV,KAAA;GACN,IAAI,yBAAyB,KAAA,GAC3B,OAAO,OAAO,kBAAkB;IAC9B,YAAY,OAAO;IACnB,mBAAmB,OAAO;IAC1B,QACE,qBAAqB,oBAAoB,SAAS,UAC9C,iEACA;IACN,OAAO;IACP,aAAa;GACf,CAAC;GAEH,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,KACG,QAAQ,cAAc,mBAAmB,iBAC1C,UAAU,UAAU,KAAA,GACpB;IACA,IAAI,UAAU,MAAM,oBAAoB,SAAS,SAC/C,aAAa,qBAAqB,KAAK;KACrC,QAAQ;KACR,SAAS,SAAS;KAClB,SAAS,SAAS;KAClB,cAAc,SAAS;KACvB,OAAO,CAAC;KACR,WAAW;IACb,CAAC;SACI;KACL,aAAa,OAAO,QACjB,aAAa,UAAU,MAAM,iBAAiB,SAAS,OAAO,CAAC,CAC/D,KAAK,OAAO,oBAAoB,KAAA,CAAS,CAAC;KAC7C,IAAI,eAAe,KAAA,KAAa,SAAS,gBAAgB,KAAA,GACvD,aAAa,qBAAqB,KAAK;MACrC,GAAG;MACH,OAAO,SAAS,YAAY,WAAW,KAAK;KAC9C,CAAC;IAEL;IACA,IAAI,SAAS,YAAY,KAAA,KAAa,UAAU,MAAM,YAAY,SAAS,SAAS;KAClF,iBAAiB,OAAO,QACrB,aAAa,UAAU,MAAM,SAAS,SAAS,OAAO,CAAC,CACvD,KAAK,OAAO,oBAAoB,KAAA,CAAS,CAAC;KAC7C,IAAI,mBAAmB,KAAA,KAAa,SAAS,gBAAgB,KAAA,GAC3D,iBAAiB,qBAAqB,KAAK;MACzC,GAAG;MACH,OAAO,SAAS,YAAY,eAAe,KAAK;KAClD,CAAC;IAEL;IACA,IACE,UAAU,MAAM,oBAAoB,SAAS,YAC5C,eAAe,KAAA,KACd,CAAC,kBAAkB,YAAY,UAAU,OAAO,SAAS,OAAO,IAClE;KACA,oBAAoB,OAAO,QACxB,aAAa,UAAU,MAAM,iBAAiB,SAAS,OAAO,CAAC,CAC/D,KAAK,OAAO,oBAAoB,KAAA,CAAS,CAAC;KAC7C,IAAI,sBAAsB,KAAA,KAAa,SAAS,gBAAgB,KAAA,GAC9D,oBAAoB,qBAAqB,KAAK;MAC5C,GAAG;MACH,OAAO,SAAS,YAAY,kBAAkB,KAAK;KACrD,CAAC;IAEL;GACF;GACA,YAAY;IACV,GAAG,kBAAkB;KACnB,eAAe,QAAQ,cAAc;KACrC,SAAS;KACT;KACA;KACA,YAAY,UAAU;KACtB;KACA;KACA;KACA,eAAe,UAAU;IAC3B,CAAC;IACD;GACF;GACA,IACE,QAAQ,kBAAkB,SAC1B,UAAU,SAAS,iBACnB,UAAU,MAAM,WAAW,KAC3B,UAAU,eAAe,KAAA,KACzB,UAAU,WAAW,SAGrB,OAAO,OAAO,kBAAkB;IAC9B,YAAY,OAAO;IACnB,mBAAmB,OAAO;IAC1B,QAAA;IACA,OAAO,UAAU;GACnB,CAAC;EAEL;EACA,OAAO,QAAQ,IACb,aAAa,OAAO,WAAW,GAAG,OAAO,OAAO,IAAI,QAAQ,SAAS,QAAQ,YAAY,UAAU,KACrG;EACA,MAAM,SAAS,OAAO,cAAc;EAIpC,MAAM,WACJ,QAAQ,oBAAoB,QAAQ,QAAQ,SAAS,QACjD,OAAO,KAAK,OAAO,sBAAsB,IACzC,OAAO,KAAwC;EACrD,IAAI,OAAO,OAAO,QAAQ,GAAG;GAE3B,MAAM,eAAe,QAAO,OADN,kBAAA,CACa,SAAS,KAAK,OAAO,oBAAoB,KAAA,CAAS,CAAC;GACtF,OAAO,SAAS,MAAM,MAAM;IAC1B,SAAS,cAAc;IACvB,YAAY,WAAW;IACvB,cAAc,WAAW;IACzB,cAAc,WAAW,MAAM;IAC/B,YAAY,QAAQ;IACpB;GACF,CAAC;EACH;EACA,MAAM,YAAY,SAAS,IAAI;GAAE,MAAM,QAAQ,QAAQ;GAAM;EAAO,CAAC;EACrE,MAAM,eAAe,OAAO,OAAO,QAAQ,IACvC,UAAU,KACR,OAAO,eACL,SAAS,MAAM,OAAO;GACpB,SAAS;GACT;GACA,YAAY,QAAQ;EACtB,CAAC,CACH,CACF,IACA;EACJ,MAAM,UAAU,OAAO,cAAc,KAAA,IACjC,eACA,aAAa,KACX,OAAO,QAAQ,+BAA+B,SAAS,CAAC,GACxD,OAAO,eAAe,wBAAwB,SAAS,CACzD;EACJ,OAAO,QAAQ,IACb,sBAAsB,QAAQ,MAAM,oBAAoB,QAAQ,OAAO,QAAQ,IAC1E,QAAQ,KAAK,SAAS,OAAO,sBAAsB,QAAQ,KAAK,QAAQ,OAAO,qBACtF;EACA,IAAI,QAAQ,cAAc,KAAA,GAAW;GACnC,OAAO,QAAQ,IAAI,UAAU,QAAQ,UAAU,MAAM,WAAW,QAAQ,UAAU,KAAK;GACvF,IAAI,QAAQ,uBAAuB,SAAS,QAAQ,UAAU,KAAA,GAC5D,IAAI,QAAQ,UAAU,iBAAiB,QAAQ,QAAQ,UAAU,gBAAgB,MAC/E,OAAO,QAAQ,KACb,+GACF;QACK;IACL,MAAM,SAAS,OAAO,mBAAmB;KACvC,iBAAiB,QAAQ,UAAU;KACnC,kBAAkB,QAAQ,UAAU;KACpC,qBAAqB,QAAQ,UAAU;KACvC,oBAAoB,QAAQ,UAAU;KACtC,cAAc,QAAQ;IACxB,CAAC;IACD,OAAO,QAAQ,IACb,sBAAsB,OAAO,eAAe,oBACvC,OAAO,iBAAiB,wBACxB,OAAO,kBAAkB,gCACzB,OAAO,SAAS,aACvB;GACF;EAEJ;EACA,MAAM,QAAQ,sBAAsB,OAAO;EAC3C,IAAI,OAAO,OAAO,QAAQ,GACxB,OAAO,SAAS,MAAM,OAAO;GAC3B,SAAS;GACT,YAAY,MAAM;GAClB,SAAS,QAAQ,OAAO;GACxB,gBAAgB,QAAQ,KAAK,SAAS;GACtC,WAAW,QAAQ,WAAW;GAC9B;GACA,YAAY,QAAQ;EACtB,CAAC;EAEH,OAAO,mBAAmB,eAAe,SAAS,MAAM,UAAU,CAAC;EACnE,OAAO,iBAAiB,eAAe,SAAS,QAAQ,YAAY,MAAM,UAAU,CAAC;EACrF,IAAI,MAAM,eAAe,WACvB,OAAO,OAAO,iBAAiB,KAAK;GAClC,YAAY,MAAM;GAClB,SAAS,MAAM;EACjB,CAAC;EAEH,OAAO;GAAE,MAAM;GAAa;EAAQ;CACtC,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,mBAAmB,MAAM,CAAC,CAAC;AACpD,CAAC;;;;;;AAOH,MAAa,sBAAsB,OAAO,IAAI,aAAa;CACzD,MAAM,SAAS,OAAO,oBAAoB;CAC1C,MAAM,cAAc,OAAO,IACzB,OAAO,OAAO,OAAO,OAAO,eAAe,wBAAwB,CAAC,GACpE,SAAS,IACX;CACA,MAAM,0BAA0B,OAAO,MAAM,aAAa;EACxD,cACE,yCACE,wDACF;EACF,QAAQ;CACV,CAAC;CACD,MAAM,WAAW,OAAO,gBAAgB,MAAM;CAC9C,MAAM,aAAa,oBAAoB,OAAO,UAAU,OAAO,OAAO,OAAO,MAAM;CACnF,MAAM,WAAW,OAAO,SAAS,2BAA2B;CAC5D,MAAM,SACJ,OAAO,uBAAuB,KAAA,IAC1B,WACA,kBAAkB,KAAK;EACrB,GAAG;EACH,mBAAmB,OAAO,qBAAqB;CACjD,CAAC;CACP,MAAM,SAAS;EACb;EACA,QAAQ,OAAO;EACf,aAAa,OAAO;EACpB,cAAc,OAAO;EACrB;EACA;CACF;CACA,MAAM,UAAU;EACd,MAAM,OAAO;EACb,eAAe,OAAO;EACtB,YAAY,OAAO;EACnB,oBAAoB,OAAO;EAC3B,iBAAiB,OAAO;EACxB;CACF;CACA,IAAI,OAAO,aAAa,aAAa;EACnC,MAAM,QAAQ,yBAAyB,OAAO,OAAO,OAAO,MAAM;EAClE,MAAM,WAAW,OAAO,SACpB,SAAS,WAAW;GAAE,GAAG;GAAQ;EAAM,CAAC,IACxC,SAAS,KAAK;GAAE,GAAG;GAAQ;EAAM,CAAC;EACtC,OAAO,OAAO,gBAAgB,UAAU,OAAO,CAAC,CAAC,KAC/C,OAAO,QAAQ,MAAM,MAAM,yBAAyB,oBAAoB,CAAC,CAC3E;CACF;CACA,MAAM,QAAQ,sBAAsB,OAAO,OAAO,OAAO,MAAM;CAC/D,MAAM,WAAW,OAAO,SACpB,SAAS,WAAW;EAAE,GAAG;EAAQ;CAAM,CAAC,IACxC,SAAS,KAAK;EAAE,GAAG;EAAQ;CAAM,CAAC;CACtC,OAAO,OAAO,gBAAgB,UAAU,OAAO,CAAC,CAAC,KAC/C,OAAO,QAAQ,MAAM,MAAM,yBAAyB,iBAAiB,CAAC,CACxE;AACF,CAAC;;AAGD,MAAa,aACX,YAAY,QACV,oBAAoB,KAClB,OAAO,UAAU,UACf,QAAQ,MACN,OAAO,GAAG,cAAc,CAAC,CAAC,KAAK,IAC3B,oBAAoB,MAAM,MAAM,YAAY,MAAM,cAAc,UAAU,MAAM,WAAW,KAC3F,OAAO,KAAK,CAClB,CACF,GACA,OAAO,QACP,OAAO,QACL,MAAM,SAAS,aAAa,OAAO,gBAAgB,OAAO,yBAAyB,CACrF,CACF,GACA,EAAE,uBAAuB,KAAK,CAChC;;AAGF,MAAa,iBAAiB;CAC5B,QAAQ;CACR,KAAK;CACL,SAAS;CACT;AACF"}
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { c as fingerprintUnchanged } from "./github-BbwYzNrC.mjs";
2
- import { C as PrReview, H as InvalidEffortInput, P as ReviewPublicationPlan, W as parseEffortPosition, a as anthropicClientLayer, c as makeOpenAiReviewModel, f as gitHubReviewLayers, l as openAiClientLayer, m as resolveReviewTarget, n as DEFAULT_PROVIDER, o as describeReviewModel, s as makeAnthropicReviewModel, t as DEFAULT_MODEL } from "./providers-NyP-4rS6.mjs";
1
+ import { c as fingerprintUnchanged } from "./github-C6jrBLA2.mjs";
2
+ import { C as PrReview, H as InvalidEffortInput, P as ReviewPublicationPlan, W as parseEffortPosition, a as anthropicClientLayer, c as makeOpenAiReviewModel, f as gitHubReviewLayers, l as openAiClientLayer, m as resolveReviewTarget, n as DEFAULT_PROVIDER, o as describeReviewModel, s as makeAnthropicReviewModel, t as DEFAULT_MODEL } from "./providers-2Jao2ZAX.mjs";
3
3
  import { Console, Effect, Layer, Option, Schema } from "effect";
4
4
  import { BudgetExceeded } from "effect-agent";
5
5
  import { FetchHttpClient } from "effect/unstable/http";
@@ -657,6 +657,17 @@ declare const StoredReviewConcern_base: Schema.Class<StoredReviewConcern, Schema
657
657
  declare class StoredReviewConcern extends StoredReviewConcern_base {}
658
658
  /** The carried-scope bound; a run that cannot fit its leftovers publishes no state. */
659
659
  declare const MAX_STORED_UNREVIEWED_PATHS = 100;
660
+ /** Failed-pass records stored beside the leftover paths; one per unit stage. */
661
+ declare const MAX_STORED_UNREVIEWED_PASSES = 24;
662
+ /** Stages a leftover path may need retried without a second general discovery. */
663
+ declare const UnreviewedStage: Schema.Literals<readonly ["discovery", "specialist", "verification"]>;
664
+ type UnreviewedStage = typeof UnreviewedStage.Type;
665
+ declare const StoredUnreviewedPass_base: Schema.Class<StoredUnreviewedPass, Schema.Struct<{
666
+ readonly stage: Schema.Literals<readonly ["discovery", "specialist", "verification"]>;
667
+ readonly paths: Schema.$Array<Schema.NonEmptyString>;
668
+ }>, {}>;
669
+ /** One failed fan-out pass whose paths should be retried, not rediscovered. */
670
+ declare class StoredUnreviewedPass extends StoredUnreviewedPass_base {}
660
671
  declare const ReviewState_base: Schema.Class<ReviewState, Schema.Struct<{
661
672
  readonly version: Schema.Literal<2>;
662
673
  readonly repository: Schema.NonEmptyString;
@@ -672,6 +683,12 @@ declare const ReviewState_base: Schema.Class<ReviewState, Schema.Struct<{
672
683
  readonly unresolvedConcerns: Schema.$Array<typeof StoredReviewConcern>;
673
684
  /** Retryable review gaps carried into the next incremental run's scope. */
674
685
  readonly unreviewedPaths: Schema.$Array<Schema.NonEmptyString>;
686
+ /**
687
+ * Which failed pass produced those leftovers. Absent on state-v2 markers
688
+ * written before this field existed; those leftovers still re-enter scope
689
+ * but cannot skip rediscovery. Present (including empty) on new markers.
690
+ */
691
+ readonly unreviewedPasses: Schema.optionalKey<Schema.$Array<typeof StoredUnreviewedPass>>;
675
692
  /**
676
693
  * True only when the producing run had complete input coverage, no
677
694
  * unsettled pass, and nothing carried. Skip-unchanged authority: an
@@ -738,6 +755,12 @@ interface ReviewSelection {
738
755
  readonly files: ReadonlyArray<ChangedFile>;
739
756
  /** Paths whose changes invalidate prior findings, including paths reverted out of the PR. */
740
757
  readonly affectedPaths: ReadonlyArray<string>;
758
+ /**
759
+ * Leftover paths whose contents did not change. Fan-out retries only the
760
+ * recorded failed stages on these paths and keeps their stored findings.
761
+ */
762
+ readonly retryPaths: ReadonlyArray<string>;
763
+ readonly retryStages: ReadonlyArray<UnreviewedStage>;
741
764
  readonly totalFiles: number;
742
765
  readonly baselineSha: string | undefined;
743
766
  readonly priorState: ReviewState | undefined;
@@ -745,6 +768,8 @@ interface ReviewSelection {
745
768
  /** Action-owned authentication capability, constructed at the composition root. */
746
769
  readonly stateAuthenticator?: ReviewStateAuthenticator["Service"] | undefined;
747
770
  }
771
+ /** Three-dot lineage from the reviewed head to the current head is usable. */
772
+ declare const isLineageAncestor: (comparison: ReviewHeadComparison, priorState: ReviewState, currentHeadSha: string) => boolean;
748
773
  /**
749
774
  * Validate that persisted state belongs to this exact PR/base lineage and the
750
775
  * same review profile. A mismatch is a full-review reason, never an error that
@@ -760,6 +785,12 @@ declare const selectReviewRange: (input: {
760
785
  readonly priorState: ReviewState | undefined;
761
786
  readonly comparison: ReviewHeadComparison | undefined;
762
787
  readonly baseComparison?: ReviewHeadComparison | undefined;
788
+ /**
789
+ * Two-dot tree comparison used when the reviewed head is not a git ancestor
790
+ * (rebase, amend, force-push). Intersected with the current PR path set so
791
+ * main-drift outside the pull request never re-enters scope.
792
+ */
793
+ readonly contentComparison?: ReviewHeadComparison | undefined;
763
794
  readonly lookupFailure?: string | undefined;
764
795
  }) => ReviewSelection;
765
796
  declare const ReviewExecutionContext_base: Context.ServiceClass<ReviewExecutionContext, "@effect-agent/pr-review/ReviewExecutionContext", ReviewSelection>;
@@ -771,8 +802,6 @@ declare class ReviewExecutionContext extends ReviewExecutionContext_base {}
771
802
  * the selected delta and may read head context only for that delta's paths.
772
803
  */
773
804
  declare const selectedPullRequestSourceLayer: (selection: ReviewSelection) => Layer.Layer<PullRequestSource, never, PullRequestSource>;
774
- /** Profile fingerprints are SHA-256 over configuration-only signatures. */
775
- declare const computeProfileFingerprint: (signature: string) => Effect.Effect<string>;
776
805
  /** Build the full-surface mission used only to resolve profile guidance. */
777
806
  declare const buildProfileMission: (metadata: PullRequestMetadata, files: ReadonlyArray<ChangedFile>) => ReviewMission;
778
807
  //#endregion
@@ -1034,6 +1063,12 @@ declare const PriorReviews_base: Context.ServiceClass<PriorReviews, "@effect-age
1034
1063
  readonly latestState: Effect.Effect<Option.Option<ReviewState>, PriorReviewLookupFailure, ReviewStateAuthenticator>;
1035
1064
  /** Compare a previously reviewed head to the live current head. */
1036
1065
  readonly compareHeads: (baseSha: string, headSha: string) => Effect.Effect<ReviewHeadComparison, PriorReviewLookupFailure>;
1066
+ /**
1067
+ * Two-dot tree comparison (`base..head`). Used when the reviewed head is
1068
+ * not a git ancestor so a rebase or amend can still name the paths whose
1069
+ * blob contents actually changed.
1070
+ */
1071
+ readonly compareTrees: (baseSha: string, headSha: string) => Effect.Effect<ReviewHeadComparison, PriorReviewLookupFailure>;
1037
1072
  }>;
1038
1073
  /**
1039
1074
  * Read-only view of this package's previously posted reviews on the target
@@ -1194,6 +1229,11 @@ interface FanOutPipelineOutcome {
1194
1229
  readonly plan: ReviewUnitPlan;
1195
1230
  /** Paths of units with an unsettled pass — retryable scope for the next run. */
1196
1231
  readonly unreviewedPaths: ReadonlyArray<string>;
1232
+ /** Failed stages paired with the leftover paths they still own. */
1233
+ readonly unreviewedPasses: ReadonlyArray<{
1234
+ readonly stage: FailedReviewPass["stage"];
1235
+ readonly paths: ReadonlyArray<string>;
1236
+ }>;
1197
1237
  /** Total settled child turns across every scheduled pass. */
1198
1238
  readonly turns: number;
1199
1239
  }
@@ -1204,6 +1244,14 @@ interface FanOutPipelineInput {
1204
1244
  readonly maxFindings?: number | undefined;
1205
1245
  /** Shared run budget observed by every child pass. */
1206
1246
  readonly budget?: RunBudgetHook<BudgetExceeded | BudgetAdapterError> | undefined;
1247
+ /**
1248
+ * Unchanged leftover paths from a prior failed pass. Those units retry only
1249
+ * the recorded stages — no second general discovery on files nobody touched.
1250
+ */
1251
+ readonly retry?: {
1252
+ readonly paths: ReadonlyArray<string>;
1253
+ readonly stages: ReadonlyArray<FailedReviewPass["stage"]>;
1254
+ } | undefined;
1207
1255
  }
1208
1256
  /**
1209
1257
  * Run the complete host-scheduled fan-out pipeline over one selected
@@ -1216,8 +1264,12 @@ declare const runFanOutReview: <Provider, ModelProvides, ModelRequires>(binding:
1216
1264
  assurance: ReviewAssurance;
1217
1265
  plan: ReviewUnitPlan;
1218
1266
  unreviewedPaths: string[];
1267
+ unreviewedPasses: {
1268
+ stage: "discovery" | "specialist" | "verification";
1269
+ paths: readonly string[];
1270
+ }[];
1219
1271
  turns: number;
1220
1272
  }, never, import("effect-agent").IdGenerator | Exclude<Exclude<ModelRequires, import("effect-agent").EngineProvidedToolServices>, import("effect/Scope").Scope>>;
1221
1273
  //#endregion
1222
- export { decideReviewRetirement as $, readFileHandler as $n, ReviewDiscoveryPass as $t, makeFileReviewerInstructions as A, MAX_PATCH_CHARS as An, selectedPullRequestSourceLayer as At, fingerprintUnchanged as B, ReviewInstructionOptions as Bn, ReviewCoverage as Bt, ReviewWorkPerspective as C, FileSliceQuery as Cn, StoredReviewConcern as Ct, defaultFileReviewerPolicy as D, ListChangedFilesQuery as Dn, fromStoredConcern as Dt, confirmedFindingForPublication as E, ListChangedFiles as En, computeProfileFingerprint as Et, GitHubReviewTarget as F, ReadFile as Fn, webCryptoReviewStateAuthenticatorLayer as Ft, parseGitHubSubmittedAt as G, WalkthroughEntry as Gn, fanOutInputCoverage as Gt, gitHubPullRequestSourceLayer as H, ReviewToolkit as Hn, assessFlatReview as Ht, PriorReviewLookupFailure as I, ReadFileDiff as In, FailedReviewPass as It, ReviewRetirementDecision as J, fileDiffView as Jn, MAX_MERGED_FINDINGS as Jt, RetirableReview as K, clampMaxFindings as Kn, flatAssurance as Kt, PriorReviews as L, ReviewConcern as Ln, FailedReviewUnit as Lt, runFanOutReview as M, MAX_WALKTHROUGH_SUMMARY_CHARS as Mn, toStoredFinding as Mt, DEFAULT_GITHUB_REVIEW_AUTHOR_LOGIN as N, PullRequestReviewer as Nn, unavailableReviewStateAuthenticatorLayer as Nt, fileReviewerInstructions as O, MAX_CONCERNS as On, fromStoredFinding as Ot, GitHubApiFailure as P, REVIEW_TOOL_RESULT_MAX_BYTES as Pn, validateReviewState as Pt, ReviewRetirementReport as Q, readFileDiffHandler as Qn, MAX_UNIT_FILES as Qt, PublishedReview as R, ReviewFinding as Rn, FlatReviewAssessment as Rt, ReviewPassMisbehaved as S, FileSlice as Sn, ReviewStateMarkerTooLarge as St, assessmentSettlesSuggestionExactly as T, FindingSeverity as Tn, buildProfileMission as Tt, gitHubReviewPublisherLayer as U, ReviewToolkitLayer as Un, boundedListReason as Ut, gitHubPriorReviewsLayer as V, ReviewMission as Vn, ReviewInputCoverage as Vt, gitHubReviewRetirementHostLayer as W, ReviewVerdict as Wn, compatibilityCoverage as Wt, ReviewRetirementHost as X, listChangedFilesHandler as Xn, MAX_REVIEW_UNITS as Xt, ReviewRetirementFailure as Y, fileReviewEvidenceChunks as Yn, MAX_REPORTED_UNASSIGNED_EVIDENCE_SHARDS as Yt, ReviewRetirementInput as Z, makeReviewInstructions as Zn, MAX_UNIT_EVIDENCE_SHARDS as Zt, MAX_REVIEW_CHILDREN as _, ChangedFilesView as _n, isReviewableFile as _r, ReviewSelection as _t, FanOutPipelineInput as a, ReviewUnit as an, PullRequestSource as ar, ReviewPublicationPlan as at, ReviewCandidate as b, FileDiffView as bn, ReviewStateAuthenticator as bt, FileReviewEvidence as c, UNIT_CHANGED_LINE_BUDGET as cn, normalizeRepoRelativePath as cr, planWalkthrough as ct, FileReviewer as d, findingAnchorInUnitEvidence as dn, ChangedPath as dr, MAX_REVIEW_STATE_MARKER_CHARS as dt, ReviewDiscoveryPerspective as en, resolveGuidance as er, hasReviewMetadataMarker as et, FileReviewerBinding as f, planReviewUnits as fn, MAX_REVIEW_CONTENT_CHARS as fr, MAX_STORED_UNREVIEWED_PATHS as ft, MAX_FILE_REVIEW_TOOL_CALLS as g, ChangedFileSummary as gn, hasReviewableContent as gr, ReviewScopeMode as gt, MAX_CHILD_FINDINGS as h, anchorViolation as hn, commentableLines as hr, ReviewMode as ht, FanOutInstructionOptions as i, ReviewRiskCategory as in, PullRequestMetadata as ir, ReviewEvent as it, reviewCandidateSubjectKey as j, MAX_WALKTHROUGH_ENTRIES as jn, toStoredConcern as jt, makeFileReviewerDefinition as k, MAX_FINDINGS as kn, selectReviewRange as kt, FileReviewReport as l, UNIT_EVIDENCE_CHAR_BUDGET as ln, ChangedFile as lr, renderAgentPrompt as lt, MAX_CHILD_CONCERNS as m, rankAndDedupeFindings as mn, annotatePatch as mr, ReviewHeadComparison as mt, ConcernCandidate as n, ReviewEvidenceShardId as nn, MAX_CHANGED_FILES as nr, AGENT_PROMPT_PREAMBLE as nt, FanOutPipelineOutcome as o, ReviewUnitId as on, PullRequestSourceFailure as or, estimateReviewEffort as ot, FindingCandidate as p, rankAndDedupeConcerns as pn, PatchLine as pr, ReviewExecutionContext as pt, RetirableReviewComment as q, defaultReviewPolicy as qn, MAX_FILE_EVIDENCE_CHARS as qt, DiscoveredConcern as r, ReviewPassId as rn, MAX_FILE_CHARS as rr, ReviewCommentDraft as rt, FileReviewBrief as s, ReviewUnitPlan as sn, ReviewInputViolation as sr, planPublication as st, CandidateAssessment as t, ReviewEvidenceShard as tn, reviewInstructions as tr, retireStaleReviews as tt, FileReviewToolkit as u, classifyReviewRisks as un, ChangedFileStatus as ur, GitCommitSha as ut, MAX_UNIT_CANDIDATES as v, CodeReview as vn, parsePatch as vr, ReviewState as vt, ReviewWorkPhase as w, FindingCategory as wn, StoredReviewFinding as wt, ReviewCandidateId as x, FileReviewEvidenceChunk as xn, ReviewStateMarker as xt, REVIEW_UNIT_CONCURRENCY as y, FileDiffQuery as yn, renderReviewContent as yr, ReviewStateAuthenticationFailure as yt, ReviewPublisher as z, ReviewGuidance as zn, ReviewAssurance as zt };
1223
- //# sourceMappingURL=fan-out-BJBTAYuh.d.mts.map
1274
+ export { decideReviewRetirement as $, listChangedFilesHandler as $n, MAX_REVIEW_UNITS as $t, makeFileReviewerInstructions as A, ListChangedFilesQuery as An, fromStoredFinding as At, fingerprintUnchanged as B, ReviewConcern as Bn, FailedReviewUnit as Bt, ReviewWorkPerspective as C, FileDiffView as Cn, ReviewStateMarkerTooLarge as Ct, defaultFileReviewerPolicy as D, FindingCategory as Dn, UnreviewedStage as Dt, confirmedFindingForPublication as E, FileSliceQuery as En, StoredUnreviewedPass as Et, GitHubReviewTarget as F, MAX_WALKTHROUGH_SUMMARY_CHARS as Fn, toStoredFinding as Ft, parseGitHubSubmittedAt as G, ReviewToolkit as Gn, assessFlatReview as Gt, gitHubPullRequestSourceLayer as H, ReviewGuidance as Hn, ReviewAssurance as Ht, PriorReviewLookupFailure as I, PullRequestReviewer as In, unavailableReviewStateAuthenticatorLayer as It, ReviewRetirementDecision as J, WalkthroughEntry as Jn, fanOutInputCoverage as Jt, RetirableReview as K, ReviewToolkitLayer as Kn, boundedListReason as Kt, PriorReviews as L, REVIEW_TOOL_RESULT_MAX_BYTES as Ln, validateReviewState as Lt, runFanOutReview as M, MAX_FINDINGS as Mn, selectReviewRange as Mt, DEFAULT_GITHUB_REVIEW_AUTHOR_LOGIN as N, MAX_PATCH_CHARS as Nn, selectedPullRequestSourceLayer as Nt, fileReviewerInstructions as O, FindingSeverity as On, buildProfileMission as Ot, GitHubApiFailure as P, MAX_WALKTHROUGH_ENTRIES as Pn, toStoredConcern as Pt, ReviewRetirementReport as Q, fileReviewEvidenceChunks as Qn, MAX_REPORTED_UNASSIGNED_EVIDENCE_SHARDS as Qt, PublishedReview as R, ReadFile as Rn, webCryptoReviewStateAuthenticatorLayer as Rt, ReviewPassMisbehaved as S, FileDiffQuery as Sn, renderReviewContent as Sr, ReviewStateMarker as St, assessmentSettlesSuggestionExactly as T, FileSlice as Tn, StoredReviewFinding as Tt, gitHubReviewPublisherLayer as U, ReviewInstructionOptions as Un, ReviewCoverage as Ut, gitHubPriorReviewsLayer as V, ReviewFinding as Vn, FlatReviewAssessment as Vt, gitHubReviewRetirementHostLayer as W, ReviewMission as Wn, ReviewInputCoverage as Wt, ReviewRetirementHost as X, defaultReviewPolicy as Xn, MAX_FILE_EVIDENCE_CHARS as Xt, ReviewRetirementFailure as Y, clampMaxFindings as Yn, flatAssurance as Yt, ReviewRetirementInput as Z, fileDiffView as Zn, MAX_MERGED_FINDINGS as Zt, MAX_REVIEW_CHILDREN as _, rankAndDedupeFindings as _n, annotatePatch as _r, ReviewScopeMode as _t, FanOutPipelineInput as a, ReviewEvidenceShardId as an, MAX_CHANGED_FILES as ar, ReviewPublicationPlan as at, ReviewCandidate as b, ChangedFilesView as bn, isReviewableFile as br, ReviewStateAuthenticationFailure as bt, FileReviewEvidence as c, ReviewUnit as cn, PullRequestSource as cr, planWalkthrough as ct, FileReviewer as d, UNIT_CHANGED_LINE_BUDGET as dn, normalizeRepoRelativePath as dr, MAX_REVIEW_STATE_MARKER_CHARS as dt, MAX_UNIT_EVIDENCE_SHARDS as en, makeReviewInstructions as er, hasReviewMetadataMarker as et, FileReviewerBinding as f, UNIT_EVIDENCE_CHAR_BUDGET as fn, ChangedFile as fr, MAX_STORED_UNREVIEWED_PASSES as ft, MAX_FILE_REVIEW_TOOL_CALLS as g, rankAndDedupeConcerns as gn, PatchLine as gr, ReviewMode as gt, MAX_CHILD_FINDINGS as h, planReviewUnits as hn, MAX_REVIEW_CONTENT_CHARS as hr, ReviewHeadComparison as ht, FanOutInstructionOptions as i, ReviewEvidenceShard as in, reviewInstructions as ir, ReviewEvent as it, reviewCandidateSubjectKey as j, MAX_CONCERNS as jn, isLineageAncestor as jt, makeFileReviewerDefinition as k, ListChangedFiles as kn, fromStoredConcern as kt, FileReviewReport as l, ReviewUnitId as ln, PullRequestSourceFailure as lr, renderAgentPrompt as lt, MAX_CHILD_CONCERNS as m, findingAnchorInUnitEvidence as mn, ChangedPath as mr, ReviewExecutionContext as mt, ConcernCandidate as n, ReviewDiscoveryPass as nn, readFileHandler as nr, AGENT_PROMPT_PREAMBLE as nt, FanOutPipelineOutcome as o, ReviewPassId as on, MAX_FILE_CHARS as or, estimateReviewEffort as ot, FindingCandidate as p, classifyReviewRisks as pn, ChangedFileStatus as pr, MAX_STORED_UNREVIEWED_PATHS as pt, RetirableReviewComment as q, ReviewVerdict as qn, compatibilityCoverage as qt, DiscoveredConcern as r, ReviewDiscoveryPerspective as rn, resolveGuidance as rr, ReviewCommentDraft as rt, FileReviewBrief as s, ReviewRiskCategory as sn, PullRequestMetadata as sr, planPublication as st, CandidateAssessment as t, MAX_UNIT_FILES as tn, readFileDiffHandler as tr, retireStaleReviews as tt, FileReviewToolkit as u, ReviewUnitPlan as un, ReviewInputViolation as ur, GitCommitSha as ut, MAX_UNIT_CANDIDATES as v, anchorViolation as vn, commentableLines as vr, ReviewSelection as vt, ReviewWorkPhase as w, FileReviewEvidenceChunk as wn, StoredReviewConcern as wt, ReviewCandidateId as x, CodeReview as xn, parsePatch as xr, ReviewStateAuthenticator as xt, REVIEW_UNIT_CONCURRENCY as y, ChangedFileSummary as yn, hasReviewableContent as yr, ReviewState as yt, ReviewPublisher as z, ReadFileDiff as zn, FailedReviewPass as zt };
1275
+ //# sourceMappingURL=fan-out-Bi1v0VaU.d.mts.map