10. Diagnose a Validator-Clean Soft Lock
A campaign can use supported fields, valid IDs, and correct references while still becoming impossible to finish. This chapter creates that failure deliberately.
Start from Checkpoint 9 or download the intentionally broken Checkpoint 10.
What you will learn
Section titled “What you will learn”- Why a one-time event is not the same as current state
- How a condition can make a valid event producer miss its only useful moment
- How a later consumer can turn one missed event into a soft lock
- Why normal-path testing is insufficient
- How to trace producers, consumers, and timing across a dependency graph
- How to repair the campaign without regenerating unrelated content
The three changes that create the failure
Section titled “The three changes that create the failure”Checkpoint 10 differs from the working Checkpoint 9 in only three ways.
1. Remove the current-state completion condition
Section titled “1. Remove the current-state completion condition”The working recover_letter objective contains:
"completeWhen": { "hasItem": "tutorial_codex:sealed_letter"}The broken variant removes that condition.
The objective can no longer look at the player’s current inventory. It now depends entirely on an action explicitly completing it.
2. Add a fragile acquisition trigger
Section titled “2. Add a fragile acquisition trigger”The broken variant adds:
{ "id": "tutorial_codex:fragile_letter_event", "event": "itemAcquired", "targetId": "tutorial_codex:sealed_letter", "once": true, "when": { "questActive": "tutorial_codex:missing_courier" }, "actions": [ { "completeQuestObjective": [ "tutorial_codex:missing_courier", "recover_letter" ] } ]}Every field is supported:
- the event name is valid,
- the item ID exists,
- the quest ID exists,
- the objective ID exists,
- the condition shape is valid,
- the action shape is valid.
The problem is timing.
The trigger listens for a moment:
the sealed letter enters inventorybut accepts that moment only when:
The Missing Courier is already active3. Make Oren depend on the completed objective
Section titled “3. Make Oren depend on the completed objective”The working Oren branch checks current inventory:
{ "hasItem": "tutorial_codex:sealed_letter"}The broken variant replaces that condition with:
{ "objectiveCompleted": [ "tutorial_codex:missing_courier", "recover_letter" ]}This turns the missed acquisition event into a progression gate. Oren will not resolve the letter until the objective says it is complete.
Validate the broken file
Section titled “Validate the broken file”Open the Author tools and validate Checkpoint 10.
The expected result is:
0 errors0 warningsThat result is not a contradiction. The validator has established that the campaign uses known structures and resolvable references.
It has not established that every required producer can still run before its consumer is needed.
Test the obvious path
Section titled “Test the obvious path”First test the path most authors are likely to try:
talk to Mara→ start The Missing Courier→ open the satchel→ acquire the letter→ talk to OrenThis path works.
Why?
- The quest is active before the item is acquired.
itemAcquiredfires for the sealed letter.- The trigger’s
questActivecondition passes. - The trigger completes
recover_letter. - Oren sees
objectiveCompleted. - Quest 1 can continue.
A successful normal-path test can therefore create false confidence.
Test the supported alternate path
Section titled “Test the supported alternate path”Now use a fresh game and reverse the first two actions:
open the satchel→ acquire the letter→ talk to Mara→ start The Missing Courier→ talk to OrenThis path fails.
Event timeline
Section titled “Event timeline”At the moment the letter is acquired:
itemAcquired: tutorial_codex:sealed_letterquestActive: tutorial_codex:missing_courier = falseThe trigger’s condition rejects the event.
Later, Mara starts the quest:
questActive: tutorial_codex:missing_courier = truehasItem: tutorial_codex:sealed_letter = truerecover_letter objective = incompleteThe inventory state is correct, but the campaign no longer observes it.
The itemAcquired event does not fire again merely because the quest became active. The only letter is already in inventory.
Oren then checks:
objectiveCompleted: recover_letterThat condition is false, so the final Quest 1 resolution branch is unavailable.
The campaign is now soft-locked:
- the file is structurally valid,
- the player still has the required item,
- all named content exists,
- no remaining action can complete the required objective.
Draw the dependency graph
Section titled “Draw the dependency graph”The broken graph is:
itemAcquired event └─ accepted only while Quest 1 is active └─ completes recover_letter └─ unlocks Oren's resolutionThe letter-first player order is:
itemAcquired event→ condition fails→ Quest 1 starts later→ no second acquisition event→ recover_letter remains incomplete→ Oren remains lockedThe important defect is not an invalid reference. It is a missing reachable producer after a permitted ordering choice.
Why the validator accepts it
Section titled “Why the validator accepts it”Static validation can confirm:
itemAcquiredis a supported event,- the target item exists,
- the quest and objective exist,
questActiveis a supported condition,completeQuestObjectiveis a supported action,- Oren’s
objectiveCompletedreference is valid.
Static validation generally cannot prove:
- whether the item can be acquired before the quest starts,
- whether the item can be acquired more than once,
- whether an event will be emitted again,
- whether all player orderings reach the same state,
- whether another producer can repair a missed event,
- whether a required dialogue branch remains reachable.
This is why the guide treats validator success as necessary evidence, not sufficient evidence.
Diagnose the soft lock systematically
Section titled “Diagnose the soft lock systematically”Do not begin by rewriting the quest. Trace the smallest failing dependency.
1. Identify the blocked consumer
Section titled “1. Identify the blocked consumer”Oren requires:
{ "objectiveCompleted": [ "tutorial_codex:missing_courier", "recover_letter" ]}The blocked consumer is therefore Oren’s Quest 1 resolution branch.
2. Find every producer
Section titled “2. Find every producer”Search for every place that can complete recover_letter.
In the broken checkpoint, the only producer is:
tutorial_codex:fragile_letter_eventThere is no completeWhen condition and no second dialogue action that repairs the objective.
3. List producer prerequisites
Section titled “3. List producer prerequisites”The trigger requires all of these to align at one moment:
event = itemAcquiredtargetId = tutorial_codex:sealed_letterquestActive = tutorial_codex:missing_courier4. Ask whether the prerequisite order is guaranteed
Section titled “4. Ask whether the prerequisite order is guaranteed”It is not guaranteed. The satchel is intentionally available before Mara starts the quest.
5. Ask whether the event is repeatable
Section titled “5. Ask whether the event is repeatable”The acquisition event for this unique quest item is not a dependable repeatable producer. Possessing the item later does not recreate the original event.
6. Test the inverse order
Section titled “6. Test the inverse order”A useful adversarial rule is:
When two actions appear independent, test them in both orders.
For this campaign:
Mara then letterletter then MaraBoth are supported story paths. Both must work.
Repair the campaign
Section titled “Repair the campaign”Restore the three working decisions from Checkpoint 9.
Restore current-state objective completion
Section titled “Restore current-state objective completion”Add back:
"completeWhen": { "hasItem": "tutorial_codex:sealed_letter"}Now the objective can reevaluate what is true now, even when the acquisition happened earlier.
Remove the fragile trigger
Section titled “Remove the fragile trigger”Delete:
tutorial_codex:fragile_letter_eventThe trigger is unnecessary once the objective observes inventory state directly.
Restore Oren’s inventory condition
Section titled “Restore Oren’s inventory condition”Change Oren’s condition back to:
{ "hasItem": "tutorial_codex:sealed_letter"}Oren’s role is to react to the letter the player currently carries. That is the most direct state test for the scene.
Why not add another repair branch?
Section titled “Why not add another repair branch?”You could add dialogue that notices the player has the letter and manually completes the missing objective. That can work, but it would be repairing a fragile model with another special case.
The cleaner design is:
inventory is the authoritative state→ objective observes inventory→ Oren observes inventoryOne durable fact serves both consumers.
Revalidate and retest
Section titled “Revalidate and retest”After restoring the Checkpoint 9 logic:
- Validate again.
- Start a fresh game.
- Test Mara first, then the letter.
- Start another fresh game.
- Test the letter first, then Mara.
- Save after acquiring the letter but before speaking to Mara.
- Reload, speak to Mara, and confirm the objective completes.
- Talk to Oren and confirm Quest 1 resolves.
- Repeat the conversation and confirm no duplicate quest transition occurs.
The save-and-reload case matters because it proves the repair depends on durable inventory state rather than a transient event still being in memory.
Build an adversarial playtest habit
Section titled “Build an adversarial playtest habit”For every major progression dependency, ask:
| Question | Example in this campaign |
|---|---|
| Can the player do this early? | Open the courier satchel before speaking to Mara |
| Can the player do this late? | Recruit Lysa after visiting the Belfry |
| Can the player do this twice? | Re-enter the Belfry or repeat dialogue |
| Can the player do this elsewhere? | Enter a different dungeon or defeat another enemy |
| Can the player save between producer and consumer? | Save after the Warden, then return to Oren |
| Is the event repeatable? | Dungeon entry is; unique item acquisition may not be |
| Is there a durable state fallback? | hasItem protects the letter-first path |
A campaign reviewer should deliberately search for paths the author did not naturally choose.
Checkpoint 10
Section titled “Checkpoint 10”Checkpoint 10 adds no legitimate feature. It preserves a known validator-clean failure made from three exact changes:
remove recover_letter.completeWhenadd quest-gated itemAcquired triggermake Oren depend on objectiveCompletedThe normal path works. The letter-first path soft-locks.
Once you can explain the failure without guessing, return to the working Checkpoint 9 logic. Chapter 11 will package the campaign, validator evidence, dependency ledger, and human playtest results into a release decision.
Continue to Chapter 11: Review, Playtest, and Release.