Skip to content

feat: one review tier, and a report_on severity filter - #28

Merged
ZhenghuaBao merged 4 commits into
mainfrom
feat/single-tier-and-report-on
Aug 26, 2026
Merged

feat: one review tier, and a report_on severity filter#28
ZhenghuaBao merged 4 commits into
mainfrom
feat/single-tier-and-report-on

Conversation

@ZhenghuaBao

Copy link
Copy Markdown
Contributor

The recipe routes every branch to one model and action.yml has hardcoded PASSES=1 with no promotion for a while now. This removes what was left of the two-tier machinery, and adds the publish-side severity filter the dashboard already offers but the Action ignored.

Single tier

action.yml goes 22 steps → 21. Removed:

  • the PR-label read — one fewer paginated API call on every run
  • the Promote tier step
  • the second per-tier report step, which was guarded on an output nothing writes any more, so it could never run
  • TIER_STATE, RESULT_CHEAP, PROMOTE, HELD, strong_ran and all their consumers

The tier sent to the control plane is now standard. It used to be strong, from when a cheap pass could escalate to a strong one — with a single pass the label described which reviewer picked a finding up rather than anything about the run. RESULT_STRONGRESULT_FINAL, result-strong.jsonresult-final.json.

summary-comment.mjs loses the Tier: line, and the blocking count now always follows --block-on. It used to follow --fix-first on a held run, which meant the summary and the merge gate could report different answers to "what is blocking this PR".

report_on

New scripts/report-filter.mjs, applied between the engine and the quiet filter:

result.json → result-reported.json → result-posted.json
                (report_on)            (quiet)
  • The published set is report_on ∪ block_on. A severity that blocks the merge can never be withheld from the timeline — otherwise a PR would fail its gate with nothing on the diff explaining why.
  • No report_on at all (a gateway that predates the field) is pass-through. An empty value means "only what blocks".
  • An unknown severity in the list exits 2 rather than guessing.

The merge gate and the run report keep reading the unfiltered result.json. Display filtering never moves enforcement or the numbers.

Docs and template

README, the workflow template and both recipes now describe one review per push. exhaustive is described as additional passes over the same diff, which is what it does.

Tests

Two structural suites had rotted quietly and this is worth calling out. settings.test.mjs and fact-proxy.test.mjs sliced action.yml with a bare indexOf pair; when a boundary step is renamed or removed, indexOf returns -1, slice(start, -1) runs to the end of the file, and every assertion in the test matches against most of action.yml — passing for the wrong reason. Both now go through a sliceStep helper that asserts both boundaries exist.

report.test.mjs now asserts invocations.length === guards.length over node "$REPORT" rather than a fixed count, so the "every report call sits behind the report input" invariant holds no matter how many report steps there are.

Local: 21 test files pass. Four failures remain on my Windows box in settings/report/installer/platforms, all pre-existing on main (repeated in-process HTTP servers crash node with 0xC0000409) — same count as the baseline, one fewer in settings.

Order of operations

The control plane needs to accept standard before this ships, or the run report is dropped — silently, since reporting is best-effort. That side is already merged and awaiting deploy.

The recipe routes every branch to one model, and action.yml has hardcoded
PASSES=1 with no promotion for a while now. This drops what was left of the
two-tier machinery and adds the publish-side severity filter the dashboard
already offers.

Single tier
- action.yml: 22 steps -> 21. Gone: the PR-label read (one fewer paginated
  API call per run), the promote step, the second per-tier report step, and
  TIER_STATE / RESULT_CHEAP / PROMOTE / HELD / strong_ran.
- The tier reported to the control plane is `standard`. It used to be
  `strong`, from when a cheap pass could escalate; with one pass the label
  described the reviewer rather than the run.
- RESULT_STRONG -> RESULT_FINAL, result-strong.json -> result-final.json.
- summary-comment.mjs: the `Tier:` line is gone, and the blocking count now
  always follows --block-on. It used to follow --fix-first on a held run,
  which meant the summary and the merge gate could disagree about what
  blocks the PR.

report_on
- New scripts/report-filter.mjs, applied between the engine and the quiet
  filter: result.json -> result-reported.json -> result-posted.json.
- The published set is report_on UNION block_on, so a severity that blocks
  the merge can never be withheld from the timeline.
- Absent report_on (a gateway that predates the field) is pass-through;
  an empty value means "only what blocks".
- The gate and the run report keep reading the unfiltered result. Display
  filtering never moves enforcement or the numbers.

Docs and template
- README, the workflow template and the recipes describe one review per
  push instead of a fast-then-strong escalation.

Tests
- settings.test.mjs: the action.yml wiring assertions now go through a
  sliceStep helper that fails when a boundary step is missing. Two of them
  had been silently matching most of the file since their end-boundary step
  was removed.
- fact-proxy.test.mjs: same fix, same cause.
- report.test.mjs: asserts every report.mjs invocation sits behind the
  `report` input, as a count equality rather than a fixed number.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ZhenghuaBao

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8bd7e71038

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread action.yml Outdated
Comment thread action.yml Outdated
Comment thread action.yml
Comment thread action.yml
Review round 1 found four real problems, three of them introduced here.

The report_on step guarded --show on `[ -n "$REPORT_ON" ]`, which sent an
empty value down the no-flag branch — and report-filter.mjs reads an absent
flag as "no setting, pass everything through". So a workspace configured as
"publish only what blocks" got every severity published instead: the exact
inversion the comment above it claimed to be preventing. --show now goes out
unconditionally. It is safe to do that because the settings step always
writes a value (the settings-disabled path writes every severity
explicitly), and if that step fails outright it fails the job rather than
leaving the output empty.

report-filter.mjs shipped with no tests, in a repo where every other script
has a .test.mjs, and the bug above sat exactly in the seam that most needed
one. New report-filter.test.mjs covers the three states of --show, the union
with block-on, the shared severity parsing, and the usage exits.
settings.test.mjs pins the unconditional --show so the guard cannot come
back.

The `fix-first` input description promised the severities were sent to the
reviewer to fix first. They are not, and were not: the only consumer is the
exhaustive early-stop loop, so the input does nothing at all on a default
(non-exhaustive) run. Description rewritten to say that. Its env line on the
summary and gate steps is now dead — those consumers went with the held-run
branch — so both are removed; the Review step keeps its copy.

The startup cleanup lost result-cheap.json and result-strong.json when the
filenames changed, but a reused self-hosted runner hard-cancelled under the
older action still has them, holding finding text and source snippets. That
step exists for exactly the files an earlier cleanup never reached, so the
legacy names go back alongside the new ones.

The recipe still documented x-cr-prev-tier as none | cheap | strong while
inviting workspace owners to write rules on it, and it had grown a second
copy of the fact block. One block now, documenting the one value, and saying
plainly that a rule matching cheap or strong will fall through to the
default.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ZhenghuaBao

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6114f6369a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread workflows/orca-code-review.yml Outdated
Comment thread action.yml
Comment thread README.md
Comment thread action.yml
Review round 2, four findings, all real.

The README promised P2 → Comment unconditionally and did not mention the
Report severities control at all. With report_on narrowed — and the shipped
default for a new workspace IS narrower than every severity — a P2 finding is
counted in the summary and never posted on the diff, with nothing anywhere
explaining the gap. The severity table now has a "Posted inline" column and a
P3 row, and says what the two settings are: merge policy decides what blocks,
Report severities decides what is posted, a blocking severity is always posted
whatever the display setting says, and the summary always counts everything.

The bundled setup skill still taught the cascade in four places. The installer
copies it and agents treat it as the configuration authority, so it was
actively teaching removed behaviour: `fix-first` described as withholding the
strong tier, `exhaustive` as extra passes on the strong tier, and SKILL.md
calling fix-first an escalation control. Fixing SKILL.md also fixed a
pre-existing platforms.test.mjs failure.

The workflow template's fix-first comment carried the same over-promise the
input description had ("ask for a concrete fix on these first"). It is the
exhaustive early-stop set and nothing else.

An older version created the repository label `orca-review:strong` and attached
it to a PR when it was promoted, to carry the tier between runs. Nothing reads
or writes it now, so a PR promoted before the upgrade keeps a label asserting a
tier that no longer exists — state this action created and would otherwise
abandon on someone's PR. New step detaches it: a blind removeLabel swallowing
404, not list-then-remove, because reading the labels is the paginated call this
change deleted and paying it every run to discover whether a migration artifact
is present costs more than the removal. continue-on-error, because cleanup must
never turn a passing review red. Before the gate, because the gate exits
non-zero on a blocking finding and a blocked PR is exactly the kind that was
promoted. Deletable once no open PR predates the release, and the comment says
so.

Also swept two stale comments the earlier commit missed: summary-comment.mjs
still documented the held-run exception as live, and action.yml called
RESULT_FINAL a per-tier snapshot overwritten by the escalation pass. And the
new step landed between the summary and the gate, so the four test slices that
used the gate as the summary's end boundary now stop at the new step instead —
including one that was still a bare indexOf pair.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ZhenghuaBao

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d4e498fcd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread README.md
Comment thread skills/setup-orca-code-review/SKILL.md
Assume no open PR carries `orca-review:strong`. The step was migration
cleanup for a label an older version attached, and it cost an API call on
every run, for ever, to undo a one-time artifact — not worth carrying in the
action for that.

Reverts the step, its test, and the four slice boundaries that had moved to
it.
@ZhenghuaBao

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 55e878a77f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread action.yml
@ZhenghuaBao
ZhenghuaBao merged commit b4fe7ee into main Aug 26, 2026
2 checks passed
akf66 added a commit that referenced this pull request Aug 26, 2026
There is no add- or remove-label step anywhere in action.yml. Three files
still described one, and the one that mattered most is the copy written into
every user's repo.

#28 retired the review cascade and updated `workflows/orca-code-review.yml`,
but the skill keeps its own copy of that workflow in `assets/`. The example
was fixed; the template users actually receive was not.

Corrected:

  - skills/.../assets/workflow.yml — "tier state label + clean/fallback PR
    comments" -> "clean/fallback PR comments", matching the example
  - references/inputs.md — github-token no longer "manages the tier label";
    "Models | per tier" is now one model, because there is one tier
  - action.yml — the input description those two were copied from

`issues: write` stays. It is still required, just for a different reason
than the comment claimed: PR comments, and the emoji reaction on a
/orcacode-review command. Only the justification was wrong.

Left alone because they are still true: the x-cr-prev-tier fact the proxy
injects (kept deliberately so a future size-based routing policy needs no
Action change), and the `tier` field in the run report — now noted in
inputs.md as always "standard", so nobody reads it as varying.

Five tests close the gap that caused this. The example workflow and the
skill template must agree, comment-stripped, on `permissions:`, `on:` and
`concurrency:`, and neither may mention a tier label. Verified by reverting
the fix: the tier-label test goes red.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant