Skip to content

feat(0.10.2): 44-cell deep integration matrix — 8 agents × 4 families + 3 frameworks × 4 families#1033

Open
raullenchai wants to merge 15 commits into
mainfrom
feat/deep-integration-tests-0102
Open

feat(0.10.2): 44-cell deep integration matrix — 8 agents × 4 families + 3 frameworks × 4 families#1033
raullenchai wants to merge 15 commits into
mainfrom
feat/deep-integration-tests-0102

Conversation

@raullenchai

Copy link
Copy Markdown
Owner

Summary

Turns the 0.10.2 PR-1 scaffold into a real 48-cell integration matrix that
exercises every Tier-1 agent + framework against the four Tier-1 family
strong picks. Each cell drives a real client SDK against a booted
rapid-mlx server on port 8802 — no mocks, no synthetic fixtures.

Matrix shape (48 real cells):

  • 8 Tier-1 agents × 4 families = 32 tool-calling cells (agents)
  • +1 shared streaming cell × 4 families = 4 SSE cells
  • 3 Tier-1 frameworks × 4 families = 12 framework cells

Strong picks per family (raullen 2026-07-06 sign-off):

Family Alias HF path Size
Qwen 3.6 qwen3.6-35b-8bit mlx-community/Qwen3.6-35B-A3B-8bit 35 GB
Gemma 4 gemma-4-31b-4bit mlx-community/gemma-4-31b-it-4bit 18 GB
DeepSeek deepseek-v4-flash-8bit mlx-community/DeepSeek-V4-Flash-8bit 50 GB
gpt-oss gpt-oss-120b-mxfp4-q8 mlx-community/gpt-oss-120b-MXFP4-Q8 65 GB

Small variants (4B/12B) fail tool-calling for reasons unrelated to the
wire path (model 降智 — capability ceiling of the quant/size). Strong
picks isolate engine regressions from model-capability noise.

Fold-ins from post-#1030 pr_validate reds

  • stress_e2e_bench: FAIL — golden_models.yaml was still on the pre-0.10
    Qwen 3.5 / diffusion-gemma / harmony triplet. Realigned to the 4 Tier-1
    families with strong picks; primary + fallback ordering preserved so
    constrained-host CI still selects the smaller candidate on RAM fit.
  • full_unit: FAILtest_deep_nest_dos.py::test_d_tool_recur_parser_depth_1000_returns_invalid_request_code
    message pin drifted (RAPID_MLX_MAX_TOOL_SCHEMA_DEPTH now catches the
    payload before the body-parser depth cap). Relaxed the assertion to
    accept either gate's message — both satisfy the security invariant
    (400 + no traceback + canonical invalid_request code).
  • full_unit: FAILtest_pr_validate_runner.py::TestSelectModels::test_real_yaml_high_ram_picks_first_qwen36_candidate
    hardcoded hermes as the qwen3.6 override parser. Updated to accept
    either qwen3_coder_xml (35B primary) or hermes (27B fallback);
    removed the diffusiongemma sub-test since the family is out of the
    registry.

Matrix run results (2026-07-06)

Verified end-to-end on the maintainer's M3 Ultra:

  • Qwen 3.6 (qwen3.6-35b-8bit, cached): 12/12 PASS in 24 s
    (9 agent cells + 3 framework cells).
  • Gemma 4 (gemma-4-31b-4bit, downloaded fresh): 12/12 PASS in 23 s
    (9 agent cells + 3 framework cells).

Pending real-run (matrix ready, weights downloading):

  • DeepSeek V4 Flash (deepseek-v4-flash-8bit, 50 GB download in flight).
  • gpt-oss 120B (gpt-oss-120b-mxfp4-q8, 65 GB queued after DeepSeek).

The matrix code is parametrized over all four families; the two pending
runs will be validated once weights finish downloading. Auto-boot
mechanism proven working end-to-end (see conftest.py _boot_server /
_wait_for_ready).

Design decisions

  • Auto-boot vs external server — the prior scaffold required a
    manually-booted server or every cell skipped; codex feat(0.10.2): Portfolio ops — 8 Tier-1 agents + 3 frameworks + integration matrix #1030 flagged the
    all-skip as regression-hiding. New conftest boots the server itself
    and tears down at session end. Set RAPID_MLX_BASE_URL to point at an
    already-loaded server if you don't want the boot dance.
  • Per-family sequential — the M3 Ultra can't hold two 50-65 GB
    models at once with operator services running. The family_alias
    parametrized fixture is session-scoped; a new server boots for each
    family, tears down, and the next boots.
  • Port 8802 hard-coded default — G1 requires never touching 8801
    (operator qwen3-vl) or 8772 (operator Holo3). Conftest hard-refuses
    to boot on those.
  • HF cache probe before boot — a session that would fetch weights
    during pytest collection is a bad experience; if the cache is empty,
    the fixture skips (or fails in strict mode) with a snapshot_download
    command to run first.

Test plan

  • Ruff clean on tests/integrations/
  • pytest tests/test_deep_nest_dos.py — 33 passed
  • pytest tests/test_pr_validate_runner.py — 30 passed
  • Qwen 3.6 matrix full run — 12/12 PASS (external server mode)
  • Qwen 3.6 matrix auto-boot mode — 1/1 PASS (spot-check TestCodexCLI)
  • Gemma 4 matrix full run — 12/12 PASS (external server mode)
  • DeepSeek V4 Flash matrix full run — pending download
  • gpt-oss 120B matrix full run — pending download
  • pr_validate CLI clean (codex_review pass)

Bugs found & fixed

  • codex_review overrides for the pre-Tier-1 golden_models registry
    (see 'Fold-ins' above).
  • test_deep_nest_dos message-pin drift (see 'Fold-ins' above).

Bugs spun out

None yet — all matrix cells that ran passed cleanly.

🤖 Generated with Claude Code

…picks, auto-boot

- conftest.py: auto-boots rapid-mlx serve on port 8802 per family;
  4-family parametrization (qwen36 / gemma4 / deepseek / gptoss);
  HF cache probe before boot; RAPID_MLX_MATRIX_STRICT respected.
- test_agents_matrix.py: 8 agents × 4 families + 1 shared streaming
  cell × 4 families = 36 real cells with tool-call assertions.
- test_frameworks_matrix.py: 3 frameworks × 4 families = 12 real cells
  with plain invoke + bind_tools tool call assertions.
- golden_models.yaml: aligned stress_e2e_bench to Tier-1 4 families
  (was qwen3.5 / qwen3.6 / diffusion-gemma / harmony); strong picks
  first, fallbacks preserved for constrained hosts.
- tests/test_deep_nest_dos.py: relax the exact-message pin — accept
  either "parsing the body" or "RAPID_MLX_MAX_TOOL_SCHEMA_DEPTH" so
  the tool-schema depth cap tightening doesn't red the DoS guard.
…atrix

Reflect the 0.10.2 PR-2 restructure: 4 Tier-1 families (Qwen 3.6, Gemma
4, DeepSeek V4 Flash, gpt-oss 120B) with strong picks; auto-boot mode;
per-family shard workflow; matrix status table gains DeepSeek + gpt-oss
columns.
… realignment

golden_models.yaml first candidate is now Qwen3.6-35B-A3B-8bit (strong
pick), which uses qwen3_coder_xml parser. Introduce a second
expected-args tuple _QWEN36_XML_ARGS and accept either the XML
parser (for the 35B pick) or hermes (for the 27B fallback) in
test_real_yaml_high_ram_picks_first_qwen36_candidate — the invariant
is 'override entry is wired through correctly', not 'parser is
literally hermes'.

Drop test_real_yaml_skips_diffusiongemma_quality_agents — the
diffusiongemma family is no longer in the Tier-1 registry. Its
DiffusionEngine coverage moves to the aliases + auto-detect layer
(see aliases.json modality: text-diffusion); no need to keep a
gate on a family that's not in the matrix.
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

PR #1033 validation scorecard

Title: feat(0.10.2): 44-cell deep integration matrix — 8 agents × 4 families + 3 frameworks × 4 families
Author: raullenchai
Diff: 8 file(s), +1419/-618 LOC, blast radius: medium

Verdict: DO NOT MERGE

step status summary time
fetch PASS 8 files, +1419/-618 LOC, blast=medium 2.9s
test_plan_check FAIL 3/9 test-plan item(s) still unchecked 0.0s
cl_description_quality PASS title OK + body has rationale (4819 chars) 0.0s
supply_chain PASS no hooks touched, no suspicious patterns, deps clean 0.0s
test_env_check PASS installed trusted-pins (2 missing plugin(s) recovered) 5.1s
codex_review skip codex CLI not found on PATH (install: npm i -g @openai/codex) 0.0s
lint PASS clean (6 file(s)) 0.0s
targeted_tests PASS 69 passed, 48 skipped in 1.34s (in 6 target file(s)) 2.2s

Details

test_plan_check — FAIL

3 unchecked test-plan item(s) out of 9 total:

  1. [ ] DeepSeek V4 Flash matrix full run — pending download
  2. [ ] gpt-oss 120B matrix full run — pending download
  3. [ ] pr_validate CLI clean (codex_review pass)

Either verify the item and check the box in the PR body, or remove the item if it's no longer applicable. PR #435 / #427 landed an incomplete fix because its - [ ] E2E verification item was left unchecked at merge — this gate exists so that doesn't repeat.

raullenchai and others added 11 commits July 6, 2026 13:38
The 0.10.2 PR-2 golden_models realignment removes diffusion-gemma from
the Tier-1 registry. The invariant this test guards ("if diffusiongemma
is present, stress_timeout_s must be 1800") is still worth keeping —
whoever re-adds the family for DiffusionEngine coverage after the next
Bug A-class regression shouldn't have to re-derive the 1800s budget
from issue #664. Skip when absent, enforce when present.
BLOCKING #1 — external-server mode now maps ``/v1/models`` id → family
and strict_skip_or_fails on mismatch. A single Qwen server can no
longer silently "cover" Gemma / DeepSeek / gpt-oss cells; the
external path now matches the auto-boot path's isolation.

BLOCKING #2 — ``_boot_server`` no longer leaks the parent-side log file
descriptor on every successful family boot. Wrap the ``open`` in a
context manager so ``Popen`` dups the fd for the child and the parent
handle is closed when the ``with`` block exits.

BLOCKING #3 — ``_hf_cache_present`` now requires at least one non-empty
weight file (``.safetensors`` / ``.npz`` / ``.bin`` / ``.gguf``) with
its symlink target resolving. A partial snapshot containing only
config.json + tokenizer.json can no longer trip the probe and
trigger a 50-65 GB in-pytest download.

NIT #1 — malformed ``RAPID_MLX_MATRIX_PORT`` (e.g. non-integer) now
yields a ``pytest.exit`` with a human-readable message instead of a
raw ``ValueError`` traceback in fixture collection.

NIT #2 — ``RAPID_MLX_SERVE_BIN`` now parses via ``shlex.split`` so a
quoted path like ``'/opt/homebrew/opt/python@3.12/bin/python3.12 -m
vllm_mlx.cli'`` — or any argv element containing a space — tokenises
correctly instead of splitting on the space.

Re-verified: auto-boot Qwen 3.6 codex-cli cell PASS in 18 s after the
refactor.
BLOCKING #1 — PydanticAI tool cell now asserts get_weather was
ACTUALLY invoked (invocation counter closure) and that the answer
references the tool's return (\"sunny\" / \"tokyo\"). A model that
answers inline while ignoring the tool prompt now fails in strict
CI instead of skating past the empty-string check.

BLOCKING #2 — qwen3.6 YAML runner test now branches on
``qwen36.model_id`` and requires the exact parser the alias-registry
maps to that checkpoint (35B → qwen3_coder_xml, 27B → hermes). The
earlier \"accept either\" acceptance let a 35B primary accidentally
wired to hermes still pass.

BLOCKING #3 — restored the hard \"diffusiongemma has 1800s override\"
assertion. Re-added the diffusion-gemma family as a non-Tier-1
supplementary entry in golden_models.yaml (with the load-bearing
DiffusionEngine-coverage rationale in-line) so a deletion is a red
red, not a silent skip. The Tier-1 four families remain the
correctness surface; diffusion-gemma is the engine-path smoke.
BLOCKING #1 — ``FamilyAlias`` gains a ``serve_args`` tuple with the
per-family ``--enable-auto-tool-choice`` / ``--tool-call-parser`` flags
(qwen3_coder_xml / gemma4 / deepseek / harmony). ``_serve_command``
appends them so the matrix boots with the intended parser wired at
the CLI layer instead of silently relying on the auto-detect table.
A regression in the auto-detect map now surfaces at that layer, not
as a tool-call cell red.

BLOCKING #2 — ``_hf_cache_present`` uses ``snap.rglob('*')`` so a
snapshot that stores weights under sub-directories (some HF repos
use a ``weights/`` or per-shard subdir layout) is no longer falsely
reported as missing.

NIT — ``_matrix_port()`` moved into the auto-boot branch. External-
server mode with a bad ``RAPID_MLX_MATRIX_PORT`` no longer crashes a
local dev run that pointed at an already-running server via
``RAPID_MLX_BASE_URL``.

Re-verified: auto-boot Qwen 3.6 CodexCLI + QwenCode cells PASS in 22 s
with the new ``serve_args`` wired.
BLOCKING #1 — restored the naive-user auto-detect path as the default.
``_serve_command`` boots plain ``serve <alias> --port <port>`` (no
explicit --tool-call-parser). ``explicit_serve_args`` on ``FamilyAlias``
is retained but only appended when ``RAPID_MLX_MATRIX_EXPLICIT_PARSER=1``
is set — that env flag gives a separate CI shard the belt-and-braces
mode round-3 codex asked for, without silently bypassing the alias
auto-detect table PyPI/Homebrew users hit.

BLOCKING #2 — TestStreamingDeltas now runs the no-leak assertions on
each streamed delta AND on the concatenated streamed_text. A server
that leaks ``<think>`` / ``<|channel|>analysis`` mid-stream but strips
them from the final assembled object no longer passes; a client that
renders as tokens arrive would see the leak.

BLOCKING #3 — PydanticAI tool assertion now uses ``and`` between
``sunny`` and ``tokyo``. An answer that merely mentions Tokyo while
ignoring the tool's ``sunny in <city>`` return no longer passes.

BLOCKING #4 — smolagents cell now increments an invocation counter
in GetWeatherTool.forward() and asserts (a) count > 0 and (b) the
answer references both ``sunny`` AND ``tokyo``. An inline model reply
with broken tool routing no longer passes.

BLOCKING #5 — boot-timeout teardown now calls ``proc.wait(timeout=10)``
after ``proc.kill()`` to reap the child. Mirrors the normal
``_shutdown_server`` path so no zombie is left behind.

Re-verified: Qwen 3.6 12/12 cells PASS in 23 s with the tightened
assertions.
BLOCKING #1 — normalize external ``RAPID_MLX_BASE_URL`` to end in
``/v1`` so a host-root (``http://127.0.0.1:8802``) or a /v1 base
(``http://127.0.0.1:8802/v1``) both probe /v1/models correctly. The
downstream SDK clients also receive the /v1 base URL either way.

BLOCKING #2 — ``_hf_cache_present`` now uses ``huggingface_hub.
constants.HF_HUB_CACHE`` (which honors ``HF_HUB_CACHE`` /
``HUGGINGFACE_HUB_CACHE`` / ``HF_HOME``). A strict matrix job with a
relocated HF cache no longer skips before boot on a spurious "cache
miss" that was really a path resolution bug.

NIT #1 — ``_wait_for_ready`` now takes an optional ``proc`` and checks
``proc.poll()`` per-iteration. A child that died at import time
(missing dep, stale editable install) surfaces immediately instead of
hanging out the full 600 s budget on a URL that will never come up.

NIT #2 — log file created via ``tempfile.NamedTemporaryFile(
delete=False)`` so a planted symlink at
``/tmp/rapid-mlx-matrix-...`` on a shared machine can't be followed
to clobber an arbitrary file the test user owns. ``delete=False``
keeps the log around for operator post-mortem.

Re-verified: Qwen 3.6 codex-cli + streaming cells PASS in 18 s.
gpt-oss 120B emits long chain-of-thought on the analysis channel
before the assistant-channel final content — 64 max_tokens hit the
limit mid-reasoning and the OpenAI SDK's ``get_final_completion()``
raised ``LengthFinishReasonError`` before we could assert on the
final object. Two fixes:

1. Bump max_tokens for the streaming test to 256 so ``count to
   three'' reaches the assistant channel on reasoning models.
2. Catch ``LengthFinishReasonError`` from ``get_final_completion``
   and fall through with ``final=None``. The per-delta assertions
   already ran during the stream iteration (leak-marker gate) — the
   final-object gate is skipped only when the model ran the
   reasoning past the token budget, which is not a wire regression.

Re-verified: gpt-oss 120B matrix now 12/12 PASS in 16 s (was 11/12
with TestStreamingDeltas failing on LengthFinishReasonError).

Total confirmed matrix passes:
* Qwen 3.6 (35B): 12/12 PASS
* Gemma 4 (31B): 12/12 PASS
* gpt-oss (120B): 12/12 PASS
* DeepSeek V4 Flash: pending download completion.
BLOCKING #1 — TestStreamingDeltas now requires ``streamed_text`` to
be non-empty. A model that spends all max_tokens on the analysis
channel and never surfaces visible content is a strict-mode fail:
'raise max_tokens or investigate' is the operator signal, not a
silent green.

BLOCKING #2 — ``_hf_cache_present`` now validates snapshot
completeness for sharded models via TWO paths:

  1. When ``model.safetensors.index.json`` is on disk, read the
     ``weight_map`` and require every referenced shard to exist
     with non-zero resolved size.
  2. When no index is present but any weight file matches the
     ``model-XX-of-YY.<ext>`` sharded pattern, parse YY and require
     all YY shards to exist. Non-sharded single-file models still
     pass on the "at least one weight file" rule.

Verified: probe now correctly returns False on a partial DeepSeek
snapshot (8 of 33 safetensors present, no index) and True on
completed Qwen 3.6, Gemma 4, gpt-oss snapshots.

Re-verified: Qwen 3.6 TestStreamingDeltas PASS in 18 s.
Round-7 codex scorecard folds:

BLOCKING #1 — conftest.py `rapid_mlx_server` was session-scoped and
depended on a parametrized `family_alias`. Pytest's finalizer ordering
across session-scoped parametrized fixtures is implementation-defined,
so "boot Qwen 3.6 → shutdown → boot Gemma 4" sequencing was not
guaranteed. Refactor to a function-scoped fixture backed by a
module-level `_ACTIVE_SERVER` cache: reuse the running server while
the family key is unchanged, tear down BEFORE booting the new one
when the family flips. Deterministic OOM-budget sequencing regardless
of pytest scope-order tie-breaking. Session-final teardown registered
via `session.addfinalizer(_teardown_active_server)`.

BLOCKING #2 — `_boot_server` only caught `FileNotFoundError` when
executing the serve command; a chmod-blocked `RAPID_MLX_SERVE_BIN`
would raise `PermissionError` (also `OSError`) and crash the harness
instead of routing through `strict_skip_or_fail`. Broaden the except
to `OSError`.

BLOCKING #3 — `TestStreamingDeltas` only accumulated `event.delta`
when it was a string, which covered the typed `ContentDeltaEvent` but
missed `ChunkEvent` (raw `.chunk.choices[i].delta.content`). Older
openai SDK releases and some proxies emit only chunks — the leak-
scan gates would silently pass on empty accumulation. Now accumulates
both event shapes into separate buckets (typed vs chunk) with per-
delta leak assertions on each; final aggregate uses typed bucket
when present (avoids double-counting in the current SDK where both
fire per content increment), falls back to chunk bucket otherwise,
and further falls back to the final completion's message content
when both buckets are empty but a `final` is available.

NIT #1 — `_hf_cache_present` initialized `index_paths` with the
same path twice as a stub for the rglob loop below. Type-annotate
the list and seed with a single entry; the rglob dedup below already
covers sub-dir instances.

NIT #2 — `tests/integrations/README.md` legend used `🔲 pending`
but the tables render `(pending)`. Align legend to `(pending)` and
update gpt-oss 120B column from `(pending)` to `✅` (all 12 cells
green from the earlier 8-agent + 3-framework + streaming session run
per pre-context matrix result).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Round-8 codex scorecard folds:

BLOCKING #1 — `rapid_mlx_server` was too generically named. Any future
non-matrix test that wired to this fixture would transitively pull in
`family_alias` (fixture dependency), which triggers
`pytest_generate_tests` to parametrize the test across all 4 families
— a silent multiplier that turns a single legacy test into 4 boot
attempts, each of which needs the family model on disk. Rename to
`rapid_mlx_matrix_server` at every callsite (3 files, 39 refs) so the
matrix scope is obvious in-code, and add a docstring warning that
this fixture is matrix-only. Non-matrix tests must boot a server
explicitly.

BLOCKING #2 — `_hf_cache_present` sharded-file heuristic only
inspected the FIRST weight file it encountered per directory (via
`weight_files.setdefault(entry.parent, entry)`) and returned True if
that one shard group was complete. A snapshot with two sharded
weight groups in the same directory (main + adapter, or main +
lm_head split) could pass preflight with an INCOMPLETE second group,
then fail at boot when the loader hit a missing shard. Refactor to
enumerate EVERY shard group by `(dir, stem, ext, total)` key and
require every group to be complete; the singles-fallback only runs
when no sharded groups exist. Verified on 5 synthetic snapshots:
partial multi-group → False, complete multi-group → True,
single-file → True, index-based partial → False, index-based
complete → True.

BLOCKING #3 — `TestStreamingDeltas` treated `LengthFinishReasonError`
as non-regression and passed on non-empty `streamed_text`, but
`streamed_text` could be non-empty ONLY because the raw-chunk fallback
(or the SDK's ContentDeltaEvent-less path on older openai versions)
captured reasoning content that leaked through as chunk content
without the `<think>` / `<|channel|>analysis` markers the leak-scan
gates check. Track a `length_finished` flag; on cutoff, require the
typed `ContentDeltaEvent` bucket (`typed_text`) to be non-empty —
that bucket is the openai SDK's typed signal for the assistant
channel specifically. Empty typed_text under length-finish means
zero user-visible content and the cell now skips/fails explicitly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

2 participants