import json import os import shutil import subprocess import sys from pathlib import Path import yaml from infospace_bench import load_infospace from infospace_bench.engine import plan_asset_sync from infospace_bench.evaluation_io import read_history from infospace_bench.history import read_metrics_file from infospace_bench.markdown_adapter import validate_infospace_artifacts from infospace_bench.semantics import list_entities, list_relations REPO_ROOT = Path(__file__).resolve().parents[1] BOOTSTRAP = REPO_ROOT / "infospaces" / "bootstrap-pilot" LEGACY_SLICE = REPO_ROOT / "infospaces" / "wealth-vsm-legacy-slice" LEGACY_COMMANDS = { "init", "status", "entities", "chapters", "evaluate", "eval-summary", "relations", "classify", "viability", "check", "history", "history-diff", "bind-discipline", "process", "stale-mappings", "graph", } def cli_env() -> dict[str, str]: env = os.environ.copy() env["PYTHONPATH"] = str(REPO_ROOT / "src") + ":/home/worsch/markitect-tool/src" return env def run_cli(*args: str, cwd: Path | None = None) -> subprocess.CompletedProcess[str]: return subprocess.run( [sys.executable, "-m", "infospace_bench", *args], check=False, cwd=cwd or REPO_ROOT, env=cli_env(), text=True, capture_output=True, ) def copy_infospace(source: Path, tmp_path: Path) -> Path: target = tmp_path / source.name shutil.copytree(source, target) return target def test_legacy_command_parity_guide_covers_required_commands() -> None: guide = REPO_ROOT / "docs" / "legacy-command-parity.md" text = guide.read_text(encoding="utf-8") for command in sorted(LEGACY_COMMANDS): assert f"`markitect infospace {command}`" in text assert "replaced" in text assert "reframed" in text assert "delegated" in text assert "deferred" in text assert "retired" in text def test_bootstrap_pilot_replacement_gate_cli_round_trip(tmp_path: Path) -> None: root = copy_infospace(BOOTSTRAP, tmp_path) status = run_cli("status", str(root)) validation = run_cli("validate", str(root)) check = run_cli("check", str(root)) viability = run_cli("viability", str(root)) graph = run_cli("graph", str(root), "--format", "mermaid") exported = run_cli("export", str(root)) workflow = run_cli("workflow", "run", str(root), "bootstrap-readiness") assert status.returncode == 0, status.stderr assert validation.returncode == 0, validation.stderr assert check.returncode == 0, check.stderr assert viability.returncode == 0, viability.stderr assert graph.returncode == 0, graph.stderr assert exported.returncode == 0, exported.stderr assert workflow.returncode == 0, workflow.stderr status_payload = json.loads(status.stdout) check_payload = json.loads(check.stdout) viability_payload = json.loads(viability.stdout) workflow_payload = json.loads(workflow.stdout) assert status_payload["slug"] == "bootstrap-pilot" assert status_payload["artifact_count"] == 4 assert status_payload["artifact_kinds"] == {"generated": 2, "source": 2} assert check_payload["metrics"]["coverage_ratio"] == 1.0 assert viability_payload["passed"] is True assert "source/prd-scope.md -->|supports| generated/lifecycle-baseline.md" in ( graph.stdout ) assert json.loads(exported.stdout)["config"]["slug"] == "bootstrap-pilot" assert workflow_payload["status"] == "completed" assert workflow_payload["outputs"][0]["artifact_id"] == ( "generated/prd-scope-readiness.md" ) metrics = read_metrics_file(root / "output" / "metrics" / "metrics.yaml") history = read_history(root / "output" / "metrics" / "history.yaml") assert metrics["coverage_ratio"] == 1.0 assert history[-1].artifact_count == 4 def test_legacy_slice_replacement_gate_exercises_semantics_and_engine() -> None: infospace = load_infospace(LEGACY_SLICE) validation = validate_infospace_artifacts(LEGACY_SLICE) entities = list_entities(LEGACY_SLICE) relations = list_relations(LEGACY_SLICE) metrics = read_metrics_file(LEGACY_SLICE / "output" / "metrics" / "metrics.yaml") history = read_history(LEGACY_SLICE / "output" / "metrics" / "history.yaml") plan = plan_asset_sync(LEGACY_SLICE) assert infospace.config.slug == "wealth-vsm-legacy-slice" assert all(result.valid for result in validation) assert [entity.slug for entity in entities] == [ "division-of-labour", "market-extent", ] assert relations[0].subject_entity_id == "entity/division-of-labour.md" assert metrics["per_artifact_mean"] == 4.6 assert history[0].snapshot_id == "legacy-slice" assert [action.action for action in plan.actions] == [ "create", "create", "create", "create", ] def test_replacement_decision_record_names_residual_owners() -> None: decision = REPO_ROOT / "docs" / "replacement-readiness-decision.md" data = yaml.safe_load( decision.read_text(encoding="utf-8").split("---", maxsplit=2)[1] ) text = decision.read_text(encoding="utf-8") assert data["decision"] == "replacement-ready-for-new-in-scope-infospace-work" assert "markitect-tool" in text assert "kontextual-engine" in text assert "infospace-bench" in text assert "Not a name-for-name CLI clone" in text