Make strong incumbent trigger validation phase

This commit is contained in:
2026-04-28 20:54:05 +08:00
parent 68cdaf56a8
commit 38ff4380e5
4 changed files with 53 additions and 8 deletions

View File

@@ -404,12 +404,11 @@ def _convergence_guard(
and not infeasible_progress["plateau_detected"]
and strong_incumbent["guard_active"]
):
reason = str(strong_incumbent["reason"])
reason = "strong_incumbent_requires_validation_probes"
return {
"should_stop_if_no_harness_can_justify_a_new_adjacent_probe": (
should_stop
or bool(infeasible_progress["stop_if_next_probe_repeats_family"])
or bool(strong_incumbent["guard_active"])
),
"reason": reason,
"infeasible_progress": infeasible_progress,
@@ -455,10 +454,14 @@ def _strong_incumbent_guard(
if state.best_trial_id == latest.get("trial_id") and gain >= 1.8:
return {
"guard_active": True,
"reason": "incumbent_exceeds_baseline_by_1_8x_and_latest_trial_is_best",
"reason": "incumbent_exceeds_baseline_by_1_8x_and_latest_trial_is_best_enter_validation_phase",
"baseline_trial_id": baseline.get("trial_id"),
"baseline_request_rate_per_gpu": baseline_rate,
"incumbent_gain_vs_baseline": gain,
"recommended_next_action": (
"validate_the_incumbent_with_adjacent_topology_or_same_topology_runtime_probes; "
"do_not_claim_global_optimum_from_the_first_large_gain"
),
}
return {
**default,
@@ -466,6 +469,7 @@ def _strong_incumbent_guard(
"baseline_request_rate_per_gpu": baseline_rate,
"incumbent_gain_vs_baseline": gain,
"reason": "need_more_evidence_before_strong_incumbent_stop",
"recommended_next_action": "continue_harness_guided_search",
}
@@ -600,7 +604,9 @@ def _proposal_rules() -> list[str]:
"For decode_tpot bottlenecks, prefer legal TP/DP topology redistribution before runtime-only knobs, then tune max-num-seqs or max-num-batched-tokens only from observed SLO headroom/failures.",
"Pick at most one primary knob family from knob_harnesses unless the history proves a coupled change is needed.",
"Use adjacent legal values around the incumbent; avoid broad exploratory jumps.",
"When strong_incumbent.guard_active is true, do not propose runtime-only tweaks unless the relevant harness guard is positively satisfied by same-topology evidence.",
"When strong_incumbent.guard_active is true, treat the run as a validation phase, not as proof of optimum: probe only adjacent topology or same-topology runtime knobs that can falsify the incumbent.",
"Do not stop solely because a strong incumbent appeared; stop only after nearby validation probes are exhausted, blocked by infeasible evidence, or repeatedly remain near the incumbent.",
"During validation, prefer probes that answer whether the incumbent is locally optimal over probes that merely chase another large gain.",
"Do not enable expert parallel for TTFT-prefill bottlenecks unless expert-parallel is the active harness and there is direct positive EP evidence.",
"If infeasible_progress blocks the last primary knob family, do not continue that family; switch families with direct bottleneck evidence or set should_stop=true.",
"If a proposed config is likely to reduce request_rate_per_gpu under the active guard, set should_stop=true instead of exploring.",

View File

@@ -63,6 +63,16 @@ def _coerce_str_list(value: Any, *, context: str) -> list[str]:
return result
def _coerce_text(value: Any, *, context: str) -> str:
if isinstance(value, str) and value.strip():
return value.strip()
if isinstance(value, Mapping) or isinstance(value, list):
text = json.dumps(value, ensure_ascii=False, sort_keys=True)
if text:
return text
raise SpecError(f"{context} must be a non-empty string.")
def _coerce_int_list(value: Any, *, context: str) -> list[int]:
if value is None:
return []
@@ -674,8 +684,8 @@ class Proposal:
expected_effects, context="proposal.expected_effects"
)
return cls(
observation=_require_str(data.get("observation"), context="proposal.observation"),
diagnosis=_require_str(data.get("diagnosis"), context="proposal.diagnosis"),
observation=_coerce_text(data.get("observation"), context="proposal.observation"),
diagnosis=_coerce_text(data.get("diagnosis"), context="proposal.diagnosis"),
config_patch=ConfigPatch.from_dict(
_require_mapping(data.get("config_patch"), context="proposal.config_patch")
),