design: pro-627 add ADR and design doc for module evaluation framework - #1580
Conversation
PR ReviewWell-structured ADR + design for a ports-and-adapters eval framework. Clean separation of concerns, explicit risk flagging, and thorough rollout sequencing. 🟡 TRY: Split Wave 3 per stage Each stage migration is independently testable and reviewable. Bundling all four risks a large, hard-to-review PR. Recommend: 🔵 CONSIDER: Four independent stage-name lists The design correctly flags that 🔵 CONSIDER:
⚪️ NIT: Unconditional The CLI |
|
Claude finished @georgia-i-ai's task in 1m 9s —— View job PR Review
|
Will consider this, definitely don't like the current multiple places to update so need find a better solution. |
Claude originally suggested breaking down, I prefer to add a single issue for this with a note that this should be broken down if needed. I feel like a lot of the changes will be similar and these scripts will become quite simple so should be possible to do in one go. |
Nazehs
left a comment
There was a problem hiding this comment.
LGTM! in my opinion I think this would have been much better excluding the code snippets reason been that the implementation might choose to name the methods, classes or variables differently which might then drift from what is captured here.
Sure, that's a fair point. The snippets are only included as a guide and not meant to be prescriptive, but I can remove if you think it comes across this way.
|
|
|
Claude finished @georgia-i-ai's task in 56s —— View job PR Review
Solid design. The ports-and-adapters cut is clean, the explicit risk flagging on ⚪️ NIT: Three code snippets remain ( 🔵 CONSIDER: |
|
Claude finished @georgia-i-ai's task in 24s —— View job PR Review
Clean update. The ⚪️ NIT: Three code snippets remain — 🔵 CONSIDER: |
|
Claude finished @georgia-i-ai's task in 49s —— View job PR Review
Clean, well-sequenced design. Ports-and-adapters cut is sharp, the independent dataset/artefact selection is a real improvement, and the explicit confidence flag on Two open items from prior reviews still unaddressed: ⚪️ NIT: Three code snippets remain ( 🔵 CONSIDER: |
This is fine to resolve at implementation. |
|
Claude finished @georgia-i-ai's task in 1m 15s —— View job PR Review
Clean update. All three previously flagged code snippets ( 🔵 CONSIDER: |
Fine to resolve at implementation time. |
5e3be42 to
7df5984
Compare
|
Claude finished @georgia-i-ai's task in 55s —— View job PR Review
|
docs/architecture/design: add new folder containing a detailed design for the eval framework
PRO-627
7df5984 to
5998d64
Compare
|
Claude finished @georgia-i-ai's task in 24s —— View job PR Review
Clean final state. Both documents are prose-only, the ports-and-adapters design is sharp, and swappability is proven rather than assumed. No new issues. Ready to merge. |

Context
themefinder/evals/currently hard-wires its execution engine to its artefact store: each of the fourstage eval scripts (
eval_generation.py,eval_mapping.py,eval_condensation.py,eval_refinement.py)hand-writes its own Langfuse-vs-local branch, duplicating most of its logic across both paths — and mapping
is the one stage where those two paths don't even agree on scoring. This PR is the ADR + detailed design for
fixing that: a ports-and-adapters layer that makes pydantic-evals the execution engine and Langfuse purely a
(swappable) dataset/artefact store, proven by a genuine swappability test rather than assumed.
No code changes here — this is ADR-0013 plus its accompanying design doc. Implementation is intentionally
sequenced as a separate, already-scoped rollout (8 issues across 5 waves, see the design doc's "Rollout
sequencing"), so this PR is reviewable as a design decision on its own.
Decisions taking during the design:
os.getenv()reads acrossevals/into oneevals/settings.py, deletingevals/metrics.pyoutright (mapping's local scoring movesonto the same evaluator the Langfuse path already uses — a disclosed behaviour change), and adding a DVC
pipeline (
dvc.yaml) as a fourth way to run evals, for dependency-aware caching and experiment tracking.benchmark.pyandgenerate_synthetic.pyare deliberately left still coupled to Langfuse for this pass —but the minimal follow-up changes to de-couple each are already scoped in the design doc, not just a TODO.
Changes proposed in this pull request
docs/architecture/decisions/0013-modular-evaluation-framework-for-themefinder.md— the ADR: decision andconsequences.
docs/architecture/design/modular-evaluation-framework.md— the detailed design: directory layout, thefour ports (
DatasetPort,EvaluatorPort,EvalRunnerPort,ArtefactStorePort, each an explicitabc.ABC) and their adapters,evals/settings.py, the DVC pipeline design, and the issue-by-issue rolloutplan.
Guidance to review
Start with the ADR, and design is detailed but seemed worth including fully rather than shortening.
Worth focusing on:
EvaluatorPortbeing implemented directly by each kindof evaluator (custom, pydantic-evals-native, later DeepEval) rather than through a generic wrapper is the
right call.
resolve_backends()— lets a run pull casesfrom Langfuse while storing results locally, or the reverse, rather than one bundled "Langfuse configured"
decision.
pydantic_evals.evaluators.EvaluatorContextcanbe constructed standalone outside
Dataset.evaluate()'s own loop, whichPydanticEvalsLLMJudgeAdapterdepends on — flagged as a spike to do first, not assumed.
bundled into one issue) is the right granularity, or should split per stage.