Skip to content

Enforce + backfill diagnostic-field discipline; gate spec_ref validity (#682, #738) - #826

Merged
aallan merged 24 commits into
mainfrom
feat/682-diagnostic-metadata
Jul 1, 2026
Merged

Enforce + backfill diagnostic-field discipline; gate spec_ref validity (#682, #738)#826
aallan merged 24 commits into
mainfrom
feat/682-diagnostic-metadata

Conversation

@aallan

@aallan aallan commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Summary

Enforces and backfills diagnostic-field discipline (#682), folds in the GC-reclamation stress marking (#738), and — folded in during the build-out's adversarial audit — corrects every pre-existing wrong spec_ref under vera/ and adds spec_ref-validity to the gate.

Release-staged as v0.0.188. Version bumped across all six sync points, CHANGELOG [Unreleased] promoted to [0.0.188] with its compare link, and HISTORY opens Stage 16 "The safety net" — so the only post-merge steps are the tag + gh release. The release bundles #682, #738, and the earlier CodeRabbit Pro+ config (#825), all previously sitting in [Unreleased].

The gate — scripts/check_diagnostic_fields.py

New deterministic gate (pre-commit + CI lint, mirroring the #597 walker-coverage gate). It AST-parses every Diagnostic(...) constructor and self._error(...) / self._warning(...) call under vera/ and fails when:

  1. A required field is missingrationale, fix, or spec_ref (spec §0.5.1), or
  2. A spec_ref is present but wrong — it must resolve to a real spec section/chapter with a matching title (e.g. citing §4.3 "Operators" when §4.3 is actually "Slot References").

The exemption surface is explicit and reasoned, never silently inferred (grounded in DESIGN.md §"Explicitness over convenience" — see the design discussion):

  • a warning is not required to carry a fix (no corrected-code template);
  • the codegen _error/_warning helpers (internal-compiler E699 / "function skipped" diagnostics with no user fix or spec section) are exempt via a documented registry in the script;
  • a one-off internal/defensive site carries a # diag-fields-exempt: <reason> marker — a dedicated token, deliberately not # noqa:-prefixed so it cannot collide with ruff's suppression namespace.

Validity title-matching is lenient (case, backticks, parentheticals ignored), so a cosmetic spec re-title doesn't break the gate while a wrong section still fails.

What changed

  • Backfilled 54 under-tagged checker diagnostics (calls/control/expressions/core/resolution) + partial direct Diagnostic(...) in the parser-error factories, tester, monomorphizer, and verifier fallback — each now has a concrete rationale, fix, and spec_ref. The issue's canonical example, vera check on @Bool.0 + @Int.0 (E140), now emits a Fix: paragraph (AC5 — pinned by a test).
  • Corrected 30-plus pre-existing wrong spec_ref citations (all predate this branch) so every spec_ref under vera/ resolves. The wrong refs were surfaced by an adversarial verify pass and confirmed by a deterministic spec-heading validator.
  • Documented typed holes (?) in a new spec/04-expressions.md §4.17 "Typed Holes" — they had no spec section, so W001 and codegen E614 cited a fabricated §3.10. Both now cite §4.17.
  • Mark the TestHostHandleReclamation573 trio as stress tests #738: marked the TestHostHandleReclamation573 GC-reclamation suite stress, deselecting it from the default per-PR pytest run (it runs full reclamation programs at scale, ~minutes locally).
  • Narrowed the interim CodeRabbit check — the advisory "Diagnostics carry full metadata" pre-merge check is reduced to the residual error_code field now that the deterministic gate covers the rest (closing the loop flagged on Enforce diagnostic-tagging discipline: pre-commit hook + backfill of 76 partial sites #682).

Scope notes (deliberately deferred)

Verification

  • pytest5437 passed, 22 skipped, 26 deselected (the now-stress suite); mypy vera/ clean; ruff check . clean.
  • scripts/check_conformance.py, check_examples.py, check_diagnostic_fields.py, check_doc_counts.py, check_site_assets.py, and the doc-example validators all pass.
  • New tests/test_diagnostic_fields.py (23 tests) covers presence detection, the severity rule, the codegen registry, the # diag-fields-exempt opt-out, plumbing-skip, spec_ref validity, and a live-tree integration check; AC5 is pinned in tests/test_checker.py.

Closes #682
Closes #738

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added an automated diagnostic metadata completeness check, validating rationale, fix, and spec_ref, with explicit opt-out support.
  • Bug Fixes
    • Improved many diagnostics with clearer rationale/fix guidance and more consistent spec_ref targets and error-code mappings.
  • Documentation
    • Updated “Typed Holes” guidance and numerous spec cross-references and examples.
  • Chores
    • Wired the validation into CI and pre-commit, added a dedicated test suite, and refreshed release/test documentation.

T and others added 2 commits June 30, 2026 17:14
… mark GC-reclamation suite stress (#738)

Add scripts/check_diagnostic_fields.py — an AST gate (wired into pre-commit +
the CI lint job, mirroring the #597 walker-coverage gate) that fails when any
Diagnostic(...) constructor or self._error/_warning call under vera/ omits
rationale, fix, or spec_ref (spec §0.5.1).  Exemptions are explicit and
reasoned, never silently inferred (DESIGN.md §"Explicitness over convenience"):
a warning needs no fix (no corrected-code template); the codegen internal /
"function skipped" helpers are registry-exempt from fix/spec_ref; and a one-off
defensive site carries a `# diag-fields-exempt: <reason>` marker — a dedicated
token, deliberately not `# noqa:`-prefixed so it cannot collide with ruff's
suppression namespace.

Backfill the 54 under-tagged checker sites (calls/control/expressions/core/
resolution) plus partial direct Diagnostic() constructions in the parser-error
factories, the tester, the monomorphizer, and the verifier's obligation
fallback, with concrete rationale/fix/spec_ref.  `vera check` on @Bool.0 +
@Int.0 (E140) now emits a Fix: paragraph
(test_E140_carries_a_fix_paragraph_682).

#738: mark TestHostHandleReclamation573 (full GC-reclamation programs, ~minutes
locally) with @pytest.mark.stress so it is deselected from the default per-PR
pytest run and runs under `pytest -m stress` / nightly CI.

Scope notes: error_code enforcement, plus a batch of pre-existing spec_ref
section/title drift the build-out's adversarial audit surfaced (30 sites,
none introduced here), are tracked as a follow-up; the interim CodeRabbit
"full metadata" advisory check is narrowed to the residual error_code field.

Not a release (no version bump); CHANGELOG [Unreleased] documents the change.

Co-Authored-By: Claude <noreply@anthropic.invalid>
…f validity (#682)

Fold-in to the diagnostic-field discipline work.  The adversarial audit behind
the gate found 30-plus diagnostics whose spec_ref cited the wrong section or
title — all predate this branch (e.g. every arithmetic/comparison/logical
operator error cited §4.3 "Operators", but §4.3 is "Slot References";
arithmetic is §4.4, comparison §4.5, logical §4.6).  A present-but-wrong
spec_ref is a misleading instruction — worse than a missing one — so:

- Corrected every wrong spec_ref under vera/ (checker, parser-error factories
  in errors.py, codegen, verifier) to resolve to a real spec section/chapter
  with a matching title.
- Documented typed holes (?) in a new spec/04-expressions.md §4.17 "Typed
  Holes" — they had NO spec section at all, so W001 and the codegen E614 cited
  a fabricated §3.10.  Both diagnostics now cite §4.17.
- Extended scripts/check_diagnostic_fields.py to enforce spec_ref VALIDITY:
  every cited section/chapter must exist with a matching title.  Title match is
  lenient (case, backticks, parentheticals ignored) so a cosmetic spec re-title
  doesn't break the gate, while a wrong section (right number, wrong rule) still
  fails.  New TestSpecRefValidity covers it; the live-tree test now asserts
  both presence and validity.
- Synced the E001 canonical example's See-line (now §5.4 "Contract Clauses")
  across README.md, docs/index.html, and spec/00-introduction.md.

Full floor green: pytest (5437 passed), mypy, ruff, conformance, examples, and
every scripts/check_*.py.  CHANGELOG [Unreleased] updated; no version bump.

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

coderabbitai Bot commented Jun 30, 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

Adds a diagnostic-field checker for vera/, wires it into CI and pre-commit, backfills diagnostic metadata and spec_ref text across compiler paths, and updates related tests, specs, docs, and version metadata.

Changes

Diagnostic field enforcement and backfill

Layer / File(s) Summary
Checker script and wiring
scripts/check_diagnostic_fields.py, .github/workflows/ci.yml, .pre-commit-config.yaml, .coderabbit.yaml
Defines the diagnostic-field checker and hooks it into CI, pre-commit, and the CodeRabbit advisory flow.
Checker diagnostics
vera/checker/calls.py, vera/checker/control.py, vera/checker/expressions.py, vera/checker/core.py, vera/checker/registration.py, vera/checker/resolution.py
Updates call, control-flow, expression, core predicate, alias registration, and named-type resolution diagnostics with structured fields, revised spec_ref strings, and a few error-code changes.
Codegen, verifier, tester, and parser diagnostics
vera/codegen/compilability.py, vera/codegen/core.py, vera/codegen/modules.py, vera/codegen/monomorphize.py, vera/verifier.py, vera/tester.py, vera/errors.py, vera/transform.py
Updates diagnostic payloads, spec_ref text, inline exemption comments, and error-code mappings across code generation, verifier, tester, parse-error helpers, and transform wrapping.
Docs, specs, tests, and release metadata
scripts/check_spec_examples.py, tests/test_checker.py, tests/test_codegen.py, tests/test_diagnostic_fields.py, spec/00-introduction.md, spec/02-types.md, spec/04-expressions.md, AGENTS.md, README.md, CHANGELOG.md, ROADMAP.md, TESTING.md, CONTRIBUTING.md, CLAUDE.md, HISTORY.md, pyproject.toml, vera/__init__.py, scripts/build_site.py
Refreshes spec examples, typed-hole documentation, diagnostic-field tests, release notes, roadmap, testing docs, contributing guidance, changelog, site generation text, and version metadata.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

  • #828: The PR adds error-code registration checks and updates ERROR_CODES, which aligns with the issue’s focus on stable error_code usage and collision prevention.

Possibly related PRs

  • aallan/vera#664: Both PRs touch vera/checker/resolution.py’s type-alias arity-mismatch diagnostics, with one changing behaviour and the other updating diagnostic metadata.
  • aallan/vera#665: Both PRs modify the [E132] cyclic type-alias diagnostic in vera/checker/registration.py.
  • aallan/vera#825: Both PRs adjust .coderabbit.yaml advisory checks around diagnostic metadata, with this PR shifting the gate from full metadata to stable error-code presence.

Suggested labels: compiler, tests, spec, ci, docs

🚥 Pre-merge checks | ✅ 6 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.12% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Diagnostics Carry An Error Code ⚠️ Warning vera/codegen/modules.py has two new error diagnostics with no error_code, and vera/codegen/core.py has one more; the stable-code requirement is not met. Add stable E###/W### codes to those diagnostics (or remove them from the changed surface if they are unintended).
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarises the main changes: diagnostic-field enforcement and the stress-test marking work.
Linked Issues check ✅ Passed The PR implements the diagnostic-field gate, backfills diagnostics, adds CI/pre-commit enforcement, and marks the heavy test trio as stress.
Out of Scope Changes check ✅ Passed The extra docs, changelog, version bumps, and spec updates all support the stated diagnostics and stress-test work.
Changelog Covers Public-Surface Changes ✅ Passed CHANGELOG.md’s 0.0.188 entry covers the diagnostics/error-code backfill, typed-hole/spec fixes, and the stress-mark change; no public-surface change is left undocumented.
Spec And Implementation Move Together ✅ Passed PASS: typed holes and alias-cycle rules in spec are matched by checker/codegen (W001/E614) and registration (E132); no other compiler semantics drift found.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/682-diagnostic-metadata

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

@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.85714% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 92.05%. Comparing base (7292f62) to head (b3e1b66).

Files with missing lines Patch % Lines
vera/checker/expressions.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #826      +/-   ##
==========================================
- Coverage   92.05%   92.05%   -0.01%     
==========================================
  Files          89       89              
  Lines       27299    27304       +5     
  Branches      324      324              
==========================================
+ Hits        25131    25134       +3     
- Misses       2160     2162       +2     
  Partials        8        8              
Flag Coverage Δ
javascript 65.58% <ø> (ø)
python 95.05% <92.85%> (-0.01%) ⬇️

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.

Stage the release machinery so v0.0.188 can be tagged + published right after
this PR merges (everything except the tag and `gh release`).

- Version bumped 0.0.187 -> 0.0.188 across pyproject.toml, vera/__init__.py,
  README.md, docs/index.html, and uv.lock (check_version_sync clean across all
  six sync points; `uv lock --check` clean).
- CHANGELOG: [Unreleased] promoted to [0.0.188] - 2026-06-30 with a fresh empty
  [Unreleased] and the compare link reference.
- HISTORY: opens Stage 16 "The safety net" (the soundness campaign wrapped at
  v0.0.187) with the v0.0.188 row.
- Regenerated site assets (docs/llms.txt, llms-full.txt, index.md, index.html).

The release bundles the diagnostic-field discipline gate + spec_ref validity +
backfill (#682), the GC-reclamation stress marking (#738), and the earlier
CodeRabbit Pro+ config (#825) — all previously sitting in [Unreleased].

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

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

🤖 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 `@CHANGELOG.md`:
- Line 23: Update the CHANGELOG entry to match the live CodeRabbit
configuration: the advisory check in .coderabbit.yaml was not retired, it was
narrowed. Reword the sentence around the `#682` diagnostic-metadata gate so it
says the metadata fields were deterministically gated and the interim advisory
check was narrowed to “Diagnostics carry an error code,” rather than claiming it
was retired.

In `@CONTRIBUTING.md`:
- Around line 92-94: The commit-stage hook count is stale and conflicts with the
updated total in the previous sentence. Update the count in the CONTRIBUTING.md
section that introduces the “commit-stage” hooks so it matches the current
number of hooks described by the surrounding text, keeping the wording around
the hook list consistent with the updated 28 commit-stage / 2 push-stage
breakdown.

In `@scripts/check_diagnostic_fields.py`:
- Around line 197-199: The exemption logic in `check_diagnostic_fields` is too
broad because `STRUCTURAL_EXEMPTIONS` is applied for every `(fam, method)` call
site, which lets unrelated codegen diagnostics skip required fields. Tighten the
bypass in the `method is not None` block by keying it to the specific diagnostic
class or error code (for example via a dedicated helper) so only the documented
E699/“function skipped” cases can omit `fix` and `spec_ref`.
- Around line 175-177: The severity extraction in the Diagnostic call handling
is too narrow: in the severity parsing logic that uses sev_kw and severity,
non-literal values like severity=level currently fall back to "error" and can
wrongly trigger fix checks. Update the Diagnostic(...) analysis to explicitly
handle non-constant severity expressions instead of silently defaulting them to
error semantics, or emit a specific violation when the severity cannot be
resolved statically.

In `@TESTING.md`:
- Line 9: The skipped-test counts are inconsistent between the overview table
and the “Skipped tests” section in TESTING.md. Update the TESTING.md content
around the skipped-tests summary so the overview count and the §Skipped tests
prose/tables match: either revert the overview to 20, or add the two new skipped
tests to the existing tables and change the line-143 summary to 22. Use the
existing “Skipped tests” section and its two tables as the source of truth when
reconciling the counts.
🪄 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: 63add640-c8f7-4786-915b-7a0d99c41ade

📥 Commits

Reviewing files that changed from the base of the PR and between 7292f62 and 9b203ed.

⛔ Files ignored due to path filters (1)
  • docs/index.html is excluded by !docs/**
📒 Files selected for processing (29)
  • .coderabbit.yaml
  • .github/workflows/ci.yml
  • .pre-commit-config.yaml
  • CHANGELOG.md
  • CLAUDE.md
  • CONTRIBUTING.md
  • README.md
  • ROADMAP.md
  • TESTING.md
  • scripts/check_diagnostic_fields.py
  • spec/00-introduction.md
  • spec/04-expressions.md
  • tests/test_checker.py
  • tests/test_codegen.py
  • tests/test_diagnostic_fields.py
  • vera/checker/calls.py
  • vera/checker/control.py
  • vera/checker/core.py
  • vera/checker/expressions.py
  • vera/checker/registration.py
  • vera/checker/resolution.py
  • vera/codegen/compilability.py
  • vera/codegen/core.py
  • vera/codegen/modules.py
  • vera/codegen/monomorphize.py
  • vera/errors.py
  • vera/tester.py
  • vera/transform.py
  • vera/verifier.py
🔗 Linked repositories identified

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

  • aallan/vera-bench (manual)

Comment thread CHANGELOG.md Outdated
Comment thread CONTRIBUTING.md Outdated
Comment thread scripts/check_diagnostic_fields.py Outdated
Comment thread scripts/check_diagnostic_fields.py
Comment thread TESTING.md Outdated
T and others added 4 commits June 30, 2026 18:11
Per review: v0.0.188 continues the same no-silent-failures campaign (Tier 0 ->
Tier 1), not a new theme.  #682's spec_ref-validity gate closes a silent-failure
class in the diagnostics layer, #738 is a Tier 1 safety-net item, and Stage 15
already carries non-verifier rows (the --json registries, ch8 conformance).  So
the v0.0.188 row stays in Stage 15.

Co-Authored-By: Claude <noreply@anthropic.invalid>
- CHANGELOG: the interim CodeRabbit check was NARROWED (to "Diagnostics carry an
  error code"), not retired — reword to match the live .coderabbit.yaml.
- CONTRIBUTING: commit-stage hook count 27 -> 28 (stale vs the 30 total / 28
  commit / 2 push breakdown in the preceding sentence).
- check_diagnostic_fields.py: a non-literal `severity=` on a direct
  Diagnostic(...) is now flagged rather than silently defaulting to "error"
  (which would wrongly demand a `fix` of a possibly-warning diagnostic).  New
  test; the live tree has no such site so the gate stays clean.
- TESTING.md: the §Skipped-tests tables were missing ch09_builtin_redefinition
  (the E151 negative from #815, x2 stages) — added the two rows and bumped the
  line-143 summary 20 -> 22 to match the overview's live count.

Not changed (CodeRabbit STRUCTURAL_EXEMPTIONS finding): the exemption is keyed to
the codegen _error/_warning helpers, which have no fix/spec_ref parameters, so
every call through them physically cannot carry those fields (non-codegen
(fam,method) get the empty-set default).  Keying on E699 would wrongly flag the
legitimate E604/E605 "function skipped" warnings that also route through the
param-less helper.

Counts resync'd (now 5,486 tests); site assets regenerated.

Co-Authored-By: Claude <noreply@anthropic.invalid>
Co-Authored-By: Claude <noreply@anthropic.invalid>
A four-dimension adversarial review of the PR (gate soundness, test mutation,
content accuracy, release docs) surfaced these — each independently verified:

- GATE SOUNDNESS (medium): the per-call opt-out was matched by a raw line
  scan, so a diagnostic whose description merely CONTAINED the text
  "# diag-fields-exempt: ..." was silently exempted from all required fields.
  Detection is now comment-aware via tokenize (only a real COMMENT token
  counts). New test pins it.
- CONTENT (medium): vera/codegen/modules.py's undefined-call backstop carried
  a factually-wrong opt-out rationale (claimed the checker's E130 shadows it /
  it is unreachable — but the checker only WARNS, E200, so a check-clean
  program reaches this fatal codegen error). Removed the exemption and gave it
  a real fix + spec_ref (Chapter 8, Section 8.5.1 "Bare Calls", mirroring
  E200), so it is now a fully-tagged user-facing error.
- TEST RIGOR (low x3): mutation testing showed three spec_ref-validity branches
  were green-for-wrong-reason — added negative tests for section-under-wrong-
  chapter, unrecognised-format, and chapter-only-wrong-title.
- CONTENT (low x2): tester.py E700 rationale broadened (a trial failure is an
  ensures violation OR a runtime trap); transform.py opt-out comment corrected
  to E009/E010 (the factory does not emit E008).

Release/docs and the §4.17 typed-hole section were verified clean. Gate clean
(presence + spec_ref validity), 28 gate tests pass, mypy + ruff clean,
test_codegen_modules green. Counts resync'd (5,490 tests).

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

@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 `@scripts/check_diagnostic_fields.py`:
- Around line 147-149: The opt-out check in check_diagnostic_fields.py is too
broad because OPT_OUT is matched as a substring in tok.string, so unrelated
comments can accidentally disable the gate. Update the comment parsing in the
token loop to only honor an explicitly anchored directive using the tok.string
value from tokenize.COMMENT, and keep the rest extraction in the same path so
only the exact opt-out marker is accepted.

In `@vera/codegen/modules.py`:
- Around line 568-585: The diagnostic in the unresolved-call path should be
split based on the qualified flag inside the code generation logic that builds
the Diagnostic in vera/codegen/modules.py. When qualified is true, update the
fix text to refer to the imported module symbol and avoid telling the user to
define the fully qualified name locally, and point spec_ref to the
qualified-call section instead of Chapter 8, Section 8.5.1 "Bare Calls"; keep
the current bare-call wording and reference only for unqualified calls. Use the
existing conditional around display/name in the diagnostic construction to
choose the correct fix/spec_ref.
🪄 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: e037aed5-870b-4805-8589-27c87bb891f1

📥 Commits

Reviewing files that changed from the base of the PR and between fca0dd9 and dc102d3.

📒 Files selected for processing (8)
  • README.md
  • ROADMAP.md
  • TESTING.md
  • scripts/check_diagnostic_fields.py
  • tests/test_diagnostic_fields.py
  • vera/codegen/modules.py
  • vera/tester.py
  • vera/transform.py
🔗 Linked repositories identified

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

  • aallan/vera-bench (manual)

@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: 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 `@scripts/check_diagnostic_fields.py`:
- Around line 147-149: The opt-out check in check_diagnostic_fields.py is too
broad because OPT_OUT is matched as a substring in tok.string, so unrelated
comments can accidentally disable the gate. Update the comment parsing in the
token loop to only honor an explicitly anchored directive using the tok.string
value from tokenize.COMMENT, and keep the rest extraction in the same path so
only the exact opt-out marker is accepted.

In `@vera/codegen/modules.py`:
- Around line 568-585: The diagnostic in the unresolved-call path should be
split based on the qualified flag inside the code generation logic that builds
the Diagnostic in vera/codegen/modules.py. When qualified is true, update the
fix text to refer to the imported module symbol and avoid telling the user to
define the fully qualified name locally, and point spec_ref to the
qualified-call section instead of Chapter 8, Section 8.5.1 "Bare Calls"; keep
the current bare-call wording and reference only for unqualified calls. Use the
existing conditional around display/name in the diagnostic construction to
choose the correct fix/spec_ref.
🪄 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: e037aed5-870b-4805-8589-27c87bb891f1

📥 Commits

Reviewing files that changed from the base of the PR and between fca0dd9 and dc102d3.

📒 Files selected for processing (8)
  • README.md
  • ROADMAP.md
  • TESTING.md
  • scripts/check_diagnostic_fields.py
  • tests/test_diagnostic_fields.py
  • vera/codegen/modules.py
  • vera/tester.py
  • vera/transform.py
🔗 Linked repositories identified

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

  • aallan/vera-bench (manual)
🛑 Comments failed to post (2)
scripts/check_diagnostic_fields.py (1)

147-149: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Anchor the opt-out directive instead of substring-matching it.

if OPT_OUT in tok.string exempts any comment that merely mentions the token, so comments like # not-diag-fields-exempt or explanatory prose can suppress the gate by accident. That turns this into a false-negative path.

Suggested fix
-            if tok.type == tokenize.COMMENT and OPT_OUT in tok.string:
-                rest = tok.string.split(OPT_OUT, 1)[1]
+            if tok.type == tokenize.COMMENT:
+                match = re.match(
+                    rf"\s*#\s*{re.escape(OPT_OUT)}(.*)$",
+                    tok.string,
+                )
+                if not match:
+                    continue
+                rest = match.group(1)
                 out[tok.start[0]] = rest.lstrip(" :").strip()
📝 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.

            if tok.type == tokenize.COMMENT:
                match = re.match(
                    rf"\s*#\s*{re.escape(OPT_OUT)}(.*)$",
                    tok.string,
                )
                if not match:
                    continue
                rest = match.group(1)
                out[tok.start[0]] = rest.lstrip(" :").strip()
🤖 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/check_diagnostic_fields.py` around lines 147 - 149, The opt-out check
in check_diagnostic_fields.py is too broad because OPT_OUT is matched as a
substring in tok.string, so unrelated comments can accidentally disable the
gate. Update the comment parsing in the token loop to only honor an explicitly
anchored directive using the tok.string value from tokenize.COMMENT, and keep
the rest extraction in the same path so only the exact opt-out marker is
accepted.
vera/codegen/modules.py (1)

568-585: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Split the qualified-call branch from the bare-call diagnostic.

When qualified is set, this now tells the user to define 'm::f' locally and cites "Bare Calls". That guidance only fits bare f(...) calls; for m::f(...) it is impossible or misleading. Please branch the fix/spec reference on qualified.

🤖 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/codegen/modules.py` around lines 568 - 585, The diagnostic in the
unresolved-call path should be split based on the qualified flag inside the code
generation logic that builds the Diagnostic in vera/codegen/modules.py. When
qualified is true, update the fix text to refer to the imported module symbol
and avoid telling the user to define the fully qualified name locally, and point
spec_ref to the qualified-call section instead of Chapter 8, Section 8.5.1 "Bare
Calls"; keep the current bare-call wording and reference only for unqualified
calls. Use the existing conditional around display/name in the diagnostic
construction to choose the correct fix/spec_ref.

…agnostic (#682)

Two CodeRabbit findings (inline posting failed on GitHub's side; addressed here):

- scripts/check_diagnostic_fields.py: the per-call opt-out was matched as a
  SUBSTRING of the comment token, so a near-miss (`# diag-fields-exempt-foo`) or
  a mid-comment mention could silently disable the gate.  It is now an ANCHORED
  directive — the comment must BE the marker, or the marker immediately followed
  by ':' or whitespace.  New test (`test_unanchored_marker_does_not_exempt`).
- vera/codegen/modules.py: the undefined-call backstop emitted one fix/spec_ref
  for both call shapes.  Split on the `qualified` flag — a module-qualified call
  (`m::f`) now gets import-oriented fix text + spec_ref §8.5.3 "Module-Qualified
  Calls"; a bare call keeps the define-or-import guidance + §8.5.1 "Bare Calls".

Gate clean (presence + spec_ref validity), 29 gate tests + test_codegen_modules
pass, mypy + ruff clean, counts resync'd (5,491 tests).

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

aallan commented Jun 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Both inline findings (which failed to post inline) are addressed in f53b73c — verified valid against current code, fixed, validated:

1. Opt-out matched as a substring (scripts/check_diagnostic_fields.py). The marker is now an anchored directive: the comment must equal # diag-fields-exempt, or be the marker immediately followed by : or whitespace. A near-miss like # diag-fields-exempt-foo, or a mid-comment mention, no longer disables the gate. Pinned by a new test_unanchored_marker_does_not_exempt (alongside the existing test_marker_inside_a_string_does_not_exempt).

2. Qualified-vs-bare undefined-call diagnostic (vera/codegen/modules.py). The backstop now splits on the qualified flag: a module-qualified call (m::f) gets import-oriented fix text and spec_ref Chapter 8, Section 8.5.3 "Module-Qualified Calls"; a bare call keeps the define-or-import guidance and Chapter 8, Section 8.5.1 "Bare Calls". The description/rationale are shared (they read correctly for both).

Gate clean (presence + spec_ref validity), 29 gate tests + test_codegen_modules green, mypy + ruff clean, doc counts resynced (5,491).

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@aallan Thanks — that addresses both concerns.

The anchored diag-fields-exempt handling in scripts/check_diagnostic_fields.py closes the substring false-positive case cleanly, and the qualified split in vera/codegen/modules.py makes the undefined-call fallback diagnostic spec-accurate for both m::f and bare calls. The added regression coverage and validation results look good.


✏️ Learnings added
Learnt from: aallan
URL: https://github.com/aallan/vera/pull/826

Timestamp: 2026-06-30T18:34:49.635Z
Learning: In `scripts/check_diagnostic_fields.py`, the `diag-fields-exempt` opt-out marker is intentionally anchored: the comment must be exactly `# diag-fields-exempt` or the marker immediately followed by `:` or whitespace. Near-miss substrings such as `# diag-fields-exempt-foo` and mid-comment mentions must not exempt a diagnostic site. This behavior is covered by tests including `test_unanchored_marker_does_not_exempt` and `test_marker_inside_a_string_does_not_exempt`.

Learnt from: aallan
URL: https://github.com/aallan/vera/pull/826

Timestamp: 2026-06-30T18:34:49.635Z
Learning: In `vera/codegen/modules.py`, the undefined-call backstop distinguishes bare and module-qualified calls using the `qualified` flag. Module-qualified calls like `m::f` use import-oriented `fix` text and `spec_ref` `Chapter 8, Section 8.5.3 "Module-Qualified Calls"`, while bare calls keep define-or-import guidance and `spec_ref` `Chapter 8, Section 8.5.1 "Bare Calls"`. The description and rationale are shared across both cases.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@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

Caution

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

⚠️ Outside diff range comments (3)
TESTING.md (1)

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

These hook descriptions overstate the gate.

check_diagnostic_fields.py intentionally does not require fix on warning diagnostics, but both entries still describe the rule as unconditional rationale/fix/spec_ref. That will send contributors looking for missing fixes on valid _warning(...) sites. Please mirror the warning exemption here as well.

Also applies to: 651-651

🤖 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 `@TESTING.md` at line 552, The hook description for check_diagnostic_fields.py
overstates the requirement by implying every diagnostic must include
rationale/fix/spec_ref, but warning diagnostics are exempt from needing fix.
Update the relevant TESTING.md entries so they explicitly mention the warning
exception, matching the actual behavior of check_diagnostic_fields.py and
avoiding confusion around valid _warning(...) diagnostics.
scripts/check_diagnostic_fields.py (2)

273-294: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Cache the spec by directory, not globally.

_load_spec() memoises the first spec_dir for the whole process. A later call with a different directory will validate against the wrong chapter/section map and produce false passes or failures. Because spec_ref_violations_in_source(..., spec_dir=...) already exposes directory injection, the cache needs to be keyed by the resolved path, or bypassed for non-default dirs.

🤖 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/check_diagnostic_fields.py` around lines 273 - 294, The _load_spec()
cache is currently shared across all spec_dir inputs, so later calls can reuse
the wrong section/chapter map. Update _load_spec() to cache per resolved spec
directory (or skip caching when a non-default directory is passed) so
spec_ref_violations_in_source(..., spec_dir=...) always validates against the
correct files. Use the existing _spec_cache handling in _load_spec(), and make
the cache key include the spec_dir identity.

325-355: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Non-literal spec_ref still slips past the validator.

spec_ref_violations_in_source() only checks refs yielded as literal strings, so self._error(..., spec_ref=COMMON_REF) satisfies the presence gate but bypasses the section/title resolver entirely. That undercuts the main guarantee this script is meant to enforce. Please reject non-literal spec_ref values explicitly, the same way non-literal severity= is now rejected for direct Diagnostic(...) calls, and add a regression test for it.

🤖 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/check_diagnostic_fields.py` around lines 325 - 355, The validator in
spec_ref_violations_in_source only resolves literal spec_ref strings, so
non-literal values can still pass the presence check and skip chapter/section
validation. Update the spec_ref handling to explicitly reject
dynamic/non-literal spec_ref arguments in the same way severity is rejected for
direct Diagnostic(...) calls, using the existing _iter_spec_refs and
spec_ref_violations_in_source flow to flag them as violations. Add a regression
test covering a call like self._error(..., spec_ref=COMMON_REF) to ensure it is
reported.
🤖 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 `@scripts/check_diagnostic_fields.py`:
- Around line 154-157: The opt-out parsing in check_diagnostic_fields.py only
matches a literal space after OPT_OUT, so valid anchored comments using other
whitespace like tabs are missed. Update the parsing branch around the OPT_OUT
handling to accept any whitespace by checking the first suffix character with
isspace() instead of comparing only to " ", and keep the existing stripping
behavior when populating out[tok.start[0]]. Add a regression test covering a
tab-separated opt-out comment to verify the helper accepts it.

In `@tests/test_diagnostic_fields.py`:
- Around line 232-243: The `test_unanchored_marker_does_not_exempt` coverage
only checks the suffix near-miss and misses the mid-comment anchoring
regression. Extend this test in `test_diagnostic_fields.py` by adding a second
assertion against `mod.check_source(...)` for a comment like `# note
diag-fields-exempt later`, and verify it still reports one violation with
missing fields `rationale`, `fix`, and `spec_ref`; this will lock down the
`_optout_lines()` anchoring behavior.

---

Outside diff comments:
In `@scripts/check_diagnostic_fields.py`:
- Around line 273-294: The _load_spec() cache is currently shared across all
spec_dir inputs, so later calls can reuse the wrong section/chapter map. Update
_load_spec() to cache per resolved spec directory (or skip caching when a
non-default directory is passed) so spec_ref_violations_in_source(...,
spec_dir=...) always validates against the correct files. Use the existing
_spec_cache handling in _load_spec(), and make the cache key include the
spec_dir identity.
- Around line 325-355: The validator in spec_ref_violations_in_source only
resolves literal spec_ref strings, so non-literal values can still pass the
presence check and skip chapter/section validation. Update the spec_ref handling
to explicitly reject dynamic/non-literal spec_ref arguments in the same way
severity is rejected for direct Diagnostic(...) calls, using the existing
_iter_spec_refs and spec_ref_violations_in_source flow to flag them as
violations. Add a regression test covering a call like self._error(...,
spec_ref=COMMON_REF) to ensure it is reported.

In `@TESTING.md`:
- Line 552: The hook description for check_diagnostic_fields.py overstates the
requirement by implying every diagnostic must include rationale/fix/spec_ref,
but warning diagnostics are exempt from needing fix. Update the relevant
TESTING.md entries so they explicitly mention the warning exception, matching
the actual behavior of check_diagnostic_fields.py and avoiding confusion around
valid _warning(...) diagnostics.
🪄 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: 4a9580a2-a9ab-467e-bfc5-3b28097f8707

📥 Commits

Reviewing files that changed from the base of the PR and between dc102d3 and f53b73c.

📒 Files selected for processing (6)
  • README.md
  • ROADMAP.md
  • TESTING.md
  • scripts/check_diagnostic_fields.py
  • tests/test_diagnostic_fields.py
  • vera/codegen/modules.py
🔗 Linked repositories identified

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

  • aallan/vera-bench (manual)

Comment thread scripts/check_diagnostic_fields.py
Comment thread tests/test_diagnostic_fields.py
…on-literal spec_ref (#682)

CodeRabbit round (2 inline + 3 outside-diff), all verified valid against
current code:

- scripts/check_diagnostic_fields.py opt-out boundary: accept ANY whitespace
  after the marker (tab, not only a literal space) via isspace(), keeping the
  existing reason-stripping.  New load-bearing test (bare-tab boundary, no
  colon — exercises the whitespace path, not the `OPT_OUT + ":"` path).
- test_unanchored_marker_does_not_exempt: add the mid-comment case
  (`# note diag-fields-exempt later`) alongside the suffix near-miss, locking
  down the anchoring of _optout_lines().
- _load_spec: cache per RESOLVED spec_dir (dict keyed by path), not a single
  shared global — a later call with a different spec_dir (e.g. a test fixture)
  no longer reuses another directory's section/chapter map.  New test.
- spec_ref validity: a NON-literal spec_ref (variable / f-string) passed the
  presence check but skipped validation entirely.  _iter_spec_refs now also
  surfaces non-literal spec_refs (and gains the same plumbing-skip as
  check_source so the _error/_warning helper constructions aren't flagged);
  spec_ref_violations_in_source flags them — mirroring the non-literal-severity
  rule.  This immediately caught codegen/modules.py:_emit_cross_module_error,
  whose last-round qualified/bare split made spec_ref a branched variable that
  was never validated; reworked to emit each branch with a LITERAL spec_ref, so
  the gate now validates both §8.5.1 "Bare Calls" and §8.5.3 "Module-Qualified
  Calls".  New tests (flagged + plumbing-skipped).
- TESTING.md: hook description noted the warning `fix` exception (warnings are
  exempt from carrying a fix).

All 4 new tests mutation-validated (RED against the pre-fix behavior).  Gate
clean, 66 tests pass (test_diagnostic_fields + test_codegen_modules), mypy +
ruff clean, counts resync'd (5,495 tests).

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

aallan commented Jun 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai All five findings (2 inline + 3 outside-diff) verified valid against current code and fixed in 04191ca — replying here since inline posting failed:

1. Opt-out boundary only matched a literal space (check_diagnostic_fields.py). The boundary check now accepts any whitespace after the marker via isspace() (tab as well as space), keeping the existing reason-stripping. Added a load-bearing test using a bare tab boundary (no colon — so it exercises the whitespace path, not the OPT_OUT + ":" path).

2. test_unanchored_marker_does_not_exempt missed the mid-comment case. Extended it with # note diag-fields-exempt later alongside the suffix near-miss — both must still report one violation. Locks down _optout_lines() anchoring.

3. _load_spec() cache shared across all spec_dir inputs. Now a dict keyed by the resolved spec_dir, so a later call with a different directory validates against the correct files. New test (test_cache_is_per_spec_dir) — RED against the old shared global.

4. Non-literal spec_ref passed presence but skipped validation. _iter_spec_refs now also surfaces non-literal spec_refs (and gained the same plumbing-skip as check_source, so the _error/_warning helper constructions aren't flagged); spec_ref_violations_in_source flags them — mirroring the non-literal-severity rule. This immediately caught codegen/modules.py:_emit_cross_module_error, whose last-round qualified/bare split had made spec_ref a branched variable that was never validated. Reworked to emit each branch with a literal spec_ref, so the gate now validates both §8.5.1 "Bare Calls" and §8.5.3 "Module-Qualified Calls". New tests (flagged + plumbing-skipped).

5. TESTING.md hook description overstated the requirement. Updated both rows to note errors carry rationale + spec_ref + fix while warnings are exempt from fix.

All 4 new tests mutation-validated (each RED against the pre-fix behavior). Gate clean, 66 tests pass, mypy + ruff clean, counts resync'ed (5,495).

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@aallan Thanks — that addresses the follow-ups cleanly.

The fixes all line up with the underlying correctness concerns:

  • accepting any whitespace after # diag-fields-exempt closes the tab-boundary hole without weakening the anchor
  • extending test_unanchored_marker_does_not_exempt to cover the mid-comment case locks down _optout_lines() more completely
  • keying _load_spec() by resolved spec_dir fixes the cross-directory cache contamination bug
  • flagging non-literal spec_ref values, while preserving the helper-plumbing skip, makes the validation rule consistent with the existing non-literal-severity handling
  • reverting vera/codegen/modules.py to branch-local literal spec_ref values is the right way to keep the qualified/bare split and still let the gate validate both refs

The mutation-tested regressions and clean validation run are exactly what I wanted to see.


✏️ Learnings added
Learnt from: aallan
URL: https://github.com/aallan/vera/pull/826

Timestamp: 2026-06-30T18:59:38.212Z
Learning: In `scripts/check_diagnostic_fields.py`, the `# diag-fields-exempt` directive boundary should accept any following whitespace via `isspace()`, not only a literal space. This is covered by a load-bearing regression test that uses a bare tab boundary without a colon.

Learnt from: aallan
URL: https://github.com/aallan/vera/pull/826

Timestamp: 2026-06-30T18:59:38.212Z
Learning: In `scripts/check_diagnostic_fields.py`, `_load_spec()` must cache spec data per resolved `spec_dir` rather than using a single shared cache entry, so validation against different specification directories does not reuse stale chapter/section data. This behavior is covered by `test_cache_is_per_spec_dir`.

Learnt from: aallan
URL: https://github.com/aallan/vera/pull/826

Timestamp: 2026-06-30T18:59:38.212Z
Learning: In `scripts/check_diagnostic_fields.py`, non-literal `spec_ref` values must be surfaced and reported as validation violations, mirroring the checker's treatment of non-literal `severity` values. The `spec_ref` scan should also apply the same plumbing skip used by `check_source`, so `Diagnostic(...)` constructions inside `_error`/`_warning` helper definitions are not flagged.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@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 `@TESTING.md`:
- Line 552: Update the remaining TESTING.md summaries so they reflect the newly
added check_diagnostic_fields.py gate: revise the validation-scripts intro that
still says “Twenty-one scripts” and update the CI Pipeline lint-job row to
include this check. Keep the affected summary sections consistent with the
current workflow and use the existing TESTING.md section headings and script/job
names to locate the stale text.
🪄 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: 52c37cd7-7f6b-455b-a031-a05f3099d3ea

📥 Commits

Reviewing files that changed from the base of the PR and between f53b73c and 04191ca.

📒 Files selected for processing (6)
  • README.md
  • ROADMAP.md
  • TESTING.md
  • scripts/check_diagnostic_fields.py
  • tests/test_diagnostic_fields.py
  • vera/codegen/modules.py
🔗 Linked repositories identified

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

  • aallan/vera-bench (manual)

Comment thread TESTING.md Outdated
…STING.md summaries (#682)

CodeRabbit (inline, TESTING.md:552): adding the gate to the validation-scripts
table left two summaries stale — the intro count ("Twenty-one" → "Twenty-two",
one validator added) and the CI Pipeline lint-job row (omitted the gate though
ci.yml runs it). Both updated; gate listed in ci.yml execution order.

Co-Authored-By: Claude <noreply@anthropic.invalid>
…ip test load-bearing (#682)

Adversarial multi-agent review of the round-3 diff surfaced three confirmed
findings; two fixed here, one deferred to #827.

- spec_ref validity only checked the FIRST citation: `_REF_SEC.search(ref)` ran
  once, so a wrong/bogus SECOND citation in a multi-section ref (5 such refs are
  live in verifier.py, e.g. `§4.7 "Let Bindings" and §11.2.1 "Nat as i64"`)
  shipped silently — the exact misleading-instruction failure the gate exists to
  prevent. Now iterates `finditer` over EVERY citation, and rejects stray
  non-citation text around the citations (a `LIES ` prefix that `.search()` had
  tolerated). Gate stays green on the live tree, confirming all 5 refs' second
  citations resolve. Tests: valid multi-section passes, wrong-second flagged,
  garbage-prefix rejected.

- test_plumbing_non_literal_spec_ref_skipped was green-before-AND-after: the
  helper-skip and the non-literal-flagging shipped together and masked each
  other, so the test never went RED against the real prior baseline. Reworked to
  assert on a LITERAL-but-invalid spec_ref inside the helper, so it goes RED via
  the literal validity path whenever the skip is removed — independent of the
  non-literal code. Renamed test_plumbing_spec_ref_skipped; keeps the threaded
  case as a second assertion.

All three new/changed tests mutation-validated (RED against the pre-fix gate).
The third finding — the name-based plumbing-skip is broader than the helper's own
construction (a stray/second Diagnostic in a helper escapes both passes; latent,
no live escape) — is deferred to #827 (decision-bearing fix, separable).

Gate clean, 36 tests pass, mypy + ruff clean, counts resync'd (5,498).

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

aallan commented Jun 30, 2026

Copy link
Copy Markdown
Owner Author

Adversarial multi-agent review of the gate diff (5 lenses × default-refute verification) — recorded for the trail.

8 candidate findings raised, 3 confirmed real (all high-confidence, severity minor), 5 refuted. Acted on in 721b5cb:

  1. spec_ref validity only checked the FIRST citation of a multi-section ref. 5 live refs in verifier.py cite two sections (e.g. §4.7 "Let Bindings" and §11.2.1 "Nat as i64"); a wrong/bogus second citation shipped silently — the exact misleading-instruction failure the gate prevents. Now iterates every citation via finditer and rejects stray non-citation text. Gate stays green on the live tree (all 5 refs' second citations resolve). +3 tests.
  2. test_plumbing_non_literal_spec_ref_skipped was green-before-and-after — the helper-skip and the non-literal-flag co-shipped and masked each other, so the test never went RED against the real prior baseline ("green both before and after" trap). Reworked to assert on a literal-but-invalid spec_ref so it's RED via the literal path whenever the skip is removed, independent of the non-literal code.
  3. Deferred → #827: the plumbing-skip keys on function name, so a stray/second Diagnostic in an _error/_warning helper (or a coincidentally-named non-helper) escapes both passes. Latent (no live escape); the fix is decision-bearing (how to structurally identify the plumbing ctor), so separable. Tracked in ROADMAP Tier 1.

All 3 new/changed tests mutation-validated (RED against the pre-fix gate).

@aallan

aallan commented Jun 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@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 `@vera/checker/calls.py`:
- Around line 618-630: Update the E220 diagnostic in calls.py where Calls._error
reports “Unresolved qualified call” so its spec_ref points to Chapter 7, Section
7.4 instead of 7.4.1. This warning is about unresolved effect-operation lookup,
so keep the existing message, rationale, and fix text, but change the spec
reference on the same _error call to the correct subsection for effect
operations.

In `@vera/checker/registration.py`:
- Line 211: The E132 spec_ref in registration should reference the alias-cycle
rule instead of the generic type-alias resolution section. Update the value used
in the registration logic around the spec_ref assignment so it points to the
rule that explicitly forbids cyclic aliases, or, if that rule does not exist
yet, add/extend the spec section to cover alias cycles and reference that from
the checker.
🪄 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: da916d50-d42f-4eff-9fca-6bb5b2beda4a

📥 Commits

Reviewing files that changed from the base of the PR and between 7292f62 and 721b5cb.

⛔ Files ignored due to path filters (5)
  • docs/index.html is excluded by !docs/**
  • docs/index.md is excluded by !docs/**
  • docs/llms-full.txt is excluded by !docs/**
  • docs/llms.txt is excluded by !docs/**
  • uv.lock is excluded by !**/*.lock, !uv.lock
📒 Files selected for processing (32)
  • .coderabbit.yaml
  • .github/workflows/ci.yml
  • .pre-commit-config.yaml
  • CHANGELOG.md
  • CLAUDE.md
  • CONTRIBUTING.md
  • HISTORY.md
  • README.md
  • ROADMAP.md
  • TESTING.md
  • pyproject.toml
  • scripts/check_diagnostic_fields.py
  • spec/00-introduction.md
  • spec/04-expressions.md
  • tests/test_checker.py
  • tests/test_codegen.py
  • tests/test_diagnostic_fields.py
  • vera/__init__.py
  • vera/checker/calls.py
  • vera/checker/control.py
  • vera/checker/core.py
  • vera/checker/expressions.py
  • vera/checker/registration.py
  • vera/checker/resolution.py
  • vera/codegen/compilability.py
  • vera/codegen/core.py
  • vera/codegen/modules.py
  • vera/codegen/monomorphize.py
  • vera/errors.py
  • vera/tester.py
  • vera/transform.py
  • vera/verifier.py
🔗 Linked repositories identified

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

  • aallan/vera-bench (manual)

Comment thread vera/checker/calls.py
Comment thread vera/checker/registration.py Outdated
T and others added 2 commits June 30, 2026 20:38
#827 is a latent, minor refinement to a CI lint gate (no live escape,
developer-facing), not runtime/user-facing safety-net work — so it belongs in
Tier 3 (polish), not Tier 1.

Co-Authored-By: Claude <noreply@anthropic.invalid>
…ly-correct sections (#682)

Two CodeRabbit findings — both cited a real section (so the validity gate passed
them) that is semantically wrong for the error:

- E220 "Unresolved qualified call" fires when `Effect.op` resolves to NO effect
  operation, but cited §7.4.1 "Ambiguous Operations" (the multi-MATCH case).
  Repointed to §7.4 "Performing Effects", which states the resolution rule the
  unresolved call violates.
- E132 (type-alias cycle) cited §3.8 "Type Alias and Reference Resolution" —
  which is actually the slot-NAMESPACE rule (`@PosInt.0` vs `@Int.0`), unrelated
  to cycles. The rule E132 enforces ("an alias must resolve to a concrete type;
  the alias chain must be acyclic") had no spec home, so a sentence stating it
  was added to spec/02-types.md §2.6.3 "Type Aliases with Refinements", which
  E132 now cites.

Gate clean (both refs resolve), spec examples pass, 622 checker/errors tests
pass, E132/E220 confirmed firing with the corrected refs via `vera check --json`.

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

aallan commented Jun 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

T and others added 3 commits June 30, 2026 23:39
… the gate (#682, #828)

Closes the cheap deterministic half of the error_code-collision gap surfaced this
PR. check_diagnostic_fields.py now verifies every LITERAL error_code on a
diagnostic under vera/ is registered in vera/errors.py ERROR_CODES (AST-extracted
from the registry), catching typos / unregistered codes. Plumbing (helper-def
Diagnostic constructions) and non-literal (threaded) codes are skipped — they
can't be checked statically.

This does NOT detect collisions (one registered code reused for two unrelated
concepts) — the four found this PR were all *registered*, just reused. The
semantic collision-detection gate + making ERROR_CODES the single home of each
code's concept (the proper fix) + error_code presence enforcement are tracked in
#828 (ROADMAP Tier 2).

+5 tests (unregistered flagged, registered passes, non-literal skipped, plumbing
skipped, _load_error_codes reads the live registry); the membership check is
mutation-validated; the live-tree integration test now also runs the new pass.
Gate clean, mypy + ruff clean, counts synced (5,505).

Co-Authored-By: Claude <noreply@anthropic.invalid>
CodeRabbit (errors.py:208 review of 26d13aa): AGENTS.md's embedded E001 example
JSON cited 'Chapter 5, Section 5.1 "Function Structure"' — doubly stale (§5.1 is
"Overview"; "Function Structure" is not a real title), and now inconsistent with
the repointed E001 diagnostic. Updated to 'Chapter 5, Section 5.2 "Function
Declaration Syntax"', matching errors.py + the README/docs/spec mirrors. (This is
a 5th E001 mirror not covered by TestErrorDisplaySync, which guards only
README/docs/index.html/spec/00 — noted in #828.)

Co-Authored-By: Claude <noreply@anthropic.invalid>
…682)

Root of the docs/index.md drift CodeRabbit flagged: scripts/build_site.py hard-
codes the E001 example with 'See: Chapter 5, Section 5.1 "Function Structure"'
(stale — §5.1 is "Overview"). Updated to §5.2 "Function Declaration Syntax" and
regenerated docs/. This was the 6th and last E001 spec_ref mirror; all now agree
with errors.py. (Only README/docs/index.html/spec/00 are guarded by
TestErrorDisplaySync; AGENTS.md and this generator were not — noted in #828.)

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

aallan commented Jun 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

…-filtering in the spec-example harness (#682)

CodeRabbit (spec/04-expressions.md §4.17): the Typed Holes section introduced `?`
with no code example. Added a canonical block — `@Int.0 + ?` in a real function —
showing the hole is inferred to type @int, type-checks with W001, and is rejected
at compile with E614.

Making that example pass check_spec_examples.py surfaced a harness bug: its check
AND verify stages treated warning-severity diagnostics as failures (`if errors:`
on the typecheck result), unlike the CLI `vera check` (exits 0 on warnings) and
unlike the verify stage's own error-only filter one line later. Both stages now
filter to error severity, so a legitimately-checkable warning-emitting example is
validated rather than mis-failed. No ripple — the baseline had no warning-emitting
spec blocks, so the §4.17 hole example is the sole (and self-testing) case.

check_spec_examples clean (89 checked, 76 check-OK, 75 verify-OK, 0 failures),
mypy + ruff + changelog + doc-count + site-asset gates pass.

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

aallan commented Jul 1, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai The outside-diff §4.17 Typed Holes finding (spec/04-expressions.md) is now addressed in f0abcc9 — thanks for the nudge; I had handled the inline comment in that review but missed this outside-diff item bundled in the same review body. Added a worked example (@Int.0 + ?) showing the hole is inferred to type @Int, type-checks with W001, and is compile-rejected with E614. Making it validate also surfaced a real harness bug: scripts/check_spec_examples.py's check and verify stages treated warning-severity diagnostics as failures (unlike the CLI vera check, and unlike the verify stage's own error-only filter one line later) — both now filter to error severity.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "--- spec/04-expressions.md typed holes section ---"
rg -n "4.17|Typed Holes|`@Int.0` \+ \?|W001|E614" spec/04-expressions.md
echo "--- check_spec_examples.py severity filters ---"
rg -n "severity" scripts/check_spec_examples.py

Length of output: 1148


@aallan Confirmed in f0abcc9 — the §4.17 worked example (@Int.0 + ?) now demonstrates the W001/E614 lifecycle exactly as described, and both the check-stage and verify-stage filters in scripts/check_spec_examples.py (lines 365 and 390) now consistently filter to d.severity == "error", matching the verify stage's pre-existing error-only filter at line 386 and the real CLI behaviour. Good catch on the harness bug — that's a legitimate correctness fix beyond the original scope item, since a warning-only example would previously have been misreported as a failing check/verify.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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 `@spec/04-expressions.md`:
- Around line 433-441: The fenced example in the spec is missing a language tag,
so update the code block in the documented expression example to use the
established Vera syntax highlighting tag. Locate the example around the scale
function snippet in the expressions spec and change the opening fence to the
appropriate language identifier, keeping the rest of the example 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: 46bb8c51-b279-4acb-bca6-612b45ed7ce1

📥 Commits

Reviewing files that changed from the base of the PR and between ecab3c2 and f0abcc9.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • scripts/check_spec_examples.py
  • spec/04-expressions.md
🔗 Linked repositories identified

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

  • aallan/vera-bench (manual)

Comment thread spec/04-expressions.md Outdated
CodeRabbit re-raised the missing language tag. Reversing my earlier decline:
verified 'vera' is not in check_spec_examples.py's skip_langs, so the tagged
block stays fully validated (parse + check + verify — confirmed lang=vera,
is_parseable=True, check=OK), and vera-tagged fences are an established spec
convention (spec/09). Tagging satisfies MD040 + syntax highlighting with no
loss of validation. check_spec_examples clean (Check OK 76, 0 failures).

Co-Authored-By: Claude <noreply@anthropic.invalid>
@aallan
aallan merged commit 802b9f8 into main Jul 1, 2026
28 checks passed
@aallan
aallan deleted the feat/682-diagnostic-metadata branch July 1, 2026 07: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.

Mark the TestHostHandleReclamation573 trio as stress tests Enforce diagnostic-tagging discipline: pre-commit hook + backfill of 76 partial sites

1 participant