Skip to content

refactor(backends): AdapterMixin verb rename/narrow + resolve_model_options + IntrinsicMetricsPlugin (Epic #929 Phase 2) #1140

Closed

Description

@planetf1

Parent epic: #929
Design proposal: PR #1080 §13, §16 Phase 2
Phase: 2 (Wave 3 — start after 1.A merges, in parallel with 1.B/1.C/1.D)
Depends on: 1.A
Blocks: 2.2, 2.3


Problem

Two related backend-surface concerns that touch the same files:

(a) Mixin verb mismatch. AdapterMixin (verified main mellea/backends/adapters/adapter.py:240) exposes five verbs: base_model_name, add_adapter, load_adapter, unload_adapter, list_adapters. The proposed design uses different verbs: load_peft_adapter, unload_peft_adapter, render_controls, set_request_adapter. This is a rename + introduce, not a pure rename.

(b) Per-call option merging. Each backend calls _simplify_and_merge on every adapter call. Duplicated logic and a known precedence bug source (PR #972 was a fix for this).

Agreed design

(a) AdapterMixin verb rename/narrow

AdapterMixin after this issue:

AdapterMixin:
  load_peft_adapter / unload_peft_adapter   # LocalFile reality
  render_controls                           # Embedded reality
  set_request_adapter                       # ServerMediated reality

Map existing implementations onto new verbs case-by-case. base_model_name and list_adapters: remove if unused after 1.A; otherwise relocate with documented justification. Bindings (2.2/2.3) call into these from their prepare/activate/etc.

Backends affected: LocalHFBackend, OpenAIBackend (the two adapter-supporting backends). Not affected: OllamaBackend, WatsonxBackend, LiteLLMBackend.

(b) Option resolution

New mellea/backends/_options.py:resolve_model_options — documents and implements precedence: caller-passed model_options= > helper defaults > backend defaults. Both adapter-supporting backends replace _simplify_and_merge with resolve_model_options on the adapter call path.

IntrinsicMetricsPlugin

New plugin at mellea/core/plugins/intrinsic_metrics.py. Three OTel metrics:

  • mellea.intrinsic.invocations — counter; labels: name, revision, binding_type, adapter_type, outcome (success/schema_error/error)
  • mellea.intrinsic.phase_duration_ms — histogram; labels: name, phase (prepare/activate/generate/parse/deactivate)
  • mellea.intrinsic.parse_failures — counter; labels: name, revision. Schema-drift detector: a climbing counter against (name, revision) means a breaking schema change was pushed upstream. Increments on each AdapterSchemaMismatchError.

Auto-wired via the existing TokenMetricsPlugin registration pattern.

Observability doc

New docs/dev/adapter_observability.md — span tree structure, metric labels, parse_failures schema-drift detector pattern, MELLEA_TRACE_CONTENT content-capture gate. Phases 2.2/2.3 add span emission details; this issue writes the structure.

Out of scope

Binding implementations (2.2, 2.3), span instrumentation (lives where verbs are implemented), HF embedded adapter support (#1018).

Acceptance criteria

  • AdapterMixin exposes exactly the four verbs above; old verbs removed or relocated with documented justification
  • LocalHFBackend and OpenAIBackend implement the new verb set
  • resolve_model_options exists, documented, tested
  • Both adapter-supporting backends use resolve_model_options instead of _simplify_and_merge on adapter call path
  • IntrinsicMetricsPlugin registerable like existing plugins
  • All three metrics registered with correct label sets
  • mellea.intrinsic.parse_failures increments on AdapterSchemaMismatchError
  • docs/dev/adapter_observability.md written; covers span tree, metric labels, parse_failures pattern, MELLEA_TRACE_CONTENT gate; markdownlint passes
  • Existing tests pass (precedence behaviour unchanged)
  • New unit tests cover precedence: caller > helper > backend
  • Test asserts AdapterMixin exposes exactly the four verbs (catches accidental re-additions)
  • Unit tests for IntrinsicMetricsPlugin using synthetic OTel exporter
  • ruff format, ruff check, mypy clean

Test plan

  • Existing backend tests pass
  • resolve_model_options precedence tests: each pair (caller-vs-helper, caller-vs-backend, helper-vs-backend)
  • Verb set test: assert AdapterMixin has exactly the four verbs
  • IntrinsicMetricsPlugin unit tests:
    • test_invocations_counter_emits_on_success
    • test_invocations_counter_emits_schema_error_outcome
    • test_parse_failures_counter_increments
    • test_phase_duration_histogram_emits_for_each_phase

Breaking changes

  • AdapterMixin verb rename — downstream backends extending AdapterMixin must update. Migration table (old → new verb names) in changelog.
  • _simplify_and_merge removal from adapter call path — internal API only.

References

Activity

  1. self-assigned this
    on May 22, 2026
  2. added
    area/telemetryOTel spans, metrics, tracing, semconv
    area/backendsProvider-specific work: Ollama, HF, LiteLLM, OpenAI, Bedrock, vLLM
    area/adapter-functionsGranite adapter functions: framework and adaptiers including RAG, Guardian, Core
    on May 22, 2026
  3. planetf1 commented on Jun 11, 2026

    @planetf1
    ContributorAuthor

    This issue uses vocabulary that has been superseded by the agreed Epic #929 glossary. Please use the following terms in any new work related to this issue:

    Old term Preferred term
    intrinsic / intrinsic function adapter function
    activated-LoRA / Activated LoRA aLoRA
    Project Granite Switch Granite Switch
    cache rewrite (re: aLoRA) cache hit / cache miss

    The canonical definitions are now in the project glossary and were established as part of #1192. Python symbol names (IntrinsicAdapter, fetch_intrinsic_metadata, etc.) keep their current names until Phase 1 (#1136) and Phase 4 (#1144).

  4. added
    p1High: important bugs (workaround exists) or high-value core features. Do soon, not on fire.
    on Jun 18, 2026
  5. 7 remaining items

  6. planetf1 commented on Jul 21, 2026

    @planetf1
    ContributorAuthor

    Update: implementation is up in #1422 (draft). Two corrections to my earlier comment on this issue, now that Phase 1 (#1269) has merged underneath it:

    Verb count is 7, not 4. My earlier comment's rationale cited call_intrinsic's old list_adapters()/add_adapter() dispatch logic — that no longer exists; Phase 1 replaced it with resolve_adapter(). This issue's acceptance criteria state "exposes exactly the four verbs" three times, but that's unsatisfiable now: resolve_adapter() depends on base_model_name and add_adapter staying on the mixin, alongside the four reality-specific verbs (load_peft_adapter/unload_peft_adapter, render_controls, set_request_adapter) plus list_adapters. So the actual shipped count is 7 universal+reality-specific verbs, not 4. Flagging this plainly rather than letting the checklist silently mismatch the code — happy to adjust the AC text if a maintainer prefers.

    Env var typo: this issue (and #1141/#1142) reference MELLEA_TRACE_CONTENT — the actual variable is MELLEA_TRACES_CONTENT. Worth fixing at the source since #1141/#1142 are both blocked on this issue anyway.

    Full verb contract, resolve_model_options precedence, and the IntrinsicMetricsPlugin skeleton's metrics are documented in docs/dev/adapter_observability.md (added in #1422).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/adapter-functionsGranite adapter functions: framework and adaptiers including RAG, Guardian, Corearea/backendsProvider-specific work: Ollama, HF, LiteLLM, OpenAI, Bedrock, vLLMarea/telemetryOTel spans, metrics, tracing, semconvp1High: important bugs (workaround exists) or high-value core features. Do soon, not on fire.refactor

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions