FLEXO ID Decision Flowchart We assume: flexo_base_id = logical identity flexo_version = content evolution lifecycle suffix = process state fingerprint = canonical JSON hash STEP 0 — What is happening? You must classify the operation into one of three categories: State transition Content modification Logical duplication / fork Everything falls into one of these. FLOWCHART START | |-- Is this operation creating a new independent lineage? | (copy into new catalog? fork? split ownership?) | |-- YES --> Generate NEW flexo_base_id | flexo_version = 1 | lifecycle_state = Draft | origin_flexo_id = previous full ID | END | |-- NO | |-- Is canonical content different from last saved version? | (compare normalized JSON, excluding lifecycle metadata) | |-- YES --> flexo_base_id stays the same | flexo_version = previous_version + 1 | lifecycle_state = Draft | END | |-- NO | |-- Is this a lifecycle transition? | |-- YES --> flexo_base_id stays the same | flexo_version stays the same | lifecycle_state changes | END | |-- NO | |-- No ID change required (metadata only, DB-only operation) END Now Let’s Make It Concrete 1️⃣ Logical Duplication (NEW BASE ID) Trigger conditions: Copy question into new catalog (independent evolution) Split catalog into two Fork domain for separate governance “Save as new” intentionally Effect: new_base_id = generate() version = 1 state = Draft origin_flexo_id = previous full ID Strict rule: If future changes must not affect original lineage → new base ID. 2️⃣ Content Modification (VERSION BUMP) Trigger: Canonical JSON changed (after normalization). Examples: Question text edited Options reordered (if order matters) Points changed Domain description changed Exam layout changed Embedded question snapshot changed Effect: base_id unchanged version += 1 state = Draft Strict rule: If fingerprint changes → version bump. No exceptions. 3️⃣ Lifecycle Transition (STATE ONLY) Trigger: Draft → Approved Approved → Signed Signed → Published Published → Obsolete Effect: base_id unchanged version unchanged state changes Strict rule: Lifecycle does not alter content version. Edge Case Handling Approved entity edited Flow: Content change detected Version bump State automatically reset to Draft So: BASE@001P → edit → BASE@002D Clean and auditable. Draft → Approved where draft ID is “temporary” Your earlier idea suggested generating new ID at approval. Under strict logic: That is unnecessary and breaks lineage. Instead: BASE@001D → BASE@001A Same logical identity. If you must isolate drafts operationally: Use different database tiers, not different IDs. * Decision Matrix Summary | Operation | New Base ID | Version++ | State Change | |-------------------------+-------------+------------+--------------| | Copy/fork | | reset to 1 | Draft | | Content edit | | | Draft | | State promotion | No | No | Yes | | Metadata-only DB change | | | | One Important Constraint Fingerprint must exclude: - lifecycle_state - owner_id - DB storage metadata Otherwise state transitions would falsely trigger version bump. Fingerprint must represent semantic content only !!! Final Integrity Principle There must never exist: - two different canonical JSONs with same base ID + version - two identical canonical JSONs with different base ID (unless forked intentionally) If those invariants hold, your identity system is mathematically clean.