Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9589a08
feat(phases): resolve staged phases; empty phases input means combined
aliasunder Sep 2, 2026
66e6e86
refactor(prompt): move the it() enumeration into the test dimension
aliasunder Sep 2, 2026
741884e
feat(review): cross-phase merge, phase column in the cost table, Revi…
aliasunder Sep 2, 2026
3d0a331
feat(orchestrate): dispatch review phases in stages and report partia…
aliasunder Sep 2, 2026
27875c6
test(orchestrate): cover parallel, sequential, partial, and all-faile…
aliasunder Sep 2, 2026
18eb637
docs: describe the parallel and sequential phases modes
aliasunder Sep 2, 2026
e8c36b9
fix(review): log phases input in review settings
aliasunder Sep 2, 2026
443fd46
style: simplify ternaries and trim repeated phases explanation
aliasunder Sep 2, 2026
40303c5
test: cover describeError branches and zero-findings-with-incomplete-…
aliasunder Sep 2, 2026
cadb3dc
fix(review): evict every overlap a merged finding outranks; thread on…
aliasunder Sep 2, 2026
21346e4
fix(orchestrate): keep the cost table when every review phase fails
aliasunder Sep 2, 2026
701a0fd
fix(prompt): scope the prior-findings note to the same issue
aliasunder Sep 2, 2026
27a1007
fix(prompt): state the merge rule in the prior-findings note; test th…
aliasunder Sep 2, 2026
170b16f
fix(prompt): describe the cross-phase collapse precisely in the prior…
aliasunder Sep 2, 2026
18dee8b
docs: drop the unqualified speed claim for the parallel phases mode
aliasunder Sep 2, 2026
1f0ea46
merge: resolve main into feat/staged-phases
aliasunder Sep 4, 2026
12f3951
docs(review): add mode layout table to the phase/stage module comment
aliasunder Sep 4, 2026
9ed1578
docs(review): clarify sequential layout as 3 stages, 3 phases (1 each)
aliasunder Sep 4, 2026
8f47495
merge: resolve main into feat/staged-phases + fix all-failed modelUsed
aliasunder Sep 4, 2026
003e998
test(review): add sequential partial-failure test — early phase fails…
aliasunder Sep 4, 2026
5454ccd
docs(review): add dispatch-stack diagram and doc comments for phased …
aliasunder Sep 4, 2026
53b327e
docs: add phase/stage mechanics explanation to AGENTS.md review section
aliasunder Sep 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/self_review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ jobs:
openrouter_api_key: ${{ secrets.OPENROUTER_KEY }}
model: ${{ vars.OPENROUTER_MODEL || 'anthropic/claude-sonnet-4-6' }}
request_timeout_seconds: ${{ vars.UMM_REQUEST_TIMEOUT_SECONDS }}
phases: ${{ vars.UMM_PHASES }}
18 changes: 14 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ src/
openrouter/ # OpenRouter I/O: @openrouter/sdk wrapper, per-attempt deadline, structured-output retry ladder, cost summary
diff/ # pure transforms over parse-diff output
context/ # workspace I/O: conventions file, changed files, import-trace scan, doc-mention scan, priority docs
review/ # pure review logic: finding schema, phases, prompt, non-finding filter, unknown-file filter, path normalization, selection, comment mapping, title similarity, context notes, summary
review/ # pure review logic: finding schema, phases + stage dispatch, prompt, non-finding filter, unknown-file filter, cross-phase merge, path normalization, selection, comment mapping, title similarity, context notes, summary
orchestrate.ts # pipeline + createPromptedGenerateFindings — fully testable with stub clients
```

Expand Down Expand Up @@ -188,9 +188,19 @@ files. Prefer SDK-provided types over redefining shapes.
## Review instruction authoring

The bot's system-prompt instructions live in `src/review/phases.ts`
(dimension constants + reporting rules) and `src/review/prompt.ts`
(identity/scope, proof-of-work, severity rubric, output discipline). When
writing or updating a review instruction, follow this formula — each
(dimension constants, the per-phase pass-scope line, reporting rules, and
the phase groups each `phases` mode dispatches) and `src/review/prompt.ts`
(identity/scope, proof-of-work, severity rubric, output discipline).

**Phase/stage mechanics:** a phase is one model call carrying a set of
review dimensions. A stage groups the phases that run concurrently; stages
run in order, and each later stage sees the earlier stages' findings.
`combined` = 1 stage, 1 phase; `parallel` = 1 stage, 3 phases;
`sequential` = 3 stages, 3 phases (1 each). The dispatch stack is
`runStages` → `runStage` → `runPhase` in `src/review/run-stages.ts`;
cross-phase finding collapse lives in `src/review/merge-phase-findings.ts`.

When writing or updating a review instruction, follow this formula — each
element is here because its absence measurably cost findings in live runs:

- **Trigger, not preference.** Action + condition + boundary: "when you see
Expand Down
52 changes: 26 additions & 26 deletions README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ inputs:
required: false
default: AGENTS.md
phases:
description: "Review phases to run. V1 supports: combined"
description: "How the review dimensions are dispatched: combined (one model call carrying every dimension) | parallel (three focused calls at once — each reads deeper than the single call; wall clock is the slowest of the three and prompt tokens roughly triple) | sequential (the same three calls in order, each seeing the earlier findings). Empty = combined, so workflows can wire an unset repo variable directly"
required: false
default: combined
context_budget_tokens:
Expand Down Expand Up @@ -93,7 +93,7 @@ outputs:
review_url:
description: URL of the submitted review; empty when no review was posted
model_used:
description: Model that produced the accepted response
description: Model(s) that produced the accepted responses, comma-separated when phases were routed to different models
skipped_reason:
description: Non-empty when the review was skipped (e.g. diff too large)

Expand Down
13 changes: 13 additions & 0 deletions src/__tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ describe("parseConfig", () => {
expect(config.requestTimeoutSeconds).toBe(900)
})

it("falls back to combined for an empty phases", () => {
const config = parseConfig(makeRawInputs({ phases: "" }))

expect(config.phases).toBe("combined")
})

it("passes phases through as a string for domain validation", () => {
// Value validation lives in review/phases.ts resolveStages
const config = parseConfig(makeRawInputs({ phases: "everything" }))

expect(config.phases).toBe("everything")
})

it("rejects a zero request_timeout_seconds", () => {
expect(() =>
parseConfig(makeRawInputs({ requestTimeoutSeconds: "0" })),
Expand Down
16 changes: 15 additions & 1 deletion src/__tests__/logger.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it, onTestFinished, vi } from "vitest"
import { createLogger } from "../logger.js"
import { createLogger, describeError } from "../logger.js"

type WrittenLine = Record<string, unknown>

Expand Down Expand Up @@ -250,3 +250,17 @@ describe("createLogger", () => {
expect(lines[1]?.sessionId).toBe("generated-later")
})
})

describe("describeError", () => {
it("formats an Error as [Name]: message", () => {
const error = new TypeError("value is not a function")

expect(describeError(error)).toBe("[TypeError]: value is not a function")
})

it("stringifies a non-Error value", () => {
expect(describeError("plain string")).toBe("plain string")
expect(describeError(42)).toBe("42")
expect(describeError(null)).toBe("null")
})
})
Loading