Skip to content

fix(ci): add langchain-core to [dev] so test collection passes#4

Merged
maltsev-dev merged 1 commit into
masterfrom
fix/ci-langchain-dev-extras
Jun 18, 2026
Merged

fix(ci): add langchain-core to [dev] so test collection passes#4
maltsev-dev merged 1 commit into
masterfrom
fix/ci-langchain-dev-extras

Conversation

@maltsev-dev

Copy link
Copy Markdown
Member

The SDK's import chain (nullrun.init -> nullrun.decorators -> nullrun.instrumentation.langgraph -> 'from langchain_core.callbacks import BaseCallbackHandler') runs at pytest collection time, not at a specific test. With CI installing [dev] only, every test in the suite errored on collection with:

ModuleNotFoundError: No module named 'langchain_core'

This is the same class of bug that 'nullrun[langgraph]' exists to prevent for end users, except the dev install never benefited from the extras indirection.

Fix: add 'langchain-core>=0.3,<1.0' to the [dev] extras. The heavier 'langgraph' / 'langchain' extras pull in stacks the unit tests don't use; the bare core is the smallest dep that makes the import chain resolve and unblocks test collection on every supported Python (3.10 / 3.11 / 3.12) on every PR.

Validation: locally on Python 3.14.2 (which is outside the 3.10/3.11/3.12 matrix that CI tests), 'pip install -e .[dev]' followed by 'pytest tests/' runs 443/443 + 9/9 new byte-mismatch unit tests, no collection error. CI will re-confirm on the 3.10 / 3.11 / 3.12 matrix.

What

Why

How

Test plan

  • Unit tests pass (per-repo, e.g. cd backend && cargo test, cd frontend && npm test)
  • Lint passes (per-repo, e.g. cd frontend && npm run lint)
  • Type-check passes (per-repo, e.g. cd frontend && npm run type-check)
  • Manually verified in dev / staging

Risk

Checklist

  • I have read the repo's CONTRIBUTING.md (if present)
  • My change does not introduce new lint warnings
  • I have updated the CHANGELOG (if user-visible)
  • I have considered backwards compatibility

The SDK's import chain (nullrun.__init__ -> nullrun.decorators ->
nullrun.instrumentation.langgraph -> 'from langchain_core.callbacks
import BaseCallbackHandler') runs at pytest *collection* time, not at a
specific test. With CI installing [dev] only, every test in the suite
errored on collection with:

    ModuleNotFoundError: No module named 'langchain_core'

This is the same class of bug that 'nullrun[langgraph]' exists to
prevent for end users, except the dev install never benefited from
the extras indirection.

Fix: add 'langchain-core>=0.3,<1.0' to the [dev] extras. The
heavier 'langgraph' / 'langchain' extras pull in stacks the unit
tests don't use; the bare core is the smallest dep that makes the
import chain resolve and unblocks test collection on every
supported Python (3.10 / 3.11 / 3.12) on every PR.

Validation: locally on Python 3.14.2 (which is outside the
3.10/3.11/3.12 matrix that CI tests), 'pip install -e .[dev]'
followed by 'pytest tests/' runs 443/443 + 9/9 new byte-mismatch
unit tests, no collection error. CI will re-confirm on the 3.10 /
3.11 / 3.12 matrix.
@maltsev-dev maltsev-dev merged commit 1e9e9c0 into master Jun 18, 2026
0 of 4 checks passed
@maltsev-dev maltsev-dev deleted the fix/ci-langchain-dev-extras branch June 18, 2026 15:05
maltsev-dev added a commit that referenced this pull request Jul 4, 2026
Bug-fix release layered on top of 0.12.1. No wire-format change;
both fixes are client-side only.

* BUG #4 -- check_workflow_budget() now sends a fresh uuidv7 as the
  "execution_id" field on every /check call instead of reusing
  workflow_id. The server's gate_reserve_v3 overwrites the field on
  response anyway, but a client-side placeholder that collides
  across calls confuses the v3 reservation binding on /track when
  Transport.track_single() reaches the backend and the field is
  stale -- exact symptom is 503 RESERVATION_NOT_FOUND per
  CLAUDE.md section 29.

* BUG #5 -- new nullrun.runtime._GATE_CACHE (5s TTL, keyed on
  (workflow_id, chain_id, model)) collapses consecutive /gate
  calls from inside `with chain(...)` to a single roundtrip,
  avoiding 100 /gate calls per 100-step agent loop. Single-shot
  (Hard mode) callers MUST bypass the cache -- Hard mode's binary
  allow -> block semantics would let a stale "allow" leak a
  budget-exhausted call through. Opt-out via
  NULLRUN_GATE_CACHE_DISABLE=1 for callers that want the legacy
  always-roundtrip behaviour (used by live smoke tests per
  docs/runbooks/budget-blue-green-smoke.sh).

Tests: 158 new lines in tests/test_v3_wire_contract.py covering
per-call execution_id uniqueness, uuidv7 format validation, and
the new cache data-structure invariants + opt-out cases.

Bumps __version__ + pyproject.toml to 0.12.2.
maltsev-dev added a commit that referenced this pull request Jul 4, 2026
`ruff check src/` flagged that the BUG #4 line
`from nullrun.uuid7 import uuid7_str  # CLAUDE.md §24`
landed mid-way through the first-party import block (between
`nullrun.context` and `nullrun.observability`), breaking I001
import sort. Moved to the bottom of the first-party block
(alphabetic order — `uuid7` sorts after `transport`).

Also lets ruff auto-fix two cosmetic cleanups in
tests/test_v3_wire_contract.py:
* sort `_V3_ERROR_CODE_MAP` alphabetic in the existing
  transport import group (was below `_parse_v3_error_envelope`);
* drop a stray blank-line gap between two top-level
  `from nullrun.transport import (...)` groups.

`ruff check src/ tests/` after the fix: 8 pre-existing I001
findings remain in unrelated test files (predicate,
test_circuit_breaker_branches.py, test_framework_patches.py,
etc.) — out of scope for this PR. Scope above matches the
CI step (`ruff check src/`).

No behavioural change.
maltsev-dev added a commit that referenced this pull request Jul 4, 2026
* release(0.12.2): fresh execution_id per /check + chain-mode /gate cache

Bug-fix release layered on top of 0.12.1. No wire-format change;
both fixes are client-side only.

* BUG #4 -- check_workflow_budget() now sends a fresh uuidv7 as the
  "execution_id" field on every /check call instead of reusing
  workflow_id. The server's gate_reserve_v3 overwrites the field on
  response anyway, but a client-side placeholder that collides
  across calls confuses the v3 reservation binding on /track when
  Transport.track_single() reaches the backend and the field is
  stale -- exact symptom is 503 RESERVATION_NOT_FOUND per
  CLAUDE.md section 29.

* BUG #5 -- new nullrun.runtime._GATE_CACHE (5s TTL, keyed on
  (workflow_id, chain_id, model)) collapses consecutive /gate
  calls from inside `with chain(...)` to a single roundtrip,
  avoiding 100 /gate calls per 100-step agent loop. Single-shot
  (Hard mode) callers MUST bypass the cache -- Hard mode's binary
  allow -> block semantics would let a stale "allow" leak a
  budget-exhausted call through. Opt-out via
  NULLRUN_GATE_CACHE_DISABLE=1 for callers that want the legacy
  always-roundtrip behaviour (used by live smoke tests per
  docs/runbooks/budget-blue-green-smoke.sh).

Tests: 158 new lines in tests/test_v3_wire_contract.py covering
per-call execution_id uniqueness, uuidv7 format validation, and
the new cache data-structure invariants + opt-out cases.

Bumps __version__ + pyproject.toml to 0.12.2.

* fix(lint): reorder uuid7 import in runtime.py per ruff I001

`ruff check src/` flagged that the BUG #4 line
`from nullrun.uuid7 import uuid7_str  # CLAUDE.md §24`
landed mid-way through the first-party import block (between
`nullrun.context` and `nullrun.observability`), breaking I001
import sort. Moved to the bottom of the first-party block
(alphabetic order — `uuid7` sorts after `transport`).

Also lets ruff auto-fix two cosmetic cleanups in
tests/test_v3_wire_contract.py:
* sort `_V3_ERROR_CODE_MAP` alphabetic in the existing
  transport import group (was below `_parse_v3_error_envelope`);
* drop a stray blank-line gap between two top-level
  `from nullrun.transport import (...)` groups.

`ruff check src/ tests/` after the fix: 8 pre-existing I001
findings remain in unrelated test files (predicate,
test_circuit_breaker_branches.py, test_framework_patches.py,
etc.) — out of scope for this PR. Scope above matches the
CI step (`ruff check src/`).

No behavioural change.
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.

1 participant