feat(devkit): add resumable workspace automation and UI review tooling
Dependency Audit / dependency-audit (push) Successful in 1m45s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Successful in 11m30s

Verified with the coordinated workspace changes by devkit full run
2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed).
This shared UI pass does not mark the individual module reviews complete.
This commit is contained in:
2026-09-09 02:03:17 +02:00
parent 14b19fbead
commit 2ffdb23f69
67 changed files with 17306 additions and 94 deletions
+175
View File
@@ -0,0 +1,175 @@
import argparse
import json
from pathlib import Path
import subprocess
import sys
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "tools/devkit"))
from govoplan_devkit import review
from govoplan_devkit.cli import main
@pytest.fixture
def args(tmp_path):
repo = tmp_path / "optional-feature"
repo.mkdir()
subprocess.run(["git", "init", "-q", str(repo)], check=True)
paths = ["webui/src/pages/CampaignPage.tsx", "webui/src/dialogs/SettingsDialog.tsx",
"webui/src/settings/AdminSettings.tsx", "webui/src/widgets/SummaryWidget.tsx", "webui/src/module.ts"]
for relative in paths:
path = repo / relative
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("// fixture only\n")
manifest = repo / "src/optional_feature/backend/manifest.py"
manifest.parent.mkdir(parents=True)
manifest.write_text("raise RuntimeError('MUST NEVER IMPORT MODULE CODE')\n")
(tmp_path / "principles.md").write_text("# Principles\nRevision **UI-2026-09-08**\n\n## UI-01 — Help beside text\n\n## UI-02 — Display first; edit deliberately\n")
inventory = {"schema_version": 1, "epic": {"repository": "meta", "number": 4, "url": "https://gitea.invalid/team/meta/issues/4"},
"issues": [{"scope_id": "campaigns", "name": "Campaign", "kind": "manifest", "repository": "optional-feature", "number": 8,
"url": "https://gitea.invalid/team/optional-feature/issues/8", "state_at_verification": "closed", "operation": "created"}]}
(tmp_path / "issues.json").write_text(json.dumps(inventory))
project = tmp_path / "project.json"
project.write_text(json.dumps({"schema_version": 1, "name": "Portable project", "repositories": [
{"name": "optional-feature", "path": "optional-feature", "aliases": ["campaign"]},
{"name": "absent-optional", "path": "absent-optional", "aliases": ["absent"]}],
"review": {"issue_inventory": "issues.json", "principles": "principles.md"},
"checks": [{"id": "ui-check", "argv": ["never-execute-this"], "repos": ["optional-feature"], "cwd": "optional-feature"}],
"profiles": {"ui": ["ui-check"]}}))
return argparse.Namespace(workspace_root=tmp_path, project=project, state_dir=tmp_path / "state",
module="campaign", bundle_module=None, profile="ui", evidence=None, output=None)
def test_bundle_contains_guidance_links_revision_and_unexecuted_check_plan(args):
result = review.handle_review(args)
assert result["module"] == "optional-feature"
assert result["inventory"]["ui_source_count"] == 5
assert not result["inventory"]["module_code_imported"]
assert result["inventory"]["manifest_paths"] == ["src/optional_feature/backend/manifest.py"]
assert result["principles"]["revision"] == "UI-2026-09-08"
assert [rule["id"] for rule in result["principles"]["rules"]] == ["UI-01", "UI-02"]
assert result["check_plan"]["stages"][0]["argv"] == ["never-execute-this"]
assert not result["check_plan"]["executed"]
assert result["review_completion"].startswith("Not assessed")
assert len(result["manual_checklist"]) >= 9
assert all("checked" not in item for item in result["manual_checklist"])
assert "state_at_verification" not in json.dumps(result)
assert "operation" not in result["issue_links"][0]
assert result["central_issue"]["number"] == 4
assert not args.state_dir.exists()
@pytest.mark.parametrize("name", ["campaign", "campaigns", "optional-feature"])
def test_alias_scope_id_and_repository_resolve_to_same_registered_module(args, name):
args.module = name
assert review.handle_review(args)["module"] == "optional-feature"
def test_bundle_alias_and_direct_cli_work_with_global_options_anywhere(args, capsys):
assert main(["--workspace-root", str(args.workspace_root), "review", "campaign", "--project", str(args.project), "--json"]) == 0
direct = json.loads(capsys.readouterr().out)
assert direct["module"] == "optional-feature"
assert main(["review", "bundle", "campaigns", "--workspace-root", str(args.workspace_root), "--project", str(args.project), "--format", "json"]) == 0
assert json.loads(capsys.readouterr().out)["module"] == direct["module"]
def test_absent_optional_repository_and_no_ui_do_not_complete_review(args):
args.module = "absent"
result = review.handle_review(args)
assert not result["repository"]["exists"]
assert result["repository"]["errors"]
assert result["inventory"]["ui_source_count"] == 0
assert result["check_plan"]["stages"] == []
assert result["review_completion"].startswith("Not assessed")
assert any("not automatic N/A" in warning for warning in result["warnings"])
assert any("not a passing" in warning for warning in result["warnings"])
def test_portable_project_does_not_inherit_govoplan_links_or_principles(args):
payload = json.loads(args.project.read_text())
payload.pop("review")
args.project.write_text(json.dumps(payload))
result = review.handle_review(args)
assert result["issue_links"] == [] and result["central_issue"] is None
assert not result["principles"]["available"]
assert "git.add-ideas.de" not in json.dumps(result)
@pytest.mark.parametrize("kind", ["symlink", "outside", "bad-url", "duplicate-scope", "foreign-repository"])
def test_review_inputs_cannot_escape_or_silently_misbind_scope(args, kind):
if kind in {"symlink", "outside"}:
payload = json.loads(args.project.read_text())
if kind == "symlink":
alias = args.workspace_root / "alias.json"
alias.symlink_to(args.workspace_root / "issues.json")
payload["review"]["issue_inventory"] = "alias.json"
else:
payload["review"]["principles"] = "../outside.md"
args.project.write_text(json.dumps(payload))
else:
path = args.workspace_root / "issues.json"
payload = json.loads(path.read_text())
if kind == "bad-url":
payload["issues"][0]["url"] = "https://gitea.invalid/team/wrong/issues/8"
elif kind == "duplicate-scope":
payload["issues"].append(payload["issues"][0])
else:
payload["issues"][0].update(repository="foreign", url="https://gitea.invalid/team/foreign/issues/8")
args.module = "campaigns"
path.write_text(json.dumps(payload))
with pytest.raises(ValueError):
review.handle_review(args)
def test_source_inventory_never_follows_symlinked_ancestors(args):
root = args.workspace_root / "indirect"
root.mkdir()
(root / "webui").symlink_to(args.workspace_root / "optional-feature/webui", target_is_directory=True)
result = review.source_inventory(root)
assert result["ui_source_count"] == 0
assert result["skipped_symlinks"] == ["webui/src"]
def test_explicit_artifact_is_only_local_and_preserves_issue_discovery_snapshot(args):
inventory = args.workspace_root / "issues.json"
original = inventory.read_bytes()
args.output = args.workspace_root / "artifacts/review.json"
result = review.handle_review(args)
assert json.loads(args.output.read_text()) == result
assert inventory.read_bytes() == original
assert args.output.stat().st_mode & 0o777 == 0o600
assert not args.state_dir.exists()
def test_attached_historical_receipt_stays_separate_from_current_review(args):
path = args.workspace_root / "historical.json"
path.write_text(json.dumps({"schema_version": 1, "run_id": "historical", "workspace_root": str(args.workspace_root),
"project_file": str(args.project), "source_fingerprint": "a" * 64, "status": "passed", "snapshot_verified": True, "generated_at": "2026-09-08",
"finished_at": "2026-09-08", "stages": [{"id": "old-check", "status": "passed", "exit_code": 0, "duration_seconds": 1, "log_path": "/not-read"}]}))
args.evidence = str(path)
result = review.handle_review(args)
assert result["evidence"]["origin"] == "external-unverified"
assert result["evidence"]["source_state"] == "historical-source-differs"
assert result["review_completion"].startswith("Not assessed")
assert not result["check_plan"]["executed"]
def test_unknown_module_and_extra_positionals_are_errors(args):
args.module = "typo"
with pytest.raises(ValueError, match="Unknown repository"):
review.handle_review(args)
args.module, args.bundle_module = "campaign", "extra"
with pytest.raises(ValueError, match="one module"):
review.handle_review(args)
def test_compact_review_exposes_scoped_coverage_limits_without_hiding_full_list(args, monkeypatch):
notes = [f"Separate suite {number} was not included." for number in range(12)]
monkeypatch.setattr("govoplan_devkit.catalog.build_stages", lambda *_args, **_kwargs: [
{"id": "source-only", "argv": ["never-execute"], "coverage_notes": notes}])
result = review.handle_review(args)
assert result["coverage_notes"] == notes
assert sum(line.startswith("Coverage limitation:") for line in result["summary"]) == 8
assert any("4 additional coverage limitations" in line for line in result["summary"])
assert not result["check_plan"]["executed"]