From 3bebef1503ab4c48ea68e9a924d3b11783de603b Mon Sep 17 00:00:00 2001 From: Igor Lins e Silva <4753812+igorls@users.noreply.github.com> Date: Mon, 27 Apr 2026 02:50:12 -0300 Subject: [PATCH] fix(miner,convo_miner): close remaining wing-name normalization gaps (#1194) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two follow-ups against the review on this PR: 1. ``miner.load_config`` no-yaml fallback was returning the raw dirname as the wing, while ``cmd_init`` writes ``topics_by_wing`` under the normalized slug. A hyphenated project mined without a ``mempalace.yaml`` file silently lost every topic tunnel — same key-miss class as #1194, just down the no-yaml branch (raised by Qodo on this PR). 2. ``convo_miner`` was applying the lower/replace rule inline at one call site. Now folded through ``normalize_wing_name`` so all wing-slug producers — ``cmd_init``, ``room_detector_local``, ``miner.load_config`` fallback, ``convo_miner`` — share a single source of truth. No behavior change for any input; pure consolidation. Added ``test_load_config_no_yaml_normalizes_hyphenated_wing`` to lock the fallback path to the normalized slug — fails on develop without the miner change. Co-Authored-By: Claude Opus 4.7 (1M context) --- mempalace/convo_miner.py | 4 +++- mempalace/miner.py | 10 +++++++++- tests/test_miner.py | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/mempalace/convo_miner.py b/mempalace/convo_miner.py index a91cf33..2cf57e4 100644 --- a/mempalace/convo_miner.py +++ b/mempalace/convo_miner.py @@ -394,7 +394,9 @@ def mine_convos( convo_path = Path(convo_dir).expanduser().resolve() if not wing: - wing = convo_path.name.lower().replace(" ", "_").replace("-", "_") + from .config import normalize_wing_name + + wing = normalize_wing_name(convo_path.name) files = scan_convos(convo_dir) if limit > 0: diff --git a/mempalace/miner.py b/mempalace/miner.py index 2d610ea..ba0c630 100644 --- a/mempalace/miner.py +++ b/mempalace/miner.py @@ -286,7 +286,15 @@ def load_config(project_dir: str) -> dict: if legacy_path.exists(): config_path = legacy_path else: - wing_name = resolved_project_dir.name + from .config import normalize_wing_name + + # Normalize the dirname-derived fallback wing the same way + # ``cmd_init`` and ``room_detector_local`` do — otherwise a + # hyphenated project mined without a yaml file lands under a + # raw-name wing while ``topics_by_wing`` was keyed under the + # normalized slug, silently dropping every topic tunnel + # (the no-yaml branch of issue #1194). + wing_name = normalize_wing_name(resolved_project_dir.name) print( f" No mempalace.yaml found in {resolved_project_dir} " f"— using auto-detected defaults (wing='{wing_name}'). " diff --git a/tests/test_miner.py b/tests/test_miner.py index 0619dbb..10124ee 100644 --- a/tests/test_miner.py +++ b/tests/test_miner.py @@ -67,6 +67,24 @@ def test_load_config_uses_defaults_when_yaml_missing(): shutil.rmtree(tmpdir) +def test_load_config_no_yaml_normalizes_hyphenated_wing(): + """Fallback wing name is normalized so it matches topics_by_wing keys. + + Regression for the no-yaml branch of #1194: ``cmd_init`` writes + ``topics_by_wing`` under the normalized slug, so the miner's + fallback wing must use the same normalization or the tunnel lookup + misses every key for hyphenated dirnames. + """ + parent = tempfile.mkdtemp() + try: + project_root = Path(parent) / "my-cool-app" + project_root.mkdir() + config = load_config(str(project_root)) + assert config["wing"] == "my_cool_app" + finally: + shutil.rmtree(parent) + + def test_scan_project_skips_mempalace_generated_files(): with tempfile.TemporaryDirectory() as tmpdir: project_root = Path(tmpdir).resolve()