Index: tests/conftest.py
===================================================================
--- tests/conftest.py	(revision 6a7dec1b7c47ac7a8618ebec0981ce40dbc3224d)
+++ tests/conftest.py	(revision 02d288d33183db0124582a151433ccd6cf55cac7)
@@ -5,43 +5,59 @@
 from flexoentity import FlexoEntity, EntityType, EntityState, Domain
 
+import pytest
+import json
+from flexoentity import EntityType, EntityState, Domain
+from builder.questions import RadioQuestion, AnswerOption  # adjust path if different
+from builder.media_items import NullMediaItem  # adjust import if needed
 
-class DummyEntity(FlexoEntity):
-    """Minimal concrete subclass for testing FlexoEntity logic."""
 
-    def __init__(self, domain, etype, state, seed="DUMMY"):
-        self._seed = seed
-        super().__init__(domain, etype, state)
+@pytest.fixture(scope="session")
+def domain():
+    """Provide a reusable domain for all entity tests."""
+    return Domain(
+        domain="SIG",
+        etype=EntityType.DOMAIN,
+        state=EntityState.DRAFT,
+        fullname="Signal Corps",
+        description="Questions related to communications and signaling systems.",
+        classification="RESTRICTED",
+        owner="test-suite"
+    )
 
-    @property
-    def text_seed(self) -> str:
-        return self._seed 
 
-    @classmethod
-    def from_dict(cls, data):
-        """Ensure enums and seed are reconstructed correctly."""
-        domain = data["domain"]
-        etype = EntityType[data["etype"]] if isinstance(data["etype"], str) else data["etype"]
-        state = EntityState[data["state"]] if isinstance(data["state"], str) else data["state"]
-        seed = data.get("text_seed", "DUMMY-CONTENT")
-        return cls(domain=domain, etype=etype, state=state, seed=seed)
+@pytest.fixture
+def radio_question(domain):
+    """Return a simple RadioQuestion entity for testing FlexoEntity logic."""
+    q = RadioQuestion(
+        domain=domain,
+        etype=EntityType.QUESTION,
+        state=EntityState.DRAFT,
+        text="Which frequency band is used for shortwave communication?",
+        options=[
+            AnswerOption(id="opt1", text="HF (3–30 MHz)", points=1),
+            AnswerOption(id="opt2", text="VHF (30–300 MHz)", points=0),
+            AnswerOption(id="opt3", text="UHF (300–3000 MHz)", points=0),
+        ]
+    )
+    return q
 
-    @classmethod
-    def from_json(cls, data_str: str):
-        return cls.from_dict(json.loads(data_str))
-    
+
 @pytest.fixture
-def entity():
-    """Generic FlexoEntity-like instance in draft state."""
-    return DummyEntity(
-        domain=Domain(domain="SIG", etype=EntityType.DOMAIN, state=EntityState.DRAFT, fullname="Signal Corps", classification="RESTRICTED"),
-        etype=EntityType.CATALOG,
-        state=EntityState.DRAFT,
-    )
+def serialized_question(radio_question):
+    """Provide the serialized JSON form for roundtrip tests."""
+    return radio_question.to_json()
+
+
+@pytest.fixture
+def deserialized_question(serialized_question):
+    """Recreate a question from JSON for consistency tests."""
+    return RadioQuestion.from_json(serialized_question)
+
 
 @pytest.fixture
 def null_media():
-    """Provide a default NullMediaItem instance for tests."""
+    """Provide a default NullMediaItem instance for media tests."""
     return NullMediaItem(
-        domain="GEN",
+        domain=domain,
         etype=EntityType.MEDIA,
         state=EntityState.DRAFT
Index: tests/test_id_lifecycle.py
===================================================================
--- tests/test_id_lifecycle.py	(revision 6a7dec1b7c47ac7a8618ebec0981ce40dbc3224d)
+++ tests/test_id_lifecycle.py	(revision 02d288d33183db0124582a151433ccd6cf55cac7)
@@ -1,89 +1,103 @@
 import pytest
-
-from flexoentity import FlexOID, FlexoEntity, EntityType, EntityState 
-
-def test_initial_state(entity):
-    assert entity.state == EntityState.DRAFT
-    assert entity.flexo_id.version == 1
-    assert len(entity.flexo_id.signature) == 16  # blake2s digest_size=8 → 16 hex
-    assert FlexoEntity.verify_integrity(entity)
+from flexoentity import FlexOID, FlexoEntity, EntityType, EntityState
 
 
-def test_approval_bumps_version(entity):
-    entity.approve()
-    assert entity.state == EntityState.APPROVED
-    assert entity.flexo_id.version == 2
+# ──────────────────────────────────────────────────────────────────────────────
+# Tests adapted to use real RadioQuestion fixture instead of DummyEntity
+# ──────────────────────────────────────────────────────────────────────────────
+
+def test_initial_state(radio_question):
+    q = radio_question
+    assert q.state == EntityState.DRAFT
+    assert q.flexo_id.version == 1
+    assert FlexoEntity.verify_integrity(q)
 
 
-def test_signing_bumps_version(entity):
-    entity.approve()
-    v_before = entity.flexo_id
-    entity.sign()
-    assert entity.state == EntityState.APPROVED_AND_SIGNED
-    assert entity.flexo_id != v_before
+def test_approval_bumps_version(radio_question):
+    q = radio_question
+    q.approve()
+    assert q.state == EntityState.APPROVED
+    assert q.flexo_id.version == 2
 
 
-def test_publish_bumps_version(entity):
-    entity.approve()
-    entity.sign()
-    v_before = entity.flexo_id.version
-    entity.publish()
-    assert entity.state == EntityState.PUBLISHED
-    assert entity.flexo_id.version == v_before + 1
+def test_signing_bumps_version(radio_question):
+    q = radio_question
+    q.approve()
+    v_before = str(q.flexo_id)
+    q.sign()
+    assert q.state == EntityState.APPROVED_AND_SIGNED
+    assert str(q.flexo_id) != v_before
 
 
-def test_modify_content_changes_fingerprint(entity):
-    old_signature = entity.flexo_id.signature
-    entity._seed = "Rephrased content"  # simulate text change
-    entity._update_fingerprint()
-    assert entity.flexo_id.signature != old_signature
+def test_publish_bumps_version(radio_question):
+    q = radio_question
+    q.approve()
+    q.sign()
+    v_before = q.flexo_id.version
+    q.publish()
+    assert q.state == EntityState.PUBLISHED
+    assert q.flexo_id.version == v_before + 1
 
 
-def test_no_version_bump_on_draft_edits(entity):
-    entity._seed = "Draft edit only"
-    entity._update_fingerprint()
-    assert entity.flexo_id.version == 1
+def test_modify_content_changes_fingerprint(radio_question):
+    q = radio_question
+    q.text = "Rephrased content"  # simulate text change
+    changed = q._update_fingerprint()
+    assert changed
 
 
-def test_version_bump_after_edit_and_sign(entity):
-    entity.approve()
-    v1 = entity.flexo_id
-    entity._seed = "Changed content"
-    entity.sign()
-    assert entity.flexo_id != v1
+def test_no_version_bump_on_draft_edits(radio_question):
+    q = radio_question
+    q.text = "Minor draft edit"
+    q._update_fingerprint()
+    assert q.flexo_id.version == 1
 
 
-def test_integrity_check_passes_and_fails(entity):
-    entity.approve()
-    assert FlexoEntity.verify_integrity(entity)
-    # simulate tampering
-    entity._seed = "Tampered text"
-    assert not FlexoEntity.verify_integrity(entity)
+def test_version_bump_after_edit_and_sign(radio_question):
+    q = radio_question
+    q.approve()
+    v1 = str(q.flexo_id)
+    q.text = "Changed content"
+    q.sign()
+    assert str(q.flexo_id) != v1
 
 
-def test_obsolete_state(entity):
-    entity.approve()
-    entity.sign()
-    entity.publish()
-    entity.obsolete()
-    assert entity.state == EntityState.OBSOLETE
+def test_integrity_check_passes_and_fails(radio_question):
+    q = radio_question
+    q.approve()
+    assert FlexoEntity.verify_integrity(q)
+
+    # simulate tampering
+    q.text = "Tampered text"
+    assert not FlexoEntity.verify_integrity(q)
 
 
-def test_clone_new_base_resets_lineage(entity):
-    entity.approve()
-    entity.sign()
-    entity.publish()
-    entity.obsolete()
-    old_id = entity.flexo_id
-    entity.clone_new_base()
-    assert entity.flexo_id != old_id
-    assert entity.state == EntityState.DRAFT
-    assert entity.flexo_id.version == 1
+def test_obsolete_state(radio_question):
+    q = radio_question
+    q.approve()
+    q.sign()
+    q.publish()
+    q.obsolete()
+    assert q.state == EntityState.OBSOLETE
 
 
-def test_mass_version_increments_until_obsolete(entity):
-    entity.approve()
+def test_clone_new_base_resets_lineage(radio_question):
+    q = radio_question
+    q.approve()
+    q.sign()
+    q.publish()
+    q.obsolete()
+    old_id = str(q.flexo_id)
+    q.clone_new_base()
+    assert str(q.flexo_id) != old_id
+    assert q.state == EntityState.DRAFT
+    assert q.flexo_id.version == 1
+
+
+def test_mass_version_increments_until_obsolete(radio_question):
+    q = radio_question
+    q.approve()
     for _ in range(FlexOID.MAX_VERSION - 2):
-        entity.sign()
+        q.sign()
     with pytest.raises(RuntimeError, match="mark obsolete"):
-        entity.sign()
+        q.sign()
Index: tests/test_id_stress.py
===================================================================
--- tests/test_id_stress.py	(revision 6a7dec1b7c47ac7a8618ebec0981ce40dbc3224d)
+++ tests/test_id_stress.py	(revision 02d288d33183db0124582a151433ccd6cf55cac7)
@@ -3,87 +3,123 @@
 Focus: collision avoidance, version ceiling, reproducibility.
 """
+
 import pytest
 import random
+import logging
+from flexoentity import FlexOID, EntityType, EntityState
+from builder.questions import RadioQuestion, AnswerOption
 
-from flexoentity import FlexOID, EntityType, EntityState, Domain
+logger = logging.getLogger(__name__)
 
-from tests.conftest import DummyEntity
-
-# ──────────────────────────────────────────────────────────────────────────────
-def test_bulk_generation_uniqueness():
-    """Generate 10,000 IDs and assert uniqueness (statistical test)."""
-    domain = Domain(domain="SIG", etype=EntityType.DOMAIN, state=EntityState.DRAFT,
-                    fullname="Signal Corps", classification="RESTRICTED", owner="MESE")
-
+def test_bulk_generation_uniqueness(domain):
+    """
+    Generate 10,000 IDs and ensure uniqueness using safe_generate().
+    If a collision occurs, safe_generate() must resolve it automatically
+    via salt + date adjustment.
+    """
     etype = EntityType.QUESTION
     estate = EntityState.DRAFT
-    seeds = [f"question {i}" for i in range(10_000)]
+    seeds = [f"question {i}" for i in range(4000000)]
 
-    ids = [FlexOID.generate(domain, etype, estate, seed) for seed in seeds]
+    # Simulate a simple in-memory repository for collision detection
+    repo = {}
 
-    assert len(ids) == len(set(ids)), "ID collisions detected in bulk generation"
+    def repo_get(oid_str):
+        return repo.get(str(oid_str))
 
+    # Generate IDs using safe_generate
+    ids = []
+    for seed in seeds:
+        oid = FlexOID.safe_generate(domain.domain, etype, estate, seed, repo=repo)
+        assert isinstance(oid, FlexOID)
+        ids.append(str(oid))
+        repo[str(oid)] = oid  # register for future collision detection
 
-def test_disambiguator_trigger():
+    unique_count = len(set(ids))
+    total_count = len(ids)
+    collisions = total_count - unique_count
+
+    logger.info(f"Generated {total_count} IDs ({collisions} collisions handled).")
+
+    # Assert that safe_generate avoided duplicates
+    assert total_count == unique_count, f"Unexpected duplicate IDs ({collisions} found)"
+
+    # Sanity check: IDs should look canonical
+    assert all(id_str.startswith("SIG-") for id_str in ids)
+    assert all("@" in id_str for id_str in ids)
+
+def test_id_generation_is_deterministic(domain):
     """
     Generating the same entity twice with same inputs yields identical ID.
     (No runtime disambiguation; IDs are deterministic by design.)
     """
-    domain = "AF"
     etype = EntityType.QUESTION
     estate = EntityState.DRAFT
     text = "identical question text"
-    id1 = FlexOID.generate(domain, etype, estate, text)
-    id2 = FlexOID.generate(domain, etype, estate, text)
-    # IDs must be identical, because we now enforce determinism, not randomization
+
+    id1 = FlexOID.generate(domain.domain, etype, estate, text)
+    id2 = FlexOID.generate(domain.domain, etype, estate, text)
+    # IDs must be identical because generation is deterministic
     assert id1 == id2
-    assert id1.signature == id2.signature
 
 
-def test_id_reproducibility_across_runs():
+def test_id_reproducibility_across_runs(domain):
     """
     The same seed on a new process (fresh _seen_hashes)
     should yield the same base ID (without suffix).
     """
-    domain = Domain(domain="SIG", etype=EntityType.DOMAIN, state=EntityState.DRAFT,
-                    fullname="Signal Corps", classification="RESTRICTED")
     etype = EntityType.CATALOG
     estate = EntityState.DRAFT
     seed = "reproducibility test seed"
-    id1 = FlexOID.generate(domain, etype, estate, seed)
-    # Reset hash cache
+
+    id1 = FlexOID.generate(domain.domain, etype, estate, seed)
     FlexOID._seen_hashes.clear()
-    id2 = FlexOID.generate(domain, etype, estate, seed)
+    id2 = FlexOID.generate(domain.domain, etype, estate, seed)
+
     assert id1 == id2
-    assert id1.signature == id2.signature
 
 
-def test_version_ceiling_enforcement():
+def test_version_ceiling_enforcement(radio_question):
     """Simulate approaching @999 to trigger obsolescence guard."""
-    entity = DummyEntity(domain="AF", etype=EntityType.EXAM, state=EntityState.DRAFT, seed="Final Exam 2025")
-    entity.approve()
+    q = radio_question
+    q.approve()
+
     # artificially bump version number to near ceiling
-    entity.flexo_id = FlexOID.from_oid_and_version(entity.flexo_id, 998)
+    q.flexo_id = FlexOID.from_oid_and_version(q.flexo_id, 998)
 
     # 998 → 999 is allowed
-    entity.sign()
-    assert entity.flexo_id.version == 999
+    q.sign()
+    assert q.flexo_id.version == 999
 
     # 999 → 1000 should raise RuntimeError
     with pytest.raises(RuntimeError):
-        entity.sign()
+        q.sign()
 
 
-def test_massive_lifecycle_simulation():
+def test_massive_lifecycle_simulation(domain):
     """
-    Generate 100 random entities, simulate multiple edits and state transitions,
+    Generate 100 random RadioQuestions, simulate multiple edits and state transitions,
     ensure all final IDs and fingerprints are unique and valid.
     """
-    entities = [DummyEntity(domain="AF", etype=EntityType.QUESTION, state=EntityState.DRAFT, seed=f"random question {i}") for i in range(100)]
+    entities = [
+        RadioQuestion(
+            domain=domain,
+            etype=EntityType.QUESTION,
+            state=EntityState.DRAFT,
+            text=f"random question {i}",
+            options=[
+                AnswerOption(id="opt4", text="HF (3–30 MHz)", points=1),
+                AnswerOption(id="opt5", text="VHF (30–300 MHz)", points=0),
+            ],
+        )
+        for i in range(100)
+    ]
 
     for e in entities:
-        # random edit, approval, signing
-        e._seed += " updated"
+        # random edit
+        e.text += " updated"
         e._update_fingerprint()
+
+        # lifecycle transitions
         e.approve()
         if random.random() > 0.3:
@@ -92,6 +128,4 @@
             e.publish()
 
-    ids = [e.flexo_id for e in entities]
-    fps = [e.flexo_id.signature for e in entities]
-    assert len(ids) == len(set(ids)), "Duplicate IDs after random lifecycle"
-    assert len(fps) == len(set(fps)), "Duplicate fingerprints after random lifecycle"
+    flexoids = [e.flexo_id for e in entities]
+    assert len(flexoids) == len(set(flexoids)), "Duplicate FlexOIDs after lifecycle simulation"
Index: tests/test_persistance_integrity.py
===================================================================
--- tests/test_persistance_integrity.py	(revision 6a7dec1b7c47ac7a8618ebec0981ce40dbc3224d)
+++ tests/test_persistance_integrity.py	(revision 02d288d33183db0124582a151433ccd6cf55cac7)
@@ -6,52 +6,58 @@
 import pytest
 
-from flexoentity import FlexOID, EntityType, EntityState
-from tests.conftest import DummyEntity
+from flexoentity import EntityState
+from builder.questions import RadioQuestion, AnswerOption
 
 
 # ──────────────────────────────────────────────────────────────────────────────
 @pytest.fixture
-def approved_entity():
-    """A fully published dummy entity for persistence tests."""
-    e = DummyEntity(
-        domain="AF",
-        etype=EntityType.QUESTION,
+def approved_question(domain):
+    """Provide a fully approved and published RadioQuestion for persistence tests."""
+    q = RadioQuestion(
+        domain=domain,
+        etype=None,  # RadioQuestion sets this internally to EntityType.QUESTION
         state=EntityState.DRAFT,
-        seed="What is Ohm’s law?"
+        text="What is Ohm’s law?",
+        options=[
+            AnswerOption(text="U = R × I", points=1),
+            AnswerOption(text="U = I / R", points=0),
+            AnswerOption(text="R = U × I", points=0),
+        ],
     )
-    e.approve()
-    e.sign()
-    e.publish()
-    return e
+    q.approve()
+    q.sign()
+    q.publish()
+    return q
 
-@pytest.mark.skip(reason="FlexOIDs are regenerated on import; enable once JSON format is stable")
-def test_json_roundtrip_preserves_integrity(approved_entity):
+
+@pytest.mark.skip(reason="FlexOIDs regenerated on import; enable once JSON format is stable")
+def test_json_roundtrip_preserves_integrity(approved_question):
     """
-    Export to JSON and reload — ensure fingerprints remain valid.
+    Export to JSON and reload — ensure fingerprints and signatures remain valid.
     """
-    json_str = approved_entity.to_json()
-    loaded = approved_entity.__class__.from_json(json_str)
+    json_str = approved_question.to_json()
+    loaded = RadioQuestion.from_json(json_str)
 
     # Fingerprint and state should match — integrity must pass
-    assert approved_entity.__class__.verify_integrity(loaded)
+    assert RadioQuestion.verify_integrity(loaded)
 
     # Metadata should be preserved exactly
-    assert approved_entity.flexo_id.signature == loaded.flexo_id.signature
-    assert approved_entity.flexo_id == loaded.flexo_id
-    assert loaded.state == approved_entity.state
+    assert approved_question.signature == loaded.signature
+    assert approved_question.flexo_id == loaded.flexo_id
+    assert loaded.state == approved_question.state
+
 
 # ──────────────────────────────────────────────────────────────────────────────
 
-@pytest.mark.skip(reason="FlexOIDs regenerated on import; tampering detection not applicable yet")
-def test_json_tampering_detection(approved_entity):
+@pytest.mark.skip(reason="FlexOIDs regenerated on import; tampering detection not yet implemented")
+def test_json_tampering_detection(approved_question):
     """Tampering with content should invalidate fingerprint verification."""
-    json_str = approved_entity.to_json()
-    tampered_data = json.loads(json_str)
-    tampered_data["text_seed"] = "Tampered content injection"
-    tampered_json = json.dumps(tampered_data)
+    json_str = approved_question.to_json()
+    tampered = json.loads(json_str)
+    tampered["text"] = "Tampered content injection"
+    tampered_json = json.dumps(tampered)
 
-    # We use DummyEntity.from_json to reconstruct (FlexoEntity is abstract)
-    loaded = approved_entity.__class__.from_json(tampered_json)
-    assert not approved_entity.__class__.verify_integrity(loaded)
+    loaded = RadioQuestion.from_json(tampered_json)
+    assert not RadioQuestion.verify_integrity(loaded)
 
 
@@ -59,14 +65,14 @@
 
 @pytest.mark.skip(reason="FlexOIDs regenerated on import; corruption detection not yet applicable")
-def test_json_file_corruption(approved_entity, tmp_path):
+def test_json_file_corruption(approved_question, tmp_path):
     """Simulate file corruption — integrity check must fail."""
-    file = tmp_path / "entity.json"
-    json_str = approved_entity.to_json()
+    file = tmp_path / "question.json"
+    json_str = approved_question.to_json()
     file.write_text(json_str)
 
-    # Corrupt the file
+    # Corrupt the file (simulate accidental byte modification)
     corrupted = json_str.replace("Ohm’s", "Omm’s")
     file.write_text(corrupted)
 
-    loaded = approved_entity.__class__.from_json(file.read_text())
-    assert not approved_entity.__class__.verify_integrity(loaded)
+    loaded = RadioQuestion.from_json(file.read_text())
+    assert not RadioQuestion.verify_integrity(loaded)
