Skip to content

fix(mt#4271): Publish a skipped check-run when the reviewer declines to run - #3563

Merged
edobry merged 2 commits into
mainfrom
task/mt-4271
Sep 2, 2026
Merged

fix(mt#4271): Publish a skipped check-run when the reviewer declines to run#3563
edobry merged 2 commits into
mainfrom
task/mt-4271

Conversation

@minsky-ai

@minsky-ai minsky-ai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

runReview returns { status: "skipped", reason: "concurrent_inflight" } from review-worker.ts:508before review-finalize.ts, the only path that publishes on the reviewed and errored outcomes. So a refusal set no check-run conclusion at all, and session_pr_wait-for-review reported reviewerCheckRunState: { status: "absent" }.

That is byte-identical to genuine reviewer silence, which is a documented bypass-merge condition. An agent walking the documented ladder honestly arrives at "reviewer absent >5 minutes" on a PR the bot REFUSED rather than missed — mem#1093, PR #3107: three consecutive waits over ~35 minutes, every one reading absent, on a healthy service. Nothing bad happened only because both bypass paths' preconditions incidentally held.

This is the last leg of ADR-030 follow-up 1. review-finalize already published on the errored outcome; mt#4881 took the thrown-review leg this morning; this takes the skip.

Key changes

  • publishTerminalCheckRunSafe (server.ts) — one function for both terminal outcomes that never reach review-finalize.ts: a review that THREW (mt#4881) and one that was DECLINED (this task). One function because it was one defect: neither set a conclusion, so both read as absent. Fail-open — a check-run write must never affect the review path, and fork PRs legitimately lack the permission.
  • buildCheckRunPayload gains skipReason → conclusion skipped. The branch sits above the blockingCount derivation deliberately: a declined review carries no findings, so falling through would emit a green success asserting the code was reviewed when nothing looked at it. The round-1 negative control below confirms that is exactly what happens without it.
  • The summary rules the bypass out in words rather than describing the state, because its reader is partway down a ladder whose next documented step is a bypass merge. The reason-specific remedy is asserted only for the reason it is true of (see Round 2).
  • /implement-task §9's zero-review branch gains a step that reads the check-run conclusion before retriggering. The old ordering wasted a round: skipped means declined, failure means ran-and-failed (mt#4881), and only absent is consistent with silence — and even then, confirm through mt#4118's delivery record, whose verdict.isSilence is the authoritative discriminator.

Nothing below the reviewer changes. packages/domain/src/repository/github-checks-run.ts:84 already accepts skipped, and mt#1307 (DONE) taught pr-watch the full conclusion enum — so the one downstream consumer of a new conclusion value already understands it.

Planning audit, the corrected line references, and the gate walk: mt#4271.

Why skipped, with the vendor citation

minsky-reviewer/findings is a required check (resolution-note-guard.ts:19, :232), so the conclusion must not block the PR. GitHub, About protected branches, verbatim:

Required status checks must have a successful, skipped, or neutral status before collaborators can make changes to a protected branch.

Both skipped and neutral satisfy a required check — they are symmetric for this purpose, contrary to the spec's original framing that they "are not symmetric and [this] has changed over time." skipped is chosen on semantics: the state being reported is a skip. failure is ruled out because it would turn a transient refusal into a merge blocker, which is worse than the silence this ends. The REST reference (docs.github.com/en/rest/checks/runs) enumerates the values but says nothing about branch-protection interaction, so it is not the page that answers this.

Round 2 — reviewer findings addressed

Both blocking findings from review 5086970933 were correct.

R1-1 (blocking) — no test proved the server's skip branch actually invokes the publisher. This is the caller-direction check /implement-task §7 item 8 names, and I had skipped it: the payload builder was unit-tested and the wiring was not — precisely the shape that ships a publisher nobody calls while every payload test stays green, reproducing the absent state this change exists to end.

The seam has to sit above createOctokit, not below: the real path mints an App installation token no test holds, so a seam placed after that call is unreachable and would verify nothing. createApp gains an optional terminalCheckRunPublisher, undefined in production.

Class, not instance: mt#4881's publishFailureCheckRunSafe had the identical untested-wiring gap two functions up, so both now route through one publishTerminalCheckRunSafe rather than only mine gaining a seam. That is a behavior-preserving refactor of code merged this morning; its own suite (failure-alert.test.ts) passes unchanged.

R1-2 (blocking) — the skip summary asserted concurrent_inflight's remedy for every reason. "Clears on a new head; a retrigger is refused" is true of one reason and nothing else yet; stating it for a future one — a permission, a rate limit — would send an operator confidently the wrong way, which is the same shape of error as the absent this whole change fixes, one layer up. The remedy is now conditional; the reason-independent half stays unconditional.

R1-3 (non-blocking) — brittle phrasing assertions. Narrowed from four exact phrases to the two carrying the contract, and replaced the rest with a test of the actual invariant: the remedy appears for concurrent_inflight and not for another reason.

Testing

Typecheck: 0 errors across 8 projects, validated against the session workspace. Lint: 0 errors, 0 warnings over 4,316 files.

Execution evidence:

$ bun --cwd services/reviewer test --preload ../../tests/setup.ts \
      src/check-run-publisher.test.ts src/server.test.ts src/failure-alert.test.ts
 103 pass
 0 fail
 216 expect() calls
Ran 103 tests across 3 files. [495.00ms]

# the ten cases this task adds, all passing:
(pass) publishCheckRun: octokitOverride seam > skip path publishes with conclusion 'skipped'
(pass) buildCheckRunPayload: declined-to-run path > conclusion is 'skipped' — not 'failure', which would block a required check
(pass) buildCheckRunPayload: declined-to-run path > conclusion is NOT 'success' — a declined review must not read as reviewed
(pass) buildCheckRunPayload: declined-to-run path > the summary names the reason and marks the state as not-silence
(pass) buildCheckRunPayload: declined-to-run path > the concurrent_inflight remedy is asserted ONLY for that reason
(pass) buildCheckRunPayload: declined-to-run path > no round parenthetical when the round is unknown
(pass) buildCheckRunPayload: declined-to-run path > a real failure outranks a skip when both are somehow set
(pass) buildCheckRunPayload: declined-to-run path > negative control: the same params WITHOUT skipReason still derive normally
(pass) terminal check-run publication wiring > a DECLINED review publishes a skip check-run carrying the reason
(pass) terminal check-run publication wiring > a REVIEWED review publishes no terminal check-run — finalize owns that path

$ bun scripts/run-related-tests.ts services/reviewer/src/server.ts \
      services/reviewer/src/check-run-publisher.ts .minsky/skills/implement-task/skill.ts
 65 pass
 0 fail
5 related test file(s) passed: .minsky/hooks/deploy-surface-detector.test.ts,
  .minsky/hooks/require-deploy-verification-before-merge.test.ts,
  services/reviewer/src/check-run-publisher.test.ts,
  services/reviewer/src/server.test.ts,
  tests/domain/implement-task-expected-head-sha.test.ts

Acceptance tests, by the spec's own numbering.

  • AT4 — RUN and passing. "A review that proceeds normally still publishes its findings check-run exactly as before, with the same conclusion it produces today." Covered by the pre-existing suite (success / neutral / failure derivations, annotation mapping, convergence summaries) plus two explicit cases: negative control: the same params WITHOUT skipReason still derive normallyconclusion: "success", and a REVIEWED review publishes no terminal check-run.
  • AT1, AT2, AT3 — UNVERIFIED pre-merge, and not for want of trying. All three require a check-run actually published by the DEPLOYED reviewer against a contended in-flight marker. Two probes, both negative: publishing one needs the reviewer App's installation token, which the service mints internally via createOctokit(cfg) and the agent does not hold; and forge_branch_protection_get on main returns Resource not accessible by integration — this integration cannot read the required-checks list at all. Deferred to the §10 post-deploy live exercise, not treated as done. [at1-deferred: mt#4271] [at2-deferred: mt#4271] [at3-deferred: mt#4271]

Success criteria. SC1 (vendor citation recorded in ## Context, choice justified against the must-not-block requirement) — done, quoted above and in the spec. SC2 (the skip publishes a check-run naming the reason) — implemented, unit-covered, and as of round 2 its wiring is covered too; its live half rides with AT1. SC4 (a live marker still produces this state, an expired one no longer can) — composes with mt#4267, DONE; nothing here touches the acquire path. SC5 (§9's ladder names this state as distinct from silence, against PR #3114's merged text) — done, written against the current merged §9.

SC3 is the one I cannot fully satisfy, and it says so explicitly: "The published conclusion does not fail the required minsky-reviewer/findings check — demonstrated against branch protection, not asserted." Branch protection is unreadable from here (probe above). The strongest evidence available, and it is live rather than asserted: PR #3504 merged at 2026-08-31T02:12:38Z with its head a6633cb92dcd6d04b86c2bde55bef3ef399297ed carrying minsky-reviewer/findings at conclusion: neutral, and forge_check_runs_list on that sha reports 13/13 passed, 0 failed. A non-success conclusion from the same documented sentence already does not block a merge in this repo. That is a class argument, not the direct skipped observation SC3 asks for — hence [sc3-deferred: mt#4271], discharged at §10.

Negative control — round 1, the conclusion branch: reverted the whole skipReason branch from buildCheckRunPayload's derivation, back to failureSummary || blockingCount > 0 ? "failure" : deriveConclusion(levels). Three tests went red, and the received value is the dangerous one rather than merely absent — Expected: "skipped" Received: "success", i.e. a green check-run claiming a review that never ran. Restored.

Negative control — round 2, the wiring: removed the publishSkipCheckRunSafe call from the skip branch in server.ts — the whole of R1-1's fix at the call site — and re-ran. The new wiring test failed with exactly the gap the reviewer named:

Expected length: 1
Received length: 0
(fail) terminal check-run publication wiring (mt#4271) > a DECLINED review publishes a skip check-run carrying the reason
 26 pass
 1 fail

Restored; 103/103. Note the sibling control stayed green through this, which is what makes the pair meaningful rather than one assertion twice.

Live verification

UNVERIFIED — the live exercise is deferred to §10 post-deploy, because the code that publishes the check-run only runs inside the deployed reviewer service and requires a contended in-flight marker to reach. This integration is NOT confirmed working until that §10 exercise runs and succeeds.

Probes run rather than assumed: the reviewer App's installation token is minted inside the service (createOctokit(cfg)) and is not reachable from the agent; forge_branch_protection_get mainResource not accessible by integration. Neither AT1's publish nor SC3's branch-protection read is available pre-merge.

What §10 will do: after the reviewer deploy lands, force a concurrent_inflight skip (two triggers against one head while the marker is held) and assert (a) a minsky-reviewer/findings check-run exists on that sha with conclusion: skipped, (b) its output names concurrent_inflight, (c) session_pr_wait-for-review reports a reviewerCheckRunState that is not absent, and (d) the PR's merge state is not blocked by it.

Deploy verification

isDeploySurfaceFile run over this PR's actual changed files: true for services/reviewer/src/check-run-publisher{,.test}.ts and services/reviewer/src/server{,.test}.ts; false for the two skill files. This is a reviewer-service deploy-surface PR and does not claim [no-deploy-impact].

Post-merge I will run deployment_wait-for-latest for reviewer with notBefore = the merge timestamp and expectCommitSha = the merge SHA, read buildIdentity, and — since the reviewer is an image-source service where that comes back indeterminate — correlate deploy-reviewer.yml's workflow run against the merge SHA and assert the health body's service identity. Then the §10 live exercise above.

Coordination

PR #3412 (mt#4639) is open and touches services/reviewer/src/server.ts, which this PR also touches; its 313-file list was read via get_files and it does not touch check-run-publisher.ts or review-worker.ts. Its changes are mechanical err.messagegetLoggableErrorSummary rewrites at log sites and do not occupy the skip branch — a rebase risk, not a correctness one. PR #774 (mt#1263) touches only review-worker.test.ts and eslint.config.js; its new runReview end-to-end tests all take the normal review path with the marker uncontended, so the skip return is untouched by them.

🤖 Generated with Claude Code

https://claude.ai/code/session_01U6kmDQENKCHPspxL5CZ5ks

…to run

`runReview` returns `{ status: "skipped", reason: "concurrent_inflight" }` from
`review-worker.ts:508` — before `review-finalize.ts`, the only path that
publishes on the reviewed and errored outcomes. So a refusal set no check-run
conclusion at all, and `session_pr_wait-for-review` reported
`reviewerCheckRunState: { status: "absent" }`: byte-identical to genuine
reviewer silence, which is a documented bypass-merge condition. An agent
walking that ladder honestly arrives at "reviewer absent" on a PR the bot
REFUSED rather than missed (mem#1093, PR #3107 — three consecutive waits over
~35 minutes, all reading `absent`).

- `publishSkipCheckRunSafe` in `server.ts`, called from the skip branch beside
  the existing status-comment write, mirroring mt#4881's
  `publishFailureCheckRunSafe`. Fail-open: a check-run write must never affect
  the review path, and fork PRs legitimately lack the permission.
- `buildCheckRunPayload` gains a `skipReason` input producing conclusion
  `skipped`. The branch sits ABOVE the blockingCount derivation deliberately: a
  declined review has no findings, so falling through would emit a green
  `success` asserting the code was reviewed when nothing looked at it — which
  the negative control confirms is exactly what happens without it.
- The summary rules the bypass out in words rather than describing the state,
  because its reader is partway down a ladder whose next documented step is a
  bypass merge.
- `/implement-task` §9's zero-review terminal branch gains a step that reads the
  check-run conclusion BEFORE retriggering: a retrigger is refused while the
  marker is held, so the old ordering wasted a round. `skipped` means declined,
  `failure` means ran-and-failed (mt#4881), `absent` alone is consistent with
  silence — and even then, confirm via mt#4118's delivery record.

`skipped` does not block a required check: GitHub's protected-branches doc
lists it beside `successful` and `neutral`, and `minsky-reviewer/findings` IS
required, so `failure` would turn a transient refusal into a merge blocker.
Nothing below the reviewer changes — the domain type already accepts `skipped`
and mt#1307 taught pr-watch the full enum.

This is the last leg of ADR-030 follow-up 1: mt#4881 took the thrown-review
leg this morning, and `review-finalize` already covered the errored one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U6kmDQENKCHPspxL5CZ5ks
@minsky-ai minsky-ai Bot added the authorship/co-authored Co-authored by human and AI agent label Sep 2, 2026
@minsky-reviewer

minsky-reviewer Bot commented Sep 2, 2026

Copy link
Copy Markdown

Minsky Reviewer Status

Verdict: APPROVED — no blocking findings
Review: View review
Model: openai/gpt-5 | Tokens: 565K prompt, 6K completion | Duration: 159s
Mode: normal

Commands

  • /review — request a fresh review

@minsky-reviewer minsky-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2


Solid targeted change that adds a skipped check-run for declined reviews and updates the implement-task ladder accordingly. The payload builder and publisher are well-covered by unit tests, but two issues block merge: (1) there’s no integration test that proves the server’s skip branch actually invokes the new publisher — the critical wiring remains unverified; and (2) the skip-summary hardcodes concurrent_inflight-specific advice, which will be wrong if any other skip reason is introduced. I also flagged a non-blocking brittleness in tests that over-assert specific summary phrasing. SC3 (live branch-protection behavior) is deferred per the PR body and marked Not Met in spec verification; either provide post-deploy evidence or amend the spec. If you address the wiring test and condition the summary on the actual reason, this is good to go.

Findings

  • [BLOCKING] services/reviewer/src/server.ts:590 — No automated test coverage that skipped path publishes a check-run (server wiring unverified)
    The behavioral change hinges on publishSkipCheckRunSafe() being invoked when runReview returns { status: "skipped" } (see services/reviewer/src/server.ts:590-599). While there are unit tests for buildCheckRunPayload and for publishCheckRun with skipReason, there is no test exercising the server’s skip branch to prove the new publisher is actually called. Given prior regressions around terminal-outcome publishing, a wiring-gap here would silently revert to reviewerCheckRunState: { status: "absent" } despite the new payload code existing.

Please add a server.test.ts (or extend the existing one) case that forces the skip path and asserts that a check-run publish is attempted. Suggested approaches:

  • Inject a seam or spy for publishCheckRun or for the Octokit used by publishSkipCheckRunSafe (mirroring the existing octokitOverride seam used in check-run-publisher.test.ts).
  • Alternatively, expose/inject a publisher callback into createApp that can be observed in tests.

Absent this, the critical behavior change remains unverified at the integration point.

  • [BLOCKING] services/reviewer/src/check-run-publisher.ts:201 — Summary text hardcodes "concurrent_inflight" even when skipReason could be other values
    In buildCheckRunPayload's skip branch (services/reviewer/src/check-run-publisher.ts:201-210), the summary concatenates:

  • A dynamic prefix naming skipReason, AND

  • A hard-coded sentence: "A concurrent_inflight refusal clears on a new head; a retrigger is refused while the marker is held."

This bakes concurrent_inflight semantics into the message regardless of the actual skipReason. If a future skip reason is introduced (e.g., permissions, rate limiting, etc.), the summary will assert the wrong remedy and mislead operators.

Requested fix:

  • Either tailor the remedy sentence conditionally when skipReason === "concurrent_inflight", or
  • Remove the concurrent_inflight-specific advice from the generic skip path and keep the summary semantically accurate for all reasons.

Tests also assume this exact wording (see check-run-publisher.test.ts "the summary rules out the bypass explicitly"), so please update/extend tests accordingly.

  • [NON-BLOCKING] services/reviewer/src/check-run-publisher.test.ts:470 — Tests assert highly specific summary phrasing — brittle against harmless copy edits
    The test "the summary rules out the bypass explicitly, and names what clears it" (services/reviewer/src/check-run-publisher.test.ts:470-492) asserts multiple exact substrings such as "NOT reviewer silence", "not a bypass condition", and "new head". These enforce editorial wording rather than contract. Minor copy edits (tone, punctuation, or reflow) would break tests without changing semantics.

Suggestion (non-blocking): narrow the assertions to the essential signals the system consumes (e.g., includes skipReason, sets title to include skipped, and conclusion is skipped). Consider exposing a structured field for the remedy if that must be asserted, rather than anchoring on free-text.

Spec verification

Criterion Status Evidence
The GitHub Checks API conclusion question above is answered with a vendor-doc citation recorded in ## Context, and the chosen value is justified against the requirement that a concurrent_inflight skip must NOT block the PR. Met PR description’s Context section quotes GitHub’s protected-branches doc verbatim and records the rationale for choosing skipped over neutral (see PR body “## Context — Third-party citation”). The code comments in services/reviewer/src/check-run-publisher.ts:120-147 also embed the citation and justification.
A concurrent_inflight skip publishes a check-run naming the reason, so session_pr_wait-for-review's reviewerCheckRunState stops reporting absent for that state. Met Implementation adds skipReason plumbing and sets conclusion "skipped" with summary/title naming the reason in services/reviewer/src/check-run-publisher.ts:179-223. The server wires the skip branch to publish via publishSkipCheckRunSafe in services/reviewer/src/server.ts:277-346 and invokes it on result.status === "skipped" at :590-599.
The published conclusion does not fail the required minsky-reviewer/findings check — demonstrated against branch protection, not asserted. Not Met Pre-merge, no live branch-protection verification is included. The PR body explicitly defers this to a post-deploy exercise (§10). While unit tests cover payload shape, the criterion requires a live demonstration against branch protection. Please provide post-deploy evidence or amend the spec to defer SC3.
A live in-flight marker still produces this state; an EXPIRED one no longer can, because mt#4267 fixed the acquire path. The two tasks compose rather than overlap. Unverifiable This criterion depends on runtime behavior across the marker-acquire path from mt#4267. The current diff does not include live verification or tests that simulate expiry vs. live markers; no repo artifact demonstrates it. Without a runnable environment, this cannot be verified from the diff alone.
/implement-task §9's ladder names this state as distinct from reviewer silence, written against PR #3114's merged text. Met Both .minsky/skills/implement-task/skill.ts:624-638 and the generated .claude/skills/implement-task/SKILL.md:627-644 add a step 2 that inspects the check-run conclusion first and distinguishes skipped/failure from absent, naming the concurrent_inflight remedy and deferring retrigger appropriately.

Documentation impact

  • no-update-needed — This PR changes internal reviewer-service behavior and the implement-task skill text. The docs are generated from .minsky/skills/implement-task/skill.ts, and the PR updates both the source and generated SKILL.md accordingly. No separate public documentation files appear to require updates.

…ng one reason's remedy for all

Both blocking findings were correct.

R1-1 (blocking) — no test proved the server's skip branch actually invokes the
publisher. This is the caller-direction check `/implement-task` §7 item 8 names,
and I had skipped it: the payload builder was unit-tested and the wiring was
not, which is precisely the shape that ships a publisher nobody calls while
every payload test stays green — reproducing the `absent` state this change
exists to end.

The seam has to sit ABOVE `createOctokit`, not below: the real path mints an App
installation token no test holds, so a seam placed after that call is
unreachable and would verify nothing. `createApp` gains an optional
`terminalCheckRunPublisher`, undefined in production.

Class, not instance: mt#4881's `publishFailureCheckRunSafe` had the identical
untested-wiring gap two functions up, so both now route through one
`publishTerminalCheckRunSafe` rather than only mine gaining a seam. That is a
behavior-preserving refactor of code merged this morning; its own suite
(`failure-alert.test.ts`) still passes unchanged.

Two tests, and the second is the control for the first: a DECLINED review
publishes a skip check-run carrying the reason; a REVIEWED review publishes
none, because finalize owns that path — without which a wiring that fired on
every outcome would pass the first assertion while overwriting the real
findings conclusion on every successful review. Both drain via
`gracefulShutdown()` rather than sleeping, so the assertion is deterministic.

R1-2 (blocking) — the skip summary asserted `concurrent_inflight`'s remedy
("clears on a new head; a retrigger is refused") for every skip reason. That
sentence is true of one reason and of nothing else yet; stating it for a future
one — a permission, a rate limit — would send an operator confidently the wrong
way, which is the same shape of error as the `absent` this whole change fixes,
one layer up. The remedy is now conditional on the reason; the
reason-independent half stays unconditional.

R1-3 (non-blocking) — narrowed the summary assertions from four exact phrases
to the two that carry the contract, and added a test that the remedy appears
for `concurrent_inflight` and not for another reason.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U6kmDQENKCHPspxL5CZ5ks

@minsky-reviewer minsky-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2


Re-verification against the current spec and diff: both prior BLOCKING findings are addressed. The skip path now explicitly publishes a check run with conclusion 'skipped' and names the reason; the server wiring calls the publisher on the declined branch and is covered by a dedicated test. The payload builder gained skipReason, produces 'skipped' (not 'success'/'failure'), and its summary clearly distinguishes this state from silence; tests assert the ordering and content. The implementation remains fail-open and uses a safe test seam; no regressions surfaced. I find no new critical defects introduced by the fixes. Spec criteria that require live post-deploy verification are correctly deferred; unit/integration coverage for in-repo behavior is present. Verdict: APPROVE.

Spec verification

Criterion Status Evidence
The GitHub Checks API conclusion question above is answered with a vendor-doc citation recorded in ## Context, and the chosen value is justified against the requirement that a concurrent_inflight skip must NOT block the PR. Met Task spec Context section quotes GitHub 'About protected branches' verbatim naming 'skipped' and 'neutral' as acceptable for required checks; code comments in services/reviewer/src/check-run-publisher.ts:109-133 reiterate the same citation and rationale ('minsky-reviewer/findings' is required; 'failure' would block).
A concurrent_inflight skip publishes a check-run naming the reason, so session_pr_wait-for-review's reviewerCheckRunState stops reporting absent for that state. Met services/reviewer/src/server.ts:602-616 calls publishSkipCheckRunSafe(...) in the skip branch; services/reviewer/src/check-run-publisher.ts:93-116 adds skipReason and conclusion 'skipped'; summary includes the reason and states 'NOT reviewer silence' (lines ~170-214). Tests cover both the wiring and payload: services/reviewer/src/server.test.ts:370-430 and services/reviewer/src/check-run-publisher.test.ts:445-572.
The published conclusion does not fail the required minsky-reviewer/findings check — demonstrated against branch protection, not asserted. Unverifiable This criterion requires post-deploy live verification against GitHub branch protection. The diff contains unit/integration tests only; no in-repo artifact can prove live branch-protection behavior. The PR body records a deferral to post-deploy (§10).
A live in-flight marker still produces this state; an EXPIRED one no longer can, because mt#4267 fixed the acquire path. The two tasks compose rather than overlap. Unverifiable This depends on live behavior of the reviewer’s marker acquisition and expiry (mt#4267). The diff adds skip check-run publishing only; no in-repo test demonstrates acquisition vs expiry composition. No live evidence is included.
/implement-task §9's ladder names this state as distinct from reviewer silence, written against PR #3114's merged text. Unverifiable The current diff portion shows only services/reviewer/* changes since the last review. Any skill text/rung edits to .minsky/skills/implement-task/skill.ts are not present in this incremental diff segment; reviewer cannot verify from the shown files alone.

Adoption sweep

Symbol Kind Consumers found Classification Notes
services/reviewer/src/server.ts: TerminalCheckRunPublication type services/reviewer/src/server.test.ts: import type { TerminalCheckRunPublication }, services/reviewer/src/server.ts: internal use in publishTerminalCheckRunSafe signature and terminalCheckRunPublisher seam Adopted New exported type used by tests via createApp seam; no external consumers required by spec.

Documentation impact

  • no-update-needed — Behavioral change is internal to the reviewer service’s check-run publishing: a skipped review now emits a GitHub check run with conclusion 'skipped'. No public CLI, API, or user-facing docs are changed or invalidated. ADR-030 already designates the Checks API as the status/liveness channel; this PR aligns with it. I checked .minsky/skills/implement-task/skill.ts presence in the repo but this incremental diff segment did not include its edits; regardless, no existing docs are made false by adding a non-blocking 'skipped' conclusion on declined runs.

@edobry
edobry merged commit 4f91f14 into main Sep 2, 2026
13 checks passed
@edobry
edobry deleted the task/mt-4271 branch September 2, 2026 08:05

@minsky-reviewer minsky-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2


Re-verified the fixes against the current spec and diff. The prior BLOCKING issues are addressed: the server’s skipped-review branch now publishes a terminal check-run via a safe, testable seam; buildCheckRunPayload accepts skipReason, yields conclusion: "skipped" (not success/failure), and crafts a summary that distinguishes this state from reviewer silence with reason-specific guidance only when appropriate. Tests cover both the payload and the server wiring. The refactor to a unified publishTerminalCheckRunSafe preserves failure behavior and remains fail-open. Skill guidance was updated to read the check-run conclusion before retriggering. I found no new critical defects introduced by these changes. Verdict: APPROVE.

Spec verification

Criterion Status Evidence
The GitHub Checks API conclusion question above is answered with a vendor-doc citation recorded in ## Context, and the chosen value is justified against the requirement that a concurrent_inflight skip must NOT block the PR. Met services/reviewer/src/check-run-publisher.ts:96-117 — inline docstring cites GitHub protected-branches doc and justifies choosing "skipped"; PR/task spec Context also records the citation and reasoning.
A concurrent_inflight skip publishes a check-run naming the reason, so session_pr_wait-for-review's reviewerCheckRunState stops reporting absent for that state. Met services/reviewer/src/server.ts:613-621 — skip branch now calls publishSkipCheckRunSafe; services/reviewer/src/check-run-publisher.ts:270-298 plumbs skipReason to payload builder; tests at services/reviewer/src/check-run-publisher.test.ts:445-470 and services/reviewer/src/server.test.ts:393-442 assert publication and content.
The published conclusion does not fail the required minsky-reviewer/findings check — demonstrated against branch protection, not asserted. Unverifiable Live branch-protection behavior cannot be verified from repo code; the task spec explicitly defers this to post-deploy (§10). No in-repo artifact can demonstrate protected-branch acceptance pre-merge.
A live in-flight marker still produces this state; an EXPIRED one no longer can, because mt#4267 fixed the acquire path. The two tasks compose rather than overlap. Unverifiable This requires live interaction with the marker acquisition/expiry path; the current diff only adds reporting. No in-repo test exercises live TTL behavior; verification depends on mt#4267 behavior outside this PR.
/implement-task §9's ladder names this state as distinct from reviewer silence, written against PR #3114's merged text. Met .minsky/skills/implement-task/skill.ts:627-640 (and generated .claude/skills/implement-task/SKILL.md:627-642) — step 2 now reads the check-run conclusion before retriggering, distinguishing skipped/failure/absent and naming the remedy for concurrent_inflight.

Adoption sweep

Symbol Kind Consumers found Classification Notes
services/reviewer/src/server.ts: TerminalCheckRunPublication type services/reviewer/src/server.test.ts:18 — imported for testing published events array shape, services/reviewer/src/server.ts:245 — used as parameter type for publishTerminalCheckRunSafe Adopted Exported primarily to support test seam verification for terminal check-run publication (mt#4271).

Documentation impact

  • updated-in-pr — User-facing skill guidance was updated to distinguish skipped/failure/absent states and to read the check-run conclusion before retriggering. See .minsky/skills/implement-task/skill.ts:624-640 and the generated .claude/skills/implement-task/SKILL.md:627-642 modified in this PR.
    Affected: .minsky/skills/implement-task/skill.ts, .claude/skills/implement-task/SKILL.md

@minsky-reviewer minsky-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent adversarial review (Chinese-wall)
Reviewer: minsky-reviewer[bot] via openai:gpt-5
Tier: 2


Re-verified the fix commit against the current spec: the previously blocking gaps are closed. The skip path now publishes a terminal check-run with conclusion "skipped" and reasoned summary via a unified, fail-open publisher; server wiring is exercised by a dedicated test seam; payload builder handles skipReason with correct ordering to avoid false "success"/"failure". Skill guidance was updated to read the check-run conclusion before retriggering. I found no new critical defects introduced by these changes. APPROVE.

Spec verification

Criterion Status Evidence
The GitHub Checks API conclusion question above is answered with a vendor-doc citation recorded in ## Context, and the chosen value is justified against the requirement that a concurrent_inflight skip must NOT block the PR. Met Implementation selects conclusion: "skipped" (services/reviewer/src/check-run-publisher.ts:179-189, 201-229), with inline vendor-quote rationale in the new skipReason docblock (services/reviewer/src/check-run-publisher.ts:93-121) and summary comments. The PR body/spec records the citation to GitHub’s protected-branches doc.
A concurrent_inflight skip publishes a check-run naming the reason, so session_pr_wait-for-review's reviewerCheckRunState stops reporting absent for that state. Met The skip branch now calls publishSkipCheckRunSafe(...) (services/reviewer/src/server.ts:613-622) which routes to publishTerminalCheckRunSafe (services/reviewer/src/server.ts:245-299, 670-691). The payload builder sets conclusion: "skipped" and includes skipReason in title/summary (services/reviewer/src/check-run-publisher.ts:201-229). Covered by tests: publish path (services/reviewer/src/server.test.ts:382-423) and payload content (services/reviewer/src/check-run-publisher.test.ts:445-569).
The published conclusion does not fail the required minsky-reviewer/findings check — demonstrated against branch protection, not asserted. Unverifiable Live protected-branch behavior cannot be validated from repo code; no in-repo branch-protection config is present. The PR description documents pre-merge probe limitations and defers live verification (AT2). No repo artifact can confirm this pre-merge.
A live in-flight marker still produces this state; an EXPIRED one no longer can, because mt#4267 fixed the acquire path. The two tasks compose rather than overlap. Unverifiable This criterion depends on live runtime behavior with a held/expired marker; the diff introduces no change to marker acquisition/expiry. Verification requires a deployed reviewer and controlled contention, which is outside the repo. Pre-merge validation is not possible here.
/implement-task §9's ladder names this state as distinct from reviewer silence, written against PR #3114's merged text (see the collision note below), not against the version that preceded it. Met Skill guidance updated to read the check-run conclusion before retriggering and distinguishes skipped/failure/absent with remedies (/.minsky/skills/implement-task/skill.ts:624-642). The generated SKILL.md reflects the same (/.claude/skills/implement-task/SKILL.md:627-645).

Adoption sweep

Symbol Kind Consumers found Classification Notes
services/reviewer/src/server.ts — TerminalCheckRunPublisher type services/reviewer/src/server.test.ts: imports type TerminalCheckRunPublication and provides a publisher callback to createApp(), services/reviewer/src/server.ts: used as optional DI param to createApp() Adopted New exported test seam type for terminal check-run publication; used by tests via createApp() injection. No external wiring required by spec.

Documentation impact

  • no-update-needed — Behavioral change is limited to the reviewer service’s internal check-run publication and the agent skill guidance. The skill’s generated docs (.claude/skills/implement-task/SKILL.md) and source (.minsky/skills/implement-task/skill.ts) were updated in this PR to instruct reading the check-run conclusion before retriggering and to distinguish skipped/failure/absent states. No other public-facing docs appear to describe the reviewer’s skipped state semantics; ADR-030 remains accurate. Therefore, documentation updates ship within this PR and no further docs need updating.

edobry added a commit that referenced this pull request Sep 2, 2026
…jected seams

## Summary

mt#4271 shipped the `skipped` check-run for a review the reviewer DECLINES, and merged with three
acceptance tests and one success criterion unverified — forcing a skip looked like it needed two
colliding agents on a live PR.

mt#4895 reframed that correctly: **the contention is a Postgres row, not an interaction between
agents**, so the layers separate. This PR closes the two that are reachable, and records a
corrected premise for the one that is not.

Where the five layers stand after this PR: L1 already covered (twice), **L2 covered here**, L3
covered by PR #3563, **L4 harness shipped here** (live integration run deferred to mt#4897), L5
recorded as unverified with its reason.

## Key changes

- **`RunReviewDeps` gains three seams** — `octokitFactory`, `prContextFetcher`, `appIdentityFetcher`
  — so the marker branch can be driven with no network. Optional fields with real defaults; every
  existing caller is unaffected.
- **`src/runreview-concurrent-inflight.test.ts`** (new) — 4 cases covering the skip return, the log
  shape, the skip-path timing write, and SC1's negative control.
- **`scripts/inflight-skip-harness.ts`** (new, round 2) — the L4 harness's decision core: stdout
  collection with a completion promise, event extraction, and the pass/fail derivation. Pure
  functions over values, covered by 14 tests.
- **`scripts/smoke-concurrent-inflight-skip.ts`** (new) — the imperative shell around it: spawn,
  post, poll, clean up. Modelled on `kill-test.ts`, with a `--negative-control` mode.

### Injected, not module-patched — and this was a decision, not a default

mt#4895's spec left the seam choice open, conditional on the still-open PR #774 landing its
`mock.module` approach. **ADR-036 §2 rule 2 settles it:** where a seam can be added by changing one
production file with no exported-type change ("an optional `deps` parameter with a real default
counts as no change"), patching is *banned at that site*. That is exactly this site. PR #3563 — the
mt#4271 PR merged this morning — used the same shape for `terminalCheckRunPublisher`, with the
reasoning this task needs verbatim: *"The seam has to sit above `createOctokit`, not below."*

Consequence: **this PR does not depend on PR #774**, and does not touch `review-worker.test.ts`,
which is the only file #774 shares. Recorded on mt#1263 as material to the merge decision it is
blocked on: #774 is `mergeable_state: dirty` and its ESLint carve-out is the mechanism ADR-036 now
prohibits.

### A spec premise this PR corrects

mt#4895's `## The precedent for L4` claimed the skip log is emitted "before any GitHub interaction",
so an L4 script needs "no real PR, no model call, and no reviewer App token." **One of those three
survives.** The marker is keyed on `pr.headSha`, so `fetchPullRequestContext` (`github-client.ts:201`,
a real `pulls.get`) necessarily precedes `acquireMarker`. `createOctokit` is *not* the blocker — it
is a pure constructor that validates nothing — but the PR fetch is: against a synthetic PR it
throws, and `runReview` dies before the marker, so no contention is possible and the log can never
fire. Only "no model call" holds. This is the same error SC1 had already corrected one section
earlier; the L4 section was never updated to match. Both the spec and the script header now say so.

### The look-alike the tests discriminate

`runReview` has TWO returns carrying `status: "skipped"`, and the routing one comes **first** —
`decideRouting` short-circuits a Tier-1 PR before the marker exists. Asserting `status === "skipped"`
alone would pass for the wrong reason, so every assertion pins `reason`, and the fixture PR body
carries the tier-3 marker so routing resolves to `shouldReview: true`.

## Round 2 — reviewer findings addressed

All three R1 findings were correct as stated. Two were real defects in the new script; the third is
answered below with what changed rather than with an argument alone.

**R1-1 (blocking) — racy stdout collection.** Correct, and it would have made SC2/SC3 intermittently
wrong in the worst way: a real skip reported as a failure. `collectStdoutLines` returned only the
array, with no completion signal, so the script killed the process and parsed `lines` while the
background reader was still draining — and a terminal event is exactly what arrives last. It now
returns `{ lines, done }`, and the shell awaits `done` after the process exits and **before**
anything reads a line.

**R1-2 (blocking) — `process.exit` inside the try bypassed cleanup.** Correct. Every failure path
inside `main`'s try now throws (`bail`) and a top-level catch sets the exit code after the `finally`
has run, so the spawned server is terminated and the Postgres handle closed. **Class, not instance:**
the reviewer cited `:320`, but the same shape was on every in-try failure path — all of them
converted, not just the one named. The env-gate `skip()` calls deliberately keep `process.exit`, and
the code now says why: they run before anything is spawned or connected, so there is no cleanup to
bypass.

**Both fixes are provable rather than asserted.** The decision logic moved into
`scripts/inflight-skip-harness.ts` — ADR-036 §3's functional core / imperative shell, applied to a
script — so the harness's own logic is covered by the suite instead of resting on a live run that has
not happened. One test reproduces R1-1 directly by asserting the line buffer is **incomplete before**
`done` and complete after; without the fix there is nothing to await and the assertion cannot be
written at all.

**R1-3 (blocking) — missing live-run evidence.** The finding is factually right: there is no live
run, and I am not claiming otherwise or asking for it to be waived as a false positive. What changed
is how much it covers.

- The credentials probe stands (all seven absent, listed below), which is §7a's documented override
  branch (b), "the author lacks live-target access."
- Independently of credentials, delivery A starts a **real** review of a real PR and posts to it.
  That is a shared-state change on a PR this task does not own — the authorization mt#4271 surfaced
  rather than took, and it is not mine to grant.
- **What was unproven is now much smaller.** R1 was right that shipping a harness whose primary path
  had never executed is weak. Round 2 covers its decision logic with 14 tests, and the failure path
  was exercised live end to end (below). What remains unproven is the *integration* — real GitHub,
  real Postgres, real contention — which is precisely what mt#4897 owns.

I have not merged past this. If the reviewer still considers the live run a merge precondition, that
is a legitimate call and mt#4897 is the gate; say so and the PR waits.

Execution evidence:

```
$ bun test --preload ../../tests/setup.ts src/runreview-concurrent-inflight.test.ts
(pass) a HELD marker makes runReview return the concurrent_inflight skip [8.13ms]
(pass) the skip records a skip-path timing row (mt#2088) rather than skipping the write [0.27ms]
(pass) the skip log carries the delivery id, which is what correlates it to a delivery [0.21ms]
(pass) negative control: an AVAILABLE marker does not return the skip — execution passes the gate [1.25ms]
 4 pass / 0 fail / 13 expect() calls

$ bun test --preload ../../tests/setup.ts scripts/inflight-skip-harness.test.ts     # round 2
(pass) collectStdoutLines > R1-1 regression: lines are INCOMPLETE before `done` resolves and COMPLETE after [3.54ms]
(pass) collectStdoutLines > flushes a trailing segment that never got a newline [2.40ms]
(pass) collectStdoutLines > reassembles a JSON object split across chunk boundaries [2.63ms]
(pass) collectStdoutLines > a null stream yields no lines and an already-resolved done [0.05ms]
(pass) findEvents > returns only objects whose event matches, in order [0.08ms]
(pass) findEvents > non-JSON banner lines are skipped rather than throwing [0.04ms]
(pass) deriveVerdict — contention mode > passes when B skipped, A did not, and a conclusion was read back
(pass) deriveVerdict — contention mode > a FAILED publish still counts as ATTEMPTED — that is the SC3 contract
(pass) deriveVerdict — contention mode > fails when neither publish signal is present — the skip never surfaced
(pass) deriveVerdict — contention mode > fails when B did not skip at all
(pass) deriveVerdict — contention mode > fails when A ALSO skipped — A holds the marker, so a skip on A means something else took it
(pass) deriveVerdict — negative-control mode > passes when no skip is observed, which is the whole point of the control
(pass) deriveVerdict — negative-control mode > FAILS when a skip is still observed — the harness cannot discriminate
(pass) deriveVerdict — negative-control mode > the publish question is N/A here, not false
 14 pass / 0 fail / 27 expect() calls

$ bun run test          # full reviewer suite
 2474 pass / 0 fail / 5431 expect() calls — Ran 2474 tests across 94 files. [4.64s]

$ validate_typecheck    # 8 projects: root, packages/domain, packages/shared, services/reviewer,
                        # services/site, src/cockpit/web, tsconfig.hooks.json, tsconfig.scripts.json
 0 errors    (infra/ skipped — deps not installed locally; CI runs it with its own install step)

$ validate_lint         # services/reviewer, 228 files
 0 errors, 0 warnings
```

**R1-2 failure path, exercised live.** Dummy credentials + an unreachable Postgres, so the spawned
server never becomes healthy and `bail` fires from inside the try:

```
$ INFLIGHT_TEST_PORT=34612 ... bun scripts/smoke-concurrent-inflight-skip.ts
inflight-skip: mode=contention owner=edobry repo=minsky pr=1 port=34612
FAIL: server did not become healthy within 20s
script exit=1

$ curl -s -m 2 -o /dev/null -w "http_code=%{http_code}\n" http://127.0.0.1:34612/health
http_code=000        # nothing listening — the spawned server is gone
```

**What that does and does not prove.** It proves the throw path reaches the top-level handler and
exits 1 with the right message. It does **not** by itself prove `finally` killed the server: the
server also failed to boot in this run, so an empty port is consistent with it having exited on its
own. The cleanup guarantee rests on control flow that is deterministic rather than probed — `bail`
throws, and the `finally` is attached to the same `try`. Recording the distinction rather than
letting the port check read as stronger evidence than it is.

**Acceptance tests, by mt#4895's own numbering.**

- **AT1 — RUN and passing.** *"`runReview` with a held marker returns the skip; with an available
  marker it does not. Both assertions in one test file, run with no network."* Both halves are in the
  4-case run above; no network — the three GitHub calls are injected.
- **AT2 — NOT run.** *"the script, run against a local Postgres, reports PASS and names which
  delivery was skipped. Run it twice."* Needs App credentials that can read a real PR, plus operator
  authorization to act on one. `[at2-deferred: mt#4897]`
- **AT3 — NOT run.** *"Negative control for L4 — with the marker released between the two deliveries,
  the script observes NO skip."* Implemented as `--negative-control`; its decision half is covered by
  the two negative-control cases in the harness suite. Same blockers as AT2 for the live half.
  `[at3-deferred: mt#4897]`
- **AT4 — DONE.** *"whatever verdict SC4 reaches is written into this spec's `## Outcome` with its
  evidence, including the case where it stays unverified."* Written; see `## Live verification`.

**Success criteria.** SC1 — done. SC2 — the runnable script is shipped and its decision logic is
covered; its live invocation is AT2. SC3 — the script asserts the publish was ATTEMPTED, and the
observable is deliberately two-sided: a `minsky-reviewer/findings` conclusion read back off the sha
when the publish succeeds, or the `review_skip_check_run_failed` warn when it fails, because both
prove the branch ran *through* the publish call rather than returning before it. Three harness tests
pin that contract, including the failed-publish case. SC4 — verdict recorded below. SC5 — discharge
written to mt#4271's spec; the four markers live in PR #3563's merged **body**, not its spec, which
mt#4895's spec now says. (R1 reported SC5 Unverifiable because the mt#4271 edit is outside this
diff — correct per the contract; the record is in mt#4271's `## Deferred-marker discharge` section.)

**Dual-mode script — both branches exercised (mt#2776).** Running only the safe branch leaves the
other's code unexecuted, and imports are hoisted, so each run below proves the whole module —
`@octokit/rest`, `@octokit/auth-app`, `postgres`, `@octokit/webhooks-methods`, and now
`./inflight-skip-harness` — resolves at runtime:

```
contention, no env          -> SKIP: MINSKY_REVIEWER_APP_ID is not set        exit 0
--negative-control, no env  -> SKIP: MINSKY_REVIEWER_APP_ID is not set        exit 0
dummy env, INFLIGHT_TEST_PR=not-a-number
                            -> FAIL: INFLIGHT_TEST_PR must be a positive integer   exit 1
dummy env, REVIEWER_PROVIDER=cohere
                            -> SKIP: not one of openai|google|anthropic       exit 0
dummy env, unreachable Postgres
                            -> FAIL: server did not become healthy within 20s  exit 1   (the R1-2 path)
```

SC1 — negative control: an AVAILABLE marker does not return the skip, and the injected
`appIdentityFetcher` is observed called exactly once, proving execution reached the first call past
the marker gate rather than merely not skipping.

Negative control — production log event, suite liveness: renamed
`runReview.skipped_concurrent_inflight` to `runReview.MUTATED_CONTROL` in `review-worker.ts` and
re-ran.

```
(fail) a HELD marker makes runReview return the concurrent_inflight skip
       error: expect(received).not.toBeNull()
(fail) the skip log carries the delivery id, which is what correlates it to a delivery
       error: expect(received).toBe(expected)
 2 pass / 2 fail
```

The two that do not assert on the log stayed green, which is what makes the pair meaningful rather
than one assertion twice. Restored; 4/4.

## Live verification

**UNVERIFIED — the reason is a missing specimen plus an authorization, not a missing mechanism.**

Publishing `skipped` shipped with PR #3563 at 2026-09-02T08:05:26Z. All six `concurrent_inflight`
occurrences on record predate it, so no historical sha can answer the question — the specimen has to
be made, and this PR ships the thing that makes it.

Probes run rather than assumed. Checked for presence, never values: `MINSKY_REVIEWER_APP_ID`,
`MINSKY_REVIEWER_INSTALLATION_ID`, `MINSKY_REVIEWER_PRIVATE_KEY`, `MINSKY_REVIEWER_WEBHOOK_SECRET`,
`MINSKY_PERSISTENCE_POSTGRES_URL`, `MINSKY_POSTGRES_URL`, `OPENAI_API_KEY` — **all seven absent.**
`forge_branch_protection_get main` re-probed → `Resource not accessible by integration`, the same
result mt#4271 got; that is `verified-1a` for the ForgeBackend channel and `inferred` for the
capability, not evidence that no channel can read it.

**mt#4897** owns the live run and the L5 observation, and its spec carries both blockers with the
probe results.

Best evidence standing, unchanged: PR #3504 merged with `minsky-reviewer/findings` at
`conclusion: neutral`, 13/13 checks passed. `neutral` and `skipped` are named in the same sentence of
GitHub's protected-branches documentation, so a non-`success` conclusion from that sentence
demonstrably does not block a merge here — a **class argument, not the direct observation**, which is
the distinction SC4 exists to keep visible.

## Deploy verification

`isDeploySurfaceFile` run over this PR's actual changed files: **true** for all five. This is a
reviewer-service deploy-surface PR and does **not** claim `[no-deploy-impact]`.

Post-merge I will run `deployment_wait-for-latest` for `reviewer` with `notBefore` = the merge
timestamp and `expectCommitSha` = the merge SHA, read `buildIdentity`, and — since the reviewer is an
image-source service where that returns `indeterminate` — correlate `deploy-reviewer.yml`'s workflow
run against the merge SHA and assert the health body's service identity rather than the status code.

Note the change is seams-plus-tests: the three new `deps` fields are undefined in production, so the
deployed behaviour is unchanged by construction. That is a reason to expect a clean deploy, not a
reason to skip verifying it.

## Coordination

**PR #774 (mt#1263)**, open — `get_files` reads exactly `eslint.config.js` and
`services/reviewer/src/review-worker.test.ts`. This PR touches **neither**; the L2 case is a sibling
file specifically so the conflict surface stays at zero while #774 sits unmerged (and conflicted).
**PR #3412 (mt#4639)**, open — touches `services/reviewer/src/server.ts`, which this PR does not
touch. Recent merges, one `git_log --path` per path, both `pathMatched: true`:
`review-worker.test.ts` — 0 commits in 7 days; `services/reviewer/scripts` — 6 commits, none
colliding with a new filename.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01LJGtdNqy7Yq9n6QXkV5fjp

Co-Authored-By: minsky-ai[bot] <minsky-ai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

authorship/co-authored Co-authored by human and AI agent

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant