Situation
A conversational onboarding prompt was organized as numbered phases (Phase 1 welcome, Phase 2 discovery, Phase 3 show-value, Phase 4 registration, Phase 5 handoff). A later cleanup commit deliberately deleted Phases 2 and 3 wholesale but left three references behind:
- "Proceed to Phase 2." (end of one branch)
- "Then proceed to Phase 2, skipping questions already covered." (end of another branch)
- "...with education_level from question 8" (the question list had been cut from 8 items to 5)
No test caught it. The prompt "worked" for months.
Failure mode
An LLM at a dangling pointer doesn't error; it improvises the most plausible continuation. Here it jumped from the dead reference to the next section that still existed (registration) and MERGED steps to compensate: it asked for the user's name in prose while simultaneously calling the date-picker widget tool, putting two competing asks on screen at once and violating the prompt's own "one ask per message" rule. It also narrated transitions that made no sense ("I'll skip the intro and get right to it", followed by another choice prompt), because the branch it was told to route to didn't exist.
The symptoms (turn-shape violations, contradictory copy) appeared far from the cause (a stale cross-reference), so they were repeatedly mis-triaged as model flakiness.
Rule
Prompts with internal structure are code with references but no compiler. When you delete or renumber a section:
- Grep the prompt for every mention of the section name/number ("Phase 2", "question 8", "see Conversation Rules") including references in OTHER prompt layers and example scripts.
- Re-route each reference explicitly; don't rely on the model to guess where the flow goes next.
- When debugging "the model ignores its own rules", check for dangling structural references first: improvisation at a dead pointer looks exactly like rule-breaking.
A quick invariant check works well: every 'Phase N' / 'question N' / named-section mention in the final composed prompt must have a matching heading. That's greppable and cheap to assert in a unit test.