Skip to content

test: add public-API surface and server recorded tests#2122

Open
Pouyanpi wants to merge 7 commits into
developfrom
test/recorded-tests-public-api-surface
Open

test: add public-API surface and server recorded tests#2122
Pouyanpi wants to merge 7 commits into
developfrom
test/recorded-tests-public-api-surface

Conversation

@Pouyanpi

@Pouyanpi Pouyanpi commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Description

Adds the recorded characterization baseline for the existing LLMRails public API and server-facing behavior. This baseline is intended to support behavior-preserving review of the decomposition stack in #2123–#2131.

What Changed

  • Adds recorded OpenAI and NVIDIA NIM coverage for generation, streaming, options, events, state, concurrency, cancellation, tool calls, tracing, knowledge-base retrieval, and Colang 2.x behavior.
  • Adds recorded server coverage for chat-completions contracts and input blocking.
  • Adds deterministic parity and embeddings-index checks.
  • Keeps credentialed live smoke coverage outside tests/recorded.
  • Grafts tests onto branch-owned cassettes and refreshes the branch-owned provider recordings.

Review Guidance

Use the LLMRails decomposition review matrix as the scenario index. It maps each characterized behavior to an exact test node and identifies which rows should be checked during each decomposition PR.

These tests intentionally characterize current behavior, including compatibility quirks. A failing row during #2123#2130 should be treated as a potential behavior regression unless the stack explicitly identifies it as an intentional semantic change in #2131.

Related Issue(s)

This is maintainer-directed test infrastructure for the linked LLMRails decomposition stack.

Verification

make replay-cassettes
# 144 passed, 1 xfailed

make test TEST=tests/server/test_server_calls_with_state.py WORKERS=1
# 8 passed

poetry run pre-commit run --all-files
poetry run pyright

AI Assistance

  • No AI tools were used.
  • AI tools were used; a human reviewed and can explain every change (tool: Codex).

Checklist

  • I've read the CONTRIBUTING guidelines.
  • This PR links to a triaged issue assigned to me.
  • My PR title follows the project commit convention.
  • I've updated the documentation if applicable.
  • I've added tests if applicable.
  • I've noted any verification beyond CI and any checks I couldn't run.
  • I did not update generated changelog files manually.
  • I addressed all CodeRabbit, Greptile, and other review comments, or replied with why no change is needed.
  • @mentions of the person or team responsible for reviewing proposed changes.

@github-actions github-actions Bot added status: needs triage New issues that have not yet been reviewed or categorized. size: XL labels Jul 2, 2026
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 44034de6-0e0f-486d-817a-3001e2bf714e

📥 Commits

Reviewing files that changed from the base of the PR and between 3fc828b and e502749.

📒 Files selected for processing (49)
  • tests/rails/llm/test_live_smoke.py
  • tests/recorded/rails/public_api/cassettes/test_colang_v2/test_colang_v2_self_check_input_rail_allows_benign_input.yaml
  • tests/recorded/rails/public_api/cassettes/test_colang_v2/test_colang_v2_self_check_input_rail_blocks_flagged_input.yaml
  • tests/recorded/rails/public_api/cassettes/test_generate/test_dialog_generate_async_llm_output_is_none.yaml
  • tests/recorded/rails/public_api/cassettes/test_generate/test_nim_generate_async_options_surfaces_reasoning_content.yaml
  • tests/recorded/rails/public_api/cassettes/test_generate/test_openai_generate_async_log_stats_token_counts.yaml
  • tests/recorded/rails/public_api/cassettes/test_generate/test_openai_generate_async_options_returns_generation_response.yaml
  • tests/recorded/rails/public_api/cassettes/test_kb/test_openai_kb_generate_async_retrieves_and_injects_chunks.yaml
  • tests/recorded/rails/public_api/cassettes/test_stream/test_nim_stream_async_reasoning_not_inlined_in_streamed_text.yaml
  • tests/recorded/rails/public_api/cassettes/test_tools/test_openai_generate_async_surfaces_tool_calls.yaml
  • tests/recorded/rails/public_api/cassettes/test_tracing/test_openai_generate_async_traced_request_matches_untraced.yaml
  • tests/recorded/rails/public_api/cassettes/test_tracing/test_openai_generate_async_untraced_request.yaml
  • tests/recorded/rails/public_api/configs.py
  • tests/recorded/rails/public_api/configs/colang_v2/config.yml
  • tests/recorded/rails/public_api/configs/colang_v2/main.co
  • tests/recorded/rails/public_api/configs/colang_v2_self_check/config.yml
  • tests/recorded/rails/public_api/configs/colang_v2_self_check/main.co
  • tests/recorded/rails/public_api/configs/colang_v2_self_check/rails.co
  • tests/recorded/rails/public_api/configs/openai_kb/config.co
  • tests/recorded/rails/public_api/configs/openai_kb/config.py
  • tests/recorded/rails/public_api/configs/openai_kb/config.yml
  • tests/recorded/rails/public_api/configs/openai_kb/kb/nemo.md
  • tests/recorded/rails/public_api/configs/openai_tools/config.yml
  • tests/recorded/rails/public_api/configs/openai_tracing/config.yml
  • tests/recorded/rails/public_api/configs/state/config.py
  • tests/recorded/rails/public_api/configs/state/config.yml
  • tests/recorded/rails/public_api/configs/state/rails.co
  • tests/recorded/rails/public_api/test_colang_v2.py
  • tests/recorded/rails/public_api/test_concurrency.py
  • tests/recorded/rails/public_api/test_events.py
  • tests/recorded/rails/public_api/test_generate.py
  • tests/recorded/rails/public_api/test_kb.py
  • tests/recorded/rails/public_api/test_options.py
  • tests/recorded/rails/public_api/test_parity.py
  • tests/recorded/rails/public_api/test_state.py
  • tests/recorded/rails/public_api/test_stream.py
  • tests/recorded/rails/public_api/test_stream_cancellation.py
  • tests/recorded/rails/public_api/test_tools.py
  • tests/recorded/rails/public_api/test_tracing.py
  • tests/recorded/server/__init__.py
  • tests/recorded/server/assertions.py
  • tests/recorded/server/cassettes/test_chat_completions/test_openai_chat_completion_public_contract.yaml
  • tests/recorded/server/configs/blocking_input/config.yml
  • tests/recorded/server/configs/blocking_input/rails.co
  • tests/recorded/server/configs/openai_baseline/config.yml
  • tests/recorded/server/conftest.py
  • tests/recorded/server/test_chat_completions.py
  • tests/server/test_server_calls_with_state.py
  • tests/test_embeddings_index_determinism.py
👮 Files not reviewed due to content moderation or server errors (48)
  • tests/rails/llm/test_live_smoke.py
  • tests/recorded/rails/public_api/test_tools.py
  • tests/recorded/rails/public_api/test_state.py
  • tests/recorded/rails/public_api/test_tracing.py
  • tests/recorded/rails/public_api/test_events.py
  • tests/recorded/rails/public_api/configs.py
  • tests/recorded/rails/public_api/test_options.py
  • tests/recorded/rails/public_api/test_generate.py
  • tests/recorded/rails/public_api/cassettes/test_colang_v2/test_colang_v2_self_check_input_rail_allows_benign_input.yaml
  • tests/recorded/rails/public_api/cassettes/test_colang_v2/test_colang_v2_self_check_input_rail_blocks_flagged_input.yaml
  • tests/recorded/rails/public_api/configs/openai_tracing/config.yml
  • tests/recorded/rails/public_api/test_parity.py
  • tests/recorded/server/configs/blocking_input/config.yml
  • tests/recorded/server/init.py
  • tests/recorded/rails/public_api/cassettes/test_generate/test_nim_generate_async_options_surfaces_reasoning_content.yaml
  • tests/recorded/rails/public_api/configs/colang_v2/config.yml
  • tests/recorded/server/cassettes/test_chat_completions/test_openai_chat_completion_public_contract.yaml
  • tests/recorded/rails/public_api/cassettes/test_kb/test_openai_kb_generate_async_retrieves_and_injects_chunks.yaml
  • tests/recorded/rails/public_api/configs/colang_v2_self_check/config.yml
  • tests/recorded/rails/public_api/test_concurrency.py
  • tests/recorded/rails/public_api/cassettes/test_tools/test_openai_generate_async_surfaces_tool_calls.yaml
  • tests/recorded/rails/public_api/cassettes/test_tracing/test_openai_generate_async_untraced_request.yaml
  • tests/recorded/rails/public_api/cassettes/test_tracing/test_openai_generate_async_traced_request_matches_untraced.yaml
  • tests/recorded/server/configs/openai_baseline/config.yml
  • tests/recorded/rails/public_api/configs/openai_kb/kb/nemo.md
  • tests/recorded/rails/public_api/configs/colang_v2/main.co
  • tests/recorded/rails/public_api/configs/colang_v2_self_check/rails.co
  • tests/recorded/server/assertions.py
  • tests/recorded/server/test_chat_completions.py
  • tests/recorded/rails/public_api/cassettes/test_generate/test_openai_generate_async_log_stats_token_counts.yaml
  • tests/recorded/rails/public_api/configs/openai_kb/config.yml
  • tests/recorded/server/conftest.py
  • tests/server/test_server_calls_with_state.py
  • tests/recorded/rails/public_api/configs/state/config.yml
  • tests/recorded/rails/public_api/test_stream.py
  • tests/recorded/rails/public_api/configs/openai_kb/config.co
  • tests/recorded/rails/public_api/configs/colang_v2_self_check/main.co
  • tests/recorded/rails/public_api/test_stream_cancellation.py
  • tests/recorded/rails/public_api/test_colang_v2.py
  • tests/recorded/rails/public_api/test_kb.py
  • tests/recorded/rails/public_api/cassettes/test_generate/test_dialog_generate_async_llm_output_is_none.yaml
  • tests/recorded/rails/public_api/configs/openai_kb/config.py
  • tests/recorded/rails/public_api/cassettes/test_generate/test_openai_generate_async_options_returns_generation_response.yaml
  • tests/recorded/server/configs/blocking_input/rails.co
  • tests/test_embeddings_index_determinism.py
  • tests/recorded/rails/public_api/configs/state/rails.co
  • tests/recorded/rails/public_api/configs/state/config.py
  • tests/recorded/rails/public_api/configs/openai_tools/config.yml

📝 Walkthrough

[!WARNING]

Walkthrough skipped

File diffs could not be summarized.

🚥 Pre-merge checks | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Test Results For Major Changes ❓ Inconclusive Custom check execution failed before a final verdict was produced. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/recorded-tests-public-api-surface

Comment @coderabbitai help to get the list of available commands.

@Pouyanpi Pouyanpi added status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile). and removed status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile). labels Jul 2, 2026
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds a comprehensive recorded characterization test baseline for LLMRails's public API and server-facing behavior, intended as a behavior-preserving regression net for the forthcoming decomposition stack (PRs #2123#2131). Tests cover generation, streaming, options, events, state threading, concurrency/contextvar isolation, cancellation, tool calls, tracing, KB retrieval, and Colang 2.x behavior — all backed by frozen VCR cassettes plus fully deterministic (FakeLLMModel) paths where cassettes cannot reproduce the scenario.

  • VCR-recorded tests pin provider contract shapes (OpenAI, NVIDIA NIM) for generate_async/generate, streaming, log stats, tools, tracing, and KB retrieval.
  • Deterministic parity matrix (test_parity.py) snapshots the full rail-pipeline assembly (activated rails, decisions, llm_calls) across all input/output/parallel configs and pass/block/modify scenarios; concurrency tests verify contextvar isolation under asyncio.gather.
  • Server tests cover the chat-completions contract and input-blocking behavior via FastAPI's TestClient; live smoke tests (test_live_smoke.py) are isolated behind a @pytest.mark.live guard and auto-skip without real API keys.

Confidence Score: 5/5

Safe to merge — purely additive test infrastructure with no changes to production code, all deterministic paths verified with FakeLLMModel, and cassette-backed paths frozen against real provider responses.

The PR adds only test code (cassettes, fixtures, and test modules). The previously flagged AsyncGenerator annotation issue in test_stream_cancellation.py is resolved in the current commit. The remaining observations are confined to test helper annotation accuracy and a minor gap in the NIM live smoke assertions, neither of which affects correctness of the characterization baseline.

tests/rails/llm/test_live_smoke.py — the NIM smoke test omits log-level assertions that the OpenAI sibling includes.

Important Files Changed

Filename Overview
tests/recorded/rails/public_api/test_stream_cancellation.py Tracks streaming teardown / partial-on-abort / task-cancellation behavior with a blocking async generator; AsyncGenerator annotation is now correctly applied (prior thread resolved).
tests/recorded/rails/public_api/test_parity.py Deterministic parity baseline across all rail pipeline configurations; fully populated inline snapshots, no cassette dependency.
tests/recorded/rails/public_api/test_concurrency.py Validates contextvar isolation under asyncio.gather by re-running the parity matrix concurrently and comparing against a sequential baseline; clean design with intentional cross-module import from test_parity.
tests/recorded/rails/public_api/test_generate.py Provider contract tests for generate/generate_async (OpenAI, NIM) with log stats, options, and error cases; well-structured with cassette-parity assertions gated on record_mode.
tests/rails/llm/test_live_smoke.py Live smoke tests for OpenAI and NIM; NIM test passes options with llm_calls logging enabled but does not assert on the log, leaving that option unused compared to the OpenAI version which validates call recording.
tests/recorded/rails/public_api/test_stream.py Streaming parity matrix (allowed/blocked/boundary/disabled), metadata flag alias, and tool-call streaming; helper _chunks carries an AsyncIterator annotation instead of AsyncGenerator.
tests/recorded/server/conftest.py Server fixture wires TestClient with config-path and rails-instance cleanup; correctly restores rails_config_path in finally, clears llm_rails_instances both before and after.
tests/recorded/server/test_chat_completions.py Server-level contract tests for chat completions, input blocking, and invalid config handling; characterizes current 200-with-error-body behavior per the PR's stated intent.
tests/recorded/rails/public_api/test_colang_v2.py Colang 2.x runtime selection, generate, process_events and self-check-input-rail coverage; xfail placeholder for unresolved llm-continuation path is documented and justified.
tests/recorded/rails/public_api/test_state.py State round-trip across Colang 1.0 turns and per-call log isolation; fully deterministic with FakeLLMModel, clear documentation of known accumulate-vs-reset semantics difference.
tests/recorded/rails/public_api/configs.py Adds RETRIEVAL_RAILS_CONFIG, STATE_CONFIG, OPENAI_TOOLS_CONFIG, OPENAI_KB_CONFIG, OPENAI_TRACING_CONFIG, TWO_INPUT_RAILS_CONFIG, and related model constants cleanly.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph "Recorded Test Suite (frozen cassettes)"
        TG["test_generate.py\nOpenAI + NIM contract\ngenerate / generate_async"]
        TS["test_stream.py\nStreaming parity matrix"]
        TSC["test_stream_cancellation.py\nTeardown / partial-on-abort"]
        TT["test_tools.py\nTool-call surfaces"]
        TTR["test_tracing.py\nTraced vs untraced parity"]
        TKB["test_kb.py\nEmbeddings + RAG retrieval"]
        TO["test_options.py\nGenerationResponse shape"]
    end
    subgraph "Deterministic (FakeLLMModel, no cassette)"
        TP["test_parity.py\nParity matrix\ninput/output/parallel × pass/block/modify"]
        TC["test_concurrency.py\nContextvar isolation\nasyncio.gather concurrent vs sequential"]
        TE["test_events.py\ngenerate_events_async"]
        TST["test_state.py\nState round-trip + log isolation"]
        TV2["test_colang_v2.py\nColang 2.x runtime"]
    end
    subgraph "Server Tests"
        TSERV["test_chat_completions.py\nHTTP contract"]
        SCONF["server/conftest.py\nTestClient fixture"]
    end
    subgraph "Live Smoke (auto-skip without real keys)"
        TLS["test_live_smoke.py\nOpenAI + NIM + KB"]
    end
    CONFIGS["configs.py\nRailsConfigSource definitions"]
    CONFIGS --> TG
    CONFIGS --> TS
    CONFIGS --> TSC
    CONFIGS --> TP
    CONFIGS --> TC
    CONFIGS --> TE
    CONFIGS --> TST
    CONFIGS --> TV2
    CONFIGS --> TKB
    CONFIGS --> TLS
    SCONF --> TSERV
    TP -- "GENERATE_CELLS / ParityCell" --> TC
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph "Recorded Test Suite (frozen cassettes)"
        TG["test_generate.py\nOpenAI + NIM contract\ngenerate / generate_async"]
        TS["test_stream.py\nStreaming parity matrix"]
        TSC["test_stream_cancellation.py\nTeardown / partial-on-abort"]
        TT["test_tools.py\nTool-call surfaces"]
        TTR["test_tracing.py\nTraced vs untraced parity"]
        TKB["test_kb.py\nEmbeddings + RAG retrieval"]
        TO["test_options.py\nGenerationResponse shape"]
    end
    subgraph "Deterministic (FakeLLMModel, no cassette)"
        TP["test_parity.py\nParity matrix\ninput/output/parallel × pass/block/modify"]
        TC["test_concurrency.py\nContextvar isolation\nasyncio.gather concurrent vs sequential"]
        TE["test_events.py\ngenerate_events_async"]
        TST["test_state.py\nState round-trip + log isolation"]
        TV2["test_colang_v2.py\nColang 2.x runtime"]
    end
    subgraph "Server Tests"
        TSERV["test_chat_completions.py\nHTTP contract"]
        SCONF["server/conftest.py\nTestClient fixture"]
    end
    subgraph "Live Smoke (auto-skip without real keys)"
        TLS["test_live_smoke.py\nOpenAI + NIM + KB"]
    end
    CONFIGS["configs.py\nRailsConfigSource definitions"]
    CONFIGS --> TG
    CONFIGS --> TS
    CONFIGS --> TSC
    CONFIGS --> TP
    CONFIGS --> TC
    CONFIGS --> TE
    CONFIGS --> TST
    CONFIGS --> TV2
    CONFIGS --> TKB
    CONFIGS --> TLS
    SCONF --> TSERV
    TP -- "GENERATE_CELLS / ParityCell" --> TC
Loading

Reviews (4): Last reviewed commit: "apply review suggestions" | Re-trigger Greptile

Comment thread tests/recorded/rails/public_api/test_stream_cancellation.py Outdated
Comment thread tests/recorded/rails/public_api/test_stream_cancellation.py Outdated
Comment thread tests/recorded/rails/public_api/test_colang_v2.py
@NVIDIA-NeMo NVIDIA-NeMo deleted a comment from coderabbitai Bot Jul 2, 2026
@Pouyanpi
Pouyanpi force-pushed the test/recorded-tests-public-api-surface branch from c82a5fb to 9490eb1 Compare July 2, 2026 13:26
Pouyanpi added 6 commits July 13, 2026 13:37
Adds recorded coverage for additional public-API surfaces (options,
parity, kb, concurrency, events, state, tracing, tools, stream
cancellation, colang 2.x) plus the server chat-completions suite and an
embeddings-index determinism guard, on top of the library-rails stack.

The colang 2.x self-check continuation test is marked xfail: a single
generate_async on an llm-continuation flow returns an intermediate
TimerBotAction polling state rather than the resolved answer.
Adds the missing test functions that consume the five stack-6 cassettes
recorded but never referenced (B6.1 reasoning_content, B1.14 log.stats,
B1.9 llm_output, A1.3 GenerationResponse shape, A3.10 streaming reasoning
not inlined). Each replays offline under --block-network; snapshots filled
from the committed cassettes.

Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
Signed-off-by: Pouyanpi <13303554+Pouyanpi@users.noreply.github.com>
@Pouyanpi
Pouyanpi force-pushed the test/recorded-tests-public-api-surface branch from 9490eb1 to 9b291f7 Compare July 13, 2026 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: XL status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant