Skip to content

Gate the facts docs/index.html and docs/index.md both state - #1174

Merged
aallan merged 2 commits into
mainfrom
fix/1154-site-drift-gate
Aug 3, 2026
Merged

Gate the facts docs/index.html and docs/index.md both state#1174
aallan merged 2 commits into
mainfrom
fix/1154-site-drift-gate

Conversation

@aallan

@aallan aallan commented Aug 3, 2026

Copy link
Copy Markdown
Owner

The blind spot

docs/index.md is the Markdown companion agents fetch via rel="alternate" and llms.txt — an LLM asking about Vera's benchmark results is served that file, not the landing page. It is not derived from docs/index.html. It is written out by build_index_md() in scripts/build_site.py, which holds the landing page's substance as a hand-maintained f-string.

scripts/check_site_assets.py verified it by calling that generator and comparing the result against the committed file. Both sides of that comparison come from the same function, so a generator that missed an edit to the hand-designed HTML produced a committed asset stale in exactly the same way, and the check was satisfied. The gate proved the asset matched the generator; nothing proved the generator matched the HTML it mirrors. A v0.0.7-era benchmark section survived every intervening release until it was caught by hand.

This is option 2 from the issue: keep the generator, gate the pair. It extends check_site_assets.py rather than adding a script — this is that script's documented blind spot, and it inherits the existing CI wiring (.github/workflows/ci.yml, lint job). No new CI job or pre-commit entry.

Facts gated

check_fact_coherence(html_path, md_path) extracts each fact from both files independently and compares:

Fact Where
VeraBench version VeraBench v0.0.18 in both
Tested Vera version Vera v0.1.8 in both
Landing-page version badge HTML <span>v<a …>0.1.8</a>, MD **Current version:** [0.1.8]
Benchmark problem count A 60-problem benchmark
Benchmark difficulty tiers across 5 difficulty tiers
Benchmark model count Nine models, three providers
Benchmark provider count same sentence
Models writing perfect Vera Six of nine frontier models
Results table 9 rows; per row the model name, tier and all three figures (Vera / Python / TypeScript)
Rows vs stated model count each file's table row count against its own prose
Editor names VS Code, Vim, TextMate

Compared as facts, not wording: number words fold onto digits (Nine = 9), HTML entities and tags are stripped from table cells, Markdown emphasis is stripped (**100%** = 100% — the win/loss marking is the presentational equivalent of the HTML's CSS class), and percentages compare as strings. The two files' prose registers are left alone.

check_version_sync.py is not duplicated: it pins the HTML badge to pyproject.toml and never reads docs/index.md. The new check compares the two documents to each other.

Extraction failure is gate failure. If a fact cannot be located in either file, that is an error naming the fact and the file — a reworded sentence must not be able to switch its own check off. A file stating one fact two different ways is also an error.

An example failure, from a deliberately drifted docs/index.html:

ERROR: 2 landing-page fact(s) diverge between docs/index.html and docs/index.md (fix build_index_md() in scripts/build_site.py):
  VeraBench version differs: …/docs/index.html says '0.0.19', …/docs/index.md says '0.0.18'
  benchmark table row 'Claude Fable 5' differs: …/docs/index.html says (tier=ceiling, Vera=42%, Python=97%, TypeScript=97%), …/docs/index.md says (tier=ceiling, Vera=100%, Python=97%, TypeScript=97%)

RED-first evidence

19 tests were written in tests/test_build_site.py before check_fact_coherence existed, and all 19 failed. Each drift case copies the committed pair into tmp_path and mutates the copy — the real files are never touched — and the mutation helper asserts its anchor is unique, so a reworded landing page turns the test red rather than silently no-op'ing.

Proved to fail: a bumped percentage in the HTML table, and in the Markdown table; a bumped VeraBench version; a bumped tested-Vera version; a diverged version badge; a changed problem count; a changed model count (which also trips the rows-vs-prose cross-check); a removed HTML table row, and a removed Markdown row; a renamed model; a changed tier; a dropped editor. Extraction failures proved to fail: a removed HTML <table class="bench-table">, a removed Markdown table header, a deleted results caveat (both facts on that line named), a removed editor claim, a missing file, and one file stating the VeraBench version two different ways.

Then mutation-validated: six extraction regexes were broken one at a time — the HTML row extractor, the HTML table anchor, the VeraBench version pattern, the Markdown table header, the Vim editor pattern, the Markdown emphasis stripper — and each turned at least one test red. None is dead weight.

The committed docs/index.html / docs/index.md pair passes: all 9 table rows match cell for cell, all 8 prose facts agree, and all three editors are named in both. No existing divergence was found.

Full gate green: pytest tests/ (8,471 passed), check_site_assets.py, check_doc_counts.py, check_explicit_encoding.py, check_version_sync.py, ruff check ., ruff check --select S vera/, mypy vera/.

Docs lockstep

CHANGELOG [Unreleased] gains a ### Fixed entry; the #1154 row is removed from KNOWN_ISSUES.md (no matching row existed in SKILL.md); CLAUDE.md and TESTING.md describe what the script now checks; CONTRIBUTING.md says plainly that docs/index.md has to be edited in build_index_md() alongside the HTML. The TESTING.md / README.md / ROADMAP.md test counts move with the 19 new tests.

Closes #1154

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Added checks to detect missing, malformed, or conflicting facts between the HTML and Markdown landing pages.
    • Site validation now reports detailed discrepancies and fails when the pages are inconsistent.
  • Documentation

    • Updated guidance for maintaining both landing-page formats.
    • Removed the related known issue.
    • Updated the documented project test count to 8,589.
  • Tests

    • Added comprehensive coverage for landing-page consistency checks and failure scenarios.

docs/index.md is not derived from the landing page: it is written out by
build_index_md() in scripts/build_site.py, which holds the HTML's substance
as a hand-maintained f-string. check_site_assets.py verified it by calling
that generator and comparing the result against the committed file, putting
the generator on both sides of the comparison — so a generator that missed
an edit to the hand-designed HTML produced a committed asset stale in
exactly the same way, and the gate passed. A v0.0.7-era benchmark section
survived every intervening release that way.

check_fact_coherence() extracts the load-bearing facts from each file
independently and fails when they diverge, naming the fact, both values and
both paths. A fact that cannot be located is itself a failure rather than a
silent skip, so a reworded sentence cannot switch its own check off.

Co-Authored-By: Claude <noreply@anthropic.invalid>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ce3128a3-4785-4aa5-940a-bd4f8b074a6e

📥 Commits

Reviewing files that changed from the base of the PR and between cdbe94c and 68c4cd6.

📒 Files selected for processing (4)
  • README.md
  • ROADMAP.md
  • TESTING.md
  • tests/test_build_site.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • aallan/vera-bench (manual)

📝 Walkthrough

Walkthrough

The site asset checker now independently validates shared facts in docs/index.html and docs/index.md. Tests cover mismatches, missing data, malformed content, and internal conflicts. Documentation records the new check and updated test counts.

Changes

Landing-page coherence

Layer / File(s) Summary
Fact extraction and checker integration
scripts/check_site_assets.py
check_fact_coherence() compares benchmark, version, count, results-table, and editor facts. main() fails on coherence or asset errors.
Coherence regression coverage
tests/test_build_site.py, TESTING.md
Tests cover matching pages, fact drift, missing or malformed content, duplicate rows, and conflicting values. Testing documentation records the expanded coverage.
Documentation and reported metrics
CHANGELOG.md, CLAUDE.md, CONTRIBUTING.md, README.md, ROADMAP.md, TESTING.md
Documentation describes the coherence check. Reported counts and coverage figures are updated to 8,589 tests, 8,473 passing tests, and 46 tests covering 698 lines.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Checker as check_site_assets.py
  participant HTML as docs/index.html
  participant Markdown as docs/index.md
  Checker->>HTML: Extract landing-page facts
  Checker->>Markdown: Extract landing-page facts
  Checker->>Checker: Compare facts and report errors
Loading

Possibly related PRs

  • aallan/vera#1153: Updated VeraBench facts that this PR checks across both landing-page formats.
  • aallan/vera#1169: Updated related VeraBench facts in the landing-page documentation.
  • aallan/vera#327: Introduced the related site-asset checking workflow.

Suggested labels: tests, ci, docs

🚥 Pre-merge checks | ✅ 7 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Diagnostics Carry An Error Code ⚠️ Warning The PR adds many coherence error messages and ERROR: outputs in scripts/check_site_assets.py, but the changed lines contain no E### or W### stable code. Assign a stable registered E### code to each new error diagnostic, and use W### for any warning diagnostic.
✅ Passed checks (7 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: gating consistency between docs/index.html and docs/index.md.
Linked Issues check ✅ Passed The changes implement issue #1154 by comparing shared facts, detecting extraction failures, and failing when the HTML and Markdown diverge.
Out of Scope Changes check ✅ Passed The documentation, tests, changelog, issue tracking, and test-count updates support the linked issue and stated implementation.
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%.
Changelog Covers Public-Surface Changes ✅ Passed The complete PR range changes no listed public-surface paths; its new site-check behaviour is explicitly described in the Unreleased Fixed entry.
Spec And Implementation Move Together ✅ Passed The PR diff against origin/main changes no files under vera/ or spec/; it only adds site-coherence checks, tests, and documentation, so no compiler/spec semantic change is unpaired.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1154-site-drift-gate

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

@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.81%. Comparing base (8eb399b) to head (68c4cd6).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1174   +/-   ##
=======================================
  Coverage   93.81%   93.81%           
=======================================
  Files          99       99           
  Lines       33457    33457           
  Branches      458      458           
=======================================
  Hits        31389    31389           
  Misses       2055     2055           
  Partials       13       13           
Flag Coverage Δ
javascript 78.61% <ø> (ø)
python 95.54% <ø> (ø)

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

aallan commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Adversarial review (maintainer-side, pre-CI): clean. Verified against the diff at cdbe94c:

  • The extraction-failure-is-failure contract holds on every path I could construct: missing file, missing/restructured table (both formats), zero rows parsed, reworded prose sentence, duplicate model row, and one file stating a fact two ways all produce a named, pathed error rather than a silent skip.
  • The rows-vs-prose cross-check is the right residual: it covers the half a pure cross-file comparison cannot see (both files agreeing on "nine models" over eight-row tables).
  • Normalization scope is correct — number-words folded, emphasis/markup stripped as presentation, percentages compared as strings, prose wording never compared.

One non-blocking observation: the editor-support check matches names file-wide, so an editor name surviving in unrelated prose (e.g. a historical mention elsewhere on the page) could satisfy the set even if the actual support claim dropped it. That failure mode errs conservative-quiet rather than false-alarm, and tightening it to the claim's sentence would re-introduce wording-fragility, so I think the trade is right as shipped — noting it so the choice is on the record.

Note for whoever merges second: this PR and the in-flight #1111 fix both edit TESTING.md's headline test counts (this one 8,568→8,587, that one →8,578; post-both reality is 8,597) — the trailing rebase reconciles them.

@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: 2

🤖 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 `@tests/test_build_site.py`:
- Around line 633-647: Add tests in tests/test_build_site.py covering both
untested check_fact_coherence failure paths: duplicate the Kimi K3 Markdown row
to exercise _index_rows and assert the error mentions “twice”, the model name,
and the Markdown path; then mutate that row to have an extra cell to exercise
_bench_rows_md and assert the error mentions “cells” and the Markdown path.
- Around line 470-471: Update the version-badge mutation in the test around
_landing_pair and _edit to anchor on the version’s digit pattern rather than the
literal “0.1” prefix. Follow the sibling tests’ _sub-based approach so the
assertion remains valid across releases while still changing the intended
version value.
🪄 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: ab2c097e-4dd1-4cd5-805a-1c1dfb1216da

📥 Commits

Reviewing files that changed from the base of the PR and between 8eb399b and cdbe94c.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • CLAUDE.md
  • CONTRIBUTING.md
  • KNOWN_ISSUES.md
  • README.md
  • ROADMAP.md
  • TESTING.md
  • scripts/check_site_assets.py
  • tests/test_build_site.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • aallan/vera-bench (manual)
💤 Files with no reviewable changes (1)
  • KNOWN_ISSUES.md

Comment thread tests/test_build_site.py Outdated
Comment thread tests/test_build_site.py
…ge mutation

Review round: the duplicate-model-row (_index_rows) and wrong-cell-count
(_bench_rows_md) error paths had no exercising test. Two tests now mutate
the Markdown benchmark table located via the checker's own header regex,
asserting the "twice" / "cells" messages name the row and the file. The
version-badge mutation anchored on a literal "[0.1" prefix that would go
stale at the next minor release; it is digit-anchored via _sub like its
sibling tests. Per-file and headline test counts move 8,587 -> 8,589.

Co-Authored-By: Claude <noreply@anthropic.invalid>
@aallan
aallan merged commit 1bc0618 into main Aug 3, 2026
28 checks passed
@aallan
aallan deleted the fix/1154-site-drift-gate branch August 3, 2026 10:58
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.

docs/index.md silently drifts from docs/index.html — check_site_assets.py compares the generator against itself

1 participant