Skip to content

VERA 2.0: Multi-target, Multi-turn Evaluator - #182

Draft
luca-belli wants to merge 74 commits into
mainfrom
feat/VERA_2.0
Draft

VERA 2.0: Multi-target, Multi-turn Evaluator#182
luca-belli wants to merge 74 commits into
mainfrom
feat/VERA_2.0

Conversation

@luca-belli

Copy link
Copy Markdown
Collaborator

No description provided.

luca-belli and others added 30 commits July 9, 2026 14:56
…gration phasing

- Introduce u/c/j entity vocabulary (user/chatbot/judge), replacing the
  ambiguous p_ prefix and "patient"/"provider" terminology throughout
- Formalize config.json/state.json traceability (immutable config + sha256
  sidecar, mutable resume state) and the orthogonal generation/judging
  config split
- Add use cases 5 (pool) and 6 (resume), resolve open questions from the
  PR thread (multi-folder judge output, multi-rubric layout, folder
  naming, provider-vs-model identifiers)
- Split migration into 4 phases: cosmetic wrapper, scoring split,
  multi-rubric support, substantial refactor
- Remove stale "why async judges are not async?" TODO
… policy

- Phase 1 is no longer "cosmetic" -- it fully replaces the top-level
  scripts with the new CLI/config surface (-u/-j/--sample/--config)
  from day one, using an informal config.json shape until Phase 3
  formalizes it as a stable interface
- Split scoring-split and multi-rubric-support into separate phases
  (5 total); multi-rubric no longer depends on artifacts that don't
  exist until a later phase
- Add per-phase "Done when" acceptance bars, incremental import-linter
  enforcement instead of all-at-once, explicit legacy-output-data and
  rollback stances
- Introduce "stable interfaces" concept: ABCs/Role/naming module/config
  schema require a design doc to change, enforced via new CODEOWNERS
  entries -- codebase is optimized for agent coding, so a small set of
  rarely-changed files get higher scrutiny than the rest
- Phase 0's rubric-loading fix moves to a reusable library helper
  instead of judge.py's soon-to-be-deleted main(), so Phase 1 reuses it
  rather than throwing it away
- Introduce the rubric bundle manifest format (rubric/prompt files +
  informational persona links) -- previews the real judging.rubrics[]
  config shape instead of a throwaway CLI convention
- judging.rubrics is a list from day one at every phase (not just
  Phase 3), closing the same schema-break risk one phase earlier
- vera judge explicitly exposes --rubric in Phase 1's CLI surface
- Phase 1 requires a parity/regression test suite against the scripts
  it replaces, and deletes them outright at phase end (no lingering
  deprecation-stub period, which also removes a MUST-NOT contradiction)
- Phase 4's acceptance bar now also verifies single-rubric backward
  compatibility, not just the new multi-rubric case
- Every phase's Done-when now implicitly covers keeping README/AGENTS
  docs current, stated once instead of per-phase
vera generate drives a multi-turn, non-deterministic LLM conversation --
exact-output parity testing against generate.py isn't meaningful the way
it might be for more structural code, and the non-determinism compounds
turn over turn. Split Phase 1's testing bar into structural parity
(automated, via the existing mock_llm.py harness) and live-LLM manual
spot-checks (explicitly not something pytest can certify), so this
doesn't get silently treated as fully covered by a single test suite.
…ongs

Phase 1 only replaces the CLI front-end -- generate_conversations/judge
internals are untouched, so structural parity testing is sufficient and
the risk is low. Phase 5's workers/ unification is what actually
rewrites the execution engine (both runners move off independent
hand-rolled asyncio queues onto the shared workers/ queue/dispatch),
which is where concurrency/timing regressions could actually appear.
The two-part testing approach (structural parity + manual live-LLM
spot-check) now attaches to Phase 5's Done-when instead.
…nfig

overlap, provider concurrency, ESCALATE governance

- scripts/pool_vera_scores.py's disposition was silently dropped from the
  original 8-phase plan when it collapsed to 6 phases -- checked again
  in Phase 5
- Explicitly acknowledge that the Phase 3 naming-scheme swap breaks
  anything outside vera.py that parses the old p_*/j_* pattern directly
- State the separation of concerns between the rubric bundle manifest
  (what a rubric is) and config.json (how to run it), since they now
  overlap in subject matter
- Flag per-provider concurrency limits as a real Phase 5 requirement --
  workers/ enables genuine parallel fan-out with no cap yet
- Clarify that documenting a phase here does not pre-clear its ESCALATE
  requirement; every phase still needs fresh sign-off before it starts
- generate_conversations/ -> generate/, scoring/ -> score/ (judge/ was
  already consistent) across architecture.md and vera-cli-use-cases.md
- Remove docs/architecture-plan.md (superseded by architecture.md,
  removal was its own stated intent once the target doc was done)
- Remove TODO (its items are now resolved or tracked in the migration
  plan's open items)
…tries

Fixes findings from a code review of PR #170 plus two open Copilot
comments: the naming-module contradiction in docs/architecture.md,
CODEOWNERS entries pointing at nonexistent files, a dead
architecture-invariants.md stub, duplicated/drifted ESCALATE guidance
in AGENTS.md, ambiguous "until migration" phrasing, and the
generate.py/judge.py vs vera.py framing contradiction in README.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tries

Fixes findings from a code review of PR #170 plus two open Copilot
comments: the naming-module contradiction in docs/architecture.md,
CODEOWNERS entries pointing at nonexistent files, duplicated/drifted
ESCALATE guidance in AGENTS.md, ambiguous "until migration" phrasing,
and the generate.py/judge.py vs vera.py framing contradiction in
README.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tion)

New storage/ package with a StorageBackend ABC (write/read/exists on raw
bytes+keys) plus LocalFilesystemStorage as the default -- same
interface-with-implementations idiom already used by llm_clients/ and
workers/, so a future non-local backend (S3) is a new implementation, not
a rewrite. Explicitly orthogonal to phases 0-5: no dependency on, and
nothing depends on it, so it can be pulled earlier or run in parallel if
a concrete need shows up. Also fixed a stale generate_conversations/
reference left in CODEOWNERS from the earlier package rename.
rubric-navigation-in-code, non-developer data/ rationale

- config.json.sha256 is one canonical computation shared by the run-id
  folder name and the sidecar -- never two independent values, and
  never embedded in config.json's own filename
- vera pipeline --target <name> is the one deliberate exception where
  a rubric bundle manifest's personas become authoritative for both
  generation and judging in one shot; every other invocation keeps
  generation/judging orthogonal
- Rubric navigation (which question comes next) is code-owned
  (QuestionNavigator), never inferred by the judge LLM from prompt text
- Rubric/persona content in data/ is explicitly required to stay
  outside code, since CLEO must be usable by non-developers
…on, run nicknames, phase testing

Addresses Emily's 2026-07-25 re-review round and the earlier RFC comments:
add the missing -c/--chatbot selection (CLI, config.json, Domain model),
anchor config.json paths to $ROOT instead of CWD (mirroring the manifest's
own-folder convention), mirror --target into the input config with its
mutual-exclusivity rule, add human-readable run nicknames alongside the
sha, split Phase 5's live-LLM testing into an automated tolerance-based
smoke tier and a qualitative manual tier, clarify that new rubrics only
need Phase 0-4, spell out the design-doc enforcement mechanism (CODEOWNERS
+ CI gate), and note that judge/score still work against old-layout data
via explicit paths even though resume does not.
Fixes two stale/wrong entries (run-id naming lost its nickname segment,
AD-23 overclaimed that old-layout data can't be read at all) and adds
two new ADs the spine was missing entirely: chatbot selection (AD-27)
and config vs. manifest path resolution (AD-28). Extends AD-15 with the
concrete design-doc enforcement mechanism and AD-21 with the target
field now mirrored into config.json, so every prose rule added to
architecture.md and vera-cli-use-cases.md today has a citable AD.
Today's additions (chatbot flag, $ROOT path rule, nicknames, phase
testing split) are still design-stage decisions. Flag both docs as
subject to revision once implementation surfaces things the design
discussion alone couldn't.
Fills the gap between the mechanical live smoke test (did it run, same
shape) and the manual spot-check (does it read well): embed old-engine
vs new-engine conversations for matching (persona, config) pairs and
compare cosine similarity against a calibrated old-vs-old baseline, so
content drift is caught statistically without requiring exact wording
match or relying on manual review alone.
…guity

generation has two competing LLM roles (chatbot, user); a bare "models"
field didn't say which. judging keeps "models" since only one LLM role
exists there, so the name is already unambiguous in that block.
Links to architecture.md from vera-cli-use-cases.md used ../ instead
of ./, since both files live under docs/. Also clarify that -c/-u/-j
in the new CLI intentionally reuse letters that mean something
different in today's generate.py/judge.py, with no coexistence window
since those scripts are deleted in Phase 1.
…de too

Phase 0 previously only wired judge.py's --rubrics flag to the new
bundle-manifest helper, leaving a manifest's personas field completely
unused until Phase 1's vera.py --target shorthand. Since a rubric
bundle manifest is meant to attach a rubric and its intended personas
as one unit, add generate.py --rubric-manifest as Phase 0's stopgap
generation-side counterpart, so the attachment is proven out on both
sides of the pipeline before the CLI unification in Phase 1.
RubricConfig.load_bundle() inlined manifest JSON parsing/validation,
which only judge.py could reach. Per the updated Phase 0 scope in
docs/architecture.md, generate.py needs to read the same manifest's
personas list, so the reading/validation logic moves to utils/ (leaf
layer) instead -- generate/ and judge/ must never import each other.
load_bundle() now delegates to utils.rubric_manifest.load_manifest();
behavior is unchanged, covered by the existing load_bundle tests plus
new direct tests for the extracted module.
load_manifest_personas() returned personas entries verbatim instead of
resolving them relative to the manifest's own folder, contradicting
docs/architecture.md's stated rule for manifest paths (the same rule
rubric_file/etc. already follow via RubricConfig.load()). Update
data/rubric_manifest.json's personas entry to the correct
manifest-relative form ("personas.tsv", not "data/personas.tsv") now
that resolution actually happens, and cover both relative and
absolute-path entries with tests.

Caught while reorganizing data/ into per-rubric subfolders on a
downstream branch -- fixing it here instead, since this PR hasn't
merged yet and is where the bug was introduced.
luca-belli and others added 30 commits July 31, 2026 11:07
--rubrics/--rubric-manifest require a full manifest path; there's no
way to select a rubric by bare name (e.g. typing "SI" anywhere on the
command line) until --target lands on the future vera.py CLI. Also
documents generate.py --rubric-manifest, which wasn't in the README
at all.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…elper

feat: add RubricConfig.load_bundle() for rubric bundle manifests
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
feat: wire --rubrics flag to RubricConfig.load_bundle()
…allback

judge/score_utils.py loaded the rubric at import time from a cwd-relative
path, so importing the module from outside the repo root raised
FileNotFoundError. Resolve it from __file__ instead.

scripts/pool_vera_scores.py's programmatic fallback still pointed at the
pre-move data/personas.tsv. Since the call site guards on is_file(), risk
level analysis silently skipped for callers that did not pass personas_tsv.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…o-si-folder

refactor: move the SI rubric bundle into data/SI/
Add note about including SHA of config files to avoid silent failures.
Refactor: decouple rubric logic from SI structure
fix: preserve scores on final assign end
…ntract

Phase 1. Docs: define unified CLI architecture contract
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