Skip to content

chore(api): lift ROUTING_TARGETS to a leaf module (breaks import cycle)#83

Open
hizrianraz wants to merge 1 commit into
mainfrom
chore/routing-targets-constants
Open

chore(api): lift ROUTING_TARGETS to a leaf module (breaks import cycle)#83
hizrianraz wants to merge 1 commit into
mainfrom
chore/routing-targets-constants

Conversation

@hizrianraz
Copy link
Copy Markdown
Contributor

@hizrianraz hizrianraz commented May 27, 2026

Pure hygiene; independent of any other in-flight PR. Per the GATE 4 GO brief: "ROUTING_TARGETS → constants module cleanup PR (retire the two noqa: PLC0415 lazy imports from AIN-285). Pure hygiene, independent, ship it."

Motivation

`services/capture_invariant.py` pulled `ROUTING_TARGETS` from `routers/inference`, which created a real circular-import bug. Any module wanting to import `capture_invariant` at top-level closed this cycle:

```
services/routing_outcomes -> services/capture_invariant
-> routers/inference (for ROUTING_TARGETS)
-> services/routing_brain
-> services/routing_outcomes ← back here
```

AIN-285 worked around it with two function-local imports (`noqa: PLC0415`). Lifting the constants to a leaf module breaks the cycle for good.

What this PR does

  • NEW: `ainfera_api/routing_targets.py` — ~75 lines, zero ainfera_api deps. Owns `INFERENCE_MODEL`, `ROUTING_ALIASES`, `ROUTING_TARGETS`, `CANONICAL_ROUTER`, the three SP-1 aliases, `MITHRIL_MODEL`/`AUTO_MODEL` back-compat names, and a pure `is_routed()` classifier. No FastAPI, no logging, no I/O.
  • `routers/inference.py` re-exports the constants + a back-compat `_is_routed` alias so existing callers (anthropic_compat, openai_compat, the test suites) don't churn.
  • `services/capture_invariant.py` imports from the leaf module — cycle broken.

What this PR does NOT change

  • Public string values (`ainfera-inference` + the three SP-1 aliases) — byte-identical.
  • `_is_routed` semantics — leaf vs router agree for every SP-1 target + a vendor-slug sample (explicit test).
  • `/v1` OpenAPI surface — route definitions unmoved.
  • Disc fix(audit): honest cap + cursor for /v1/audit/public and /v1/audit/{id} #12 invariants — no routing weight / threshold / candidate-set change. Pure structural move.

What this enables (next PR)

When AIN-285 (PR #82) rebases onto this, the two `noqa: PLC0415` lazy imports become plain top-level imports of `get_counter`. One-line cleanup per call site; PR #82's diff shrinks.

Test plan

  • `ruff check` + `ruff format --check` + `mypy --strict` clean.
  • 550/550 unit + smoke tests green (was 546; +4 from `test_routing_targets_module.py` which locks the leaf-module invariant, the back-compat re-exports, the capture_invariant rewire, and leaf-vs-router `is_routed` agreement).
  • CI green on integration suite (no behavior change expected).

🤖 Generated with Claude Code


Note

Low Risk
Pure refactor with re-exports and tests; no change to routing strings, API routes, or dispatch logic.

Overview
Moves SP-1 routing-target constants (ainfera-inference, alias frozensets, is_routed) out of routers/inference.py into a new leaf module ainfera_api/routing_targets.py, so services can classify routed vs passthrough without importing the FastAPI inference router (and its brain/ORM chain).

capture_invariant.py now imports ROUTING_TARGETS from that leaf module, breaking a circular import (capture_invariantrouters/inference → … → back to services). The inference router re-exports the same names and _is_routed so existing from ainfera_api.routers.inference import … call sites stay unchanged; new code is directed to routing_targets.

Adds tests/unit/test_routing_targets_module.py to guard the leaf has no internal ainfera_api deps, back-compat re-exports, the capture_invariant import path, and leaf is_routed vs router _is_routed parity. Public routing strings and dispatch behavior are unchanged.

Reviewed by Cursor Bugbot for commit 6d34f39. Bugbot is set up for automated code reviews on this repo. Configure here.

New module ainfera_api/routing_targets.py owns the SP-1 routing-string
constants: INFERENCE_MODEL, ROUTING_ALIASES, ROUTING_TARGETS,
CANONICAL_ROUTER, MITHRIL/AUTO/AUTO_SLASH aliases, MITHRIL_MODEL +
AUTO_MODEL back-compat names, and a pure is_routed() classifier.

Motivation: capture_invariant.py pulled ROUTING_TARGETS from
routers/inference, which forced a 50-import chain and created a real
circular-import bug. Any module wanting to import capture_invariant
at top-level closed the cycle:

  services/routing_outcomes -> services/capture_invariant
                            -> routers/inference (for ROUTING_TARGETS)
                            -> services/routing_brain
                            -> services/routing_outcomes

AIN-285 had to work around this with two function-local imports
(noqa: PLC0415). With ROUTING_TARGETS lifted to a leaf module, any
future module — including the AIN-285 wire-ins when feat/ain-285
rebases — can use plain top-level imports.

## What changed

- NEW: ainfera_api/routing_targets.py (~75 lines, zero ainfera_api
  deps). Owns the constants + is_routed(). No FastAPI / no logging /
  no I/O.
- routers/inference.py imports from the leaf module and re-exports
  the constants + _is_routed (back-compat alias for is_routed). All
  existing callers — anthropic_compat.py, openai_compat.py, test
  suites — keep working unchanged.
- services/capture_invariant.py imports ROUTING_TARGETS from the leaf
  module instead of routers/inference. Cycle broken.

## What did NOT change

- Public string values (every SP-1 constant has the same value).
- _is_routed semantics — the router-level alias and the leaf-level
  is_routed return identical results for every input (tested
  explicitly against canonical + 3 aliases + vendor slugs + empty).
- /v1 OpenAPI surface (the route definitions in routers/inference
  are unmoved).

## What enables (future PRs)

When feat/ain-285-capture-metric (PR #82) rebases onto this:
- routers/inference.py — the lazy get_counter import becomes top-level.
- services/routing_outcomes.py — same retirement.
- Both noqa: PLC0415 comments come out.

## Tests

- NEW: tests/unit/test_routing_targets_module.py (4 tests) locks:
  * routing_targets.py has zero ainfera_api imports (leaf invariant)
  * back-compat re-exports work for every constant + _is_routed
  * capture_invariant imports from leaf, not from router
  * leaf is_routed() agrees with router _is_routed for every SP-1
    target + a vendor-slug sample (so the two impls can't drift)
- 550/550 unit + smoke tests green (was 546; +4 from the new file).
- ruff check + ruff format --check + mypy --strict clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants