fix(graph): normalize wing slug at init so topic tunnels fire for hyphenated dirs (#1194)

`init` was recording `topics_by_wing[<raw-dirname>]` while `mempalace.yaml`
got the lower-cased separator-collapsed slug. At mine time the miner
read the slug from the yaml and missed the registry key, so
`_compute_topic_tunnels_for_wing` returned 0 silently for every project
whose folder contained a `-` or a space — the most common shape in the
wild.

Extracted the rule into `config.normalize_wing_name()` and routed both
`cli.cmd_init` (registry write) and `room_detector_local.detect_rooms_local`
(yaml write) through it. Added a regression test in `test_cli.py`
asserting the registry call uses the normalized slug, plus four direct
unit tests for the helper.

Refs #1180.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
bensig
2026-04-25 02:47:15 -07:00
committed by igorls
parent bc5d3fa911
commit b7f0a8af01
6 changed files with 72 additions and 7 deletions
+32
View File
@@ -138,6 +138,38 @@ def test_cmd_init_with_entities(mock_config_cls, tmp_path):
cmd_init(args)
@patch("mempalace.cli.MempalaceConfig")
def test_cmd_init_normalizes_wing_name_for_topics_registry(mock_config_cls, tmp_path):
"""Regression for #1194: hyphenated dir names must be normalized to the
same slug ``mempalace.yaml`` uses, otherwise ``topics_by_wing`` keys
miss the miner's lookup at mine time and tunnels are silently dropped.
"""
project = tmp_path / "my-cool-app"
project.mkdir()
fake_files = [project / "a.txt"]
detected = {
"people": [{"name": "Alice"}],
"projects": [],
"topics": [{"name": "Bun"}],
"uncertain": [],
}
confirmed = {"people": ["Alice"], "projects": [], "topics": ["Bun"]}
args = argparse.Namespace(dir=str(project), yes=True)
with (
patch("mempalace.entity_detector.scan_for_detection", return_value=fake_files),
patch("mempalace.entity_detector.detect_entities", return_value=detected),
patch("mempalace.entity_detector.confirm_entities", return_value=confirmed),
patch("mempalace.miner.add_to_known_entities") as mock_register,
patch("mempalace.room_detector_local.detect_rooms_local"),
patch("builtins.open", MagicMock()),
patch("mempalace.cli._maybe_run_mine_after_init"),
):
mock_register.return_value = "/tmp/known_entities.json"
cmd_init(args)
mock_register.assert_called_once()
assert mock_register.call_args.kwargs["wing"] == "my_cool_app"
@patch("mempalace.cli.MempalaceConfig")
def test_cmd_init_with_entities_zero_total(mock_config_cls, tmp_path, capsys):
"""When entities detected but total is 0, prints 'No entities' message."""