Skip to content

feat: Gemma 4 12B multimodal duo — default main+multimodal serve (#69) (v0.32.1) - #72

Merged
OriNachum merged 30 commits into
mainfrom
spec/gemma-duo-issue-69
Jun 30, 2026
Merged

feat: Gemma 4 12B multimodal duo — default main+multimodal serve (#69) (v0.32.1)#72
OriNachum merged 30 commits into
mainfrom
spec/gemma-duo-issue-69

Conversation

@OriNachum

Copy link
Copy Markdown
Contributor

Implements #69 — makes lobes serve/init default to a main + multimodal duo: the Qwen3.6-27B-MTP primary (main) plus a Gemma 4 12B multimodal gear (vision + audio), with the tier vocabulary reframed to main / minor / multimodal and the Qwen3-14B demoted to a legacy candidate.

Built through the devague /think → /spec-to-plan → /assign-to-workforce chain (the converged spec + plan are committed under docs/specs/ and docs/plans/). The 9-task plan was fanned out to parallel agents in isolated git worktrees with TDD-gated merges.

What's in it

  • Catalog (t2): new role_hint="multimodal" Gemma gear; TIER_ROLEmain/minor/multimodal (+ cheap/normal/hard back-compat); 14B → candidate.
  • Parser (t1): infer_parser returns pythonic for Gemma 4 ids.
  • Compose (t3): default-on vllm-multimodal (no --language-model-only → vision+audio; native-MTP spec-config; util 0.12); 14B behind a legacy profile; DSpark a disabled-by-default env toggle.
  • Gateway (t4): routes model=main/minor/multimodal (+ back-compat); fixed a tier_aliases() ordering bug exposed by the mixed vocabulary.
  • Serve (t5): lobes init/serve default to the duo; --single/--legacy restores the legacy single-model scaffold.
  • Pressure seam (t6): degraded mode downgrades main/multimodalminor (multimodal is a different capability, not a cheaper rung); status --pressure reports the new vocab.
  • Smoke (t8): live-gated duo-reachability + legacy-selectable test.
  • Docs (t9 + t9b): new docs/gemma-4-12b-nvfp4.md + fleet-topology / 14B-demotion / pressure-seam updates across gateway-fleet.md, qwen3-14b-nvfp4.md, validate-tiers.md, README.md, CLAUDE.md.

Live validation (t7) — why the gear ships configured, not load-tested

t7 ran on the DGX Spark with zero fleet disruption (co-resident, primary/mesh untouched). The checkpoint downloads fine, but Gemma 4 12B's gemma4_unified architecture does not load on any released NGC vLLM image — absent from nv26.04 (vLLM 0.19.0 / TF 4.57.6) and nv26.05.post1 (vLLM 0.21.0 / TF 5.6.0). So the gear is honestly status="configured".

The code is complete and correct; the live image/audio/MTP validation + load-tested promotion happen once a supporting image exists. The custom-image unblock (start with nightly Transformers) is tracked in #71. The smoke test's live assertions stay gated behind LOBES_SMOKE_BASE_URL.

Quality

  • uv run pytest794 passed, 6 skipped (skips: 3 live smoke gated on a running gateway, 3 numpy-absent audio parity).
  • black / isort / flake8 / bandit (0 medium, 0 high) all clean.
  • Version bumped 0.32.0 → 0.32.1.
  • Diverse-mind review: the colleague backend (local Qwen 27B) authored the Gemma doc and reviewed both the keystone (4/5) and the full branch (4/5) — it surfaced a real _TIER_ROLE drift hazard between _pressure_policy.py and catalog.py, fixed with a sync test.

Implements #69 (live load-test pending #71).

— lobes (Claude)

🤖 Generated with Claude Code

https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR

OriNachum and others added 27 commits June 30, 2026 15:45
/think frame for making `lobes serve` default to the Qwen3.6-27B-MTP + Gemma 4 12B NVFP4 duo. Gemma takes a new 'multimodal' role (vision + audio); tiers reframed to main/minor/multimodal; native MTP on by default with the DeepSeek DSpark draft as a disabled experiment; the Qwen3-14B is demoted to a legacy candidate. Five accepted plan risks parked for /spec-to-plan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
/spec-to-plan forward leg: 9 tasks across 5 dependency waves covering all 26 spec targets, 6 accepted-risk objects. Pressure-ladder seam (main/minor/multimodal) resolved as task t6 (degrade to minor under pressure). Ready for /assign-to-workforce.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
Add a _RULES entry matching "gemma-4" / "gemma4" → "pythonic" so that
`infer_parser("sakamakismile/gemma-4-12B-coder-fable5-composer2.5-MTP-NVFP4")`
returns "pythonic". Gemma 4 (Google DeepMind) uses a Python-style
function-call syntax; vLLM's Gemma 4 recipe prescribes
--tool-call-parser pythonic.

Markers are scoped to "gemma-4" / "gemma4" to avoid matching older
Gemma 1/2/3 checkpoints whose tool-call story is less established.

Unit test added to tests/test_parser.py asserting the exact model id.
TODO(risk r2): confirm parser value against the served checkpoint
during t7 live validation on the Spark.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
… demotion

- Add SupportedModel for sakamakismile/gemma-4-12B-coder-fable5-composer2.5-MTP-NVFP4
  (role_hint=multimodal, tool_parser=pythonic, modelopt_fp4, native MTP
  speculative_config, status=configured). TODO(risk r4): confirm the Gemma4
  native-MTP method string in t7. TODO(risk): confirm native context (using 128K).
- Demote nvidia/Qwen3-14B-NVFP4 from role_hint=middle to candidate (KEPT, not deleted).
- Reframe TIER_ROLE to main/minor/multimodal with cheap/normal/hard back-compat
  aliases; normal+multimodal -> Gemma, main+hard -> primary, cheap+minor -> 4B.
- Add docs/gemma-4-12b-nvfp4.md stub (full content in t9).
- Extend tests/test_catalog.py with Gemma-gear, tier-resolution and 14B-demotion tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
…B->candidate)

Integration fix after t2 keystone: the 14B is now a legacy candidate and normal->multimodal. Catalog-domain, owned by no single task.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
…profile, DSpark off

- New vllm-multimodal service (NO profiles: key, always starts with the fleet)
  serving sakamakismile/gemma-4-12B-coder-fable5-composer2.5-MTP-NVFP4 at
  util=0.12, 128K context, tool-call-parser=pythonic, --speculative-config
  gemma4_mtp, --trust-remote-code; NO --language-model-only so vision+audio stay
  active (the headline capability).
- Gateway wired: MULTIMODAL_BASE_URL / MULTIMODAL_SERVED_NAME added to gateway
  environment; vllm-multimodal added to depends_on.
- vllm-middle comment updated to "LEGACY CANDIDATE – no longer the normal tier".
- env.example: MULTIMODAL_* section added; DSpark draft-model override documented
  as a commented, disabled-by-default experiment; GPU budget comment updated to
  the new default (primary 0.45 + multimodal 0.12 + embed 0.06 + rerank 0.06 = 0.69).
- Three new template assertions in test_cli_fleet.py: multimodal is default-on
  (no profiles:), command lacks --language-model-only and has gemma4_mtp
  speculative-config, and vllm-middle is behind a profiles: key.

TODOs left: TODO(risk r4) — confirm Gemma4 native-MTP method in t7;
            TODO(risk r5) — measure real multimodal util (vision+audio KV) in t7.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
…imodal wiring

- _config.py: replace _DEFAULT_MIDDLE/MIDDLE_BASE_URL/MIDDLE_SERVED_NAME with
  _DEFAULT_MULTIMODAL (pinned Gemma 4 12B id) / MULTIMODAL_BASE_URL /
  MULTIMODAL_SERVED_NAME; backend name changes from "middle" to "multimodal"
  (default url http://vllm-multimodal:8000). The 14B Qwen3 is now legacy —
  no tier resolves to it; address it explicitly by model id if needed.

- _routing.py: fix tier_aliases() to handle the new mixed-vocabulary TIER_ROLE
  (primary: main/minor/multimodal + back-compat: cheap/normal/hard). The old
  algorithm relied on ascending-capability key order which the new TIER_ROLE
  breaks. New algorithm: sort unique roles by last occurrence in tier_role.values()
  (the back-compat aliases appear last in ascending order, anchoring the correct
  [minor, multimodal, primary] sequence), then apply upward fallback on unique
  roles only, and replicate results to all tier aliases. All six tier names
  (main/minor/multimodal + cheap/normal/hard) now resolve correctly with proper
  upward fallback when a gear is absent.

- tests/test_gateway_tiers.py: full rewrite — 6 old "middle" tests renamed/updated
  to "multimodal"; 7 new tests added (main->primary, multimodal->Gemma backend,
  normal->multimodal back-compat, multimodal absent falls back to primary, primary
  vocab assertions in full-fleet tests, new tier_aliases helper test for minor-
  absent/multimodal-present escalation). 23 tests total, all passing.

- tests/test_gateway_server.py, tests/test_tier_request.py: update _fleet_cfg /
  _full_fleet helpers to use MULTIMODAL_BASE_URL/MULTIMODAL_SERVED_NAME.

- tests/test_status_pressure.py: fix pre-existing break from TIER_ROLE reframing
  (_MIDDLE_ID → _MULTIMODAL_ID for the normal tier; was failing before this PR).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
… (main/minor/multimodal vocab)

Resolve the pressure-ladder seam under the #69 main/minor/multimodal vocabulary.
multimodal is a different capability (vision+audio), not a cheaper rung below
main, so "downgrade under pressure" cannot walk main->multimodal->minor. The
only cheaper target is minor: under degraded pressure (swap>75% OR iowait>50%)
both a main and a multimodal request collapse to minor (reason=pressure); below
the degraded floor nothing is downgraded (the old linear intermediate band is
gone). Back-compat cheap/normal/hard inputs still normalize to the new vocab.

- _pressure_policy.decide: binary degraded model in new vocab; max_allowed_tier
  is minor when degraded else main; allowed_tier granted as requested when warm,
  minor when degraded. Adds normalize_tier(); keeps the degraded thresholds +
  env overrides and retains the no-hard/prefer-cheap thresholds as advisory
  (no longer cap the tier — no intermediate rung). Docstring documents the seam.
- _tier_request: served_tier reported in main/minor/multimodal; override path
  normalizes; is_tier_alias recognizes all six tier keys (catalog.TIER_ROLE).
- status.py: lobes status --pressure queries with requested_tier=main and
  reports tier/model in the new vocabulary.
- Migrate pressure/tier-request tests (test_pressure_policy, test_tier_request,
  test_status_pressure, test_gateway_server) off the old cheap/normal/hard->cheap
  degraded behavior. Full suite green (774 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
…ab (#69)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
…LET...

Expand the stub file docs/gemma-4-12b-nvfp4.md into a COMPLETE per-model doc for the Gemma 4 12B 'multimodal' fleet gear (issue #69), closely matching the structure and tone of the sibling doc docs/qwen3-14b-nvfp4.md. Read these for accuracy BEFORE writing: lobes/catalog.py (the SupportedModel entry whose id is sakamakismile/gemma-4-12B-coder-fable5-composer2.5-MTP-NVFP4 — role_hint=multimodal, tool_parser=pythonic, quantization=modelopt_fp4, speculative_config gemma4_mtp, status=configured), lobes/templates/fleet/docker-compose.yml (the default-on vllm-multimodal service and its flags), and docs/qwen3-14b-nvfp4.md (template). The doc MUST cover: (1) what it is — Gemma 4 12B unified multimodal (text+IMAGE+AUDIO via Gemma4UnifiedForConditionalGeneration), native MTP draft head, NVFP4; (2) the pinned checkpoint id; (3) tier alias usage: model=multimodal (and model=normal back-compat) resolves here at the gateway, role_hint=multimodal; (4) serving in the fleet: it is DEFAULT-ON (not a profile), served WITHOUT --language-model-only so vision AND audio are active, --tool-call-parser=pythonic, native-MTP --speculative-config, --gpu-memory-utilization 0.12; (5) the DSpark experiment — DISABLED by default, an env override swaps in deepseek-ai/dspark_gemma4_12b_block7; (6) a GPU budget table for the default fleet: primary 0.45 + multimodal 0.12 + embed 0.06 + rerank 0.06 = 0.69 on the 128GB GB10; (7) accepted plan risks pending t7 live validation on the Spark: exact checkpoint pick, the gemma4_mtp method string, the 131072 native context, and the measured GPU util; (8) a Related docs section linking gateway-fleet.md, qwen3.6-27b-text-nvfp4-mtp.md, and qwen3-14b-nvfp4.md. Write ONLY docs/gemma-4-12b-nvfp4.md. Do not touch any other file.

Implement the task above in this repository.

Rules:
- Make the SMALLEST change that correctly satisfies the task.
- Follow the repository's existing patterns, style, and conventions — read the
  neighbouring files first so your change reads like the surrounding code.
- Keep edits lint-clean: respect the project's maximum line length and end every
  text file with exactly one trailing newline.
- You may read, create, modify files, and run commands as needed.
- Don't widen the scope: do exactly what was asked, nothing more.

When you are done, call finish with a short summary of exactly what you changed
and why.
…l swap) + topology wording

Verification correction on the colleague-authored doc: DSpark is a speculative-decoding draft head, enabled via MULTIMODAL_SPECULATIVE_CONFIG, not by replacing MULTIMODAL_MODEL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
…eam) to the Gemma duo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
Colleague full-branch review (#69) flagged the duplicated tier->role map in _pressure_policy.py as a silent-drift risk. Add a sync assertion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
… nv26.04/26.05 (track in #71)

Live validation on the DGX Spark: the Gemma 4 12B multimodal gear does not load on any released NGC vLLM image (gemma4_unified arch absent from vLLM 0.19.0/0.21.0 + Transformers 4.57.6/5.6.0). Gear stays status=configured; custom-image unblock tracked in #71.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

feat: Gemma 4 12B multimodal duo — default main+multimodal serve (v0.32.1)

✨ Enhancement ⚙️ Configuration changes 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Adds Gemma 4 12B NVFP4 as a new multimodal gear and default-on generate backend.
• Reframes tiers to main/minor/multimodal with cheap/normal/hard back-compat.
• Makes lobes init/serve default to the fleet duo; --single/--legacy restores legacy.
Diagram

graph TD
    CLI["lobes init / serve"] --> |"default: fleet duo"| COMPOSE["docker-compose.yml"]
    COMPOSE --> PRIMARY["vllm-primary\n27B MTP"]
    COMPOSE --> MULTIMODAL["vllm-multimodal\nGemma 4 12B"]
    COMPOSE --> EMBED["vllm-embed / rerank"]
    PRIMARY --> GW
    MULTIMODAL --> GW
    EMBED --> GW
    GW["Gateway"] --> ROUTING["_routing.py\ntier_aliases()"]
    ROUTING --> CATALOG[("catalog.py\nTIER_ROLE")]
    GW --> PRESSURE["_pressure_policy.py\ndecide()"]
    PRESSURE --> TIEREQ["_tier_request.py\nresolve_tier_request()"]
    TIEREQ --> |"degraded → minor"| ROUTING
    subgraph Legend
        direction LR
        _svc["Service"] ~~~ _db[("Catalog/Data")] ~~~ _mod["Module"]
    end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Keep linear tier ladder (multimodal as normal rung)
  • ➕ Simpler pressure policy (no seam special-casing)
  • ➕ More gradual downgrade path conceptually
  • ➖ Semantically wrong for multimodal inputs: minor cannot satisfy image/audio requests
  • ➖ Creates misleading behavior where a multimodal request might be silently served by text-only capabilities
2. Separate multimodal routing lane (not a tier alias)
  • ➕ Avoids mixing capability sibling (multimodal) into the tier ladder
  • ➕ Simplifies pressure logic for text-only tiers
  • ➖ More invasive API/UX change; diverges from a single model= selection mechanism
  • ➖ Requires additional client knowledge and routing rules

Recommendation: The chosen approach (a unified multimodal checkpoint as the default second backend) best matches the goal of adding vision+audio without sidecars. The key architectural call—treating multimodal as a capability sibling rather than a cheaper rung—is correct and is consistently reflected in routing, pressure policy, and tests. Shipping the gear as status=&#x27;configured&#x27; is appropriate given the current NGC vLLM image incompatibility; the added sync test preventing tier-map drift is a strong guardrail.

Files changed (39) +2888 / -789

Enhancement (6) +312 / -174
catalog.pyAdd Gemma 4 multimodal gear; reframe tiers to main/minor/multimodal +80/-19

Add Gemma 4 multimodal gear; reframe tiers to main/minor/multimodal

• Adds Gemma 4 12B NVFP4 as 'role_hint='multimodal'' with 'tool_parser='pythonic'' and native MTP speculative config. Demotes Qwen3-14B-NVFP4 to 'role_hint='candidate''. Updates 'TIER_ROLE' to primary vocabulary 'main/minor/multimodal' with 'cheap/normal/hard' retained as aliases.

lobes/catalog.py

init.pyDefault init to fleet duo; add --single/--legacy; make --fleet a no-op alias +46/-15

Default init to fleet duo; add --single/--legacy; make --fleet a no-op alias

• Flips 'lobes init' default to scaffold the fleet duo. Adds mutually-exclusive '--single/--legacy' to restore the legacy single-model scaffold, and updates '--audio' compatibility checks accordingly.

lobes/cli/_commands/init.py

status.pyUpdate status --pressure to use main tier and new vocabulary +12/-6

Update status --pressure to use main tier and new vocabulary

• Switches '--pressure' to call 'decide(..., requested_tier='main')' and documents the new ceiling semantics under degraded pressure.

lobes/cli/_commands/status.py

_config.pyAdd multimodal backend wiring; set Gemma 4 as default multimodal served name +21/-20

Add multimodal backend wiring; set Gemma 4 as default multimodal served name

• Introduces 'MULTIMODAL_*' env keys and defaults, wiring an optional 'multimodal' backend and replacing the former tier role of the 14B middle backend.

lobes/gateway/_config.py

_pressure_policy.pyImplement pressure seam for non-linear tiers; add normalize_tier() +145/-114

Implement pressure seam for non-linear tiers; add normalize_tier()

• Replaces linear tier ladder logic with main/minor/multimodal vocabulary and a binary warm/degraded behavior. Under degraded pressure, both 'main' and 'multimodal' collapse to 'minor'. Adds 'normalize_tier()' and retains advisory constants for back-compat observability.

lobes/gateway/_pressure_policy.py

_parser.pyInfer pythonic tool parser for Gemma 4 model IDs +8/-0

Infer pythonic tool parser for Gemma 4 model IDs

• Adds an 'infer_parser' rule mapping 'gemma-4'/'gemma4' IDs to the 'pythonic' tool-call parser.

lobes/runtime/_parser.py

Bug fix (1) +42 / -19
_routing.pyFix tier_aliases ordering for mixed vocab; resolve via role last-occurrence +42/-19

Fix tier_aliases ordering for mixed vocab; resolve via role last-occurrence

• Fixes ordering bug by deriving capability order from roles’ last occurrence positions in 'TIER_ROLE', then mapping all aliases (including back-compat) to resolved served names.

lobes/gateway/_routing.py

Refactor (1) +24 / -17
_tier_request.pyUpdate tier request handling for new vocabulary and seam semantics +24/-17

Update tier request handling for new vocabulary and seam semantics

• Uses 'frozenset(TIER_ROLE)' as tier alias set, removes index-based downgrade checks, normalizes overridden tiers, and relies on 'decide()'’s reason/allowed tier outputs.

lobes/gateway/_tier_request.py

Tests (11) +1166 / -371
test_catalog.pyAdd tests for Gemma multimodal gear, tier reframe, and 14B demotion +104/-0

Add tests for Gemma multimodal gear, tier reframe, and 14B demotion

• Adds assertions for Gemma gear fields, parser inference alignment, native MTP config presence, 'TIER_ROLE' vocabulary, and 'resolve_tier()' mappings including back-compat aliases.

tests/test_catalog.py

test_catalog_tiers.pyUpdate tier tests to main/minor/multimodal vocabulary +21/-16

Update tier tests to main/minor/multimodal vocabulary

• Adjusts tier resolution tests to new vocabulary and ensures 'normal' now resolves to multimodal instead of the legacy 14B middle.

tests/test_catalog_tiers.py

test_cli_fleet.pyAdd CLI tests for duo default and legacy selection flags +58/-0

Add CLI tests for duo default and legacy selection flags

• Adds tests ensuring CLI behavior matches the new default fleet duo and the '--single/--legacy' restore path.

tests/test_cli_fleet.py

test_gateway_server.pyUpdate gateway server tests for new tier names and multimodal wiring +20/-19

Update gateway server tests for new tier names and multimodal wiring

• Updates tests to use main/minor/multimodal tiers and new MULTIMODAL_* environment wiring semantics.

tests/test_gateway_server.py

test_gateway_tiers.pyRewrite tier alias tests for multimodal backend + new vocabulary +159/-62

Rewrite tier alias tests for multimodal backend + new vocabulary

• Adds/updates tests for multimodal backend wiring, primary vocabulary aliases, back-compat alias behavior, and upward fallback semantics.

tests/test_gateway_tiers.py

test_init.pyRewrite init tests for fleet-duo default and --single/--legacy paths +107/-18

Rewrite init tests for fleet-duo default and --single/--legacy paths

• Validates that default init scaffolds fleet templates including gateway Dockerfile and 'vllm-multimodal', while '--single/--legacy' produces the legacy single-model compose. Updates audio overlay expectations under new defaults.

tests/test_init.py

test_parser.pyAdd Gemma 4 parser inference test +7/-0

Add Gemma 4 parser inference test

• Adds coverage ensuring 'infer_parser' returns 'pythonic' for Gemma 4 IDs.

tests/test_parser.py

test_pressure_policy.pyRewrite pressure policy tests for seam behavior and drift guard +191/-200

Rewrite pressure policy tests for seam behavior and drift guard

• Updates tests to new vocabulary, validates degraded collapse to 'minor', and adds a drift guard ensuring '_pressure_policy._TIER_ROLE' matches 'catalog.TIER_ROLE'.

tests/test_pressure_policy.py

test_smoke_duo.pyAdd duo smoke tests (CI routing + optional live image/audio probes) +343/-0

Add duo smoke tests (CI routing + optional live image/audio probes)

• Introduces a two-layer smoke suite: CI-only routing/config assertions and optional live gateway calls (gated on 'LOBES_SMOKE_BASE_URL') covering text+image+audio requests.

tests/test_smoke_duo.py

test_status_pressure.pyUpdate status --pressure tests for main/minor ceiling semantics +59/-20

Update status --pressure tests for main/minor ceiling semantics

• Updates assertions to reflect 'main' as warm ceiling and 'minor' as degraded ceiling under the seam policy.

tests/test_status_pressure.py

test_tier_request.pyUpdate tier request tests for seam and back-compat normalization +97/-36

Update tier request tests for seam and back-compat normalization

• Updates request/override tests for new vocabulary, ensures 'hard' normalizes to 'main', and validates multimodal downgrade-to-minor behavior under degraded pressure.

tests/test_tier_request.py

Documentation (17) +1219 / -185
currentPoint devague to the new current frame +1/-1

Point devague to the new current frame

• Updates the devague pointer to the latest /think frame used for this PR’s spec generation.

.devague/current

current_planPoint devague to the new current plan +1/-1

Point devague to the new current plan

• Updates the devague pointer to the latest /spec-to-plan plan artifact for this PR.

.devague/current_plan

lobes-now-defaults-to-a-spark-duo-the-qwen3-6-27b.jsonAdd devague /think frame for Gemma duo default +314/-0

Add devague /think frame for Gemma duo default

• Adds the full devague reasoning frame that produced the Gemma duo spec for issue #69.

.devague/frames/lobes-now-defaults-to-a-spark-duo-the-qwen3-6-27b.json

lobes-now-defaults-to-a-spark-duo-the-qwen3-6-27b.jsonAdd devague plan JSON for Gemma duo build +340/-0

Add devague plan JSON for Gemma duo build

• Adds the devague /spec-to-plan JSON output used to coordinate the implementation work.

.devague/plans/lobes-now-defaults-to-a-spark-duo-the-qwen3-6-27b.json

lobes__public.jsonlUpdate eidetic memory for new default topology and tiers +6/-5

Update eidetic memory for new default topology and tiers

• Updates stored project memory entries to reflect the new main/minor/multimodal vocabulary and default duo topology.

.eidetic/memory/lobes__public.jsonl

CHANGELOG.mdAdd v0.32.1 changelog entry +7/-0

Add v0.32.1 changelog entry

• Documents the v0.32.1 release, highlighting the default duo and tier vocabulary changes.

CHANGELOG.md

CLAUDE.mdUpdate contributor/agent guidance for duo defaults and tiers +25/-20

Update contributor/agent guidance for duo defaults and tiers

• Updates project guidance to reflect the new default deployment topology and tier vocabulary.

CLAUDE.md

README.mdUpdate README for default duo and main/minor/multimodal tiers +25/-17

Update README for default duo and main/minor/multimodal tiers

• Updates quickstart and tier documentation to match the new default-on fleet duo behavior.

README.md

gateway-fleet.mdDocument fleet duo topology and new tier vocabulary +73/-60

Document fleet duo topology and new tier vocabulary

• Updates fleet topology docs and tier routing guidance for main/minor/multimodal, including legacy 14B demotion context.

docs/gateway-fleet.md

gemma-4-12b-nvfp4.mdAdd Gemma 4 12B NVFP4 gear doc +171/-0

Add Gemma 4 12B NVFP4 gear doc

• Adds a dedicated reference doc for the Gemma 4 12B multimodal gear, including known image compatibility limitations.

docs/gemma-4-12b-nvfp4.md

2026-06-30-lobes-now-defaults-to-a-spark-duo-the-qwen3-6-27b.mdAdd build plan doc for issue #69 +78/-0

Add build plan doc for issue #69

• Adds the human-readable 9-task plan for implementing the default duo and tier reframe.

docs/plans/2026-06-30-lobes-now-defaults-to-a-spark-duo-the-qwen3-6-27b.md

qwen3-14b-nvfp4.mdMark Qwen3-14B as legacy candidate in docs +42/-31

Mark Qwen3-14B as legacy candidate in docs

• Updates the 14B doc to reflect demotion from tier resolution to explicit-by-id legacy use.

docs/qwen3-14b-nvfp4.md

2026-06-30-lobes-now-defaults-to-a-spark-duo-the-qwen3-6-27b.mdAdd spec doc for issue #69 +63/-0

Add spec doc for issue #69

• Adds the converged spec describing the duo defaults, tier vocabulary, and accepted risks.

docs/specs/2026-06-30-lobes-now-defaults-to-a-spark-duo-the-qwen3-6-27b.md

validate-tiers.mdUpdate tier validation docs for new vocabulary +49/-41

Update tier validation docs for new vocabulary

• Updates validation guidance to use main/minor/multimodal and documents back-compat aliases.

docs/validate-tiers.md

serve.pyClarify serve semantics: brings up scaffolded deployment (duo by default) +12/-2

Clarify serve semantics: brings up scaffolded deployment (duo by default)

• Updates help/docstring to reflect that 'lobes serve' starts the scaffolded compose (fleet duo by default, legacy single-model when initialized with '--single').

lobes/cli/_commands/serve.py

server.pyUpdate gateway server docs for main/minor/multimodal tiers +6/-4

Update gateway server docs for main/minor/multimodal tiers

• Updates documentation to match new tier names and the seam behavior (multimodal degrades to minor under pressure).

lobes/gateway/server.py

_compose.pyDocument that CLI default now scaffolds FLEET templates +6/-3

Document that CLI default now scaffolds FLEET templates

• Updates comments to clarify that the CLI default is now the fleet template set, while helper defaults remain for back-compat.

lobes/runtime/_compose.py

Other (3) +125 / -23
docker-compose.ymlAdd default-on vllm-multimodal service; wire MULTIMODAL_*; mark middle as legacy +96/-17

Add default-on vllm-multimodal service; wire MULTIMODAL_*; mark middle as legacy

• Adds 'vllm-multimodal' service for Gemma 4 (vision+audio enabled; native MTP config), makes it default-on, wires gateway env vars, and relegates 'vllm-middle' to legacy opt-in.

lobes/templates/fleet/docker-compose.yml

env.exampleAdd MULTIMODAL_* env section; update GPU budget; mark middle as legacy +28/-5

Add MULTIMODAL_* env section; update GPU budget; mark middle as legacy

• Adds a new multimodal env section including speculative config defaults and DSpark experiment. Updates GPU utilization budgeting and annotates 14B middle settings as legacy candidate.

lobes/templates/fleet/env.example

pyproject.tomlBump version to 0.32.1 +1/-1

Bump version to 0.32.1

• Updates the project version from 0.32.0 to 0.32.1.

pyproject.toml

@qodo-code-review

qodo-code-review Bot commented Jun 30, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (3) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 16 rules

Grey Divider


Action required

1. Tier alias main used ✗ Dismissed 📘 Rule violation ⌂ Architecture
Description
The PR introduces/uses model="main" and model="multimodal" as caller-facing tier values, but the
compliance rule only permits capability-tier aliases cheap, normal, or hard at generate call
sites. This breaks the required tier-alias contract for callers and routing.
Code

tests/test_smoke_duo.py[R273-290]

+            "model": "main",
+            "messages": [{"role": "user", "content": "Reply with the word hello."}],
+            "max_tokens": 16,
+            "temperature": 0,
+        },
+    )
+    content = resp["choices"][0]["message"].get("content") or ""
+    assert content.strip(), f"model=main returned empty content; full response: {resp}"
+
+
+@_live
+def test_live_multimodal_image_text_returns_valid_output() -> None:
+    """model=multimodal (Gemma 4 12B) accepts an image+text content-parts request."""
+    base_url = os.environ["LOBES_SMOKE_BASE_URL"]
+    resp = _post_chat(
+        base_url,
+        {
+            "model": "multimodal",
Relevance

⭐⭐ Medium

PR #70 established cheap/normal/hard aliases, but team also evolves tier vocab; no clear enforcement
precedent.

PR-#70

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 1513047 constrains caller routing inputs to the tier aliases cheap/normal/hard, but the
PR updates caller examples/tests to send model="main" and model="multimodal".

Rule 1513047: Route lane selection by capability-tier alias with upward fallback
tests/test_smoke_duo.py[266-290]
docs/gateway-fleet.md[132-145]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Caller-facing `model` tier values in tests/docs now use `main`/`multimodal`, but compliance requires callers use only `cheap`/`normal`/`hard` tier aliases.

## Issue Context
Even if the gateway supports additional synonyms, the compliance checklist explicitly constrains the allowed caller inputs to `cheap|normal|hard`.

## Fix Focus Areas
- tests/test_smoke_duo.py[273-290]
- docs/gateway-fleet.md[132-145]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. vllm-multimodal wrong base image 📎 Requirement gap ☼ Reliability
Description
The new vllm-multimodal service is configured to run on nvcr.io/nvidia/vllm:26.04-py3, not the
required nvcr.io/nvidia/vllm:26.05.post1-py3 base for the Gemma4 custom image. This violates the
compliance requirement and increases risk of Gemma4 incompatibility at runtime.
Code

lobes/templates/fleet/docker-compose.yml[379]

+    image: nvcr.io/nvidia/vllm:26.04-py3   # same image as vllm-primary (NGC ARM64/Blackwell)
Relevance

⭐ Low

Fleet compose consistently uses nvcr.io/nvidia/vllm:26.04-py3; no evidence they enforce 26.05.post1
base.

PR-#70

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 1513050 requires the custom Gemma4 image to be based on nvcr.io/nvidia/vllm:26.05.post1-py3,
but the PR configures vllm-multimodal to use nvcr.io/nvidia/vllm:26.04-py3.

Custom vLLM image is based on nvcr.io/nvidia/vllm:26.05.post1-py3
lobes/templates/fleet/docker-compose.yml[379-379]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`vllm-multimodal` is configured to use `nvcr.io/nvidia/vllm:26.04-py3`, but the compliance requirement mandates basing the Gemma4 custom image on `nvcr.io/nvidia/vllm:26.05.post1-py3`.

## Issue Context
This service is the default-on multimodal worker; using the wrong base image/tag violates the checklist and can block Gemma4 support.

## Fix Focus Areas
- lobes/templates/fleet/docker-compose.yml[379-379]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Legacy tier override ignored ✓ Resolved 🐞 Bug ≡ Correctness
Description
resolve_tier_request() normalizes legacy tier names (cheap/normal/hard) to the new vocabulary
before resolving served_name, so an operator GATEWAY_ALIASES override keyed only by a legacy
tier name is bypassed. Because the running gateway always supplies pressure via PressureCache,
tier requests go through this path by default and legacy-tier overrides stop working silently.
Code

lobes/gateway/_tier_request.py[R133-141]

+        # Force the requested tier (normalized to the new vocabulary) despite
+        # pressure. ``decide`` already validated the alias above.
+        served_tier = _pressure_policy.normalize_tier(requested_tier)
        reason = "manual_override"
    else:
+        # ``decide`` already returns the granted tier (new vocab) and the reason
+        # (pressure when degraded or constrained, else default).
        served_tier = decision["allowed_tier"]
-        downgraded = _tier_index(served_tier) < _tier_index(requested_tier)
-        reason = "pressure" if (downgraded or decision["mode"] == "degraded") else "default"
+        reason = decision["reason"]
Relevance

⭐ Low

PR #70 tier override path uses requested tier on override and resolves via table.aliases; covered by
tests.

PR-#70

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
resolve_tier_request() converts requested_tier to the canonical new-vocab tier and then calls
_served_name_for() with that canonical name, but operator overrides are merged into
table.aliases by their literal key; with PressureCache enabled, tier requests use this path and
no longer consult the legacy-key override.

lobes/gateway/_tier_request.py[61-73]
lobes/gateway/_tier_request.py[132-147]
lobes/gateway/_config.py[169-170]
lobes/gateway/server.py[284-292]
lobes/gateway/server.py[586-591]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Tier requests (e.g. `model=hard`) are normalized to the new vocabulary (`main`) before alias lookup, so a `GATEWAY_ALIASES` entry like `hard=my/custom` no longer affects routing once the request goes through `resolve_tier_request()`.

### Issue Context
- `_served_name_for()` only consults `table.aliases` using the tier string it is given.
- `resolve_tier_request()` now emits/uses the normalized tier name for `served_tier` and for `_served_name_for()`.
- The gateway server wires `PressureCache()` by default, so tier requests generally take the pressure-aware path.

### Fix Focus Areas
Pick one of these concrete approaches:
1) **Expand operator overrides at config build time**: when parsing `GATEWAY_ALIASES`, if a key is a legacy tier (`cheap|normal|hard`), also set the canonical synonym (`minor|multimodal|main`), and vice versa.
2) **Make `_served_name_for()` synonym-aware**: when asked for `main`, also consider `hard`; for `multimodal`, also consider `normal`; for `minor`, also consider `cheap`, preferring explicit operator overrides.

Add a unit test proving `GATEWAY_ALIASES=hard=...` still affects `model=hard` when routed through `resolve_tier_request()`.

- lobes/gateway/_tier_request.py[61-147]
- lobes/gateway/_config.py[168-175]
- lobes/gateway/server.py[252-292]
- lobes/gateway/server.py[586-592]
- tests/test_tier_request.py[120-160]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Middle backend unreachable ✓ Resolved 🐞 Bug ≡ Correctness
Description
build_config() no longer wires a vllm-middle backend (it dropped all MIDDLE_* handling), so
starting the compose vllm-middle profile and setting MIDDLE_BASE_URL will not make the gateway
route 14B requests to that backend. Requests for the 14B served name will instead resolve to the
gateway default model because there is no backend entry serving that name.
Code

lobes/gateway/_config.py[R135-139]

+            name="multimodal",
+            url_key="MULTIMODAL_BASE_URL",
+            name_key="MULTIMODAL_SERVED_NAME",
+            default_url="http://vllm-multimodal:8000",
+            default_name=_DEFAULT_MULTIMODAL,
Relevance

⭐ Low

PR #70 explicitly wires MIDDLE_BASE_URL/MIDDLE_SERVED_NAME optional backend in build_config().

PR-#70

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The fleet compose template still advertises MIDDLE_BASE_URL/MIDDLE_SERVED_NAME as the way to
route to the legacy 14B backend, but build_config() never reads those env keys anymore, so no
Backend with that served name exists and resolve_model() will fall back to the gateway’s default
model.

lobes/templates/fleet/docker-compose.yml[453-465]
lobes/gateway/_config.py[104-140]
lobes/gateway/_routing.py[100-113]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The gateway config builder no longer creates a backend from `MIDDLE_BASE_URL` / `MIDDLE_SERVED_NAME`, but the fleet compose template still exposes those env vars and provides a `vllm-middle` service behind the `middle` profile. As a result, operators cannot route requests to the legacy 14B backend even when they enable the profile.

### Issue Context
- `vllm-middle` still exists in the fleet compose and the gateway service still documents `MIDDLE_*`.
- `build_config()` only wires `fallback`, `minor`, `multimodal`, `embed`, and `rerank`.

### Fix Focus Areas
- Reintroduce an optional `middle` generate backend wired from `MIDDLE_BASE_URL`/`MIDDLE_SERVED_NAME`.
- Ensure the middle backend is *not* part of tier aliases (it should be reachable by explicit model id only).
- Add/adjust tests to cover “middle profile enabled => backend reachable by served_name”.

- lobes/gateway/_config.py[97-175]
- lobes/templates/fleet/docker-compose.yml[453-472]
- tests/test_gateway_tiers.py[1-240]
- tests/test_smoke_duo.py[175-240]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (2)
5. gemma4_unified load failure noted 📎 Requirement gap ☼ Reliability
Description
The PR explicitly documents that the Gemma 4 12B gemma4_unified checkpoint does not load on
released NGC vLLM images. This conflicts with the compliance requirement that the multimodal gear
must boot successfully and load the pinned checkpoint.
Code

docs/gemma-4-12b-nvfp4.md[R139-157]

+> **t7 ran on the DGX Spark (2026-06-30) and the gear does NOT load on any
+> released NGC vLLM image.** This is why `status` stays `configured` (not
+> `load-tested`). The unblock work is tracked in **[issue #71](https://github.com/agentculture/lobes-cli/issues/71)**.
+
+Gemma 4 12B's architecture is **`model_type: gemma4_unified`** (all community
+NVFP4 12B checkpoints use it). Neither released image registers it:
+
+| Image | vLLM | Transformers | `gemma4_unified` |
+|---|---|---|---|
+| `nvcr.io/nvidia/vllm:26.04-py3` (current fleet) | 0.19.0 | 4.57.6 | ❌ |
+| `nvcr.io/nvidia/vllm:26.05.post1-py3` | 0.21.0 | 5.6.0 | ❌ (ships `Gemma4MTPModel` + standard `Gemma4`, not `Unified`) |
+
+vLLM crashes at config load (`model type gemma4_unified ... install Transformers
+from source`). **r1** (checkpoint exists/valid) is resolved ✓; **r3** (loads on
+the image) is resolved-negative ✗; the rest are untestable until r3 clears:
+
+1. **r3 — runtime support** *(the blocker, → #71)*: needs a vLLM image whose
+   Transformers registers `gemma4_unified` (build from a 26.05 base + nightly
+   Transformers, or await an NGC release).
Relevance

⭐ Low

Team allows docs noting “not load-tested / doesn’t load yet”; similar push to “record outcomes now”
rejected in PR #7.

PR-#7

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 1513054 requires successful boot and checkpoint load, but the PR-added documentation and
catalog comments state the gear does not load on released images due to gemma4_unified not being
recognized.

Multimodal gear boots successfully and loads gemma4_unified checkpoint
docs/gemma-4-12b-nvfp4.md[139-157]
lobes/catalog.py[223-226]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Documentation in this PR states the multimodal gear cannot load the `gemma4_unified` checkpoint on released images, which violates the requirement that it boots and loads successfully.

## Issue Context
To satisfy compliance, the runtime image must include Transformers support for `gemma4_unified` and the deployment must be validated to successfully load the pinned checkpoint.

## Fix Focus Areas
- docs/gemma-4-12b-nvfp4.md[139-157]
- lobes/catalog.py[223-226]
- lobes/templates/fleet/docker-compose.yml[378-424]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Gemma catalog status not promoted 📎 Requirement gap ≡ Correctness
Description
The new Gemma 4 multimodal catalog entry remains status="configured" rather than being promoted to
load-tested. This violates the compliance requirement to promote status and record validation
metrics once readiness is achieved.
Code

lobes/catalog.py[235]

+        status="configured",
Relevance

⭐ Low

They keep catalog status="configured" until a real load-test; resisted forced promotion/metrics in
PR #7.

PR-#7

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 1513061 requires promoting catalog status from configured to load-tested and recording
metrics, but the PR sets the Gemma 4 entry to status="configured" and the doc also states `Status:
configured`.

Catalog status promoted from configured to load-tested and metrics recorded
lobes/catalog.py[233-236]
docs/gemma-4-12b-nvfp4.md[7-11]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Gemma 4 12B multimodal gear is still marked `status="configured"`, but the compliance checklist requires promoting it to `load-tested` and recording validation numbers in the doc.

## Issue Context
This rule is specifically about release-readiness workflow: catalog status and documentation must reflect completed validation.

## Fix Focus Areas
- lobes/catalog.py[235-236]
- docs/gemma-4-12b-nvfp4.md[7-11]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread tests/test_smoke_duo.py


SonarCloud python:S1135 flagged three bare TODO(risk …) comments on PR #72,
all marking deferred Gemma 4 12B live-validation work (native context, the
native-MTP method string, the pythonic tool parser). That work is now blocked
on a gemma4_unified-capable vLLM image and formally tracked in issue #71, so
the comments are reworded from "TODO(risk …)" to "Risk … (pending #71)" — they
cite the tracking issue instead of an untracked TODO. The premise of S1135
(untracked work rots) no longer holds, and the fix improves traceability.

- lobes/catalog.py: 2 markers (native context default; native-MTP method)
- lobes/runtime/_parser.py: 1 marker (pythonic parser confirmation)

Comment-only; 158 catalog/parser/tier tests pass, black/isort/flake8 clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
…verrides

Two regressions surfaced by Qodo review on PR #72 (#69 Gemma duo):

1. Middle backend unreachable. The #69 14B demotion removed the `middle`
   optional-backend wiring from build_config(), but the fleet compose still
   ships the `vllm-middle` service (profile `middle`), still exposes
   MIDDLE_BASE_URL / MIDDLE_SERVED_NAME on the gateway, and still documents
   "set MIDDLE_BASE_URL … so it routes 14B requests." Result: enabling the
   profile silently fell back to the primary. Re-wire the optional `middle`
   generate backend — reachable by explicit served name, and (because "middle"
   is not a TIER_ROLE role) deliberately NOT a tier alias.

2. Legacy-keyed operator override ignored. resolve_tier_request() normalizes a
   legacy tier (hard→main) before the alias lookup, so a GATEWAY_ALIASES
   override keyed only by a legacy name (hard/cheap/normal) was bypassed on the
   pressure-aware path (the default path, since PressureCache is always wired).
   build_config() now mirrors a tier-keyed override onto its vocabulary
   synonyms via _expand_tier_alias_synonyms(); explicit keys still win and
   non-tier custom aliases pass through untouched.

Tests: +4 middle-wiring tests + 3 override-expansion tests in
test_gateway_tiers.py, +1 end-to-end legacy-override test in test_tier_request.py.
Full suite 802 passed, 6 skipped; black/isort/flake8/bandit clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9gvEGUZaAUHey7mVHEHLR
@sonarqubecloud

Copy link
Copy Markdown

@OriNachum

Copy link
Copy Markdown
Contributor Author

Qodo review triage

Thanks for the review — went through all six findings: 2 fixed, 4 pushed back with reasoning.

Fixed (both in 764c8b1)

#5 Middle backend unreachable (🐞 Bug). Confirmed — a real regression. The #69 14B demotion dropped the middle optional-backend wiring from build_config(), but the fleet compose still ships the vllm-middle service (profile middle), still exposes MIDDLE_BASE_URL/MIDDLE_SERVED_NAME on the gateway, and still tells operators (compose comment) to set them "so it routes 14B requests." So enabling the profile silently fell back to the primary. Re-wired the optional middle generate backend — reachable by its explicit served name, and (because "middle" is not a TIER_ROLE role) deliberately not a tier alias, matching the "address it explicitly by model id" intent. +4 regression tests.

#6 Legacy tier override ignored (🐞 Bug). Confirmed. resolve_tier_request() normalizes a legacy tier (hardmain) before the alias lookup, so a GATEWAY_ALIASES=hard=… override (which worked on main) was silently bypassed on the pressure-aware path — and that's the default path, since PressureCache is always wired. build_config() now mirrors a tier-keyed override onto its vocabulary synonyms (hardmain, cheapminor, normalmultimodal); explicit keys still win and non-tier custom aliases pass through untouched. +4 regression tests, including an end-to-end legacy-override test through the normalized path.

Pushed back

#1 Tier alias main used (📘 Rule violation). Intended change — replied inline + resolved. PR #69 evolves the caller-facing vocabulary to main/minor/multimodal with cheap/normal/hard kept as back-compat; CLAUDE.md now documents exactly this. Rule 1513047 derives from PR #70's older contract, which this PR supersedes; the legacy aliases still resolve, so no caller breaks.

#2 vllm-multimodal base image (📎 Requirement gap). Rule 1513050 (base on nvcr.io/nvidia/vllm:26.05.post1-py3) is an acceptance criterion of issue #71 (the custom-image follow-up), not this PR. Per the doc table this PR adds, 26.05.post1 also fails to load gemma4_unified (it ships Gemma4MTPModel + standard Gemma4, not Unified) — so switching the base now buys nothing functional. The gear stays on the fleet-standard 26.04 (same as primary/minor/embed/rerank) until #71 delivers the gemma4_unified-capable custom image.

#3 gemma4_unified load failure noted (📎 Requirement gap). The doc honestly records the t7 finding (doesn't load on released images) and tracks the unblock in #71 — that's recording reality, not a defect. Rule 1513054 ("boots and loads") is again #71's acceptance criterion. (The relevance note itself flags the team's preference to keep "doesn't load yet" docs and the PR #7 precedent against forced promotion.)

#4 Catalog status not promoted (📎 Requirement gap). status="configured" is correct precisely because the gear can't be load-tested yet (#71). Promotion to load-tested + recorded metrics happens once #71 unblocks live validation; forcing it now would be dishonest (and was rejected in PR #7, per the same note).

Net: the two genuine routing bugs are fixed with tests; the four findings derived from #71's acceptance criteria / the vocabulary evolution are working-as-intended for this PR and tracked where they belong. Full suite: 802 passed, 6 skipped (live/numpy-gated); black/isort/flake8/bandit clean.

  • lobes (Claude)

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