Parent epic: #929
Design proposal: PR #1080
Phase: 1 (Wave 3 — start after 1.A merges)
Depends on: 1.A
Independent of: 1.C, 1.D, 2.1 (all run in parallel in Wave 3)
Problem
mellea/stdlib/components/intrinsic/rag.py contains six helpers in one file: check_answerability, rewrite_question, clarify_query, find_citations, check_context_relevance, flag_hallucinated_content. All construct via IntrinsicAdapter(...) (a deprecation shim after 1.A). Signatures do not consistently accept model_options=. None has output validation — schema drift from upstream _RAG_REPO weights silently changes behaviour.
Per-helper PRs would all touch the same file and serialise behind one another. One PR migrates the whole file.
Agreed design
Follows the per-helper-file migration template from PR #1080:
- Migrate construction — replace
IntrinsicAdapter(...) with Adapter(identity=..., io_contract=..., weights=...)
- Normalise signature — add
model_options: dict | None = None as keyword argument to every helper
- Add output validation — declare each helper's expected output contract; wire
io_contract.parse() to raise AdapterSchemaMismatchError on contract-breaking deltas only (missing required field, type change). Forward-compatible additions (extra optional fields) do NOT raise.
- Update docs and examples — docstrings must document declared output contract + new parameters;
docs/examples/intrinsics/ examples that call these helpers must be updated in the same PR
Six helpers, six declared output contracts. Implementer confirms each contract against current _RAG_REPO weights before writing the tests — document the verification in the PR description.
Scope
mellea/stdlib/components/intrinsic/rag.py
- Tests under
test/stdlib/components/intrinsic/test_rag.py
Out of scope
Other helper files (1.C, 1.D), backend changes (Phase 2), shim removal (4.1), refactoring beyond additive model_options=.
Acceptance criteria
For each of the six helpers:
Test plan
Per helper (six pairs of tests):
test_<helper>_contract_enforced — feed synthetic output missing a required field; assert AdapterSchemaMismatchError
test_<helper>_forward_compat — feed output with an extra optional field; assert it does NOT raise
Existing happy-path tests pass unchanged.
Note on flag_hallucinated_content: return type is boolean-like. Document expected output type explicitly in docstring; coercion responsibility stays with caller.
Breaking changes
None at signature level (additive model_options=). Callers that previously swallowed KeyError on schema mismatch will now see AdapterSchemaMismatchError — surface in changelog.
References
Parent epic: #929
Design proposal: PR #1080
Phase: 1 (Wave 3 — start after 1.A merges)
Depends on: 1.A
Independent of: 1.C, 1.D, 2.1 (all run in parallel in Wave 3)
Problem
mellea/stdlib/components/intrinsic/rag.pycontains six helpers in one file:check_answerability,rewrite_question,clarify_query,find_citations,check_context_relevance,flag_hallucinated_content. All construct viaIntrinsicAdapter(...)(a deprecation shim after 1.A). Signatures do not consistently acceptmodel_options=. None has output validation — schema drift from upstream_RAG_REPOweights silently changes behaviour.Per-helper PRs would all touch the same file and serialise behind one another. One PR migrates the whole file.
Agreed design
Follows the per-helper-file migration template from PR #1080:
IntrinsicAdapter(...)withAdapter(identity=..., io_contract=..., weights=...)model_options: dict | None = Noneas keyword argument to every helperio_contract.parse()to raiseAdapterSchemaMismatchErroron contract-breaking deltas only (missing required field, type change). Forward-compatible additions (extra optional fields) do NOT raise.docs/examples/intrinsics/examples that call these helpers must be updated in the same PRSix helpers, six declared output contracts. Implementer confirms each contract against current
_RAG_REPOweights before writing the tests — document the verification in the PR description.Scope
mellea/stdlib/components/intrinsic/rag.pytest/stdlib/components/intrinsic/test_rag.pyOut of scope
Other helper files (1.C, 1.D), backend changes (Phase 2), shim removal (4.1), refactoring beyond additive
model_options=.Acceptance criteria
For each of the six helpers:
Adapter(identity=..., io_contract=..., weights=...)— noIntrinsicAdapter(...)calls in helper codemodel_options: dict | None = NoneAdapterSchemaMismatchErrordocs/examples/intrinsics/examples that call these helpers updated; examples passuv run pytest docs/examples/intrinsics/(or skipped with correct marker if backend-gated)ruff format,ruff check,mypycleanTest plan
Per helper (six pairs of tests):
test_<helper>_contract_enforced— feed synthetic output missing a required field; assertAdapterSchemaMismatchErrortest_<helper>_forward_compat— feed output with an extra optional field; assert it does NOT raiseExisting happy-path tests pass unchanged.
Breaking changes
None at signature level (additive
model_options=). Callers that previously swallowedKeyErroron schema mismatch will now seeAdapterSchemaMismatchError— surface in changelog.References
docs/dev/proposals/929-issue-plan.mdgh issue list --search "rag" --state open— check for any open issues against specific RAG helpers and reference them in PR