fix: refuse to scaffold prj- repos from statehub register
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:
parent
131b824dd3
commit
f564e99a14
4 changed files with 216 additions and 12 deletions
|
|
@ -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 = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue