fix: refuse to scaffold prj- repos from statehub register
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

STATE-WP-0080-T01: detect project flavor from classification, GOAL.md,
or a prj- slug, then exit pointing at rmgr scaffold. Durable-repo
write path is unchanged. Rebind 0080 hub IDs to the live workstream
and open T02 now that RMGR-WP-0004-T03 has landed.
This commit is contained in:
tegwick 2026-08-18 21:36:53 +02:00
parent 131b824dd3
commit f564e99a14
4 changed files with 216 additions and 12 deletions

View file

@ -11,6 +11,9 @@ import custodian_cli
from custodian_cli import cmd_fix_consistency
from statehub_register import (
RegisterInference,
detect_project_flavor_signal,
refuse_project_flavor_scaffold,
run_register,
_invoke_llm,
_normalise_inference,
_parse_json_object,
@ -101,6 +104,107 @@ def test_write_registration_files_primes_codex_repo(tmp_path: Path):
assert "statehub fix-consistency" in workplan
def test_detect_project_flavor_from_classification(tmp_path: Path):
(tmp_path / ".repo-classification.yaml").write_text(
"repo_classification:\n category: project\n domain: infotech\n",
encoding="utf-8",
)
assert detect_project_flavor_signal(tmp_path) == (
".repo-classification.yaml category=project"
)
def test_detect_project_flavor_from_goal_md(tmp_path: Path):
(tmp_path / "GOAL.md").write_text(
"---\nrepo_flavor: project\n---\n\n# Project goal\n",
encoding="utf-8",
)
assert detect_project_flavor_signal(tmp_path) == "GOAL.md repo_flavor=project"
def test_detect_project_flavor_from_prj_directory_name(tmp_path: Path):
repo = tmp_path / "prj-example"
repo.mkdir()
assert detect_project_flavor_signal(repo) == "slug prefix prj- (prj-example)"
def test_detect_project_flavor_from_repo_slug_argument(tmp_path: Path):
repo = tmp_path / "example"
repo.mkdir()
assert detect_project_flavor_signal(repo) is None
assert detect_project_flavor_signal(repo, "prj-example") == (
"slug prefix prj- (prj-example)"
)
def test_classification_project_takes_precedence_over_slug(tmp_path: Path):
repo = tmp_path / "prj-example"
repo.mkdir()
(repo / ".repo-classification.yaml").write_text(
"repo_classification:\n category: project\n domain: infotech\n",
encoding="utf-8",
)
assert detect_project_flavor_signal(repo) == (
".repo-classification.yaml category=project"
)
def test_durable_repo_is_not_project_flavor(tmp_path: Path):
(tmp_path / ".repo-classification.yaml").write_text(
"repo_classification:\n category: tooling\n domain: infotech\n",
encoding="utf-8",
)
assert detect_project_flavor_signal(tmp_path, "demo-service") is None
def test_refuse_project_flavor_scaffold_points_at_rmgr(tmp_path: Path):
repo = tmp_path / "prj-example"
repo.mkdir()
with pytest.raises(SystemExit, match="rmgr scaffold") as exc:
refuse_project_flavor_scaffold(repo)
message = str(exc.value)
assert "refuses to scaffold a project-flavor repository" in message
assert "never PRJ-WP-" in message
assert str(repo) in message
def test_run_register_refuses_prj_repo_without_writing_or_calling_api(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
):
repo = tmp_path / "prj-example"
repo.mkdir()
(repo / ".repo-classification.yaml").write_text(
"repo_classification:\n category: project\n domain: infotech\n",
encoding="utf-8",
)
called: list[str] = []
monkeypatch.setattr(
"statehub_register._check_api",
lambda *_args, **_kwargs: called.append("api"),
)
monkeypatch.setattr(
"statehub_register.write_registration_files",
lambda **_kwargs: called.append("write") or [],
)
args = argparse.Namespace(path=str(repo), repo_slug=None)
with pytest.raises(SystemExit, match="rmgr scaffold"):
run_register(args)
assert called == []
assert not (repo / "INTENT.md").exists()
assert not (repo / "workplans").exists()
def test_write_registration_files_is_idempotent_without_force(tmp_path: Path):
inference = RegisterInference()
kwargs = {