Files
relayview-skills/tests/test_packages.py
T
adminandClaude Opus 5.5 28c221cdd2 Guide Designer prototypes to hand over the user's own commands
The Human answers a prototype's design question by using it as the
software's user will, so the prototype method now has the Designer prepare
the scenario itself and give the Human the real command, syntax and
directory a user would use, with any reset command offered for that
purpose alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 22:54:14 -05:00

189 lines
10 KiB
Python

import json
import hashlib
import shutil
import tempfile
import unittest
import zipfile
from pathlib import Path
from tools.packages import PackageError, check_package, package_archive
ROOT = Path(__file__).resolve().parents[1]
class PackageTests(unittest.TestCase):
def test_designer_release_modes_and_source(self):
automatic = "issue-designer-default"
manual = (
"designer-wayfinder", "designer-grilling", "designer-prototype",
"designer-research", "designer-domain-modeling", "designer-triage",
"designer-to-spec", "designer-to-tickets",
)
for name in (automatic, *manual):
with self.subTest(name=name):
package = ROOT / "packages" / name
skill = (package / "SKILL.md").read_text()
frontmatter = skill.split("---", 2)[1]
self.assertEqual("disable-model-invocation: true" in frontmatter, name in manual)
version = {automatic: "0.6.1", "designer-prototype": "0.6.2"}.get(name, "0.6.0")
self.assertIn(f"relayview-version: {version}", frontmatter)
manifest = json.loads((package / "relayview-skill.json").read_text())
self.assertEqual(manifest["source"], {"kind": "first-party", "reference": f"v{version}"})
check_package(package)
def test_tdd_is_available_to_owner_started_implementers(self):
package = ROOT / "packages/tdd-auto"
skill = (package / "SKILL.md").read_text()
frontmatter = skill.split("---", 2)[1]
self.assertIn("name: tdd-auto", frontmatter)
self.assertNotIn("disable-model-invocation: true", frontmatter)
self.assertIn("relayview-version: 0.3.1", frontmatter)
manifest = json.loads((package / "relayview-skill.json").read_text())
self.assertEqual(manifest["source"], {"kind": "first-party", "reference": "v0.3.1"})
check_package(package)
self.assertIn("disable-model-invocation: true", (ROOT / "packages/tdd/SKILL.md").read_text())
def test_migrated_role_guidance_has_one_declared_role_step(self):
expected = {"codebase-design": ("planner", "planning"), "grill-me": ("planner", "planning"),
"grilling": ("planner", "planning"), "to-questionnaire": ("planner", "planning"),
"diagnosing-bugs": ("implementer", "implementation"),
"domain-modeling": ("implementer", "implementation"),
"migrate-to-shoehorn": ("implementer", "implementation"),
"pr": ("implementer", "implementation"), "prototype": ("implementer", "implementation"),
"scaffold-exercises": ("implementer", "implementation"),
"shared-abstraction-refactor": ("implementer", "implementation"),
"split-large-files": ("implementer", "implementation"),
"tdd": ("implementer", "implementation"),
"writing-for-agents": ("implementer", "implementation"),
"code-review": ("reviewer", "review"),
"c4-diff": ("reviewer", "review"),
"research": ("planner", "planning"),
"improve-codebase-architecture": ("planner", "planning"),
**{name: ("designer", "design") for name in (
"issue-designer-default", "designer-wayfinder", "designer-grilling", "designer-prototype",
"designer-research", "designer-domain-modeling", "designer-triage",
"designer-to-spec", "designer-to-tickets")}}
for name, role_step in expected.items():
with self.subTest(name=name):
package = ROOT / "packages" / name
manifest = json.loads((package / "relayview-skill.json").read_text())
self.assertEqual((manifest["role"], manifest["step"]), role_step)
check_package(package)
def test_release_package_and_starter_are_valid(self):
for path in sorted((ROOT / "packages").iterdir()) + [ROOT / "examples/starter-planner"]:
check_package(path)
with tempfile.TemporaryDirectory() as directory:
first = package_archive(path, Path(directory) / "one.zip")
second = package_archive(path, Path(directory) / "two.zip")
self.assertEqual(first, second)
def test_maintained_guidance_covers_distinct_role_steps(self):
expected = {
"planner-scope": ("planner", "planning", "scope.md", "Plan"),
"implementer-handoff": ("implementer", "implementation", "handoff.md", "documentation"),
}
for name, (role, step, resource, marker) in expected.items():
with self.subTest(name=name):
package = ROOT / "packages" / name
manifest = json.loads((package / "relayview-skill.json").read_text())
self.assertEqual((manifest["role"], manifest["step"]), (role, step))
self.assertEqual(manifest["source"], {"kind": "first-party", "reference": "v0.2.0"})
self.assertIn(resource, [item["path"] for item in manifest["files"]])
self.assertIn(marker, (package / "SKILL.md").read_text() + (package / resource).read_text())
def test_user_fork_is_distinct_under_same_role_limits(self):
with tempfile.TemporaryDirectory() as directory:
package = Path(directory) / "implementer-handoff"
shutil.copytree(ROOT / "packages/implementer-handoff", package)
original = check_package(package)
resource = package / "handoff.md"
resource.write_text(resource.read_text() + "\n- Prefer the team's concise PR summary format.\n")
manifest_path = package / "relayview-skill.json"
manifest = json.loads(manifest_path.read_text())
manifest["source"] = {"kind": "user", "reference": "team-fork-1"}
next(item for item in manifest["files"] if item["path"] == "handoff.md")["sha256"] = hashlib.sha256(resource.read_bytes()).hexdigest()
manifest_path.write_text(json.dumps(manifest))
self.assertNotEqual(check_package(package), original)
self.assertEqual((manifest["role"], manifest["step"]), ("implementer", "implementation"))
def test_rejects_scripts_and_undeclared_files(self):
with tempfile.TemporaryDirectory() as directory:
package = Path(directory) / "planner-scope"
shutil.copytree(ROOT / "packages/planner-scope", package)
(package / "helper.py").write_text("print('unsafe')\n")
with self.assertRaises(PackageError):
check_package(package)
def test_rejects_permission_expansion(self):
with tempfile.TemporaryDirectory() as directory:
package = Path(directory) / "planner-scope"
shutil.copytree(ROOT / "packages/planner-scope", package)
manifest = package / "relayview-skill.json"
data = json.loads(manifest.read_text())
data["tools"] = ["shell"]
manifest.write_text(json.dumps(data))
with self.assertRaises(PackageError):
check_package(package)
def test_rejects_role_mismatch(self):
with tempfile.TemporaryDirectory() as directory:
package = Path(directory) / "planner-scope"
shutil.copytree(ROOT / "packages/planner-scope", package)
manifest = package / "relayview-skill.json"
data = json.loads(manifest.read_text())
data["role"] = "reviewer"
manifest.write_text(json.dumps(data))
with self.assertRaises(PackageError):
check_package(package)
def test_rejects_changed_resource(self):
with tempfile.TemporaryDirectory() as directory:
package = Path(directory) / "planner-scope"
shutil.copytree(ROOT / "packages/planner-scope", package)
(package / "scope.md").write_text("changed\n")
with self.assertRaises(PackageError):
check_package(package)
def test_rejects_frontmatter_permission_request(self):
with tempfile.TemporaryDirectory() as directory:
package = Path(directory) / "planner-scope"
shutil.copytree(ROOT / "packages/planner-scope", package)
skill = package / "SKILL.md"
skill.write_text(skill.read_text().replace("metadata:\n", "tools: [shell]\nmetadata:\n"))
manifest = package / "relayview-skill.json"
data = json.loads(manifest.read_text())
next(item for item in data["files"] if item["path"] == "SKILL.md")["sha256"] = hashlib.sha256(skill.read_bytes()).hexdigest()
manifest.write_text(json.dumps(data))
with self.assertRaises(PackageError):
check_package(package)
def test_rejects_owner_incompatible_frontmatter_values(self):
for old, new in (
("metadata:\n", "disable-model-invocation: yes\nmetadata:\n"),
("description: Check assigned issue scope, neighboring work, and verification before drafting a Plan.", "description: "),
):
with self.subTest(new=new), tempfile.TemporaryDirectory() as directory:
package = Path(directory) / "planner-scope"
shutil.copytree(ROOT / "packages/planner-scope", package)
skill = package / "SKILL.md"
skill.write_text(skill.read_text().replace(old, new))
manifest = package / "relayview-skill.json"
data = json.loads(manifest.read_text())
next(item for item in data["files"] if item["path"] == "SKILL.md")["sha256"] = hashlib.sha256(skill.read_bytes()).hexdigest()
manifest.write_text(json.dumps(data))
with self.assertRaises(PackageError):
check_package(package)
def test_archive_carries_license_and_notice(self):
with tempfile.TemporaryDirectory() as directory:
archive_path = Path(directory) / "planner-scope.zip"
package_archive(ROOT / "packages/planner-scope", archive_path)
with zipfile.ZipFile(archive_path) as archive:
self.assertEqual(archive.read("LICENSE"), (ROOT / "LICENSE").read_bytes())
self.assertEqual(archive.read("NOTICE.md"), (ROOT / "NOTICE.md").read_bytes())
if __name__ == "__main__":
unittest.main()