Skip to content

feat: wire rivet mechanical oracle into AI review#28

Merged
avrabe merged 1 commit intomainfrom
feat/rivet-oracle-integration
Apr 26, 2026
Merged

feat: wire rivet mechanical oracle into AI review#28
avrabe merged 1 commit intomainfrom
feat/rivet-oracle-integration

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented Apr 26, 2026

Why

PR #26 shipped the rivet-oracle module as a building block. This PR makes it actually run during PR review for repos that ship `rivet.yaml`. The result: name-anchored, mechanically-validated findings produced without the model's involvement, prepended to whatever the model produces.

This realises the "model proposes, oracle decides" pattern. Oracle findings:

  • bypass the slop filter (mechanically validated by construction)
  • bypass quote-or-die (anchored to `artifact_id`, not file:line)
  • promote the verdict to `request_changes` when severity = error

Result on rivet PRs: a review with actual evidence-grade findings even if Ollama times out, hallucinates, or returns empty findings.

What

`src/rivet-fetch.js` (new)

  • `hasRivetYaml()` — cheap pre-check via Contents API. Skipping tarball download when this returns false saves ~50 MB per PR for non-instrumented repos.
  • `fetchAndExtractTarball()` — pulls `GET /tarball/{ref}`, pipes through `tar -xz --strip-components=1` into a tempdir.
  • `withTempRepoCheckout()` — orchestrator with cleanup-on-error.

`src/ai-review.js`

Before the model call, run the oracle if (a) `rivet_oracle.enabled`, (b) `binary_path` configured, (c) `rivet.yaml` at PR head. Failures non-fatal — model path still runs. Oracle findings merged into rendered comment.

`src/ai-review-prompt.js`

  • `computeVerdict()` now promotes to `request_changes` when any oracle finding has severity `error`.
  • `renderReviewMarkdown()` formats oracle findings differently: severity-emoji + `artifact_id` + oracle name, vs file:line + `quoted_line` for model findings.

Config

New `rivet_oracle:` section in `config.yml` with schema validation.

What's NOT here

  • The rivet binary on netcup. Manual SCP after merge until PR-D ships the auto-installer.
  • Cache for tarball / oracle results.
  • Integration test that spawns rivet for real (would need binary in CI; tests stub the runner).

Test plan

  • 766 tests pass (was 753 — added 13 covering tarball fetch, has-yaml pre-check, severity-error verdict promotion, oracle finding render format, mixed oracle+model output)
  • eslint clean
  • After deploy + manual rivet install on netcup: open a small PR against `pulseengine/rivet` and verify the bot's review contains an oracle-validated finding (e.g. `🔴 \`SPAR-REQ-001\` (rivet-validate)`).
  • Temper PRs (no rivet.yaml) get reviews with no oracle section — unchanged from feat: hardened AI review — strict JSON, slop filter, quote-or-die #24's behaviour.

Risk & rollout

  • Risk: medium. New code paths run only when binary exists at configured path; without it, oracle silently skips. So shipping this before the binary is safe — behaviour reverts to PR feat: hardened AI review — strict JSON, slop filter, quote-or-die #24's model-only review.
  • Rollout: self-update on merge. Then SCP `rivet-v0.4.3-x86_64-unknown-linux-gnu.tar.gz` to netcup, extract to `/opt/temper/data/rivet/rivet`, `chmod +x`. Next rivet PR opened gets oracle findings.

🤖 Generated with Claude Code

## Why
PR #26 shipped the rivet-oracle module as a building block. This PR makes
it actually run during PR review for repos that ship rivet.yaml. The
result: name-anchored, mechanically-validated findings produced *without*
the model's involvement, prepended to whatever the model produces.

This realises the "model proposes, oracle decides" pattern. Oracle
findings:
  - bypass the slop filter (mechanically validated by construction)
  - bypass quote-or-die (anchored to artifact_id, not file:line)
  - promote the verdict to `request_changes` when severity = error

Result on rivet PRs: a review that has actual evidence-grade findings even
if Ollama times out, hallucinates, or returns empty findings.

## What

### `src/rivet-fetch.js` (new)
- `hasRivetYaml(octokit, owner, repo, ref)` — cheap pre-check via Contents
  API. Returns false on 404 / auth errors. Skipping the tarball when this
  returns false saves ~50 MB per PR for non-instrumented repos.
- `fetchAndExtractTarball(...)` — pulls `GET /tarball/{ref}`, pipes through
  `tar -xz --strip-components=1` into a tempdir.
- `withTempRepoCheckout(...)` — orchestrator that creates the tempdir,
  fetches+extracts, runs the caller's callback, and cleans up (even on
  error).

### `src/ai-review.js`
Before the model call, run the oracle if (a) `rivet_oracle.enabled`,
(b) `binary_path` configured, (c) `rivet.yaml` exists at PR head.
Failures are non-fatal and logged at warn — the model path still runs.
Oracle findings are merged into the rendered comment.

### `src/ai-review-prompt.js`
- `computeVerdict()` now promotes to `request_changes` when any oracle
  finding has severity `error` (broken cross-refs, missing required fields).
- `renderReviewMarkdown()` formats oracle findings differently from model
  findings: severity-emoji + `artifact_id` + oracle name, vs file:line +
  quoted_line for model findings.

### `config.yml`
New `rivet_oracle:` section:
```yaml
rivet_oracle:
  enabled: true
  binary_path: "data/rivet/rivet"
  timeout_ms: 60000
```
Schema validated.

## What's NOT here
- The rivet binary on netcup. Manual install (one shot) until PR-D ships
  the auto-installer.
- Cache for tarball / oracle results across reviews on the same SHA.
- Integration test that spawns rivet for real (would need the binary in
  CI; today's tests stub the runner).

## Test plan
- [x] 766 tests pass (was 753 — added 13 covering tarball fetch, has-yaml
      pre-check, severity-error verdict promotion, oracle finding render
      format, mixed oracle+model output)
- [x] eslint clean
- [ ] **After deploy + manual rivet install on netcup**: open a small PR
      against `pulseengine/rivet` and verify the bot's review contains an
      oracle-validated finding (e.g. `🔴 SPAR-REQ-001 (rivet-validate)`).
- [ ] Verify temper PRs (no rivet.yaml) still get reviews with no oracle
      section — should be unchanged from #24's behaviour.

## Risk & rollout
- Risk: medium. New code paths run only when binary exists at the
  configured path; without it, the oracle silently skips. So shipping this
  before installing the binary is safe — the behaviour reverts to PR #24's
  model-only review.
- Rollout: self-update on merge. Then SCP the rivet-v0.4.3 Linux binary
  to `/opt/temper/data/rivet/rivet` and `chmod +x`. After that, the next
  rivet PR opened gets oracle-validated findings.

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

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@avrabe avrabe merged commit 90f0b7f into main Apr 26, 2026
5 checks passed
@avrabe avrabe deleted the feat/rivet-oracle-integration branch April 26, 2026 19:39
@avrabe
Copy link
Copy Markdown
Contributor Author

avrabe commented Apr 26, 2026

/review-pr

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