generated from coulomb/repo-seed
162 lines
5.3 KiB
Python
162 lines
5.3 KiB
Python
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
|