Files
recipes/test_identity_cat.py
gilesb 10c6af3736 feat: initial recipes repo with identity-cat
- Recipe schema using artdag primitives (SOURCE, EFFECT)
- identity-cat: applies identity effect to cat image
- Test verifying identity property: output_hash == input_hash
- Demonstrates content-addressed DAG execution

Owner: @giles@artdag.rose-ash.com

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 23:25:40 +00:00

112 lines
3.0 KiB
Python

#!/usr/bin/env python3
"""
Test the identity-cat recipe.
Verifies that identity(cat) produces the same content hash as cat.
"""
import hashlib
import sys
import tempfile
from pathlib import Path
# Add artdag to path
sys.path.insert(0, str(Path(__file__).parent.parent / "artdag"))
from artdag.dag import DAG, Node, NodeType
from artdag.engine import Engine
from artdag import nodes # Register executors
def file_hash(path: Path) -> str:
"""Compute SHA3-256 hash of a file."""
hasher = hashlib.sha3_256()
# Resolve symlinks to get actual content
actual_path = path.resolve() if path.is_symlink() else path
with open(actual_path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""):
hasher.update(chunk)
return hasher.hexdigest()
def main():
# Cat image location (from registry)
cat_url = "https://rose-ash.com/content/images/2026/01/cat.jpg"
cat_hash = "33268b6e167deaf018cc538de12dbe562612b33e89a749391cef855b320a269b"
# Try to find cat locally
cat_paths = [
Path("/home/giles/Pictures/cat.jpg"),
Path.home() / "Pictures" / "cat.jpg",
]
cat_path = None
for p in cat_paths:
if p.exists():
cat_path = p
break
if not cat_path:
print(f"Cat image not found locally. Download from: {cat_url}")
sys.exit(1)
# Verify input hash
input_hash = file_hash(cat_path)
print(f"Input: {cat_path}")
print(f"Input hash: {input_hash}")
if input_hash != cat_hash:
print(f"WARNING: Input hash doesn't match registry!")
print(f"Expected: {cat_hash}")
# Build the DAG: SOURCE -> EFFECT(identity) -> output
dag = DAG()
# Node 1: SOURCE(cat)
source_node = Node(
node_type=NodeType.SOURCE,
config={"path": str(cat_path)},
inputs=[],
name="source_cat",
)
source_id = dag.add_node(source_node)
# Node 2: EFFECT(identity)
effect_node = Node(
node_type="EFFECT",
config={"effect": "identity"},
inputs=[source_id],
name="apply_identity",
)
effect_id = dag.add_node(effect_node)
dag.set_output(effect_id)
# Execute
with tempfile.TemporaryDirectory() as cache_dir:
engine = Engine(cache_dir)
result = engine.execute(dag)
if not result.success:
print(f"FAILED: {result.error}")
sys.exit(1)
# Verify output hash
output_hash = file_hash(result.output_path)
print(f"\nOutput: {result.output_path}")
print(f"Output hash: {output_hash}")
# The identity property: output hash == input hash
if output_hash == input_hash:
print("\n✓ PASS: identity(cat) == cat")
print(" Output hash equals input hash - identity property verified!")
else:
print("\n✗ FAIL: identity(cat) != cat")
print(f" Expected: {input_hash}")
print(f" Got: {output_hash}")
sys.exit(1)
if __name__ == "__main__":
main()