Skip to content

perf(server): lazy-load Pydantic schema generation to fix storyboard readiness flake#435

Merged
bokelley merged 2 commits intomainfrom
claude/issue-412-lazy-pydantic-schema-init
May 3, 2026
Merged

perf(server): lazy-load Pydantic schema generation to fix storyboard readiness flake#435
bokelley merged 2 commits intomainfrom
claude/issue-412-lazy-pydantic-schema-init

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented May 3, 2026

Closes #412

Summary

_generate_pydantic_schemas(), _generate_pydantic_output_schemas(), and _apply_pydantic_schemas() previously ran at module import time, causing ~4.5s of Pydantic type-import and schema-generation work to race with the storyboard readiness probe. This produced "Agent unreachable" failures across PRs #391, #405, #406, #407.

Schema generation is now deferred to the first get_tools_for_handler() call, which fires during create_mcp_tools() at server construction — after the process is ready but before any wire request arrives. _PYDANTIC_SCHEMAS and _PYDANTIC_OUTPUT_SCHEMAS start as empty {} dicts and are populated via .update() so any external references (test files importing those symbols) stay valid. A _schemas_applied sentinel makes subsequent calls no-ops (~0ms on the hot path).

What tested

  • pytest tests/test_mcp_schema_drift.py tests/test_tools_list_output_schema.py tests/test_spec_coverage.py tests/test_server_dx.py — 78 passed
  • pytest tests/ (excluding integration/conformance) — 2816 passed, 17 skipped, 1 xfailed
  • mypy src/adcp/ — no issues (749 source files)
  • ruff check src/ — all checks passed
  • Import-time delta measured: ~4.5s of schema generation moved out of import adcp.server onto first create_mcp_tools() call

Test infrastructure change

tests/conftest.py gains a scope="session" autouse fixture that calls _ensure_pydantic_schemas_applied() before any test body runs. This ensures tests that import _PYDANTIC_SCHEMAS or read ADCP_TOOL_DEFINITIONS["inputSchema"]/["outputSchema"] directly continue to see the Pydantic-generated schemas rather than the hand-crafted stubs.

Nits (not fixed — noted for awareness)

  • _schemas_applied has no type annotation (mypy infers bool correctly from the global rebinding)
  • No logger.warning if generation raises — exception propagates to create_mcp_tools() caller, same as old import-time crash behavior; per-tool failures still produce logger.debug as before

Pre-PR review

  • code-reviewer: approved — call site in get_tools_for_handler is correct; schemas are applied before _register_handler_tools reads outputSchema from returned dicts; .update() mutation is safe; no blockers
  • dx-expert: approved (1 blocker fixed — stale "at import time" in test_spec_coverage.py assertion message; fixed in follow-up commit); 3 nits noted above

Triage-managed PR. This bot does not currently iterate on
review comments or PR conversation threads (only on the source
issue). To unblock:

  • Push fixup commits directly: gh pr checkout <num>
    fix → push.
  • Or re-trigger: comment /triage execute on the source
    issue.

See adcp#3121
for context.

Session: https://claude.ai/code/session_01NnoQN3c6Wi5LY5DEUBp8W2


Generated by Claude Code

claude added 2 commits May 3, 2026 02:52
…board readiness flake

_generate_pydantic_schemas(), _generate_pydantic_output_schemas(), and
_apply_pydantic_schemas() previously ran at module import time, causing
heavy Pydantic type imports to race with the storyboard readiness probe
and producing "Agent unreachable" failures across PRs #391, #405, #406, #407.

Generation is now deferred to the first get_tools_for_handler() call (which
fires during create_mcp_tools() at server construction, not at import time).
_PYDANTIC_SCHEMAS and _PYDANTIC_OUTPUT_SCHEMAS start as empty dicts and are
populated via .update() so external references stay valid. The _schemas_applied
sentinel makes subsequent calls no-ops (~0ms overhead on the hot path).

Import-time delta: ~4.5s of schema generation is moved from `import adcp.server`
to the first `create_mcp_tools()` call.

Tests updated: conftest.py gains a session-scoped autouse fixture that triggers
lazy init before any test reads ADCP_TOOL_DEFINITIONS schema fields; stale
"at import time" references in docstrings and error messages are updated.

Closes #412

https://claude.ai/code/session_01NnoQN3c6Wi5LY5DEUBp8W2
Addresses pre-PR review findings: test_spec_coverage.py assertion message
still referenced 'at import time', and _ensure_pydantic_schemas_applied
docstring understated the in-place mutation and misdirected to
get_tools_for_handler instead of create_mcp_tools.

https://claude.ai/code/session_01NnoQN3c6Wi5LY5DEUBp8W2
@bokelley bokelley marked this pull request as ready for review May 3, 2026 03:59
@bokelley bokelley merged commit 8664ea3 into main May 3, 2026
10 of 13 checks passed
@bokelley bokelley deleted the claude/issue-412-lazy-pydantic-schema-init branch May 3, 2026 03:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(server): lazy-load Pydantic outputSchema generation to avoid storyboard readiness flake

2 participants