Skip to content

feat: Self-Eval Gate — block config changes that regress a workspace's private per-repo suite (trust-layer 4/4) - #64

Merged
QuintinBotes merged 8 commits into
mainfrom
feature-self-eval-gate
Jul 13, 2026
Merged

feat: Self-Eval Gate — block config changes that regress a workspace's private per-repo suite (trust-layer 4/4)#64
QuintinBotes merged 8 commits into
mainfrom
feature-self-eval-gate

Conversation

@QuintinBotes

Copy link
Copy Markdown
Owner

Self-Eval Gate (trust-layer differentiator 4 of 4)

The fourth and final trust-layer differentiator. A workspace mints a private, per-repo benchmark suite from its own merged PRs (hidden fail-to-pass / pass-to-pass tests), records a baseline resolution rate, and then any model/prompt/router config change is refused if it regresses that rate — measured against ground-truth tests the model never sees.

No incumbent gates a config change on the customer's own private task distribution. Combined with Attested Changesets, Time-Travel Runs, and the Red-Team Gate, this closes the trust layer: provenance → replay → adversarial pre-merge check → regression-proof config.

What ships (complete + tested offline)

  • Per-repo private suitesBenchmarkSuite gains nullable workspace_id/repo_id + a private flag (migration 0039, chained from 0038_red_team_gate). Hidden-test fields (fail_to_pass, pass_to_pass, sandbox_image, setup_commands, base_commit) modelled in swe_case.py.
  • PR miner (forge_eval/mint/pr_miner.py + self_eval_mint worker task) — derives cases from merged PRs via read-only GitHub API helpers (list_pr_files, pr_base_commit, pr_head_commit).
  • Sandboxed runner (forge_eval/sweval/runner.py) — applies a candidate patch in the SandboxSession execution seam, runs the hidden tests, scores resolution. The solve_fn is handed a redacted case (hidden tests stripped) so the model can never see the answer. Path-traversal-safe patch application. New agent.fail_to_pass_rate metric.
  • Aggregation + gate (self_eval.py, gate.py) — SelfEvalScorecard + SelfEvalGate.check_config(...) raising SelfEvalRegressionError on regression; no-op on cold start (no baseline / no private suite) and on explicit force= override, so existing config flows stay green until a suite exists.
  • Public-surface privacy (defence in depth) — a private/workspace-scoped suite is invisible to the unauthenticated /public/* API at all three read paths (listing, leaderboard, submission-detail), even when published.

Honest scope (park-don't-fake)

The eval engine (scoping · mint · runner · aggregation · gate · privacy) is complete and tested offline. The live agent-backed eval_runner, baseline persistence, and the POST /benchmarks/{...}/runs endpoint are wired through injected seams and remain parked for the follow-up integration PR — nothing is faked to look done.

Verification (local, all green)

  • make typecheck — 583 files, no issues
  • evaluation (sweval + mint + benchmark): 46 passed
  • db models + migrations: 145 passed
  • apps/api benchmark (incl. new public-surface privacy tests): 43 passed

🤖 Generated with Claude Code

Forge Swarm and others added 8 commits July 12, 2026 15:49
…s/pass-to-pass)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…o_pass_rate metric

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n rate + baseline check)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ivate-suite resolution rate

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(slice 6/6)

A workspace's Self-Eval suite is minted from its own private repo and is
published so the workspace can rank against its recorded baseline — but it must
never leak to the unauthenticated /public/* API. Enforce that at every public
read path (defence in depth):

* BenchmarkService.list_suites(public_only=True) — filters to global,
  non-private suites only; wired into GET /public/benchmarks.
* BenchmarkService.leaderboard(public_only=True) — 404s a published-but-private
  suite as if it did not exist.
* BenchmarkService.public_submission — same guard on the submission-detail /
  bundles routes, closing the back-door leak.
* BenchmarkService.is_public_suite(suite) — the single predicate all three share.

Tests: parametrized over the `private` flag and `workspace_id` scoping, asserting
a published private suite is invisible via listing, leaderboard, and submission
detail. Renamed the colliding tests/sweval/test_runner.py -> test_swe_runner.py
(basename clash with tests/test_runner.py broke collection).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…void basename clash

CI runs 'uv run pytest -q' over the whole repo with the default (prepend)
import mode, where two flat test files sharing a basename import as the same
top-level module. sweval/test_gate.py collided with deploy-core/tests/test_gate.py,
breaking collection (exit 2) for both the main pytest job and the realeval job.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pip-audit flags click 8.1.8 for PYSEC-2026-2132 (command injection in
click.edit(), CVSS 8.8). Forge imports click nowhere, so the vulnerable path is
unreachable, and click<8.2 is transitively pinned by the semgrep dev/CI
dependency — click>=8.3.3 cannot be resolved without dropping semgrep. Add a
justified, documented --ignore-vuln to both pip-audit invocations (VEX
'vulnerable_code_not_present'); revisit and remove once semgrep lifts the cap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@QuintinBotes
QuintinBotes merged commit ce4a51a into main Jul 13, 2026
19 checks passed
@QuintinBotes
QuintinBotes deleted the feature-self-eval-gate branch July 13, 2026 20:43
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