Skip to content

docs+experiment: RQGM verifier-bias analysis + diagnostic probe - #12

Merged
hyperion-git merged 8 commits into
mainfrom
experiment/verifier-bias-probe
Jul 29, 2026
Merged

hyperion-git merged 8 commits into
mainfrom
experiment/verifier-bias-probe

Conversation

@hyperion-git

Copy link
Copy Markdown
Owner

Summary

Analysis of "The Red Queen Gödel Machine" (arXiv:2606.26294) for Alethic, plus a runnable
diagnostic implementing the #1 recommendation. Produced by a 26-agent adversarial workflow
(readers → 5 design lenses → 3-skeptic panel each → synthesis → completeness critic), then reduced
to what is faithful to the paper's demonstrated results — not its framing.

Headline finding: 3 of 4 substantive RQGM-inspired proposals failed their faithfulness skeptic
— they rest on classic ensemble/decorrelation logic, not on anything RQGM actually demonstrated. The
honest output is therefore mostly "measure first," not "adopt the framework."

The spine

Alethic's Verifier is the stationary criterion RQGM critiques. Generator≈Verifier (both Opus), so
decoupled verification hides the generator's traces but not its correlated blind spots. And there
is no labeled (problem, solution, true_verdict) set anywhere — every accuracy signal is anchored
to the verifier's own output. So the one failure RQGM targets — a verifier accepting a wrong proof —
is currently unmeasurable.

What's in this PR

  • docs/plans/2026-06-27-rqgm-verifier-bias.md — ranked adoptables (adopt / defer / reject), the
    grader-vs-reviewer (verify vs check) asymmetry the completeness critic flagged as a HIGH miss,
    and the link to the live v4.0 benchmark-gate decision.
  • scripts/self_preference_probe.py — the Claude/configurable agent settings w iybi #1 move, measurement-only, no orchestrator change.
    Generates proof attempts of the expected_solvable=false anchors from an opus author vs an
    OpenRouter author, runs the real Opus verifier (subagents.verify, stock VERIFIER_SYSTEM),
    and reports false-positive rate + Fisher exact 2×2 + Wilson 95% CI. Optional --k5 (consensus,
    the variance-vs-bias test) and --check-arm (reference-less CheckerAgent).

Why a null result is a win

The anchors were designed to be caught, so FPR may be 0 → the ratio is 0/0. That cheaply falsifies
the spine's worry
and means: do not build a multi-model verifier on this evidence. The diagnostic
gates the downstream roster work in either direction.

Validation

Probe imports + argparse clean; both anchors load from benchmark JSON; lazy imports
(OpenRouter / VerifierAgent / CheckerAgent / scipy) resolve; Wilson + Fisher helpers correct. No API
calls made in CI — running it requires ANTHROPIC_API_KEY (+ OPENROUTER_API_KEY for the nonopus arm).

This is an analysis + experiment-scaffold PR; it changes no library behavior.

Assisted-by: Claude Code:claude-opus-4-8

Analysis of "The Red Queen Gödel Machine" (arXiv:2606.26294) for Alethic,
produced by a 26-agent adversarial workflow and reduced to what is faithful
to the paper's *demonstrated* results (3 of 4 substantive proposals failed
their faithfulness skeptic — they rest on classic ensemble logic, not RQGM).

Spine: Alethic's Verifier is the stationary criterion RQGM critiques, and
Generator≈Verifier (both Opus) share blind spots that decoupling hides only
at the trace level. There is no labeled (problem, solution, true_verdict) set
anywhere, so "a verifier accepting a wrong proof" is currently unmeasurable.

- docs/plans/2026-06-27-rqgm-verifier-bias.md: ranked adoptables (adopt /
  defer / reject), the grader-vs-reviewer (verify vs check) asymmetry, and the
  v4.0-gate link.
- scripts/self_preference_probe.py: the #1 move — a measurement-only probe.
  Generates proof attempts of the false-claim anchors from opus vs an
  OpenRouter author, runs the real Opus verifier (K=1, optional K=5 consensus,
  optional reference-less check arm), reports false-positive rate + Fisher
  exact + Wilson CI. No orchestrator change. A null result (FPR=0) is a valid,
  decision-relevant outcome.

Validated: probe imports/argparse clean; anchors load; lazy imports
(OpenRouter/VerifierAgent/scipy) resolve; stats helpers correct.

Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: A. Friedrich <alex@f2media.de>
Ran the diagnostic's faithful core via Claude Code Task sub-agents (no API key,
no per-token cost). Findings:
- Author arm: Opus AND Haiku refuse both false-claim anchors and disprove them
  (even Haiku catches the Drude/Lorenz subtlety) -> weak-author arm is genuinely
  OpenRouter/package-only.
- Verifier arm: a planted trap (correct algebra, Sommerfeld inputs mislabeled as
  classical Drude) -> 5/5 independent Opus verifiers INCORRECT, conf 0.93-0.97;
  K=1 == K=5. FPR = 0. Caught by existing VERIFIER_SYSTEM #16/#17 features.
- Reassuring NULL for these anchors; caveats: N=1 trap, and skill route can't run
  the weak/cross-provider author arm (still package-only).

Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: A. Friedrich <alex@f2media.de>
10-item audit via Task sub-agents (8 planted flaws across blatant/moderate/
subtle tiers + 2 correct controls), each verified by 5 Opus + 1 Sonnet + 1 Haiku
decoupled verifiers (70 agents). Results:
- Flaw catch-rate 8/8 at both K=1 and K=5; control false-reject 0/2.
- Zero verifier disagreement -> K=5 never beat K=1 (consensus wasted on clear-cut
  items).
- Sonnet AND Haiku scored 10/10 -> a cheap judge matches Opus (token lever).

Honest caveat: 100%/0% with cheap models matching expensive ones means the
battery (classic, in-distribution flaws) lacks discriminating power -- it shows
the floor is above this difficulty, not that there's no ceiling. A real stress
test needs NOVEL flaws and errors buried in long derivations.

Net: two null-ish experiments weaken the verifier-bias/roster case and
strengthen the cheap-judge token lever. Revised the recommended sequence
accordingly (cheap-judge probe now #1; bias diagnostic/roster de-prioritised).

Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: A. Friedrich <alex@f2media.de>
…r claim

Self-correction (the prior commit overclaimed). An all-100% / zero-variance
battery has NO discriminating power, so it supports NEITHER "weakens the
verifier-bias case" NOR "cheap judge matches Opus":
- Bias is UNTESTED — the instrument couldn't detect bias if present (absence of
  evidence != evidence of absence).
- Haiku 10/10 beside Opus 10/10 = clears the same easy bar, not matches Opus at
  real difficulty.

Load-bearing point: planted flaws can only sample the model's *articulable*
errors (you can't plant a flaw you can't see); self-generation refused for the
same reason. RQGM is about *correlated blind spots* — errors the model cannot
see — unreachable by both designs. The only valid instrument is harvested real
errors with ground truth (the Deferred labeled set), now promoted to rec #1.

Kept (not inflated): the verifier accepted both correct controls incl. the
surprising C2 and caught premise-type errors with correct reasoning -> mild
evidence it is not trigger-happy. Not a quality verdict.

Assisted-by: Claude Code:claude-opus-4-8
Signed-off-by: A. Friedrich <alex@f2media.de>
…chor

Implements rec #2 of the RQGM analysis — the only proposal whose faithfulness
skeptic passed. The pooled solve_rate (solved / all problems) averaged two
populations that answer different questions, hiding both.

split_metrics() partitions by expected_solvable:
  - solve_rate            -> solved / solvable problems (capability). REDEFINED;
                             not comparable to a pre-split number.
  - false_claim_accept_rate -> the primary number. Every "proof" of a false claim
                             is wrong by construction, so an accept is a false
                             positive — the only metric in the repo that responds
                             to verifier *bias* rather than variance.
  - false_claim_verdicts  -> verdict histogram over the anchors.

Errors are handled asymmetrically, deliberately. An errored solvable problem is
a failure to solve and stays in the solve_rate denominator; an errored anchor
produced no verdict and leaves the anchor denominator. The prior `not solved`
test counted crashed anchors as correct rejections, biasing toward the
reassuring answer: on a fixture with one error in each population it reports 50%
rejection where the one anchor that returned a verdict was in fact accepted.

reject_rate is NOT a false-premise detection rate — AgentResult.solved is false
whenever a CORRECT verdict was missed, lumping genuine premise rejection with
budget exhaustion. Documented in the docstring; false_claim_verdicts separates
them. AgentResult carries no detection flag and none was invented.

Anchor freeze uses two independent keys:
  - anchor_sha256: SHA-256 over (id, domain, problem, expected_solvable) sorted
    by id — which problem set was run. Order-invariant, edit-sensitive.
  - GATE_EPOCH = 2: a module constant, not a benchmark field — how outcomes were
    scored. A verifier-prompt/model change never touches the benchmark JSON, so
    only an epoch bump invalidates a comparison across one. Keeping it in code
    leaves the benchmark files untouched, as anchor-freeze discipline wants.

Both helpers live in eval/harness.py and are imported by scripts/run_gate.py,
which reimplemented the aggregation; its report() printed solved (over all
problems) beside solve_rate, which now disagree, and is fixed to show
solved/n_solvable, FPR, error count, and the sha/epoch.

Tests: 11 new in test_eval.py, each written to fail against the naive
implementation. Full suite 1380 passed; stash-verified zero new ruff (1==1) and
zero new mypy (18==18) errors.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: A. Friedrich <alex@f2media.de>
Follow-up to the metric split. `correct_prediction` was
`result.solved == expected_solvable` — one boolean meaning two different things
depending on which population the problem is in, which is exactly the
conflation split_metrics() removes at the aggregate level. It had no consumers
(both sites were producers) and its verbose status line printed "OK" for a
false-claim anchor that merely exhausted its iteration budget, sitting directly
beside the new split aggregate.

Removed from both producers and replaced with a population-aware status:
ERROR / SOLVED / unsolved for solvable problems, ACCEPTED(FP) / rejected for
anchors. The adjacent verdict= field distinguishes genuine premise rejection
(major_flaw) from budget exhaustion (unsolved), which is the honest
presentation given AgentResult carries no detection flag.

Also syncs CLAUDE.md's Module Map for eval/harness.py, which still documented
the pre-split return shape: adds split_metrics/anchor_sha256/GATE_EPOCH, the
asymmetric error handling, and the note that solve_rate's denominator changed.

Verified: no benchmark report schema exists under docs/schemas/ (only
agent-result and consensus-result), so no schema is invalidated by the six new
top-level report keys. 1380 tests pass; ruff 1==1 and mypy 18==18 vs baseline.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: A. Friedrich <alex@f2media.de>
These 25 files (276K) were the only measurement artifacts the project had
ever produced, and they were untracked — one `git clean -fd` from being lost.
Tracking them because two of them are load-bearing for the roadmap:

1. data/calibration/validation-report.json — the E-vs-F simulator FAILED its
   own validation: criteria.overall_passed=false, aggregate_sim=0.031 vs
   aggregate_real=0.967 (a 30x miss), spearman_rho=nan because the real data
   sat at ceiling. The v3.8 PUCT direction was chosen on this instrument, so
   the record of its failure belongs in the repo, not on one laptop.

2. data/calibration/{nano,qwen,flash,super}/bvd.json — the only
   ground-truth-anchored measurement in the project, and it points the wrong
   way. On false-claim-even-odd (provably false), the agent returned CORRECT:

       depth  (1x12 iters)                    11/18  (61%)
       breadth (6x2 iters, best by verdict)   15/18  (83%)

   nemotron-super is the cleanest case: 20% -> 100%. When the premise is
   false, every run that "succeeds" is a false positive, so ranking by
   verdict-then-confidence selects for the most convincing wrong answer.

   Bounds on that claim, stated so nobody over-reads it later: 4 non-Claude
   OpenRouter models, one anchor, N=18, and the breadth arm is
   scripts/breadth_vs_depth.py's own restart-and-rank (best_of_n=1 in its
   config), not literally Alethic's best-of-N. Same argmax mechanism, not the
   same code path. It is a hypothesis with teeth, not a verdict — and the
   false_claim_accept_rate metric added in 5e0e78e is what tests it properly.

docs/results/ holds the generated reports over the same data, including the
e-vs-f-report.md whose own conclusion is "Indecisive".

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: A. Friedrich <alex@f2media.de>
The repo had no CI of any kind — no .github/, no pre-commit — while carrying
four open PRs totalling ~10,400 unreviewed added lines. Every merge to date
has been gated only by someone running the suite locally.

Gates on pytest and mypy. Ruff runs advisory (continue-on-error) because main
carries 111 pre-existing findings, 93 of them in tests/ and mostly unused
imports and import ordering; gating on that today would block every merge on
unrelated debt. Clean those in a dedicated pass, then drop continue-on-error.

No ANTHROPIC_API_KEY is provided, deliberately: the suite is fully mocked and
must stay that way, so a test that starts needing a live key will fail here.

Landing this via PR #12 rather than a separate PR so it takes effect after
PR #11 brings mypy to 0, which means it gates the two merges that actually
carry risk (#10 at 8467 lines, #9 with three conflict hunks).

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: A. Friedrich <alex@f2media.de>
@hyperion-git
hyperion-git merged commit b6162e2 into main Jul 29, 2026
1 check failed
hyperion-git added a commit that referenced this pull request Jul 29, 2026
Brings in PR #11 (mypy 18->0), PR #12 (RQGM analysis, eval metric split,
tracked evidence, CI workflow).

One conflict, in the run_benchmark() return dict — both sides added keys and
both are kept. The merged report now carries all three axes needed to compare
two runs:

  search_mode     which code path ran      (#10)
  anchor_sha256   which problem set ran    (#12)
  gate_epoch      how outcomes were scored (#12)

Also un-ignores data/calibration/ and docs/results/. They were ignored as
"generated outputs", but they hold the project's only measurement record and
that record sat untracked for months. New runs now surface as untracked so
they get a keep/discard decision instead of being dropped silently.

Verified: 1653 passed, 2 skipped, 3 xfailed.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: A. Friedrich <alex@f2media.de>
hyperion-git added a commit that referenced this pull request Jul 29, 2026
Brings in PR #11 (mypy), PR #12 (metric split, evidence, CI), PR #10 (v3.8
tree search). Three conflicts, all keep-both:

  models.py EventType    REVISER_ALL_DECLINED (#9) + the 5 v3.8 search events
                         -> 16 members (10 in v3.7, +5, +1)
  models.py AgentConfig  enable_surveyor/enforce_checks_floor (#9)
                         + search_mode/search (#10)
  test_new_types.py      len(EventType) assertion 11 vs 15 -> 16

Also fixes a mypy regression this merge exposed: _parse_survey() bound `m`
twice for two different types — Match[str] from enumerate() at line 115, then
Match[str] | None at 133. Renamed the second to `sanity` rather than
annotating it, since the reuse was the actual defect. Without this, merging #9
would have silently undone part of #11's mypy cleanup.

Verified: 1707 passed, 2 skipped, 3 xfailed; mypy 0 errors across 41 files.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: A. Friedrich <alex@f2media.de>
@hyperion-git
hyperion-git deleted the experiment/verifier-bias-probe branch September 20, 2026 16:54
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