Skip to content

[bug] llm_classifier: fallback and affinity-reuse decisions emit switchyard.requests without a tier attribute #276

Description

@thossullivan

Symptom

switchyard.requests is emitted without a tier attribute when an llm_classifier decision comes from the capable-target fallback or from affinity reuse. The same strong model lands in two time series, one labeled and one not, and a metrics consumer cannot unify them or tell a deliberate strong classification from a fallback. In one production session we saw 1 request labeled tier="weak" and 45 requests on the strong model with no tier at all.

Reproduction

Covered by two tests in the linked PR, which fail on current main:

  • judge_unavailable_fallback_keeps_the_tier_label: judge upstream errors, the cascade's DefaultTarget decides, and the emitted series has no tier.
  • affinity_reuse_keeps_the_tier_label: the second request of a pinned session is decided by AffinityRouter and likewise loses the tier.

Expected vs. actual

  • Expected: every routed decision carries the tier of the model actually selected, as the context-overflow fallback already does via fallback_decision's cascade find_map (crates/libsy/src/algorithms/fall_through.rs:221-233).
  • Actual: DefaultTarget and AffinityRouter do not implement Classifier::routing_tier, the trait default returns None (crates/libsy/src/core/classifier.rs:75-77), and the tier attribute is omitted at emission (crates/libsy/src/observability.rs:548-551, decision tier from fall_through.rs:294). The routing log has the twin symptom: an empty tier that is indistinguishable from a route with no tiering.

Environment

  • Switchyard version / commit: current main; first observed on a v0.1.0 build (6ff491ac)
  • OS / arch: macOS ARM64, source build
  • Inbound format: Chat Completions
  • Backend: OpenAI-compatible (observed live via OpenRouter)

Additional context

Related: #205 counts how often the classifier failed open and why; this issue is about which tier actually served, so the two compose. #272 covers why agentic sessions hit the fallback so often. Fix in the linked PR resolves the tier across the cascade with the same find_map pattern the overflow path uses.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions