Skip to content

decouple qwen3 serving from lib contract - #85

Open
bumble0918 wants to merge 3 commits into
hw-native-sys:mainfrom
bumble0918:feature/2026-07-14
Open

decouple qwen3 serving from lib contract#85
bumble0918 wants to merge 3 commits into
hw-native-sys:mainfrom
bumble0918:feature/2026-07-14

Conversation

@bumble0918

@bumble0918 bumble0918 commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

decouple qwen3 serving from lib contract

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change defines a lib-owned serving contract and migrates Qwen3 compilation, weight preparation, and runtime kernel argument construction to that contract. Batching tests now obtain contracts and prepared weights through pypto-lib.

Changes

Contract-driven serving

Layer / File(s) Summary
Serving contract model
docs/lib-serving-decoupling-architecture.md
Documents contract registration, ABI metadata, kernel and tensor argument specifications, loading, validation, and responsibility boundaries.
Contract execution and compatibility
docs/lib-serving-decoupling-architecture.md
Documents contract-owned compilation, runtime argument construction, weight preparation, compatibility checks, lifecycle, testing, and migration criteria.
Qwen3 contract-based compilation
examples/model/qwen3_14b/runner/npu_executor.py, pypto-lib
Loads the Qwen3 contract, compiles its stages, derives limits from contract metadata, and prepares weights through contract.prepare_weights.
Runtime dispatch and batching validation
examples/model/qwen3_14b/runner/npu_runner.py, tests/test_batching.py
Delegates prefill/decode argument construction to contract builders and updates batching tests for contract-prepared weights and tensor-wrapped arguments.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Qwen314BExecutor
  participant pyptoLibContractRegistry
  participant ModelServingContract
  participant Qwen314BModelRunner
  Qwen314BExecutor->>pyptoLibContractRegistry: find Qwen3 contract
  pyptoLibContractRegistry-->>Qwen314BExecutor: ModelServingContract
  Qwen314BExecutor->>ModelServingContract: load, validate, bind, and compile stages
  ModelServingContract-->>Qwen314BExecutor: compiled kernels and prepared weights
  Qwen314BModelRunner->>ModelServingContract: build prefill/decode runtime arguments
  ModelServingContract-->>Qwen314BModelRunner: raw kernel ABI tuples
Loading

Possibly related issues

  • hw-native-sys/pypto-lib issue 752 — Covers the pypto-lib serving contract layer consumed by this change.
  • hw-native-sys/pypto-serving issue 65 — Describes the lib-serving decoupling implemented here.

Possibly related PRs

Poem

I’m a rabbit hopping through the ABI,
With contracts tucked beneath my ear.
Kernels compile, weights pack just right,
Runtime tuples now grow clear.
Qwen3 bounds through the serving lane—
No copied secrets remain!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No pull request description was provided, so there is nothing substantive to assess. Add a brief description of the main change and its purpose.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the main change: moving Qwen3 serving onto a lib contract-driven boundary.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@bumble0918 bumble0918 changed the title Feature/2026 07 14 decouple qwen3 serving from lib contract Jul 14, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request implements a decoupled architecture between pypto-serving and pypto-lib by refactoring the Qwen3-14B executor and runner to use a contract-based registry instead of hardcoded kernel paths, constants, and layouts. The review feedback identifies critical issues where removing the pypto-lib directory from sys.path in finally blocks will cause ModuleNotFoundError during deferred imports. Additionally, the feedback points out a potential TypeError in both the executor code and the design documentation where contract is redundantly passed as an explicit argument to validate_kernels.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +50 to 61
def _get_pypto_lib_qwen3_contract(model: RuntimeModel) -> object:
"""Select the Qwen3 contract through pypto-lib's registry."""
sys.path.insert(0, str(_PYPTO_LIB_DIR))
try:
spec.loader.exec_module(module)
from contract.registry import find_contract_for_model_config # noqa: PLC0415

return find_contract_for_model_config(model.config)
finally:
try:
sys.path.remove(str(_PYPTO_LIB_QWEN14B_DIR))
sys.path.remove(str(_PYPTO_LIB_DIR))
except ValueError:
pass

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Removing _PYPTO_LIB_DIR from sys.path in the finally block of _get_pypto_lib_qwen3_contract will cause subsequent calls to contract methods (such as contract.load_kernels() on line 130 or contract.prepare_weights() on line 157) to fail with ModuleNotFoundError if they perform any dynamic or deferred imports from the pypto-lib submodule. Since pypto-lib is a submodule and not installed as a package, _PYPTO_LIB_DIR must remain in sys.path for the duration of the model loading, compilation, and execution process.

def _get_pypto_lib_qwen3_contract(model: RuntimeModel) -> object:
    """Select the Qwen3 contract through pypto-lib's registry."""
    if str(_PYPTO_LIB_DIR) not in sys.path:
        sys.path.insert(0, str(_PYPTO_LIB_DIR))
    from contract.registry import find_contract_for_model_config  # noqa: PLC0415
    return find_contract_for_model_config(model.config)

Comment thread tests/test_batching.py
Comment on lines +192 to +204
def _qwen3_contract():
import sys

sys.path.insert(0, str(PYPTO_LIB_DIR))
try:
from contract.registry import get_contract

return get_contract("qwen3", "14b")
finally:
try:
sys.path.remove(str(PYPTO_LIB_DIR))
except ValueError:
pass

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Just like in npu_executor.py, removing PYPTO_LIB_DIR from sys.path in the finally block of _qwen3_contract will cause subsequent calls to contract methods (such as prepare_weights on line 576) to fail with ModuleNotFoundError if they perform any dynamic or deferred imports from the pypto-lib submodule.

def _qwen3_contract():
    import sys

    if str(PYPTO_LIB_DIR) not in sys.path:
        sys.path.insert(0, str(PYPTO_LIB_DIR))
    from contract.registry import get_contract

    return get_contract("qwen3", "14b")

)
contract = _get_pypto_lib_qwen3_contract(model)
loaded_kernels = contract.load_kernels()
contract.validate_kernels(contract, loaded_kernels, _contract_validation_model(model, contract))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Calling contract.validate_kernels(contract, loaded_kernels, ...) passes contract explicitly as the first positional argument. If validate_kernels is defined as a standard instance method on ModelServingContract (i.e., def validate_kernels(self, loaded_kernels, model)), calling it this way will result in a TypeError because contract is passed twice (once implicitly as self, and once explicitly as the first positional argument).

Suggested change
contract.validate_kernels(contract, loaded_kernels, _contract_validation_model(model, contract))
contract.validate_kernels(loaded_kernels, _contract_validation_model(model, contract))


```python
loaded_kernels = contract.load_kernels()
contract.validate_kernels(contract, loaded_kernels, model)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

In the example code, contract.validate_kernels(contract, loaded_kernels, model) explicitly passes contract as the first positional argument. If validate_kernels is an instance method, calling it this way will result in a TypeError in Python. It should be updated to match the standard instance method invocation.

Suggested change
contract.validate_kernels(contract, loaded_kernels, model)
contract.validate_kernels(loaded_kernels, model)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
examples/model/qwen3_14b/runner/npu_runner.py (1)

82-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

contract: object blocks static attribute access checks.

contract is later accessed as self._compiled.contract.kernels["prefill"].runtime_args_builder(...) (lines 718, 733). Under mypy, object only supports operations valid for all objects (isinstance, equality); attribute access like .kernels is flagged as [attr-defined], unlike Any. If this repo runs a type checker, this field's usage will fail static checks.

🔧 Suggested fix
-    contract: object
+    contract: Any

Consider a Protocol capturing the minimal kernels: dict[str, ...] / runtime_args_builder interface for stronger typing, if feasible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/model/qwen3_14b/runner/npu_runner.py` at line 82, Replace the
`contract: object` annotation in the relevant runner class with a structural
type describing the accessed interface: a `kernels` mapping containing entries
that expose `runtime_args_builder(...)`. Update the compiled-contract annotation
to use this protocol so the accesses in the prefill paths remain type-safe under
mypy.
tests/test_batching.py (1)

192-206: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cache _qwen3_contract() to avoid repeated sys.path churn.

This helper mutates the global sys.path and re-imports on every call; it's invoked from every _compiled_kernels(...) call across the test module plus directly, so the path insert/remove happens far more often than needed for what should be a stable lookup.

♻️ Suggested fix
+import functools
+
+
+@functools.lru_cache(maxsize=1)
 def _qwen3_contract():
     import sys
 
     sys.path.insert(0, str(PYPTO_LIB_DIR))
     try:
         from contract.registry import get_contract
 
         return get_contract("qwen3", "14b")
     finally:
         try:
             sys.path.remove(str(PYPTO_LIB_DIR))
         except ValueError:
             pass
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_batching.py` around lines 192 - 206, Cache the result of
_qwen3_contract() so the contract lookup and temporary sys.path
insertion/removal occur only once. Apply the cache at the helper boundary,
preserving the existing get_contract("qwen3", "14b") behavior and return value
for all callers, including direct calls and _compiled_kernels(...).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/model/qwen3_14b/runner/npu_executor.py`:
- Around line 50-61: Update the wrapper compilation logic to use the stage
spec’s public_name attribute wherever it currently accesses stage.name. Preserve
the existing contract lookup flow and ensure all generated wrapper references
use the supported public_name contract surface.

In `@pypto-lib`:
- Line 1: Update the pypto-lib submodule gitlink from the unreachable commit
6c7f71f69986b2072664a02f573d5df5f8bc4f93 to a commit that is available from the
configured pypto-lib repository, preserving the submodule reference and ensuring
it can be fetched by clean checkouts.

---

Nitpick comments:
In `@examples/model/qwen3_14b/runner/npu_runner.py`:
- Line 82: Replace the `contract: object` annotation in the relevant runner
class with a structural type describing the accessed interface: a `kernels`
mapping containing entries that expose `runtime_args_builder(...)`. Update the
compiled-contract annotation to use this protocol so the accesses in the prefill
paths remain type-safe under mypy.

In `@tests/test_batching.py`:
- Around line 192-206: Cache the result of _qwen3_contract() so the contract
lookup and temporary sys.path insertion/removal occur only once. Apply the cache
at the helper boundary, preserving the existing get_contract("qwen3", "14b")
behavior and return value for all callers, including direct calls and
_compiled_kernels(...).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f7964068-78b5-4022-a4de-b994564cb7c5

📥 Commits

Reviewing files that changed from the base of the PR and between 49297c2 and 70e46b3.

📒 Files selected for processing (5)
  • docs/lib-serving-decoupling-architecture.md
  • examples/model/qwen3_14b/runner/npu_executor.py
  • examples/model/qwen3_14b/runner/npu_runner.py
  • pypto-lib
  • tests/test_batching.py

Comment on lines +50 to 61
def _get_pypto_lib_qwen3_contract(model: RuntimeModel) -> object:
"""Select the Qwen3 contract through pypto-lib's registry."""
sys.path.insert(0, str(_PYPTO_LIB_DIR))
try:
spec.loader.exec_module(module)
from contract.registry import find_contract_for_model_config # noqa: PLC0415

return find_contract_for_model_config(model.config)
finally:
try:
sys.path.remove(str(_PYPTO_LIB_QWEN14B_DIR))
sys.path.remove(str(_PYPTO_LIB_DIR))
except ValueError:
pass

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail

echo "== file outline =="
ast-grep outline examples/model/qwen3_14b/runner/npu_executor.py --view expanded || true

echo
echo "== relevant lines in executor =="
nl -ba examples/model/qwen3_14b/runner/npu_executor.py | sed -n '1,340p'

echo
echo "== contract docs references =="
rg -n "public_name|compile_args_builder|runtime_args_builder|host_jit_fn|stage\.name|name field" docs examples/model/qwen3_14b -S || true

Repository: hw-native-sys/pypto-serving

Length of output: 1155


🏁 Script executed:

python3 - <<'PY'
from pathlib import Path
p = Path('examples/model/qwen3_14b/runner/npu_executor.py')
text = p.read_text()
for needle in ['_get_pypto_lib_qwen3_contract', 'load_kernels', 'prepare_weights', '_compile_contract_stage', 'stage.name', 'stage.public_name']:
    print(f'== {needle} ==')
    idx = text.find(needle)
    if idx == -1:
        print('not found')
        continue
    start = max(0, text.rfind('\n', 0, idx-200))
    end = min(len(text), text.find('\n', idx+400))
    print(text[start:end])
PY

Repository: hw-native-sys/pypto-serving

Length of output: 3671


🏁 Script executed:

python3 - <<'PY'
from pathlib import Path
docs = Path('docs/lib-serving-decoupling-architecture.md')
if docs.exists():
    text = docs.read_text()
    for needle in ['public_name', 'compile_args_builder', 'runtime_args_builder', 'host_jit_fn']:
        print(f'== {needle} ==')
        for i, line in enumerate(text.splitlines(), 1):
            if needle in line:
                print(f'{i}: {line}')
else:
    print('docs file missing')
PY

Repository: hw-native-sys/pypto-serving

Length of output: 1131


🏁 Script executed:

set -euo pipefail

echo "== executor excerpt =="
nl -ba examples/model/qwen3_14b/runner/npu_executor.py | sed -n '40,170p'

echo
echo "== stage/contract excerpt =="
nl -ba examples/model/qwen3_14b/runner/npu_executor.py | sed -n '240,310p'

echo
echo "== docs excerpt =="
nl -ba docs/lib-serving-decoupling-architecture.md | sed -n '210,230p'

Repository: hw-native-sys/pypto-serving

Length of output: 228


🏁 Script executed:

set -euo pipefail

echo "== pypto-lib references =="
rg -n "pypto-lib|public_name|compile_args_builder|runtime_args_builder|host_jit_fn|stage\.name|KernelSpec|contract\.kernels|find_contract_for_model_config" . -S

echo
echo "== likely contract/spec definition files =="
fd -a "kernel" .
fd -a "contract" .
fd -a "spec" .

echo
echo "== focused search around KernelSpec / stage fields =="
rg -n "class .*KernelSpec|public_name|name:|host_jit_fn|compile_args_builder|runtime_args_builder" docs examples/model/qwen3_14b . -S

Repository: hw-native-sys/pypto-serving

Length of output: 21275


🏁 Script executed:

set -euo pipefail

echo "== sys.path import patterns =="
rg -n "sys\.path\.insert|sys\.path\.remove|importlib\.import_module|from contract\.registry|load_kernels\(|prepare_weights\(|kernel_binder\(" examples/model -S

echo
echo "== deepseek executor import helper =="
python3 - <<'PY'
from pathlib import Path
p = Path('examples/model/deepseek_v4/runner/npu_executor.py')
text = p.read_text().splitlines()
for start in [200, 380]:
    end = min(len(text), start + 90)
    print(f'--- lines {start+1}-{end} ---')
    for i in range(start, end):
        print(f'{i+1:4d}: {text[i]}')
PY

echo
echo "== qwen executor surrounding compile path =="
python3 - <<'PY'
from pathlib import Path
p = Path('examples/model/qwen3_14b/runner/npu_executor.py')
text = p.read_text().splitlines()
for start in [118, 244]:
    end = min(len(text), start + 70)
    print(f'--- lines {start+1}-{end} ---')
    for i in range(start, end):
        print(f'{i+1:4d}: {text[i]}')
PY

Repository: hw-native-sys/pypto-serving

Length of output: 16831


Use stage.public_name here
The stage spec exposes public_name; stage.name is not part of the contract surface, so this will raise when compiling the wrappers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/model/qwen3_14b/runner/npu_executor.py` around lines 50 - 61, Update
the wrapper compilation logic to use the stage spec’s public_name attribute
wherever it currently accesses stage.name. Preserve the existing contract lookup
flow and ensure all generated wrapper references use the supported public_name
contract surface.

Comment thread pypto-lib
@@ -1 +1 @@
Subproject commit 3bbd72d00b9b90fe6e70b9077840b3cf6f978f73
Subproject commit 6c7f71f69986b2072664a02f573d5df5f8bc4f93

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git -C pypto-lib cat-file -e 6c7f71f69986b2072664a02f573d5df5f8bc4f93^{commit}
git -C pypto-lib grep -nE 'serving contract|contract registry|prepared weights' \
  6c7f71f69986b2072664a02f573d5df5f8bc4f93 -- .

Repository: hw-native-sys/pypto-serving

Length of output: 341


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== submodule config =="
git config -f .gitmodules --get-regexp '^submodule\.' || true

echo
echo "== gitlink =="
git ls-tree HEAD pypto-lib || true

echo
echo "== remote for submodule =="
git -C pypto-lib remote -v || true

echo
echo "== any refs matching the pin prefix =="
git -C pypto-lib show-ref | rg '6c7f71f69986b2072664a02f573d5df5f8bc4f93|pypto-lib' || true

Repository: hw-native-sys/pypto-serving

Length of output: 851


Pinned submodule commit is unreachable

pypto-lib points to 6c7f71f69986b2072664a02f573d5df5f8bc4f93, but that commit isn’t available from https://github.com/hw-native-sys/pypto-lib.git. Update the gitlink to a fetchable commit before merging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pypto-lib` at line 1, Update the pypto-lib submodule gitlink from the
unreachable commit 6c7f71f69986b2072664a02f573d5df5f8bc4f93 to a commit that is
available from the configured pypto-lib repository, preserving the submodule
reference and ensuring it can be fetched by clean checkouts.

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