Index: flexoentity/flexo_entity.py
===================================================================
--- flexoentity/flexo_entity.py	(revision 33be5a0f6e1f5aa9c9c28a845407bba23932e13b)
+++ flexoentity/flexo_entity.py	(revision 37b5d111a63a7caf8477361289173c4798e334cb)
@@ -230,19 +230,32 @@
             return True
         return False
-   
-    # ───────────────────────────────────────────────────────────────
-    def _transition(self, target_state: EntityState):
-        """Internal helper for state transitions with version and fingerprint checks."""
-        if target_state == EntityState.OBSOLETE:
-            self.state = target_state
-            return
-
-        # Check if version should bump
-        if self.should_version(target_state):
-            self._update_fingerprint()
-            self.flexo_id = FlexOID.next_version(self.flexo_id)
-
+
+   def _transition(self, target_state: EntityState):
+    """
+    Internal helper for state transitions with version/fingerprint checks
+    and forward-only enforcement.
+    """
+
+    allowed = self.allowed_transitions()
+
+    if target_state.name not in allowed:
+        raise ValueError(
+            f"Illegal state transition: {self.state.name} → {target_state.name}. "
+            f"Allowed: {', '.join(allowed) or 'none'}"
+        )
+
+    # special case: marking obsolete
+    if target_state == EntityState.OBSOLETE:
         self.state = target_state
         self.updated_at = datetime.now(UTC)
+        return
+
+    # version bump only for stable/external states
+    if self.should_version(target_state):
+        self._update_fingerprint()
+        self.flexo_id = FlexOID.next_version(self.flexo_id)
+
+    self.state = target_state
+    self.updated_at = datetime.now(UTC)
 
     # ───────────────────────────────────────────────────────────────
@@ -277,4 +290,5 @@
         Draft entities receive a new permanent FlexOID with incremented version.
         """
+        
         if self.state == EntityState.DRAFT:
             new_version = self.flexo_id.version + 1
Index: org/FlexoEntity.org
===================================================================
--- org/FlexoEntity.org	(revision 33be5a0f6e1f5aa9c9c28a845407bba23932e13b)
+++ org/FlexoEntity.org	(revision 37b5d111a63a7caf8477361289173c4798e334cb)
@@ -6,6 +6,20 @@
 ** Was ist ein Hash?
 
-Ein Hash ist wie eine Art eindeutige Kennnummer oder ein "Fingerabdruck" für Daten, der
+Ein Hash ist ein hoffentlich eindeutiger "Fingerabdruck" für Daten, der
 sich aus eben diesen Daten über den Algorithmus einer Hash-Funktion errechnet.
+
+Die Eingabedaten bezeichnet man als Seed, das Ergebnis als Digest.
+
+Man gibt die Saat (das Futter) an die Hashfunktion zum Zerkauen/Zerkleinern (Hashen),
+das wird verdaut, nebenbei noch gewürzt (Salt) und kommt als Digest wieder heraus.
+Die Länge der Ausgabe ist fest.
+
+** Ein wichtiger Punkt
+
+Wichtig ist auch zu verstehen, dass Hashes sogenannte "One-Way-Funktionen" sind.
+Das heißt, man kann das Hashing nicht einfach umkehren, um das ursprüngliche Objekt wiederherzustellen.
+Ein Hash ist also eine Einbahnstraße: Er dient nur dazu, die Daten zu repräsentieren,
+aber man kann nicht vom Hash auf die originalen Daten zurückrechnen.
+Aus Kacke kann man kein Essen zaubern.
 
 ** Was ist kein Hash?
@@ -32,11 +46,4 @@
 hat sich etwas geändert. Das spart enorm viel Aufwand.
 
-** Ein wichtiger Punkt
-
-Wichtig ist auch zu verstehen, dass Hashes sogenannte "One-Way-Funktionen" sind.
-Das heißt, man kann das Hashing nicht einfach umkehren, um das ursprüngliche Objekt wiederherzustellen.
-Ein Hash ist also eine Einbahnstraße: Er dient nur dazu, die Daten zu repräsentieren,
-aber man kann nicht vom Hash auf die originalen Daten zurückrechnen.
-
 ** Beispiele für den Einsatz von Hashes
 
@@ -48,4 +55,9 @@
 root:$6$tsicHaoV3Q$YtAbiIvrHGXFtAJYz9tcEYWHXiGVQ40sJAgzPAbc57lIq9jH8eYjWXwctSW6YQnrMznRFcm6yXLnnY9mHhso20
 enno:$6$sdygzfEgx0$YpaZJMQdkZgxGPclphz6RojqNG.PSNEq1oIHRP4kvZRN2iuS5MQrxt0nCkrYQIcpDGyohrb1o0S/GkWrFriWL1
+
+Der Hash ist länger als das Passwort. Das dient der Sicherheit, weil man zwar nicht zurückrechnen,
+wohl aber vorwärtsrechnen kann. Hash-Funktionen sind deterministisch.
+Bei Linux-Passworteinträgen hat man hier $6$ den Hashalgorithmus kodiert, im daraufolgendem $.....$ das Salz
+und im Rest den eigentlichen Hash kodiert
 
 - **Git-Commits**: In Versionskontrollsystemen wie Git werden Hashes benutzt, um jeden Schwung an
@@ -168,9 +180,19 @@
 erreicht haben. Ein Zertifikat kann nur ausgestellt werden, wenn der passende Einstufungstest die Stufe
 Veröffentlicht hat. Das origin-Feld des Zertifikats sollte sinnvollerweise die ID des Tests enthalten.
-	
+
 ** Erhöhung der Versionsnummer oder neue ID
 
 Sobald - aus Gründen - eine neue ID vergeben werden muss, wird ggf. die Ursprungs-ID
 im Feld origin der neuen FlexoEntity gespeichert. So ist immer ein Suchen im Stammbaum möglich.
+
+AF-Q251022-70F759@001D
+│  │ │       │     │ │
+│  │ │       │     │ └── State (Draft, Approved, Signed, Published, Obsolete)
+│  │ │       │     └──── Version
+│  │ │       └────────── Hash (3 bytes, 6 Stellen)
+│  │ └────────────────── Date (YYMMDD)
+│  └──────────────────── Entity type (Question)
+└─────────────────────── Domain (e.g. Air force)
+
 
 Eine einfache Erhöhung der Versionsnummer (am Ende der ID) ist unter Umständen auch ausreichend,
@@ -178,6 +200,18 @@
 für das Projekt FlexoGrader recht umfangreich und soll hier nicht weiter besprochen werden.
 Da es aber im Hintergrund passiert und vom Endanwender nicht bemerkt wird, behindert der
-Mechanismus die Nutzung des FlexoGrader (TM) nicht. 
-
+Mechanismus die Nutzung des FlexoGrader nicht. 
+
+** Reifegrad
+
+Das Konzept und Design hat die Alpha-Phase verlassen, der Code ist aber noch deutlich Beta.
+RC1 etwa Anfang Dezember (nach meinem Urlaub). Änderungen an der FlexOID sind nicht mehr zu erwarten, beim API der FlexoEntity schon eher.
+
+Das Perfekte ist der Feind des Guten, aber ...
+
+Als Gegenbeispiel für unausgereiftes Design ist Pythons eingebaute datetime Bibliothek.
+Da könnte man ein Buch drüber schreiben. Halb Drama, halb Komödie.
+
+- dateutil, arrow, pendulum, maya, moment, delorean, pytz, zoneinfo + numpy/pandas
+  
 ** Lizenz
 
