Skip to content

fix(sampling): preset fallback (not greedy 0) when generation_config absent — #228 review guard#267

Open
rsafier wants to merge 1 commit into
mainfrom
fix/sampling-defaults-preset-fallback
Open

fix(sampling): preset fallback (not greedy 0) when generation_config absent — #228 review guard#267
rsafier wants to merge 1 commit into
mainfrom
fix/sampling-defaults-preset-fallback

Conversation

@rsafier

@rsafier rsafier commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Adds the guard requested in the #228 review, on top of current main.

Background

The generation_config.json sampling-defaults feature from #228 was absorbed into main during the #229 merge (sampling_setup.rs / completions.rs now default temp/top_k/top_p from state.default_*). What did not land is the guard the SeedSource/GLM-5.2 review made a merge condition:

Correctness: … If generation_config.json is missing or fails to parse, these likely default to 0/0.0 — meaning temperature=0 and top_k=0 silently force greedy decoding instead of falling back to preset.
Recommendation: Block until (1) state.default_* fallback values are confirmed safe, (2) regression tests cover missing generation_config.json, (3) comment trimmed.

Main's load_sampling_defaults currently avoids literal greedy (it falls back to hard-coded 0.6/20/0.95), but those magic constants duplicate the model's curated MODEL.toml preset and can silently drift from it — so the fallback is safe-by-accident, not by construction, and there was no test locking it in.

The guard

Source the per-field fallback from the same [sampling.non_thinking] preset that already drives the penalties. Single source of truth; the defaults are provably non-degenerate for any well-formed MODEL.toml. Behavior when generation_config.json is present (every shipped Holo/Qwen model) is unchanged — a present config that legitimately requests temperature=0 is still honored; the guard only backfills absent fields.

  • runtime.rs: field resolution split into a pure, testable resolve_sampling_defaults(Option<&Value>, &SamplingCategory, top_n_sigma, min_p); load_sampling_defaults now takes the preset and warn!s when the config is absent/unparseable.
  • serve.rs: pass &sampling_presets.non_thinking (SamplingPresets is Copy, still used downstream).

Review items closed

  1. Fallback values confirmed safe — now the model's curated preset, non-greedy by construction.
  2. Regression tests (4): missing config → preset (asserts temp/top_k/top_p all non-zero); present config overrides preset; partial config falls back per-field; present temperature=0 honored.
  3. Comment — the resolution logic carries a factual doc comment; no editorializing.

Validation

  • cargo fmt -p spark-server --check clean.
  • cargo clippy -p spark-server -- -D warnings clean.
  • cargo test -p spark-server --bin spark569 passed, 0 failed (incl. the 4 new).

Delivers the guard #228 asked for; #228's own branch predates #229 and is closed as absorbed. Signed commit.

@SeedSource

Copy link
Copy Markdown
Collaborator

[BETA] Automated PR review — SeedSource AI pipeline

Advisory only, not a merge gate. AI-generated (internal risk-triage, Atlas serve gate, GLM-5.2 review), attributed per Atlas convention.

Triage

  • Risk: low - serve-test-required (triage advisory): True - path-heuristic (authority): True
  • Rationale: Fixes sampling default fallback to prevent silent greedy behavior when config is missing.
  • Serving-path files: crates/spark-server/src/main_modules/serve.rs, crates/spark-server/src/main_modules/serve_phases/runtime.rs

Serve gate

  • Build: 18s - Qwen3.6-35B-A3B-FP8 on GB10 node1
  • Top-k KL vs main: 0.0001 (no shift vs main) - decode delta +0.1%
  • Coherence probe: coherence=pass ping=10/10 (note: our test_coherence.py is flaky here; KL is the reliable serve signal)

GLM-5.2 code review

Correctness: Logic is sound. Field-by-field fallback via and_then on Option<&Value> correctly handles absent/unparseable configs and partial configs. Explicit temperature=0 is honored. Tests cover the key cases.

Risk: Low. The change replaces hard-coded fallbacks (0.6/20/0.95) with preset values. If SamplingPresets::default().non_thinking differs from the old constants, behavior changes for models lacking generation_config.json — this is the intended fix, but it's a behavioral change worth flagging in release notes. The sampling_presets variable is assumed in scope at the call site (not shown in diff); verify it's initialized before this line.

Quality: Clean extraction into resolve_sampling_defaults improves testability. One concern: top_n_sigma and min_p still fall back to CLI args rather than the preset — intentional per the doc comment, but the "single source of truth" claim is slightly overstated. The warn log fires when gen_cfg.is_none() but not when the config is present yet missing individual fields; consider a debug log per-field for traceability. Tests are adequate and well-scoped.

Pipeline: build+serve on GB10, GLM-5.2 via NVIDIA NIM, internal risk-triage classifier. External diff treated as untrusted input. Public repo.

@rsafier
rsafier force-pushed the fix/sampling-defaults-preset-fallback branch from ac6bb1c to b22b2e9 Compare July 12, 2026 23:35
…eration_config absent

Addresses the #228 review (SeedSource/GLM-5.2): the generation_config.json
sampling-defaults feature shipped, but its absent/unparseable-config
fallback used hard-coded constants (0.6/20/0.95) that duplicate — and can
drift from — the model's curated MODEL.toml preset. The review flagged the
risk that a missing/malformed config could leave defaults at a silent
greedy 0.

Guard: source the per-field fallback from the same `[sampling.non_thinking]`
preset that already drives the penalties, so there is a single source of
truth and the defaults are provably non-degenerate. A config that is
*present* and legitimately requests `temperature=0` is still honored — the
guard only backfills absent fields.

- runtime.rs: split the field resolution into a pure, testable
  `resolve_sampling_defaults(Option<&Value>, &SamplingCategory, ..)`;
  `load_sampling_defaults` now takes the preset and warns when the config
  is absent.
- serve.rs: pass `&sampling_presets.non_thinking` (Copy, still available
  downstream).
- Regression tests: missing config → preset (non-greedy); present config
  overrides; partial config falls back per-field; present temperature=0 is
  honored.

fmt + clippy -D warnings + spark-server tests (569) all pass.
@rsafier
rsafier force-pushed the fix/sampling-defaults-preset-fallback branch from b22b2e9 to f02716f Compare July 13, 2026 00:43
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