Skip to content

docs: rewrite the results narrative for the first full-60 sweep - #120

Merged
aallan merged 14 commits into
mainfrom
docs/v0-0-18-results
Jul 28, 2026
Merged

docs: rewrite the results narrative for the first full-60 sweep#120
aallan merged 14 commits into
mainfrom
docs/v0-0-18-results

Conversation

@aallan

@aallan aallan commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Depends on #117, which fixed the grading defects these numbers were produced under. Merge that first.

The numbers are new, not updated

The v0.0.16 sweep output-graded 36 of the 60 problems. The 24 it could not grade were the ADT, pattern-matching and effect-handler problems, so every previously published figure was computed on the subset that suited Python and TypeScript best. This sweep grades all 60 in all five languages. The two sets are not comparable and the README opens by saying so.

What changed in the story

v0.0.16 (36 problems) v0.0.18 (60 problems)
Vera average 99.0% 98.7%
Python 98.0% 96.7%
TypeScript 98.4% 99.7%

Against Python, Vera wins for six of nine models. Against TypeScript it wins one, draws five and loses three — because TypeScript now scores 100% for six models and there is no headroom left to win. That is a fact about saturation rather than about Vera, and the saturation section says so plainly: closing the coverage gap made saturation worse, since the comparison languages handle the newly-graded ADT problems well.

The zero-training-data comparison is the one saturation has not eaten, and it is now the strongest result in the release: Vera 98.2%, AILANG 96.8%, Aver 92.4% across the five models that ran all three, with Vera ahead of Aver on every one of them. A figure version of that three-language chart is new and sits below the Vera-versus-Aver section.

The coverage section is rewritten, not updated

It used to argue that pass@1 could not see the problems without test cases. #107 closed that gap, so the old chart degenerated to "0 of 60" beside a 0% hero stat that read as Vera failing everything. It now reports where vera check and vera run disagree: six of 539 graded pairs cleared the static gate and were still wrong (1.1%), against zero working programs refused.

Scope

  • README.md, assets/README.md, 9 regenerated figures, 1 new figure.
  • assets/GRAPHS.md was rewritten to match but is gitignored (talk notes), so it is not in this diff.
  • All 19 assets regenerated after the final re-grade; timestamps verified against the results files.

Drafted against the writing-voice skill and audited with its checker. assets/README.md comes back clean; README.md's remaining findings are markdown image syntax read as exclamation marks.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Refreshed the main README to reflect the updated VeraBench sweep/reporting regime, including revised results narrative (Vera v0.1.8), expanded cross-language coverage, and updated guidance for interpreting spreads and “% solved”.
    • Updated analytical sections covering reasoning mode, refusals, contract vs runtime outcomes, and benchmark saturation, and expanded controlled comparisons (now including AILANG).
    • Revised workflow and reporting guidance, including re-grading without re-running and runtime retrieval of the Vera language reference with a --skill-md override.
  • Chores
    • Updated README instructions for regenerating assets and commands, including generation of fig-ztd.png for the ztd slide type.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The documentation updates refresh VeraBench results and analysis for Vera v0.1.8, expand language comparisons, clarify evaluation metrics and benchmark workflows, document regrading and reporting, and update plot regeneration instructions.

Changes

Benchmark documentation

Layer / File(s) Summary
Results and analysis updates
README.md, assets/README.md
Results tables, benchmark interpretation, controlled comparisons, metric definitions, overview text, and sweep denominator documentation are updated for Vera v0.1.8 and additional language dimensions.
Benchmark installation and execution workflow
README.md
Compiler requirements, full-sweep execution, scoreboard monitoring, and no-resume behaviour are clarified.
Regrading and report generation
README.md, assets/README.md
Stored-result replay, runtime skill retrieval, report generation, and plot regeneration instructions are documented or updated.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

Suggested labels: docs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: a documentation rewrite of the results narrative for the first full-60 sweep.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/v0-0-18-results

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

@aallan
aallan changed the base branch from main to fix/sweep-triage-classification July 28, 2026 02:05
Base automatically changed from fix/sweep-triage-classification to main July 28, 2026 02:09
Every number is new. The v0.0.16 sweep output-graded 36 of the 60 problems,
and the 24 it could not grade were the ADT, pattern-matching and
effect-handler problems, so those numbers were computed on the subset that
suited Python and TypeScript best. The two sets are not comparable, and the
README says so up front.

The story changed with them. Vera beats Python for six of the nine models
and averages 98.7% against Python's 96.7%; against TypeScript it wins once,
draws five and loses three, because TypeScript now scores 100% for six
models and there is no headroom left to win. That is a fact about
saturation rather than about Vera, and the saturation section says so.

The zero-training-data comparison is the one saturation has not eaten, and
it is now the strongest result in the release: Vera 98.2% against AILANG
96.8% and Aver 92.4% on the five models that ran all three, with Vera ahead
of Aver on every one. A figure version of that three-language chart is new
(assets/fig-ztd.png), sitting below the Vera-versus-Aver section.

The coverage section is rewritten rather than updated. It used to be about
the problems pass@1 could not see; that gap is closed, so it now reports
where `vera check` and `vera run` disagree: six of 539 graded pairs cleared
the static gate and were still wrong, against zero working programs
refused.

assets/GRAPHS.md was rewritten to match, but it is gitignored (talk notes
rather than a published asset), so it does not appear in this diff.

Drafted against the writing-voice skill and audited with its checker.
assets/README.md comes back clean; README.md's remaining findings are
markdown image syntax read as exclamation marks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@aallan
aallan force-pushed the docs/v0-0-18-results branch from e197c86 to 5f63493 Compare July 28, 2026 02:10

@coderabbitai coderabbitai 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.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@assets/README.md`:
- Around line 88-94: Update the asset documentation surrounding the regeneration
commands to consistently reference version 0.0.18, revise the denominator from
the outdated 36-problem description, and add fig-ztd.png to the figure
inventory. Keep the inventory aligned with all three commands shown in the diff.

In `@scripts/plot_narrative.py`:
- Around line 1158-1164: Update the narrative count in the `fig.text` block to
use the number of model targets that actually contribute Vera rows, matching the
filtering performed by the tally loop around `mode != "Vera"`; do not use the
unfiltered `len(rows_by_target)` value.

In `@scripts/regrade.py`:
- Line 154: Update the worker function one() to return its transition label
instead of mutating the shared tally, then collect those labels from
ThreadPoolExecutor.map and increment tally on the main thread after the worker
calls complete. Preserve the existing transition labels and printed output while
removing all worker-thread writes to tally.
- Around line 243-247: Update the target-processing loop around path.read_text()
to detect files with no lines before accessing the first line, and continue to
the next target when the file is empty. Preserve the existing language filter
and regrade_file flow for non-empty target files.

In `@scripts/rerun_failed.py`:
- Line 269: Update the covered-count calculation in the rerun-failed sweep guard
to count only truthy problem IDs, matching the filtering used by
sweep_status.py. Preserve unique-ID counting while excluding missing or empty
IDs so the guard cannot treat an incomplete sweep as clean.

In `@vera_bench/adt_render.py`:
- Around line 557-564: Update _ts_kind to match the intended handling of unknown
nominal and capitalized types: either preserve the original casing for the
capitalization check before lowercasing, or explicitly treat all unknown names
as "object" and remove the unreachable base[0].isupper() condition. Also
simplify the final return by removing the unreachable else branch, since known
_TS_CLASS values already return earlier.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 577dae0c-52ed-4554-87c2-0a0e517f0eab

📥 Commits

Reviewing files that changed from the base of the PR and between 2c5a7bf and e197c86.

⛔ Files ignored due to path filters (9)
  • assets/fig-coverage.png is excluded by !**/*.png
  • assets/fig-delta.png is excluded by !**/*.png
  • assets/fig-generation.png is excluded by !**/*.png
  • assets/fig-reasoning.png is excluded by !**/*.png
  • assets/fig-refusal.png is excluded by !**/*.png
  • assets/fig-saturation.png is excluded by !**/*.png
  • assets/fig-vera-vs-aver.png is excluded by !**/*.png
  • assets/fig-ztd.png is excluded by !**/*.png
  • assets/results-graph.png is excluded by !**/*.png
📒 Files selected for processing (14)
  • CHANGELOG.md
  • KNOWN_ISSUES.md
  • README.md
  • assets/README.md
  • scripts/plot_narrative.py
  • scripts/plot_results.py
  • scripts/plot_slide.py
  • scripts/regrade.py
  • scripts/rerun_failed.py
  • scripts/sweep_status.py
  • tests/test_rerun_failed.py
  • tests/test_sweep_status.py
  • vera_bench/adt_render.py
  • vera_bench/runner.py

Comment thread assets/README.md

@coderabbitai coderabbitai 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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@assets/README.md`:
- Around line 88-94: Update the asset documentation surrounding the regeneration
commands to consistently reference version 0.0.18, revise the denominator from
the outdated 36-problem description, and add fig-ztd.png to the figure
inventory. Keep the inventory aligned with all three commands shown in the diff.

In `@scripts/plot_narrative.py`:
- Around line 1158-1164: Update the narrative count in the `fig.text` block to
use the number of model targets that actually contribute Vera rows, matching the
filtering performed by the tally loop around `mode != "Vera"`; do not use the
unfiltered `len(rows_by_target)` value.

In `@scripts/regrade.py`:
- Line 154: Update the worker function one() to return its transition label
instead of mutating the shared tally, then collect those labels from
ThreadPoolExecutor.map and increment tally on the main thread after the worker
calls complete. Preserve the existing transition labels and printed output while
removing all worker-thread writes to tally.
- Around line 243-247: Update the target-processing loop around path.read_text()
to detect files with no lines before accessing the first line, and continue to
the next target when the file is empty. Preserve the existing language filter
and regrade_file flow for non-empty target files.

In `@scripts/rerun_failed.py`:
- Line 269: Update the covered-count calculation in the rerun-failed sweep guard
to count only truthy problem IDs, matching the filtering used by
sweep_status.py. Preserve unique-ID counting while excluding missing or empty
IDs so the guard cannot treat an incomplete sweep as clean.

In `@vera_bench/adt_render.py`:
- Around line 557-564: Update _ts_kind to match the intended handling of unknown
nominal and capitalized types: either preserve the original casing for the
capitalization check before lowercasing, or explicitly treat all unknown names
as "object" and remove the unreachable base[0].isupper() condition. Also
simplify the final return by removing the unreachable else branch, since known
_TS_CLASS values already return earlier.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 577dae0c-52ed-4554-87c2-0a0e517f0eab

📥 Commits

Reviewing files that changed from the base of the PR and between 2c5a7bf and e197c86.

⛔ Files ignored due to path filters (9)
  • assets/fig-coverage.png is excluded by !**/*.png
  • assets/fig-delta.png is excluded by !**/*.png
  • assets/fig-generation.png is excluded by !**/*.png
  • assets/fig-reasoning.png is excluded by !**/*.png
  • assets/fig-refusal.png is excluded by !**/*.png
  • assets/fig-saturation.png is excluded by !**/*.png
  • assets/fig-vera-vs-aver.png is excluded by !**/*.png
  • assets/fig-ztd.png is excluded by !**/*.png
  • assets/results-graph.png is excluded by !**/*.png
📒 Files selected for processing (14)
  • CHANGELOG.md
  • KNOWN_ISSUES.md
  • README.md
  • assets/README.md
  • scripts/plot_narrative.py
  • scripts/plot_results.py
  • scripts/plot_slide.py
  • scripts/regrade.py
  • scripts/rerun_failed.py
  • scripts/sweep_status.py
  • tests/test_rerun_failed.py
  • tests/test_sweep_status.py
  • vera_bench/adt_render.py
  • vera_bench/runner.py
🛑 Comments failed to post (5)
scripts/plot_narrative.py (1)

1158-1164: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Model count is unfiltered while the pair count is filtered.

The tally loop skips any mode != "Vera" (Line 992), but len(rows_by_target) counts every target key including a non-Vera one, should load_rows ever return one. The two numbers in the same sentence would then be drawn from different populations.

♻️ Count the models that actually contributed
     escapes: list[tuple[str, str, str]] = []  # (model, problem, cause)
+    models_seen: set[str] = set()
     agree = false_alarms = graded = 0
     for (model, mode), rows in sorted(rows_by_target.items()):
         if mode != "Vera":
             continue
+        models_seen.add(model)
-        f"program — {graded} pairs across {len(rows_by_target)} models.\n"
+        f"program — {graded} pairs across {len(models_seen)} models.\n"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    fig.text(
        0.5,
        0.865,
        f"`vera check` and `vera run` are independent verdicts on the same "
        f"program — {graded} pairs across {len(models_seen)} models.\n"
        "Contracts bound what a program may do; they do not say everything "
        "it must do, so a few satisfy them and are still wrong.\n"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/plot_narrative.py` around lines 1158 - 1164, Update the narrative
count in the `fig.text` block to use the number of model targets that actually
contribute Vera rows, matching the filtering performed by the tally loop around
`mode != "Vera"`; do not use the unfiltered `len(rows_by_target)` value.
scripts/regrade.py (2)

154-154: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

tally is mutated from up to eight threads — the census can lose counts.

Counter.__iadd__ on a key (tally["changed"] += 1) is a load-add-store, not an atomic operation, so concurrent one() calls under ThreadPoolExecutor will drop increments. The printed transition table is the entire output of a dry run, and an undercount here reads as "the fix touched fewer rows than it did" — the opposite of the honest census the docstring promises. The row data itself is safe; only the tally is racy.

Cheapest fix: have one() return the label and fold the counts on the main thread.

🔒 Fold the tally after the map, not inside the workers
-    def one(row: dict) -> dict:
+    def one(row: dict) -> tuple[dict, list[str]]:
         cp = row.get("code_path")
         problem = problems.get(row.get("problem_id"))
         if not cp or problem is None:
-            tally["no-code"] += 1
-            return row
+            return row, ["no-code"]
         src = results_dir / cp
         if not src.exists():
-            tally["missing-file"] += 1
-            return row
+            return row, ["missing-file"]
         before = {k: row.get(k) for k in VERDICT_FIELDS}
         with tempfile.TemporaryDirectory(prefix="vb-regrade-") as tmp:
             try:
                 fresh = evaluate(
                     row, src.read_text(encoding="utf-8"), problem, Path(tmp), vera
                 )
             except Exception as exc:  # a grader crash is not a verdict
-                tally["grader-error"] += 1
                 row["regrade_error"] = f"{type(exc).__name__}: {exc}"[:200]
-                return row
+                return row, ["grader-error"]
         new = dict(row)
         new.update({k: v for k, v in fresh.items() if k in VERDICT_FIELDS})
         after = {k: new.get(k) for k in VERDICT_FIELDS}
         if _same_verdict(before, after):
-            tally["unchanged"] += 1
-            return row
-        else:
-            tally["changed"] += 1
-            was, now = _bucket(before), _bucket(after)
-            tally[f"{was} -> {now}"] += 1
-        return new
+            # Same verdict, different sandbox path. Return the ORIGINAL row
+            # so the file keeps the message the sweep actually recorded.
+            return row, ["unchanged"]
+        return new, ["changed", f"{_bucket(before)} -> {_bucket(after)}"]
 
     if workers > 1:
         with ThreadPoolExecutor(max_workers=workers) as pool:
-            out = list(pool.map(one, rows))
+            done = list(pool.map(one, rows))
     else:
-        out = [one(r) for r in rows]
+        done = [one(r) for r in rows]
+    out = []
+    for row, labels in done:
+        out.append(row)
+        tally.update(labels)
     return out, tally

Also applies to: 163-198

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/regrade.py` at line 154, Update the worker function one() to return
its transition label instead of mutating the shared tally, then collect those
labels from ThreadPoolExecutor.map and increment tally on the main thread after
the worker calls complete. Preserve the existing transition labels and printed
output while removing all worker-thread writes to tally.

243-247: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

An empty target file aborts the whole run with IndexError.

path.read_text().splitlines()[0] assumes at least one line. vera-bench run unlinks and recreates its output file, so a zero-byte target in results/ is an ordinary mid-sweep state — and here it kills the regrade of every remaining target, after the earlier ones may already have been rewritten under --apply. Skip it instead.

🛡️ Skip a file with no rows
     for path in targets:
-        head = json.loads(path.read_text().splitlines()[0])
-        if args.language and head.get("language") != args.language:
+        lines = [ln for ln in path.read_text().splitlines() if ln.strip()]
+        if not lines:
+            print(f"    {path.name[:64]:66} empty — skipping", flush=True)
+            continue
+        head = json.loads(lines[0])
+        if args.language and head.get("language") != args.language:
             continue
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    for path in targets:
        lines = [ln for ln in path.read_text().splitlines() if ln.strip()]
        if not lines:
            print(f"    {path.name[:64]:66} empty — skipping", flush=True)
            continue
        head = json.loads(lines[0])
        if args.language and head.get("language") != args.language:
            continue
        rows, tally = regrade_file(path, results_dir, problems, vera, args.parallel)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/regrade.py` around lines 243 - 247, Update the target-processing loop
around path.read_text() to detect files with no lines before accessing the first
line, and continue to the next target when the file is empty. Preserve the
existing language filter and regrade_file flow for non-empty target files.
scripts/rerun_failed.py (1)

269-269: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

None counts as a problem, so the in-flight guard is one short of sweep_status.

{r.get("problem_id") for r in rows} admits None for any row without an id, inflating covered by one — which is enough to let a file that is one problem short read as complete and be spliced while the sweep is still writing it. sweep_status.py (Line 220) filters: {r["problem_id"] for r in rows if r.get("problem_id")}. Match it, given the comment claims the same denominator.

🛡️ Use the same denominator it claims to
-    covered = len({r.get("problem_id") for r in rows})
+    covered = len({r["problem_id"] for r in rows if r.get("problem_id")})

Based on the guideline that rerun_failed.py must never run against a target the sweep is still processing, since both processes write the same output file, and on the guideline to use unique problem-ID coverage when determining sweep cleanliness.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    covered = len({r["problem_id"] for r in rows if r.get("problem_id")})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/rerun_failed.py` at line 269, Update the covered-count calculation in
the rerun-failed sweep guard to count only truthy problem IDs, matching the
filtering used by sweep_status.py. Preserve unique-ID counting while excluding
missing or empty IDs so the guard cannot treat an incomplete sweep as clean.

Source: Coding guidelines

vera_bench/adt_render.py (1)

557-564: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Two dead branches in _ts_kind — the case check can never fire.

base is already lower-cased on Line 557, so base[0].isupper() on Line 562 is always False. The docstring's rule that an unknown capitalised name (alias, union) is unreadable therefore never applies: List becomes "object" and is aligned as a readable type. Only the len(base) <= 2 clause is actually rejecting anything (type variables). Likewise on Line 564, the else base arm is unreachable because Line 558 already returned for any base in _TS_CLASS.values().

If aligning unknown nominal types as "object" is the intent (the recursive-alias test suggests it is), say so and drop the dead clause; if capitalised unknowns really should be unreadable, test the case before lower-casing.

♻️ Make the intent match the behaviour
-    base = re.sub(r"<[^>]*>", "", t or "").strip().lower()
-    if base in _TS_CLASS.values():
-        return base
-    if base in {k.lower() for k in _TS_CLASS}:
-        return _TS_CLASS[next(k for k in _TS_CLASS if k.lower() == base)]
-    if not base or len(base) <= 2 or base[0].isupper():
-        return None
-    return "object" if base not in _TS_CLASS.values() else base
+    raw = re.sub(r"<[^>]*>", "", t or "").strip()
+    base = raw.lower()
+    if base in _TS_CLASS.values():
+        return base
+    for k, v in _TS_CLASS.items():
+        if base == k.lower():
+            return v
+    # A short name is a type variable (`T`, `K`) — unreadable, never
+    # "object". Any other nominal type aligns with a non-scalar argument.
+    if not base or len(base) <= 2:
+        return None
+    return "object"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    raw = re.sub(r"<[^>]*>", "", t or "").strip()
    base = raw.lower()
    if base in _TS_CLASS.values():
        return base
    for k, v in _TS_CLASS.items():
        if base == k.lower():
            return v
    # A short name is a type variable (`T`, `K`) — unreadable, never
    # "object". Any other nominal type aligns with a non-scalar argument.
    if not base or len(base) <= 2:
        return None
    return "object"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vera_bench/adt_render.py` around lines 557 - 564, Update _ts_kind to match
the intended handling of unknown nominal and capitalized types: either preserve
the original casing for the capitalization check before lowercasing, or
explicitly treat all unknown names as "object" and remove the unreachable
base[0].isupper() condition. Also simplify the final return by removing the
unreachable else branch, since known _TS_CLASS values already return earlier.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 55-68: Correct the full-spec score-range statement in the README
to account for the Aver values shown in the model results table, including its
actual 90%–95% range, or explicitly limit the claim to Vera, Python, and
TypeScript. Update both the referenced summary and the corresponding statement
around the table’s earlier range description.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7bb4b93f-4804-4de5-bea0-e33512d3832d

📥 Commits

Reviewing files that changed from the base of the PR and between e197c86 and 5f63493.

⛔ Files ignored due to path filters (9)
  • assets/fig-coverage.png is excluded by !**/*.png
  • assets/fig-delta.png is excluded by !**/*.png
  • assets/fig-generation.png is excluded by !**/*.png
  • assets/fig-reasoning.png is excluded by !**/*.png
  • assets/fig-refusal.png is excluded by !**/*.png
  • assets/fig-saturation.png is excluded by !**/*.png
  • assets/fig-vera-vs-aver.png is excluded by !**/*.png
  • assets/fig-ztd.png is excluded by !**/*.png
  • assets/results-graph.png is excluded by !**/*.png
📒 Files selected for processing (2)
  • README.md
  • assets/README.md

Comment thread README.md Outdated
aallan and others added 2 commits July 28, 2026 03:18
The Vera-TypeScript-Python ordering reads as a puzzle until the languages
are grouped by when they check types. Python is dynamically typed and finds
the error at runtime; TypeScript rejects it first; Vera is on the TypeScript
side of that line and adds contracts and a prover on top.

Grouped that way the result is the thesis rather than a counterexample:
Vera 98.7% and TypeScript 99.7% against Python's 96.7%, so both constrained
languages finish ahead of the loose one, and the language nobody trained on
is in the leading group.

The failure modes agree. Python's failures land as runtime wrong answers
rather than compile rejections, thirteen against three across the sweep;
TypeScript has one of each. A loose language cannot reject a bad program up
front, so the mistake survives to execution.

The section states its own caveat rather than leaving it to be found. Some
of Python's deficit is ours: TypeScript is structurally typed, so at the
boundary where the grader builds a test value it accepts an object carrying
a field the model's type never declared, where Python's constructor raises.
On two problems the identical modelling choice scored solved in TypeScript
and not solved in Python (#121). The direction holds; the three points are
provisional.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both findings were mine from this session, and both were live.

I bumped the regeneration block in assets/README.md to v0.0.18 and added the
fig-ztd.png command, but left the prose around it describing the v0.0.16
charts and a 36-problem denominator, and did not add the new figure to the
inventory. A regeneration block that produces one set of assets beside prose
describing another is worse than either alone. The provenance, the
denominator (1.7 points per problem, not 2.8), the coverage chart's
description and the ztd entry are all brought into line, and every figure the
README embeds is now documented.

The README claimed "every full-spec column bunches between 93% and 100%".
Expanding that table to include Aver and AILANG made it false: Aver runs 90%
to 95%. The claim is now scoped to the three columns it actually describes,
with Aver's range stated rather than quietly excluded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
README.md (1)

380-395: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Qualify the regrading scope.

regrade.py leaves API-error/no-code rows, rows with missing code files, unknown problems, and grader-error rows unchanged. Therefore, “Every result row records” a code path and “It re-grades every row” are too broad; document that regrading applies only to eligible rows with valid stored code.

As per path instructions, **/*.md files are reviewed for factual accuracy and broken links, not grammar or prose style.

Suggested wording
-Every result row records the path to the code the model actually wrote, under
+Eligible result rows record the path to the code the model actually wrote, under
...
-It re-grades every row rather than only the ones a fix was expected to help,
+It re-grades every eligible row with stored code rather than only the ones a fix was expected to help,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 380 - 395, Update the regrading documentation around
regrade.py to qualify that only eligible rows with valid stored code are
regraded. State that API-error/no-code rows, rows with missing code files,
unknown problems, and grader-error rows remain unchanged, and replace the broad
claims that every result row records code and every row is regraded.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@README.md`:
- Around line 380-395: Update the regrading documentation around regrade.py to
qualify that only eligible rows with valid stored code are regraded. State that
API-error/no-code rows, rows with missing code files, unknown problems, and
grader-error rows remain unchanged, and replace the broad claims that every
result row records code and every row is regraded.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 39634429-9e93-4764-ac18-d2d909c9dcd1

📥 Commits

Reviewing files that changed from the base of the PR and between 5f63493 and a020f72.

📒 Files selected for processing (1)
  • README.md

aallan and others added 2 commits July 28, 2026 03:23
The Results section opened by asking the reader to compare against numbers
they have never seen: an earlier sweep, its 36-problem denominator, and a
warning that the two are not comparable. None of that is published anywhere,
so it was meta-commentary in the position where the finding should be. Cut.

Two other passages were framed the same way and are now framed as properties
of the chart instead. The generation caveat says Claude Opus 4 was measured
against an older compiler and a smaller set of graded problems, which is what
a reader needs in order to distrust that step; it no longer cites bench
versions to say so. The saturation section states that six models score 100%
in TypeScript and six in Vera, rather than reporting that the number moved
since last time.

The full-results table drops the Aver and AILANG columns. Both languages have
two sections of their own at the end, and carrying them in the headline table
put a five-model subset beside a nine-model one, with dashes standing in for
targets that were never run. The range claim beneath it now describes exactly
the three columns that remain, verified against the table rather than
asserted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The static-typing section grouped the three languages correctly and then
stopped short of the point. Vera is the only one of the three that no model
has read: TypeScript earns 99.7% with an enormous amount of the language in
every training set, and Vera reaches 98.7% from a single document in the
prompt. Whatever familiarity is buying TypeScript, Vera appears to supply by
other means, and the candidate is the structure it imposes.

The zero-training-data comparison tests that rather than asserting it, because
it holds exposure at zero for all three languages and varies only the design.
Vera 98.2%, AILANG 96.8%, Aver 92.4%, with Vera also ahead of Python on the
same five models. The most constrained of the three scores highest.

Stated as compensation rather than superiority, because the data does not
support superiority: Vera is a point behind TypeScript and the delta chart
shows it. The claim is that mandatory contracts and typed slot references are
worth roughly what a training corpus is worth, which is both defensible and
the more interesting result.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
README.md (2)

356-358: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Distinguish provider timeouts from test-execution timeouts.

scripts/sweep_status.py treats test N: execution failures as real results even when their message contains “timed out”; only provider or infrastructure timeouts are transient. Clarify this here to avoid re-running non-terminating solutions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 356 - 358, Update the “Watch the scoreboard” guidance
in README.md to clarify that only provider or infrastructure timeouts are
transient; test-execution failures reported as “test N:” results, including
messages containing “timed out,” are real results that must be kept and not
re-run.

374-389: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Limit the regrading claim to rows with stored code.

scripts/regrade.py leaves API-error rows, missing code paths, and runs performed with --no-store-code unchanged. Therefore, “Every result row records” and “It re-grades every row” are too broad; qualify them as applying to rows with an existing stored code path, and state that other rows are skipped.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 374 - 389, Update the README description of
scripts/regrade.py to limit its claims to result rows with an existing stored
code path. Revise “Every result row records” and “It re-grades every row”
accordingly, and explicitly state that API-error rows, missing code paths, and
runs using --no-store-code are skipped and left unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 94-95: Update the TypeScript saturation count in the README
analysis from six of nine models to eight of nine, matching the table and
excluding only Claude Fable 5.

---

Outside diff comments:
In `@README.md`:
- Around line 356-358: Update the “Watch the scoreboard” guidance in README.md
to clarify that only provider or infrastructure timeouts are transient;
test-execution failures reported as “test N:” results, including messages
containing “timed out,” are real results that must be kept and not re-run.
- Around line 374-389: Update the README description of scripts/regrade.py to
limit its claims to result rows with an existing stored code path. Revise “Every
result row records” and “It re-grades every row” accordingly, and explicitly
state that API-error rows, missing code paths, and runs using --no-store-code
are skipped and left unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1c048977-9abe-476b-9315-f4b8a61765bd

📥 Commits

Reviewing files that changed from the base of the PR and between c30e798 and 761f516.

📒 Files selected for processing (1)
  • README.md

Comment thread README.md Outdated
'and they score no better in Python' had an ambiguous subject and, read the
obvious way, claimed no model does better in Python. Two do: Opus 4.8 by five
points and Sonnet 5 by one.

Replaced with the three averages, which carry the same point without the
ambiguity and set up the section that follows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aallan and others added 2 commits July 28, 2026 03:37
…eresting

Five of them, all the same move: a preamble telling you a fact matters,
followed by the fact, which would have carried itself.

  "The losses are worth naming."
  "The number worth watching is the other cell, and it is zero."
  "That grouping is what makes the Vera number interesting, because..."
  "...which is the substance of the saturation problem discussed below."
  "...worth roughly what a training corpus is worth, which is a stranger
   and more useful result."

Each is now just the statement. The paragraph about Opus 4.8 and Sonnet 5
opens on the five-point gap, the coverage section says "The other cell is
zero", and the compensation argument opens on Vera being the only one of the
three no model has read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
It was built backwards. Two sentences of analytical scaffolding ("which
makes every model-and-problem pair a two-by-two: the static gate passed or it
did not... Two of those cells are agreement"), then the data, then a callback
that only parsed if you had held the grid in your head ("The other cell is
zero").

The grid was never the point and the reader does not need it. The section now
opens on the number: six programs out of 539 compiled, satisfied their
contracts, and were still wrong. The four that matter are described by what
they did rather than by which quadrant they fall in, and the closing
paragraph states the second finding in its own terms instead of referring
back to a diagram: nothing that ran correctly was refused, and nothing
refused ran correctly.

Also dropped "the honest limit", which was doing the same job as the
"worth naming" sentences cut in bf57d6b. The four programs kept every promise
they made and returned the wrong answer; that is the limit, stated.

Same treatment applied to assets/GRAPHS.md, which carried the same framing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.62%. Comparing base (864eef3) to head (cb010d2).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #120   +/-   ##
=======================================
  Coverage   86.62%   86.62%           
=======================================
  Files          15       15           
  Lines        2871     2871           
=======================================
  Hits         2487     2487           
  Misses        384      384           
Flag Coverage Δ
python 86.62% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

aallan and others added 6 commits July 28, 2026 10:54
Applying the shape of the index.html rewrite. Three problems, all of them
padding rather than content.

The three averages were stated three separate times: in the opener, again at
"Group the three languages that way", and again at "TypeScript's 99.7% is
earned with...". They now appear once, in the opener, and the static-typing
section argues from them instead of restating them.

The static-typing section was five paragraphs saying what index.html says in
two. It opens on the fact now ("The difference between the Python and
TypeScript results is not random") rather than on a definition, and the
payoff about sorting by constraint gets its own short paragraph instead of
trailing a 98-word one. Cut the hedging with it: "appears to be supplying by
other means, and the obvious candidate is the structure it imposes" became
"Vera earns very nearly the same result without that, from a single skill
file in context", which is your phrasing and better than mine.

Four other paragraphs ran past 75 words for no reason. The two-modes
explanation is two paragraphs because it describes two modes; the generations
caveat drops a clause it had already made; the reasoning-mode paragraph stops
explaining itself twice; and "turns out to be a materially easier task than"
is now "is easier than".

No paragraph in the section is over 75 words. It is 1,928 words, down from
2,290, with nothing removed but repetition.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A three-point gap on a single run per model, with some of it traceable to a
grading asymmetry we have not fixed yet (#121), does not support a flat
claim. 'Probably' is what the evidence carries.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Better narrative throughout: the delta section now points at the saturation
section rather than asserting the ceiling twice, the two Vera modes are
labelled with the column names they produce, and the caveats that were
paragraphs are blockquotes.

One factual correction, and it was my error rather than the rewrite's.
"TypeScript scores 100% for six of the nine models" is wrong in both places
it appears: it is eight of nine, with only Claude Fable 5 short at 97%. Vera
is the one at six. That strengthens the saturation argument rather than
weakening it, since there is even less room at the top than the text
claimed.

The 1.1% moved out of a parenthetical that made it read as though 1.1% of
programs compiled. It is now its own sentence after the finding.

Typos: "were ran", "an skills file", "this results says", "wrote program",
"While benchmark", "Typescript", "langauges", a stray "and" in the refusals
paragraph, and a sentence that named Vera twice for one comparison. Trailing
whitespace on five lines.

Every numeric claim re-verified against the v0.0.18 result rows: the
win/draw/loss counts, the 13-against-3 failure split, the pro-path deltas,
Vera over Aver by one to ten points, the zero-training-data averages, the
87-100% range, and both anchor links.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Splicing paragraphs in left ragged line breaks. Prose only; headings,
tables, blockquotes, images and code fences untouched, and every markdown
link still resolves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The section compares two verdicts, static and runtime, so it can only use
rows that have both. One program never compiled and therefore never ran,
which is why the denominator is 539 rather than 9 x 60. A reader doing the
multiplication now finds the answer in the sentence.

It still counts as not solved in the headline: GPT-5.6 Sol reads 98% in Vera
because of it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rade moved

assets/README.md was still describing the v0.0.16 sweep in four places, all of
them wrong against the current data:

  "Vera wins outright for four of the nine models"  -> six against Python,
      one against TypeScript, and the reason is that TypeScript reaches 100%
      for eight of nine and leaves nothing to win
  "Five refusals in the whole run"                  -> four
  "Nothing moves in any of the four languages"      -> Vera +2, Vera NL -2
  "The seven README figures"                        -> eight, since fig-ztd

It also claimed the ztd slide had no committed counterpart, which stopped
being true when fig-ztd.png landed, and described fig-coverage as counting
problems when it now counts programs.

README.md carried a fifth: "Python gains 2 and TypeScript loses 4" across the
generation chain. Those were the numbers before the TypeScript export fix was
re-graded. The chart regenerated and the prose did not, so the two disagreed.
It is Python +1 and TypeScript flat, verified against a freshly rendered chart
that is byte-identical to the committed one.

Both files rewritten in the voice of the Results section rather than patched:
the finding first, no announced significance, caveats as blockquotes,
contractions kept.

Every figure the README embeds is documented in assets/README, checked
mechanically. All eight.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@aallan
aallan merged commit 4306f10 into main Jul 28, 2026
10 checks passed
@aallan
aallan deleted the docs/v0-0-18-results branch July 28, 2026 11:30
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