feat: release Dever 0.1.4 with enforceable project guidance

This commit is contained in:
Antigravity committed 2026-10-09 05:33:57 +00:00
1 parent 201bdee372
commit 89629c2197
86 files changed
+2798 -338

No files matched your search

+76
View File
@@ -5,6 +5,7 @@ import contextlib
import io
import json
from pathlib import Path
import shutil
import sys
import tempfile
import unittest
@@ -177,6 +178,81 @@ class GateTests(unittest.TestCase):
(root / "Cargo.lock").write_text("changed immutable input")
self.assertNotEqual(author_before, gate.input_fingerprint({}, config, "author"))
def test_skill_sources_invalidate_evidence_but_generated_caches_do_not(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
for name in ("Cargo.toml", "Cargo.lock"):
(root / name).write_text(name)
sources = ("skills/assets/template/AGENTS.md", "skills/references/development.md",
"skills/assets/examples/jobs/module/report/archive/app.dever")
for name in sources:
path = root / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("original")
original = gate.source_fingerprint(root)
for name in sources:
path = root / name
with self.subTest(source=name):
path.write_text("changed")
self.assertNotEqual(original, gate.source_fingerprint(root))
path.unlink()
self.assertNotEqual(original, gate.source_fingerprint(root))
path.write_text("original")
self.assertEqual(original, gate.source_fingerprint(root))
for cache in ("__pycache__", "target", ".git"):
path = root / "skills/assets/examples/jobs" / cache / "generated"
path.parent.mkdir()
path.write_text("generated bytes")
self.assertEqual(original, gate.source_fingerprint(root))
path.write_text("changed generated bytes")
self.assertEqual(original, gate.source_fingerprint(root))
path.unlink()
self.assertEqual(original, gate.source_fingerprint(root))
def test_python_plan_runs_real_skill_checks_and_rejects_each_failure(self):
config = {"tools": {"cargo": sys.executable, "python": sys.executable}}
commands = gate.command_plan("python", config)
skill_commands = [command for command in commands if "test/skill_examples.py" in command]
self.assertEqual(len(skill_commands), 1)
command = skill_commands[0]
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
(root / "test").mkdir()
shutil.copyfile(gate.ROOT / "test/skill_examples.py", root / "test/skill_examples.py")
for name in ("skills", "library"):
shutil.copytree(gate.ROOT / name, root / name)
logs = root / "logs"
logs.mkdir()
with patch.object(gate, "ROOT", root):
record, content = gate.run_command(command, logs, 0, 10)
gate.check_output("python", record, content)
test_count = record["python_tests"]
self.assertGreater(test_count, 0)
for number, (relative, broken, case) in enumerate((
("skills/SKILL.md", "[broken](missing.md)",
"test_relocated_skill_links_and_release_file_limits"),
("skills/references/signatures.md", "```signatures\ndever.io.missing() ()\n```\n",
"test_signature_index_matches_public_library_declarations"),
("skills/references/language.md",
(root / "skills/references/language.md").read_text().replace(
'"Hello, "', '"Incorrect tutorial, "', 1
),
"test_tutorial_code_matches_relocated_checked_sources"),
), 1):
path = root / relative
original = path.read_bytes()
path.write_text(broken)
with self.subTest(check=case), self.assertRaisesRegex(RuntimeError, "command exited 1"):
gate.run_command(command, logs, number, 10)
result = json.loads((logs / f"{number:03d}.command.json").read_text())
self.assertEqual(result["exit_code"], 1)
self.assertEqual(result["python_tests"], test_count)
log = (logs / f"{number:03d}.log").read_text()
self.assertTrue(
f"FAIL: {case}" in log or f"ERROR: {case}" in log, log
)
path.write_bytes(original)
def test_cleanup_cannot_delete_author_binary(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)