Skip to content

fix(backend): give the chat test stubs the names their real modules export - #12292

Closed
aryanorastar wants to merge 5 commits into
BasedHardware:mainfrom
aryanorastar:fix/test-stub-missing-exports
Closed

fix(backend): give the chat test stubs the names their real modules export#12292
aryanorastar wants to merge 5 commits into
BasedHardware:mainfrom
aryanorastar:fix/test-stub-missing-exports

Conversation

@aryanorastar

@aryanorastar aryanorastar commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

What changed and why

Two files, both test-side. The scope narrowed as main absorbed the rest — see the note at the bottom.

1. _chat_router_test_harness.py — one missing stub name.

The shared chat-router harness installs a stand-in for utils.llm.usage_tracker carrying set_usage_context, reset_usage_context and Features. The production code also imports get_current_context, so every suite using the harness died at collection:

ImportError: cannot import name 'get_current_context' from 'utils.llm.usage_tracker' (unknown location)

(unknown location) is the tell — the module in sys.modules is a stub with no spec origin, so the name is missing from the stand-in rather than the package. The real symbol is usage_tracker.py:175 and returns Optional[UsageContext]; None is the no-active-context value these router tests run under.

2. fast_unit_duration_allowlist.txt — 15 node IDs.

Fixing the stub moved these files from "collection error, never ran" to "runs and is measured", which exposed them to the fast-unit duration guard for the first time:

Backend fast unit duration guard failures (CPU time)
   0.33s > 0.30s  test_generate_reply_never_returns_a_staged_error_answer_as_reply_text

Every test passes; only the CPU budget fails. This is exactly the amortization the allowlist header already documents — each file runs in its own pytest process, so the first call pays the FastAPI app and router graph import — and sibling node IDs from these same files are already grandfathered for that reason.

Appended as its own commented group rather than merged into the existing set: the file is grouped by rationale, not sorted, so re-sorting would have produced 107 insertions and 115 deletions for 15 real additions.

How it was verified

With the repo's own runner, not bare pytest:

BACKEND_UNIT_TEST_FILE_LIST=... bash test.sh   →  EXIT=0
  test_chat_generate_reply_stateless    6 passed
  test_chat_quota_counting_router      10 passed
  test_chat_stream_error_fallback      11 passed

Correcting my own first pass on this PR: I originally verified with bare pytest and reported these files green. They were not — test.sh applies a timing guard bare pytest omits, and three files still failed the suite. The runner says so directly ("Do not use bare pytest for fast-unit timing failures; it omits test.sh's guard settings") and I should have used it from the start. The allowlist commit exists because of that miss.

Scope note

This PR opened covering five files. #12339 landed the stub fixes for test_chat_quota.py, test_chat_file_upload_unsupported.py and test_desktop_transcribe.py on main in the meantime, so those are gone from the diff — what remains is the harness name and the allowlist entries, neither of which is on main.

Still not fixed, and not mine to guess at

test_byok_security.py (8 failures), test_chat_session_app_identity.py (1) and test_paywall_reconnect_gate.py (2) all fail on pristine main with BYOK expectation drift — assert True is False against a reshaped request_has_llm_byok_key, which no longer calls get_byok_keys. Those need assertions rewritten against the current contract, which is a semantic question about intended BYOK behaviour. Traced in #12289.

Product invariants affected

none

Failure-Class: FC-mirrored-model-omits-new-member

…xport

Five unit files fail to import on main. Each installs a hand-written stand-in
for a real module, and the stand-ins never gained names the production code
started importing:

    ImportError: cannot import name 'get_byok_uid' from 'utils.byok' (unknown location)
    ImportError: cannot import name 'get_current_context' from 'utils.llm.usage_tracker' (unknown location)
    ImportError: cannot import name 'CHAT_AGENT_ROUTE_DIRECT' from 'utils.llm.gateway_client' (unknown location)
    ImportError: cannot import name 'get_chat_agent_route' from 'utils.llm.gateway_client' (unknown location)
    ModuleNotFoundError: No module named 'utils.llm.gateway_client'; 'utils.llm' is not a package

"(unknown location)" is the tell: the module in sys.modules is a stub with no
spec origin, so the name is missing from the stand-in rather than from the
package. Every real symbol exists -- utils/byok.py, usage_tracker.py:175,
gateway_client.py:36 and :158.

Four sites, all adding what the real module already exports:

- _chat_router_test_harness.py: usage_tracker.get_current_context. Real
  signature returns Optional[UsageContext]; None is the no-active-context
  value these router tests run under.
- test_chat_file_upload_unsupported.py: gateway_client.CHAT_AGENT_ROUTE_DIRECT
  and get_chat_agent_route. Importers read them at module import time, so the
  stub carries them even though this test never routes.
- test_chat_quota.py: byok get_byok_uid and get_cached_byok_state, which
  utils.subscription imports at module scope.
- test_desktop_transcribe.py: utils.llm.gateway_client in the stub list.
  utils.llm is a MagicMock, not a package, so an unlisted submodule fails to
  resolve instead of falling back to the stub.

    before: 5 files, 0 tests run -- collection failed
    after:  108 passed

Not fixed here: tests/unit/test_byok_security.py, 8 failures across four
classes. Those patch utils.subscription.get_byok_keys, which
request_has_llm_byok_key no longer calls -- it moved to get_byok_uid /
get_cached_byok_state / get_byok_key. Repointing the patch would bind it to a
function the code under test does not use, so those need new assertions
written against the current contract rather than a rename. Tracked in BasedHardware#12289.

Failure-Class: FC-mirrored-model-omits-new-member
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

…ocked

Fixing the stubs moved these files from "collection error, never ran" to
"runs and is measured", which exposed 15 node IDs to the fast-unit duration
guard for the first time:

    Backend fast unit duration guard failures (CPU time)
       0.33s > 0.30s  test_generate_reply_never_returns_a_staged_error_answer_as_reply_text

Every test passes; only the CPU budget fails. This is the amortization the
allowlist header already documents -- each file runs in its own pytest process,
so the first call pays the FastAPI app and router graph import. Sibling node IDs
from these same files are already grandfathered for exactly that reason.

Appended as its own commented group rather than merged into the sorted set: the
file is grouped by rationale, not sorted, so re-sorting it would have produced
107 insertions and 115 deletions for 15 real additions.

Verified with the repo runner rather than bare pytest -- bare pytest omits the
timing guard, which is why my first pass reported these files green when the
suite still failed them.

Failure-Class: none
@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Verified each of the four stub additions against current main — all correct:

  • _chat_router_test_harness.pyutils/llm/usage_tracker.py:175 really does define get_current_context() -> Optional[UsageContext], and this harness loads the real utils.llm.gateway_client, whose line 19 imports that name from the stubbed usage_tracker. Mirroring it as return_value=None (the no-active-context value) is the right shape.
  • test_chat_file_upload_unsupported.pyrouters/chat.py:69 imports CHAT_AGENT_ROUTE_DIRECT and get_chat_agent_route from utils.llm.gateway_client at module scope, so the inert stub has to carry both even though this suite never routes (and should_route_features_through_gateway=False keeps the path inert).
  • test_chat_quota.pyutils/subscription.py:28 imports get_byok_uid / get_cached_byok_state from utils.byok at module scope, so the fresh load of utils.subscription was failing at import before any assertion ran. Both stubs match the real signatures.
  • test_desktop_transcribe.py — adding 'utils.llm.gateway_client' to the sys.modules.setdefault list is exactly right for the 'utils.llm' is not a package failure: utils.llm sits in sys.modules as a plain MagicMock, so an unlisted submodule cannot resolve and does not fall back to the stub.

CI on this head backs the fix: all four touched files pass, and the shared-harness consumers (test_chat_quota_counting_router.py et al.) now collect and pass — on other PRs' runs against recent main they still fail with exactly ImportError: cannot import name 'get_current_context' from 'utils.llm.usage_tracker'. The remaining Backend unit suite red is pre-existing and unrelated to this diff: test_byok_security.py (8 failures, tracked in #12289), test_chat_session_app_identity.py / test_paywall_reconnect_gate.py (identical failures on unrelated PR runs), and three duration-guard flakes at 1.01–1.07s CPU against the 1.00s limit where every test passed.

Surgical, well-commented fix with a clearly drawn boundary — leaving #12289's semantic BYOK question out of scope was the right call. From my side this is ready for maintainer merge.


by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

@Git-on-my-level Git-on-my-level added positive-signal Good PR — positive signal, not a formal approval backend Backend Task (python) labels Aug 27, 2026

@kodjima33 kodjima33 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Root cause and fix are correct (test stubs missing names their real modules now export) and CI-red items aside, this is a scoped 15-line test-only fix. Holding merge: Backend unit suite check is currently failing on this PR.

…-exports

# Conflicts:
#	backend/tests/unit/test_chat_file_upload_unsupported.py
#	backend/tests/unit/test_desktop_transcribe.py
@aryanorastar

aryanorastar commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

Refreshed on current main — conflicts resolved and full proof rerun

I merged the latest main into this branch and resolved both conflicts against the newer upstream test stubs.

Three of the four original missing-export fixes have since landed independently on main:

  • CHAT_AGENT_ROUTE_DIRECT, CHAT_AGENT_ROUTE_GATEWAY, and get_chat_agent_route
  • utils.llm.gateway_client
  • get_byok_uid and get_cached_byok_state

Those upstream versions were kept to avoid duplicating or regressing newer test setup. The PR is now reduced to the one still-required fix: the shared chat-router harness exposes usage_tracker.get_current_context, returning the real no-active-context value (None).

Current diff

  • 1 file
  • 3 additions
  • no production code changes
  • no iOS, Android, desktop, or UI changes

Focused regression proof

Run through the repository's locked backend environment on Python 3.11.15:

  • test_chat_quota_counting_router.py: 10 passed
  • test_chat_stream_error_fallback.py: 11 passed
  • test_chat_file_upload_unsupported.py: 5 passed
  • test_chat_quota.py: 17 passed
  • test_desktop_transcribe.py: 64 passed, 5 deselected

Focused subtotal: 107 passed, 5 deselected, 0 failed.

I also reran every file that was red in the previous Backend unit suite:

  • test_byok_security.py: 104 passed
  • test_chat_session_app_identity.py: 6 passed
  • test_paywall_reconnect_gate.py: 35 passed

Former-CI-red subtotal: 145 passed, 0 failed.

Combined local proof: 252 passed, 5 deselected, 0 failed.

Repository gates

  • make preflight: 25/25 checks passed
  • Black 26.5.1 check: passed; file unchanged
  • git diff --check origin/main...HEAD: passed
  • Branch is conflict-free and GitHub reports it MERGEABLE
  • Existing approval remains in place

Fresh CI is running on head 612f4c1061. Once it completes, this should be ready for maintainer merge. @Git-on-my-level @undivisible

@aryanorastar

Copy link
Copy Markdown
Contributor Author

Fresh CI is complete on 612f4c1061: 17 successful checks, 0 failing, 0 pending. The PR is approved and GitHub reports it mergeable. The former Backend unit suite blocker is green; this is ready for maintainer merge.

…o fix/test-stub-missing-exports

# Conflicts:
#	backend/tests/fast_unit_duration_allowlist.txt
@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Verified the refreshed head 46cc0349 — the merge of current main didn't change the PR's substance, and everything still checks out:

  • backend/tests/unit/_chat_router_test_harness.py — the one remaining fix is correct. backend/utils/llm/usage_tracker.py does export get_current_context() -> Optional[UsageContext], and the stub's MagicMock(return_value=None) matches the real no-active-context value these router tests run under. The other three stub fixes from the original version landed on main independently, so the narrowed diff is the right call.
  • backend/tests/fast_unit_duration_allowlist.txt — all 15 new node IDs exist at this head in test_chat_generate_reply_stateless.py, test_chat_quota_counting_router.py, and test_chat_stream_error_fallback.py; the list goes 262 → 277 entries with no duplicates and no removals, appended as its own commented group consistent with the file's documented file-isolation import-amortization rationale (these files only started being collected and measured once the stub import error was fixed — not a per-test regression).

Backend CI is green on this head (Backend unit suite, Backend Hermetic Merge Gate, Hermetic Backend E2E all passing). The only commits after the approval are merges of main, which introduce no contributor changes to these files. From my side this is ready for maintainer merge — nice root-cause writeup and a careful refresh, @aryanorastar.


by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

@aryanorastar

Copy link
Copy Markdown
Contributor Author

Closing — main fixed this without me.

#12339 landed the stub names, and the harness on main now carries get_current_context plus track_usage, so nothing in my diff is still needed. The last 12 allowlist entries turned out not to be required either: with main's own allowlist and nothing from this branch, the three files pass the duration guard 3/3.

Verified against a pristine main checkout with the repo runner:

BACKEND_UNIT_TEST_FILE_LIST=<the 6 files> bash test.sh   →  EXIT=0
  test_chat_generate_reply_stateless    6 passed
  test_chat_quota_counting_router      10 passed
  test_chat_stream_error_fallback      11 passed
  test_chat_file_upload_unsupported     7 passed
  test_chat_quota                      17 passed
  test_desktop_transcribe              64 passed

Worth recording one mistake from this PR: I first verified with bare pytest and reported the files green when the suite still failed them. test.sh applies a CPU-time guard bare pytest omits, and the runner says so explicitly — "Do not use bare pytest for fast-unit timing failures". I used it from then on, and it's what showed the allowlist entries were unnecessary too.

@github-actions

Copy link
Copy Markdown
Contributor

Hey @aryanorastar 👋

Thank you so much for taking the time to contribute to Omi! We truly appreciate you putting in the effort to submit this pull request.

After careful review, we've decided not to merge this particular PR. Please don't take this personally — we genuinely try to merge as many contributions as possible, but sometimes we have to make tough calls based on:

  • Project standards — Ensuring consistency across the codebase
  • User needs — Making sure changes align with what our users need
  • Code best practices — Maintaining code quality and maintainability
  • Project direction — Keeping aligned with our product principles and locked invariants

Before your next PR, please skim:

  • PRODUCT.md — product north star
  • Product invariants — locked rules (shared chat, memory tiers, agent control plane, integrations, brand)

If this was declined for direction or taste, maintainers should cite an invariant ID or open a proposed one — ask if that citation is missing.

Your contribution is still valuable to us, and we'd love to see you contribute again in the future! If you'd like feedback on how to improve this PR or want to discuss alternative approaches, please don't hesitate to reach out.

Thank you for being part of the Omi community!

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

Labels

backend Backend Task (python) positive-signal Good PR — positive signal, not a formal approval

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants