From e0707d8072846ad0746814c36b4747eba1f7352c Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Thu, 16 Apr 2026 08:20:36 +0200 Subject: [PATCH] feat(tooling): always log retry reasons in gemma_naming.py (#833) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retry rejection lines (dedup, blocklist, placeholder, stem_cap, empty, error) now print unconditionally, not only under --verbose. The fallback line also includes a tally of the rejection reasons that exhausted all attempts, e.g.: fallback: GJ144e-1/range_43 → 'Kirkwood Spine' [blocklist=2 dedup=1] Diagnostic run on 20 bodies confirms dedup is the primary fallback driver. Gemma converges on a narrow set of range names ("The Ridge", "Blackwood Range", "The Spine") that collide across bodies in the same corridor. Blocklist catches "Thames" and "The Great Divide" correctly. Zero stem-cap or subprocess-error fallbacks observed. Co-Authored-By: Claude Opus 4.6 (1M context) --- tooling/planet-gen/gemma_naming.py | 33 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/tooling/planet-gen/gemma_naming.py b/tooling/planet-gen/gemma_naming.py index 9672bbf5e..94bf7a6d6 100755 --- a/tooling/planet-gen/gemma_naming.py +++ b/tooling/planet-gen/gemma_naming.py @@ -1401,11 +1401,11 @@ def name_feature( for stem in _extract_stems(final): stem_counts[stem] = stem_counts.get(stem, 0) + 1 + rejections: dict[str, int] = {"empty": 0, "placeholder": 0, "blocklist": 0, + "dedup": 0, "stem_cap": 0, "error": 0} + for attempt in range(max_attempts): seed = _seed_for(world_seed, body_id, local_id, attempt) - # Rotate the example pool per attempt so retries get a different - # prompt, not just a different seed — big variety payoff for a - # small model like Gemma 2 2B. prompt = _build_prompt( feature_type, inflection=palette["inflection"], @@ -1420,31 +1420,31 @@ def name_feature( try: raw = voice.request(prompt, seed) except RuntimeError as e: - if verbose: - log(f" subprocess error on {body_id}/{local_id} attempt " - f"{attempt}: {e} — retrying") + rejections["error"] += 1 + log(f" error {body_id}/{local_id} attempt {attempt}: {e}") continue cleaned = post_process(raw) if not cleaned: + rejections["empty"] += 1 + log(f" empty {body_id}/{local_id} attempt {attempt}") continue if is_placeholder(cleaned): - if verbose: - log(f" placeholder '{cleaned}' ({body_id}/{local_id}) — retrying") + rejections["placeholder"] += 1 + log(f" placeholder '{cleaned}' {body_id}/{local_id}") continue if is_blocked(cleaned, blocklist): - if verbose: - log(f" blocklist hit '{cleaned}' ({body_id}/{local_id}) — retrying") + rejections["blocklist"] += 1 + log(f" blocklist '{cleaned}' {body_id}/{local_id}") continue if _is_duplicate(cleaned): - if verbose: - log(f" dedup hit '{cleaned}' ({body_id}/{local_id}) — retrying") + rejections["dedup"] += 1 + log(f" dedup '{cleaned}' {body_id}/{local_id}") continue over_stem = _exceeds_stem_cap(cleaned) if over_stem is not None: - if verbose: - log(f" stem cap hit '{cleaned}' (stem '{over_stem}' at " - f"cap {stem_cap}) {body_id}/{local_id} — retrying") + rejections["stem_cap"] += 1 + log(f" stem_cap '{cleaned}' ('{over_stem}' ≥{stem_cap}) {body_id}/{local_id}") continue _commit_name(cleaned) return cleaned @@ -1461,7 +1461,8 @@ def name_feature( fallback = fallback_name(corridor, feature_type, salt + bump) used.add(fallback) body_used.add(fallback) - log(f" fallback: {body_id}/{local_id} → '{fallback}'") + reasons = " ".join(f"{k}={v}" for k, v in rejections.items() if v > 0) + log(f" fallback: {body_id}/{local_id} → '{fallback}' [{reasons}]") return fallback