Skip to content

refactor(intrinsics): rag.py whole-file migration to new Adapter types (Epic #929 Phase 1) #1137

@planetf1

Description

@planetf1

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:

  1. Migrate construction — replace IntrinsicAdapter(...) with Adapter(identity=..., io_contract=..., weights=...)
  2. Normalise signature — add model_options: dict | None = None as keyword argument to every helper
  3. 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.
  4. 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:

  • Constructs via Adapter(identity=..., io_contract=..., weights=...) — no IntrinsicAdapter(...) calls in helper code
  • Accepts model_options: dict | None = None
  • Has a declared output contract documented in its docstring
  • Forward-compat: synthetic output with an extra optional field does NOT raise
  • Contract-break: synthetic output missing a required field raises AdapterSchemaMismatchError
  • Existing helper tests pass (behavioural neutrality)
  • docs/examples/intrinsics/ examples that call these helpers updated; examples pass uv run pytest docs/examples/intrinsics/ (or skipped with correct marker if backend-gated)
  • ruff format, ruff check, mypy clean

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

Metadata

Metadata

Assignees

Labels

area/intrinsicsGranite intrinsic adapters: RAG, Guardian, Corearea/stdlibCore abstractions: Context, MOT, SamplingStrategy, formatters, serializationrefactor

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions