Skip to content

fix(OMN-16823): recognize CodeRabbit's agreement-plus-deferral concession class in the CR-thread gate - #2057

Merged
jonahgabriel merged 3 commits into
devfrom
jonah/omn-16823-cr-concession-detect
Aug 28, 2026
Merged

jonahgabriel merged 3 commits into
devfrom
jonah/omn-16823-cr-concession-detect

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Aug 28, 2026 •

Copy link
Copy Markdown
Contributor

Closes OMN-16823

Problem

scripts/check-unresolved-threads.sh backs the required gate / CodeRabbit Thread Check context. It counted a CodeRabbit review thread as blocking even after CodeRabbit had conceded the finding in-thread and agreed to defer it to a ticket, because its concession match only recognized you're right / apologize / correct behavior / retract / understood ... reasonable.

The live case is omnibase_core#1604, thread 2 of 3 on src/omnibase_core/models/cli/model_cli_user_config_logging.py. CodeRabbit's own reply, verbatim:

@jonahgabriel, agreed that EnumLogLevel cannot represent this YAML contract. Its lowercase values would cause an unintended serialized-value migration.

The finding requested a separate uppercase-valued enum, not reuse of EnumLogLevel. However, deferring the validation design to OMN-16037 is reasonable because the current PR must avoid silent rewrites of existing configuration files.

An unambiguous concession plus an explicit deferral — and the required context stayed red, with no path to green short of making a change the reviewer itself agreed was not required. Same family as OMN-15815 / OMN-15532: a required context unsatisfiable by construction.

Fix — detection only

The widened class is a conjunction, not a keyword list:

  • an agreement token (agreed, agree, concur, fair point, ...), AND
  • a deferral/acceptance token (defer*, reasonable, pragmatic, tradeoff, out of scope, separate ticket, OMN-####, ...), AND
  • no negation-or-escalation marker (disagree, do not agree, still stands, reiterate, escalate, finding stands, ...),

evaluated over the salient reply body — auto-generated <details> blocks and HTML comments are stripped first, so CodeRabbit's own "Learnings" boilerplate cannot supply either token. The pre-existing human-rebuttal precondition and the truncated-thread conservatism both still gate it. The gate cannot degrade into "any CodeRabbit reply clears the thread".

Also collapses the previously byte-duplicated concession regex in CONCESSION_JQ and BLOCKING_JQ into one shared CR_CONCEDED_JQ predicate. That duplication is precisely how a widened match lands in the audit line but not in the count.

No auto-resolution — pr_review_bot remains the sole resolver

This change introduces no auto-resolution and no resolve path of any kind. It changes only the wording match that decides whether a thread still counts. Asserted mechanically, not just in prose: the suite greps the gate script for resolveReviewThread / unresolveReviewThread / --resolve and fails if any appears (PASS: no thread-resolution mutation present in the gate script). No [skip-*] token, no bypass, no required-check removal is used anywhere in this change.

Evidence — TDD red-first, negative controls proven by execution

RED before the fix, with the verbatim #1604 reply as the fixture:

FAIL Case K: expected 0 got 1

GREEN after, 24 assertions. The OMN-16823 surface:

PASS: Case K blocking=0 for the verbatim omnibase_core#1604 agreement-plus-deferral concession
PASS: Case K concession ack names class=agreement_deferral
PASS: Case L blocking=1 for an unanswered CodeRabbit finding
PASS: Case M blocking=1 when CodeRabbit escalates while using deferral vocabulary
PASS: Case N blocking=1 for a negated agreement (do not agree ... is reasonable)
PASS: Case O blocking=1 for agreement on a sub-point with the finding kept
PASS: Case P blocking=1 when concession vocabulary only appears inside a details block
PASS: Case Q blocking=1 — agreement-plus-deferral without a human rebuttal is not a concession
PASS: Case R blocking=1 — truncated thread stays conservative despite a concession in the fetched slice
PASS: no thread-resolution mutation present in the gate script
ALL TESTS PASSED

Cases L–R are the permanent negative controls required by AC3, each proven red by execution rather than argued. M is the one a bare keyword search gets wrong: CodeRabbit escalating while reusing the entire deferral vocabulary ("I disagree that deferring the validation design to OMN-16037 is reasonable"). P proves the salient-body stripping: the concession vocabulary sits only inside a <details>Learnings</details> block while the visible reply keeps the finding.

Falsifiability is by discrimination, not assertion: restoring only scripts/check-unresolved-threads.sh to its origin/dev content in the same worktree and re-running reproduces FAIL Case K: expected 0 got 1.

Enforcement (Operating Rule 5)

The filter suite was an opt-in script wired to nothing. It now runs in two enforced places:

  • pre-commit hook cr-thread-gate-filters (verified firing: CR-thread-gate jq filter tests (OMN-16823)....Passed)
  • a step in the CI quality job, which feeds the required quality-gate context

plus tests/scripts/test_check_unresolved_threads_filters.py, a pytest entrypoint that executes the real suite and additionally asserts by name that the positive case and all seven negative controls are still present — so a regression that quietly deletes a control fails rather than silently passing.

dod_evidence

OCC evidence companion: contracts/OMN-16823.yaml + drift/dod_receipts/OMN-16823/dod-omn-16823-concession-detection-behavior/ in onex_change_control (merges first). Both bound checks are BEHAVIOR class and both execute the filters rather than reading a file.

Evidence-Ticket: OMN-16823
Evidence-Source: OCC#7390

…sion class

check-unresolved-threads.sh counted a CodeRabbit thread as blocking even after
CodeRabbit conceded the finding in-thread and agreed to defer it to a ticket.
Its concession regex only matched "you're right" / "apologize" / "correct
behavior" / "retract" / "understood ... reasonable" — not the phrasing
CodeRabbit actually used on omnibase_core#1604 thread 2 of 3:

  "agreed that `EnumLogLevel` cannot represent this YAML contract ...
   deferring the validation design to OMN-16037 is reasonable"

The required `gate / CodeRabbit Thread Check` context was therefore
unsatisfiable by construction: no path to green short of making a change the
reviewer itself had agreed was not required.

DETECTION change only. The widened class is a conjunction — an agreement token
AND a deferral/acceptance token AND no negation-or-escalation marker — matched
over the SALIENT reply body (auto-generated <details> blocks and HTML comments
stripped, so CodeRabbit's own "Learnings" boilerplate cannot supply either
token). The pre-existing human-rebuttal precondition and the truncated-thread
conservatism both still gate it, so the check cannot degrade into "any
CodeRabbit reply clears the thread".

Also collapses the previously byte-duplicated concession regex in CONCESSION_JQ
and BLOCKING_JQ into one shared CR_CONCEDED_JQ predicate — the duplication is
how a widened match lands in the audit line but not in the count.

Enforcement (Rule 5): the filter suite now runs as a pre-commit hook AND as a
step in the CI `quality` job, which feeds the required `quality-gate` context.
It was previously an opt-in script wired to nothing.

TDD red-first: Case K (the verbatim #1604 reply) failed 1 != 0 before the fix.
Permanent negative controls added, all proven by execution:
  L unanswered CodeRabbit finding                          -> blocking
  M CodeRabbit escalates using the deferral vocabulary     -> blocking
  N "do not agree that deferring ... is reasonable"        -> blocking
  O agreement on a sub-point, finding kept                 -> blocking
  P tokens only inside a <details> learnings block         -> blocking
  Q agreement-plus-deferral with no human rebuttal         -> blocking
  R truncated thread with a concession in the slice        -> blocking

No auto-resolution is introduced. `pr_review_bot` remains the sole resolver of
CodeRabbit threads; the suite asserts the script contains no resolve mutation.

Refs: OMN-16823
The jq filter suite was reachable only from a bash invocation nobody made. It
now also runs as a pytest unit test, so the default local test run covers it,
and — because `pytest` is a BEHAVIOR-class command head for node_dod_verify —
the OCC evidence for this ticket can be behavior-proving rather than a static
file read.

The wrapper executes the real suite; it does not re-implement the filters. It
additionally asserts by name that the OMN-16823 positive case (the verbatim
omnibase_core#1604 concession) and all seven permanent negative controls are
still present, so a regression that quietly deletes a control fails here even
if the shell suite's own exit code were loosened.

Refs: OMN-16823
@coderabbitai

coderabbitai Bot commented Aug 28, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 42 minutes.

View limit details

Limit details: You’ve used the included review currently available. Your 132 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 453502a8-f721-4d8b-a4ca-eb4e7c04a53e

📥 Commits

Reviewing files that changed from the base of the PR and between 103f647 and 8f28233.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • .pre-commit-config.yaml
  • .secrets.baseline
  • scripts/check-unresolved-threads.sh
  • tests/scripts/test_check_unresolved_threads.sh
  • tests/scripts/test_check_unresolved_threads_filters.py

Comment @coderabbitai help to get the list of available commands.

jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Aug 28, 2026
…iclaude#2057 (#7390)

* evidence(OMN-16823): author OCC companion for OmniNode-ai/omniclaude#2057

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 7af10ac426e254904be523b5ce8a2b7aada67d53.

* evidence(OMN-16823): self-bind OCC#7390 + rebind contract_sha256

---------

Co-authored-by: omnimarket-bot <bot@omninode.ai>
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Hostile Reviewer — DEGRADED (informational)

Blocking findings (critical/error): 0
Total findings: 0
Models succeeded: none

Note: All reviewer models failed or were unavailable. Degraded results are informational during the pilot phase (OMN-8524) and do not block merge.


Gate semantics (pilot phase)

Verdict Meaning Blocks merge?
passed No critical/error findings No
blocked CRITICAL or ERROR findings found Yes
degraded Reviewer ran but every model failed mid-run No (pilot)
infra_error cli_review failed to run at all (install/crash) after 2 attempts Yes

Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8524)

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