Plausible fields can describe an impossible conversation

Conversation systems often grow one useful piece at a time. Qualification state is added in one place and appointment state in another. Eventually, a lead can carry values that look individually reasonable but conflict together:

bot state: appointment_slot_selection
qualification state: qualification_next_field

That is not historical information. It is competing control state.

The precedence rule

I treat an active appointment flow as authoritative. When a lead moves into appointment selection, the persistence path clears qualification routing fields such as the pending qualification action and expected field. It does not erase collected qualification answers; those remain useful history.

This is a small but important distinction: remove conflicting control instructions, not valuable context.

Two guards are better than one

The branch arbiter should prevent an invalid combination before processing begins. The canonical persistence step should still validate the state before writing it.

routing guard โ†’ execution โ†’ persistence guard

The second guard is deliberately defensive. Future workflow edits, stale payloads, or an overlooked branch can reintroduce old fields. A persistence rule can normalise the next valid turn instead of leaving somebody to repair records manually.

What I learned

Historical data can be distributed. Current control state needs a single operational truth, explicit precedence, and invariants that are checked at the write boundary.

What should happen next

Long term, I want one versioned conversation-state object and transition validation around it. The guards are a practical safety net; a formal model will make future changes easier to reason about.