"""Tests for HDK bug fixes (Task 1 verification).""" def test_hash_separator_prevents_collision(): """Hash with parents must use || separator to prevent collisions.""" from hdk.core.hash_engine import HashEngine e = HashEngine() h1 = e.hash_with_parents("abc", ["def", "ghi"]) h2 = e.hash_with_parents("abcdef", ["ghi"]) assert h1 != h2, "Different inputs must produce different hashes" def test_hash_separator_present(): """Hash computation must use || separator, not concatenation.""" from hdk.core.hash_engine import HashEngine import hashlib e = HashEngine() result = e.hash_with_parents("a", ["b", "c"]) # Expected: sha256("a||b||c") expected_combined = "a||b||c" expected = hashlib.sha256(expected_combined.encode()).hexdigest() assert result == expected def test_actor_fields_in_node(): """HDKNode must support actor fields: user_id_token, llm_model, llm_provider, agent_name.""" from hdk.models import HDKNode, NodeLevel, EventType from datetime import datetime, timezone node = HDKNode( id="test", level=NodeLevel.EVENT, timestamp=datetime.now(timezone.utc), content_hash="hash", parent_chain=[], self_hash="self", node_hash="node", event_type=EventType.LLM_RESPONSE, user_id_token="u-123", llm_model="gemini-2.0-flash", llm_provider="google", agent_name="write_spin", ) assert node.user_id_token == "u-123" assert node.llm_model == "gemini-2.0-flash" assert node.llm_provider == "google" assert node.agent_name == "write_spin" def test_actor_fields_in_hash(): """Actor fields must be included in node hash computation.""" from hdk.core.hash_engine import HashEngine from hdk.models import HDKNode, NodeLevel, EventType from datetime import datetime, timezone e = HashEngine() base_node = HDKNode( id="test", level=NodeLevel.EVENT, timestamp=datetime.now(timezone.utc), content_hash="content_hash", parent_chain=[], self_hash="self", node_hash="", event_type=EventType.LLM_RESPONSE, ) node_with_model = HDKNode( id="test", level=NodeLevel.EVENT, timestamp=base_node.timestamp, content_hash="content_hash", parent_chain=[], self_hash="self", node_hash="", event_type=EventType.LLM_RESPONSE, llm_model="gemini-2.0-flash", ) h1 = e.create_node_hash(base_node) h2 = e.create_node_hash(node_with_model) assert h1 != h2, "Different actor fields must produce different hashes" def test_canary_counter_advances(): """Canary read counter must advance with each authorized_read.""" from hdk.core.dag import DAGStorage from hdk.core.canary import CanaryLayer dag = DAGStorage(":memory:") canary = CanaryLayer(dag, key=bytes(range(32))) canary.initialize() c1 = canary.authorized_read() c2 = canary.authorized_read() assert canary.get_read_counter() == 2 assert c1 != c2 def test_anchor_backward_compat_fields(): """Anchor payload must include hash, version, timestamp for backward compat.""" from hdk.core.dag import DAGStorage from hdk.core.canary import CanaryLayer from hdk.hedera.anchor import OfflineAnchorService from hdk.config import HederaConfig dag = DAGStorage(":memory:") canary = CanaryLayer(dag, key=bytes(range(32))) canary.initialize() config = HederaConfig(anchor_interval=1) service = OfflineAnchorService(dag, canary, config) from hdk.models import HCSAnchor from datetime import datetime, timezone import json as _json anchor = HCSAnchor( anchor_sequence=0, merkle_root="abc123", node_count=5, timestamp=datetime.now(timezone.utc), canary_checkpoint=_json.dumps({"commitment": "commit", "generation": 42}), prev_anchor_hash="", ) payload = service.build_anchor_payload(anchor) assert "hash" in payload assert payload["hash"] == anchor.merkle_root assert "version" in payload assert "timestamp" in payload def test_new_event_types_exist(): """All new EventType values must exist.""" from hdk.models import EventType expected = [ "GRADE", "SYSTEM", "EDITOR_TYPE", "EDITOR_PASTE", "EDITOR_AI_INSERT", "EDITOR_DROP", "EDITOR_DELETE", "EDITOR_UNDO", "EDITOR_SNAPSHOT", "CERTIFICATE_INVALIDATED", "AGENT_STEP", ] for name in expected: assert hasattr(EventType, name), f"EventType.{name} missing"