Skip to content

feat(lucebox): guided CLI for buyers and contributors - #335

Open
easel wants to merge 26 commits into
Luce-Org:mainfrom
easel:feat/lucebox-cli
Open

feat(lucebox): guided CLI for buyers and contributors#335
easel wants to merge 26 commits into
Luce-Org:mainfrom
easel:feat/lucebox-cli

Conversation

@easel

@easel easel commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

Ship one simple inference CLI for both Lucebox buyers and open-source contributors.

Running lucebox opens the branded ASCII menu. Wi-Fi, Bluetooth, and device provisioning are intentionally outside this PR; this surface is focused on selecting, configuring, and running the inference engine.

Buyer flow

  • lucebox setup guides backend/image selection, model selection, optimization, background-service installation, and start.
  • lucebox models select shows a numbered catalog, downloads when needed, and activates factory-preloaded models without contacting Hugging Face.
  • lucebox optimize explains the decision for DFlash, PFlash, KVFlash, and Spark before applying it.
    • Automatic is model-, primary-GPU-, VRAM-, host-RAM-, and installed-asset-aware.
    • Advanced lets the user override those four product choices while context, cache, and DDTree details remain safely tuned.
  • Automatic profiles are replanned when the model changes; direct low-level edits become a preserved Custom profile.
  • The menu exposes start, stop, status, logs, active model, backend, optimization mode, and engine state.

Safe optimization behavior

  • DFlash is enabled only when a non-empty matching draft/speculator is installed.
  • PFlash is automatic only for the validated Qwen3.6 dense long-context path and uses one shared Qwen3-0.6B BF16 scorer.
  • KVFlash is enabled automatically only under real Qwen-family memory pressure; otherwise exact full-KV execution is preferred.
  • Spark is enabled automatically only for supported MoE models under VRAM pressure and with at least 32 GB reported host RAM for cold experts.
  • Automatic profiles leave KV dtype selection to each model family and do not reintroduce the quality-risky blanket tq3_0 fallback.
  • Zero-byte model/scorer placeholders and incompatible KVFlash + FA-window settings are rejected.

Hardware behavior

  • NVIDIA CUDA and AMD ROCm image/runtime selection.
  • RTX 3090 + Strix defaults to CUDA; an explicit ROCm choice retunes against the AMD device facts.
  • R9700 + Strix selects ROCm and pins the largest-VRAM AMD device with ROCR_VISIBLE_DEVICES.
  • Strix-only ROCm remains supported.
  • Automatic tuning uses one selected primary GPU and never sums VRAM across devices. Transparent multi-GPU layer sharding is not claimed by this release.

Contributor flow

The same ./lucebox.sh menu detects a source checkout and adds:

  • lucebox build [cuda|rocm] — native dflash_server build for the selected accelerator.
  • lucebox native [cuda|rocm] — run the selected model with the native engine.
  • lucebox harness — Claude Code, Codex, OpenCode, Hermes, Pi, OpenClaw, and Open WebUI picker.
  • Native and harness paths receive the same DFlash/PFlash/KVFlash/Spark profile as the buyer container path.

All menu actions keep scriptable equivalents for CI and expert workflows.

Package and installation

  • install.sh installs the small host wrapper; buyer machines can receive the wrapper, image, models, and shared optimizer scorer preinstalled.
  • The typed lucebox/ Python package remains the source of truth for TOML config, model downloads, optimization planning, and launch construction.
  • The package builds as a wheel and source distribution with the lucebox console entry point.

Validation

  • 166 Python tests on macOS and on Lucebox5.
  • Ruff correctness checks and MyPy (11 typed source modules).
  • ShellCheck, Bash syntax checks, and the 71-case wrapper/entrypoint/harness integration suite on Lucebox5.
  • Final wheel + source distribution build; clean isolated wheel install and console-entry-point smoke.
  • Lucebox5 hardware probe: R9700 gfx1201 + Strix gfx1151, ROCm 7.2.4, 125 GB RAM.
  • Lucebox5 live offline/preload flow: activate Qwen3.6-27B, apply Automatic, persist DFlash + PFlash at 98,304 context, pin the R9700 by stable ROCm UUID, and render the final launch contract.
  • All nine findings from Cubic's automated review were handled and regression-tested.
  • GitHub CI and CUDA/ROCm image jobs for commit 12d1ab51 (running).

Lucebox5 currently has no Docker installation, so this validation covers real hardware detection, CLI/config behavior, and the ROCm launch contract, but not an end-to-end container inference request. Existing GitHub CUDA/ROCm build and GPU jobs provide the engine/image coverage.

Out of scope

  • Wi-Fi/Bluetooth/Tailscale onboarding.
  • Transparent automatic multi-GPU layer sharding.
  • Benchmark sweeps that mutate a user's profile automatically.
  • A separate GUI.

@easel
easel force-pushed the feat/lucebox-cli branch 2 times, most recently from 91276a7 to 62b21f0 Compare June 4, 2026 02:50
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 4, 2026
## What

Containerization stack for lucebox-hub. Dockerfile + docker-bake.hcl
build the lucebox-hub image (build-env and runtime stages);
scripts/build_image.sh drives local builds; server/scripts/entrypoint.sh
emits IMAGE_INFO / HOST_INFO sidecars consumed by /props. GitHub Actions
add .github/workflows/docker.yml (build & publish), update ci.yml, and
add release-luce-bench.yml for tagging. Workspace-root files
(pyproject.toml, uv.lock, Makefile, lefthook.yml, .gitignore, README)
live here because the Dockerfile uv-syncs the workspace at build time.

## Why

Provides the reproducible image and CI pipeline every other split PR
deploys into. Centralizing build/publish here keeps Dockerfile,
entrypoint, and workspace-root pinning in one reviewable change.

## Dependencies

- Luce-Org#335 (lucebox-cli): Dockerfile COPYs lucebox/ into the image
- Luce-Org#337 (lucebench-harness): Dockerfile COPYs luce-bench/ into the image
@easel
easel force-pushed the feat/lucebox-cli branch from 62b21f0 to 8732b35 Compare June 4, 2026 05:02
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 4, 2026
## What

Containerization stack for lucebox-hub. Dockerfile + docker-bake.hcl
build the lucebox-hub image (build-env and runtime stages);
scripts/build_image.sh drives local builds; server/scripts/entrypoint.sh
emits IMAGE_INFO / HOST_INFO sidecars consumed by /props. GitHub Actions
add .github/workflows/docker.yml (build & publish), update ci.yml, and
add release-luce-bench.yml for tagging. Workspace-root files
(pyproject.toml, uv.lock, Makefile, lefthook.yml, .gitignore, README)
live here because the Dockerfile uv-syncs the workspace at build time.

## Why

Provides the reproducible image and CI pipeline every other split PR
deploys into. Centralizing build/publish here keeps Dockerfile,
entrypoint, and workspace-root pinning in one reviewable change.

## Dependencies

- Luce-Org#335 (lucebox-cli): Dockerfile COPYs lucebox/ into the image
- Luce-Org#337 (lucebench-harness): Dockerfile COPYs luce-bench/ into the image
@easel
easel force-pushed the feat/lucebox-cli branch 2 times, most recently from 6c9078b to 360d332 Compare June 4, 2026 17:17
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 4, 2026
## What

Containerization stack for lucebox-hub. Dockerfile + docker-bake.hcl
build the lucebox-hub image (build-env and runtime stages);
scripts/build_image.sh drives local builds; server/scripts/entrypoint.sh
emits IMAGE_INFO / HOST_INFO sidecars consumed by /props. GitHub Actions
add .github/workflows/docker.yml (build & publish), update ci.yml, and
add release-luce-bench.yml for tagging. Workspace-root files
(pyproject.toml, uv.lock, Makefile, lefthook.yml, .gitignore, README)
live here because the Dockerfile uv-syncs the workspace at build time.

## Why

Provides the reproducible image and CI pipeline every other split PR
deploys into. Centralizing build/publish here keeps Dockerfile,
entrypoint, and workspace-root pinning in one reviewable change.

## Dependencies

- Luce-Org#335 (lucebox-cli): Dockerfile COPYs lucebox/ into the image
- Luce-Org#337 (lucebench-harness): Dockerfile COPYs luce-bench/ into the image
@easel
easel force-pushed the feat/lucebox-cli branch 2 times, most recently from 1d588db to 0d8e1ff Compare June 4, 2026 18:38
@easel
easel marked this pull request as ready for review June 4, 2026 19:18

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 52 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread harness/src/harness/clients/opencode.py Outdated
Comment thread lucebox/src/lucebox/autotune.py Outdated
Comment thread harness/src/harness/bench.py Outdated
Comment thread lucebox.sh Outdated
Comment thread lucebox/src/lucebox/sweep.py Outdated
Comment thread lucebox/src/lucebox/sweep.py Outdated
Comment thread harness/clients/run_lucebench.sh Outdated
Comment thread lucebox.sh Outdated
Comment thread lefthook.yml Outdated
Comment thread lucebox/src/lucebox/docker_run.py Outdated
@easel
easel force-pushed the feat/lucebox-cli branch from 0d8e1ff to 73f04f4 Compare June 4, 2026 23:30
easel pushed a commit to easel/lucebox-hub that referenced this pull request Jun 5, 2026
@easel
easel force-pushed the feat/lucebox-cli branch 2 times, most recently from bb7bb11 to a56b51b Compare June 8, 2026 22:08
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 8, 2026
Containerization stack for lucebox-hub. Dockerfile + docker-bake.hcl
build the lucebox-hub image (build-env and runtime stages);
scripts/build_image.sh drives local builds; server/scripts/entrypoint.sh
emits IMAGE_INFO / HOST_INFO sidecars consumed by /props. GitHub Actions
add .github/workflows/docker.yml (build & publish), update ci.yml, and
add release-luce-bench.yml for tagging. Workspace-root files
(pyproject.toml, uv.lock, Makefile, lefthook.yml, .gitignore, README)
live here because the Dockerfile uv-syncs the workspace at build time.

Provides the reproducible image and CI pipeline every other split PR
deploys into. Centralizing build/publish here keeps Dockerfile,
entrypoint, and workspace-root pinning in one reviewable change.

- Luce-Org#335 (lucebox-cli): Dockerfile COPYs lucebox/ into the image
- Luce-Org#337 (lucebench-harness): Dockerfile COPYs luce-bench/ into the image
davide221 added a commit to easel/lucebox-hub that referenced this pull request Jun 9, 2026
…R + personal refs

Strip forward-references to lucebox-cli (Luce-Org#335) and luce-bench (Luce-Org#337) plus the
contributor's personal repos so the docker stack stands alone:

- delete .github/workflows/release-luce-bench.yml (luce-bench PyPI publish;
  fires only on luce-bench-v* tags, needs a luce-bench/ dir not in this repo)
- Makefile: drop test/smoke/bench/profile targets (invoke lucebench/lucebox
  modules absent here) and their now-unused vars
- .gitignore: drop luce-bench/snapshots and external baseline-repo URLs
- pyproject.toml / Dockerfile / docker.yml: de-reference Luce-Org#335/Luce-Org#337/luce-bench
  in comments

No functional change: deps, workspace members, ruff config, and every build
instruction are untouched, so CI stays green. The siblings re-add their own
scaffolding when they land.

Co-Authored-By: WOZCODE <contact@withwoz.com>
@easel
easel force-pushed the feat/lucebox-cli branch 2 times, most recently from 5a7e617 to c46e358 Compare June 11, 2026 15:15

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lucebox/src/lucebox/docker_run.py">

<violation number="1" location="lucebox/src/lucebox/docker_run.py:231">
P3: Several newly added helper functions are dead code (defined but never called anywhere in the codebase).</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/test_lucebox_sh.sh
@easel
easel force-pushed the feat/lucebox-cli branch 3 times, most recently from a731f1d to 71139a5 Compare June 16, 2026 17:22
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 16, 2026
…oad core

Defer second-order features to follow-up PRs so this PR is just the host
wrapper and the CLI needed to install, launch/serve, configure, and
download models. Cuts the PR from ~11.2k to ~6.2k added lines.

Deferred out of this PR (land as stacked follow-ups):
- Agent-client adapters + bench: the entire net-new harness/ package
  (bench.py, the six clients, run_lucebench.sh) and the client launcher
  verbs. harness/ reverts to main's loose-scripts state; the root
  pyproject no longer adds harness as a workspace member/dep.
- Autotune sweep + profiles: candidate_configs, the Profile registry and
  per-arch brackets, sweep.py, and the `autotune` command. The host-derived
  DFLASH_* heuristic (runtime_from_host) STAYS — config.live_config needs it
  to bake serve defaults — slimmed into autotune.py.
- profile + smoke commands and their modules.

Coupling fixes:
- recommend_preset moved autotune.py -> download.py (models sub-app uses it).
- Wrapper: drop the autotune --sweep exec-routing special case and trim
  usage/completion/exec-set to the core verbs.

Tests/CI follow the surface: deferred-feature tests removed; runtime_from_host
heuristic tests kept; new guard asserts the deferred verbs are NOT registered.
CI pytest step scoped to lucebox. lucebox 72 passed, wrapper 53 passed,
ruff + mypy + shellcheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 37 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lucebox/src/lucebox/docker_run.py">

<violation number="1" location="lucebox/src/lucebox/docker_run.py:231">
P3: Several newly added helper functions are dead code (defined but never called anywhere in the codebase).</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread lucebox.sh Outdated
easel and others added 19 commits August 1, 2026 13:02
User-facing host wrapper + in-container Python CLI for launching and
configuring the lucebox-hub image. Completes the docker-stack (Luce-Org#334)
follow-up that intentionally shipped images without the CLI package.

Host surface:
- install.sh bootstrap + lucebox.sh wrapper (probe host, systemd unit,
  serve/pull/update/check/logs)
- config.toml as system of record (env > file > defaults)

In-container package (lucebox/):
- check, pull, print-run, print-serve-argv
- config {get,set,unset}
- models {list,download} with VRAM-tier recommend_preset
- VRAM-tier DFLASH_* heuristic (runtime_from_host); seeds config.toml
  on first models download --activate so 24 GB hosts get 98k/tq3_0
  instead of the 16k class default
- prefix_cache stays off by default (agent tool-prompt regression)

Image/workspace:
- COPY lucebox into CUDA and ROCm images; uv workspace member
- entrypoint host_info missing-dir guard + pure-bash trim

Tests/CI: lucebox pytest, wrapper sandbox scripts, lefthook.

Deferred to follow-ups: autotune sweep/profiles, profile/smoke,
agent-client harness adapters.
Make the buyer and contributor CLI model-aware and hardware-aware across CUDA, ROCm, and heterogeneous Lucebox builds. Add explainable Automatic/Advanced DFlash, PFlash, KVFlash, and Spark profiles; safe artifact, memory, and cache validation; native harness forwarding; and R9700/Strix device pinning.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 10 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/test_lucebox_sh.sh
Comment thread lucebox/src/lucebox/calibration.py

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 30 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lucebox/tests/test_placement.py">

<violation number="1" location="lucebox/tests/test_placement.py:625">
P3: The test's stated purpose is to prove Python capabilities match the engine table, but the newly added prefix_slots column is captured only to keep the following draft column aligned and is never cross-checked. A drift between C++ default_prefix_cache_slots and Python prefix_cache_slots would go unnoticed. Consider asserting capability.prefix_cache_slots == int(row["prefix_slots"]) (mirroring how the other columns are validated) or, if the Python architecture table intentionally doesn't track this value, note that on the capability struct so the column doesn't get silently dropped.</violation>
</file>

<file name="server/test/test_entrypoint_cache_defaults.sh">

<violation number="1" location="server/test/test_entrypoint_cache_defaults.sh:90">
P3: The tailored failure message is effectively unreachable: on a regression the entrypoint aborts non-zero and this test's own `set -e` terminates before the grep executes, so the operator just sees a bare exit code instead of this diagnostic. Wrap the entrypoint invocation in an explicit `if ! ...; then cat "$gb10_stderr"; exit 1; fi` so the clear message is printed on failure, and optionally assert the serve actually completes.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread server/src/server/http_server.cpp Outdated
Comment thread server/src/flashprefill.h Outdated
Comment thread server/src/deepseek4/deepseek4_backend.cpp
r'\{"(?P<arch>[^\"]+)",\s*'
r"(?P<split>true|false),\s*(?P<remote>true|false),\s*"
r"(?P<pflash>true|false),\s*(?P<offload>true|false),\s*"
r"(?P<prefix_slots>[0-9]+),\s*"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: The test's stated purpose is to prove Python capabilities match the engine table, but the newly added prefix_slots column is captured only to keep the following draft column aligned and is never cross-checked. A drift between C++ default_prefix_cache_slots and Python prefix_cache_slots would go unnoticed. Consider asserting capability.prefix_cache_slots == int(row["prefix_slots"]) (mirroring how the other columns are validated) or, if the Python architecture table intentionally doesn't track this value, note that on the capability struct so the column doesn't get silently dropped.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lucebox/tests/test_placement.py, line 625:

<comment>The test's stated purpose is to prove Python capabilities match the engine table, but the newly added prefix_slots column is captured only to keep the following draft column aligned and is never cross-checked. A drift between C++ default_prefix_cache_slots and Python prefix_cache_slots would go unnoticed. Consider asserting capability.prefix_cache_slots == int(row["prefix_slots"]) (mirroring how the other columns are validated) or, if the Python architecture table intentionally doesn't track this value, note that on the capability struct so the column doesn't get silently dropped.</comment>

<file context>
@@ -622,6 +622,7 @@ def test_python_architecture_capabilities_match_engine_table() -> None:
         r'\{"(?P<arch>[^\"]+)",\s*'
         r"(?P<split>true|false),\s*(?P<remote>true|false),\s*"
         r"(?P<pflash>true|false),\s*(?P<offload>true|false),\s*"
+        r"(?P<prefix_slots>[0-9]+),\s*"
         r"(?P<draft>kNever|kMono|kBoth),"
     )
</file context>

DFLASH_TARGET="$TARGET" \
DFLASH_DRAFT="$TMP_DIR/no-draft" \
DFLASH_SERVER_BIN="$FAKE_SERVER" \
bash "$ENTRYPOINT" serve >/dev/null 2>"$gb10_stderr"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: The tailored failure message is effectively unreachable: on a regression the entrypoint aborts non-zero and this test's own set -e terminates before the grep executes, so the operator just sees a bare exit code instead of this diagnostic. Wrap the entrypoint invocation in an explicit if ! ...; then cat "$gb10_stderr"; exit 1; fi so the clear message is printed on failure, and optionally assert the serve actually completes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/test/test_entrypoint_cache_defaults.sh, line 90:

<comment>The tailored failure message is effectively unreachable: on a regression the entrypoint aborts non-zero and this test's own `set -e` terminates before the grep executes, so the operator just sees a bare exit code instead of this diagnostic. Wrap the entrypoint invocation in an explicit `if ! ...; then cat "$gb10_stderr"; exit 1; fi` so the clear message is printed on failure, and optionally assert the serve actually completes.</comment>

<file context>
@@ -65,4 +65,32 @@ assert_arg_pair "$configured_output" --prefix-cache-slots 4
+    DFLASH_TARGET="$TARGET" \
+    DFLASH_DRAFT="$TMP_DIR/no-draft" \
+    DFLASH_SERVER_BIN="$FAKE_SERVER" \
+    bash "$ENTRYPOINT" serve >/dev/null 2>"$gb10_stderr"
+if grep -Fq "syntax error: operand expected" "$gb10_stderr"; then
+    echo "entrypoint attempted arithmetic on GB10 [N/A] memory" >&2
</file context>

Resolves conflicts against the DS4 snapshot-lifecycle, streaming-cancellation,
and monolithic prefix-cache work that landed on main after this branch's
server commit:

- deepseek4_backend.{h,cpp}: adopt main's SnapshotAux/generate_from_state
  snapshot machinery wholesale; keep this branch's pure
  deepseek4_dspark_supports_cuda_sm() qualification helpers and its sm_121
  DSpark gate.
- prefix_cache.cpp: keep this branch's arch-aware resolve_chat_markers()
  signature (needed to gate Laguna's plain-text XML markers) while adopting
  main's exact-control-token DeepSeek detection and EOS-based boundaries.
- test_server_unit.cpp: keep both sides' new tests; adapt main's DeepSeek
  marker test to the arch-aware signature.
- run_hermes.sh: main's run_with_timeout mechanics with this branch's
  'custom' Hermes provider.
- flashprefill.h: unqualified BF16 devices (GB10 sm_121) now route through
  the exact ggml FA path instead of returning -2, which both graph callers
  treated as a hard scorer failure.
- http_server.cpp: the local-PFlash unsupported-GPU fallback no longer
  returns early from prepare_prompt, so over-context requests still hit
  effective_prompt_overflows() and get the normal 400.
- deepseek4_backend.cpp: qualify the DFLASH_DS4_DRAFT_GPU device before
  creating the DSpark draft backend; the startup gate only covered the
  target GPU.
- calibration.py: include the image registry in the calibration
  fingerprint so changing LUCEBOX_IMAGE forces a fresh probe.
- test_lucebox_sh.sh: cover the originally-stopped engine in the
  calibration lifecycle test; commit and rollback must stop the unit
  rather than restart it.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="server/src/deepseek4/deepseek4_backend.cpp">

<violation number="1" location="server/src/deepseek4/deepseek4_backend.cpp:705">
P3: The predicate `draft_kind != target_kind || draft_gpu != cfg_.device.gpu` is now duplicated between this new qualification guard and the existing backend-creation branch a few lines below. The two copies can silently diverge (e.g. if the backend-creation condition grows another trigger such as `separate_draft_stream`), which could bypass the qualification. Consider hoisting the shared condition into a single named bool and reusing it in both places.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

// Startup qualification covers only the target GPU. DFLASH_DS4_DRAFT_GPU
// can select a different CUDA device, so qualify the resolved draft
// device before creating a backend on it.
if (draft_kind == PlacementBackend::Cuda &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: The predicate draft_kind != target_kind || draft_gpu != cfg_.device.gpu is now duplicated between this new qualification guard and the existing backend-creation branch a few lines below. The two copies can silently diverge (e.g. if the backend-creation condition grows another trigger such as separate_draft_stream), which could bypass the qualification. Consider hoisting the shared condition into a single named bool and reusing it in both places.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/src/deepseek4/deepseek4_backend.cpp, line 705:

<comment>The predicate `draft_kind != target_kind || draft_gpu != cfg_.device.gpu` is now duplicated between this new qualification guard and the existing backend-creation branch a few lines below. The two copies can silently diverge (e.g. if the backend-creation condition grows another trigger such as `separate_draft_stream`), which could bypass the qualification. Consider hoisting the shared condition into a single named bool and reusing it in both places.</comment>

<file context>
@@ -699,6 +699,21 @@ bool DeepSeek4Backend::load_spec_drafter() {
+    // Startup qualification covers only the target GPU. DFLASH_DS4_DRAFT_GPU
+    // can select a different CUDA device, so qualify the resolved draft
+    // device before creating a backend on it.
+    if (draft_kind == PlacementBackend::Cuda &&
+        (draft_kind != target_kind || draft_gpu != cfg_.device.gpu)) {
+        int draft_sm = 0;
</file context>

The client launchers now reject zero-byte GGUF placeholders, so the
model-free timeout tests must stub the target/draft with one byte of
content instead of touch.
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