Skip to content

scribe judge (SOUND / UNSOUND / UNDETERMINED) + best-of-n sampling#17

Merged
LucidSamuel merged 2 commits into
mainfrom
feat/judge-best-of-n
Jul 21, 2026
Merged

scribe judge (SOUND / UNSOUND / UNDETERMINED) + best-of-n sampling#17
LucidSamuel merged 2 commits into
mainfrom
feat/judge-best-of-n

Conversation

@LucidSamuel

Copy link
Copy Markdown
Owner

The verdict engine as one command, plus kernel-filtered sampling — built to the three review amendments.

scribe judge

scribe judge --gadget benchmark/suite/02-boolean-check.toml
# SOUND: lean/ZkGadgets/Bench/Judgeboolean_check.lean        (exit 0)

Prover first (a kernel-accepted proof settles the question; sound gadgets prove in 1–2 iterations, so this order minimizes expected cost) — refuter only on exhaustion. Stable, documented exit codes for third-party CI (amendment 3):

Exit Verdict
0 SOUND — kernel-accepted proof
1 UNDETERMINED — neither within budget
2 UNSOUND — kernel-checked counterexample
3 infrastructure error

Best-of-n (--samples-per-iter K on judge/verify/refute/proof-pilot/halva-bridge)

  • Replay determinism (amendment 1, the blocking one): the journal records every candidate (CandidateRecord: response, status accepted/build_failed/patch_rejected/duplicate/not_tried, build output) plus the acceptance index. --replay applies source_after states exactly as before; pre-best-of-n transcripts load unchanged (serde defaults, round-trip tested).
  • Dedupe + ordering (amendment 2): candidates hash-deduped before the build phase, tried shortest-first, ties broken by sampling order — the plan is deterministic given the responses.
  • Sampling is concurrent (Backend is now Send + Sync; scoped threads); builds are sequential with early exit, so success costs one build. On total failure the feedback is the last tried candidate's error, matching the file left on disk. Lake-build mode only; LSP mode warns and samples once.

Live validation (claude-sonnet-5)

  • judge boolean-check --samples-per-iter 2SOUND, exit 0, iteration 1 (concurrent sampling exercised for real)
  • judge zero-indicator (planted is-zero bug) → prove exhausts → refuter finds the counterexample at iteration 1 → UNSOUND, exit 2

8 new tests; workspace green; clippy clean. Per the sequencing note: this lands before the crates.io extraction so proof-pilot's 0.1 API ships with --samples-per-iter.

scribe judge --gadget <toml>: the verdict engine as one command. Prover runs
first (a kernel-accepted proof settles the question and sound gadgets usually
prove in 1-2 iterations); only on exhaustion does the adversarial refuter run.
Verdicts carry kernel-checked artifacts and STABLE documented exit codes so
third parties can script judge in their own CI:
  0 SOUND / 1 UNDETERMINED / 2 UNSOUND / 3 infrastructure error.

Best-of-n sampling (--samples-per-iter K on judge, verify, refute, proof-pilot,
and halva-bridge): K attempts per iteration, kernel filters. Design per review
amendments:
- Replay determinism preserved: the journal records EVERY candidate
  (CandidateRecord: response, status accepted/build_failed/patch_rejected/
  duplicate/not_tried, build output) plus the acceptance index; --replay
  applies source_after states as before, and pre-best-of-n transcripts load
  unchanged (serde defaults, round-trip tested).
- Candidates are hash-deduplicated before the build phase (low-temperature
  samples collapse to identical proofs; builds dominate cost) and tried
  shortest-first, ties broken by sampling order for determinism.
- Sampling is concurrent (Backend now Send + Sync; scoped threads), builds
  sequential with early exit; feedback on total failure is the LAST tried
  candidate's error, matching the file state on disk.
- Lake-build mode only; LSP mode warns and samples once.

Live validation: judge(boolean-check, samples-per-iter=2) → SOUND exit 0 at
iteration 1; judge(zero-indicator negative) → prove exhausts, refuter finds
the counterexample at iteration 1 → UNSOUND exit 2.

8 new tests (planner dedupe/ordering/reject paths, old-journal compat, judge
and refute arg parsing); workspace green; clippy clean.

@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: 265889203b

ℹ️ 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".

};

// ── Phase 1: prove ───────────────────────────────────────────────────────
let prove_scaffold = lean_emit::emit_lean(&gadget).unwrap_or_else(|e| {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject missing specs before proving

When scribe judge --gadget is run on a gadget TOML without soundness_spec, this phase calls emit_lean, whose existing fallback emits a theorem with conclusion True; an LLM can close that trivial scaffold and the command exits SOUND even though there was no spec to judge. The refuter path already treats this as MissingSpec, so judge should check gadget.soundness_spec before starting the prover or use an emitter that requires it.

Useful? React with 👍 / 👎.

…ss under partial sampling failures

Review findings on #17:

- High: make_backend (and require_api_key) exited 1 internally on missing
  keys/URLs/unknown backends, so 'scribe judge --backend anthropic' without
  ANTHROPIC_API_KEY exited 1 — violating judge's documented exit-3
  infrastructure contract. make_backend now returns Result and the CALLER owns
  the exit code: judge exits 3, verify/refute/demo/proof-pilot/halva-bridge
  keep their documented 1. Verified: judge → 3 (missing key and unknown
  backend), refute → 1.

- Medium: partial concurrent-sample failures were filtered out before
  planning, so candidate records omitted them and sample_index/accepted_sample
  no longer referred to the original K requested samples. plan_candidates now
  consumes the raw Result vector: failed requests are recorded in place with
  status "request_failed" (error in build_output, empty llm_response) and
  surviving candidates keep their original indexes. 'The journal records every
  candidate' now includes sampling failures; new unit test pins it.
@LucidSamuel
LucidSamuel merged commit 8dad774 into main Jul 21, 2026
5 checks passed
@LucidSamuel
LucidSamuel deleted the feat/judge-best-of-n branch July 21, 2026 11:15
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