Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lab 4: Handoff Point

Lab 4 moves Boundary Check’s reach/leave activity into an external child questphase. The registered root starts the child, waits for its Out1 return, then performs a visible parent-only confirmation before completing the quest.

RecordValue
Structural validation date2026-08-09
Runtime test dateNot yet recorded

Structurally validated: both seven-resource checkpoints round-trip with WolvenKit 8.19.0. Follow the test guide for child entry, return, streaming, and save/reload.

Follow Author Handoff Point in WolvenKit to expand the start checkpoint. Then use Test Handoff Point to bind the candidate, saves, observations, and logs.

What the lab demonstrates

registered root -> completed == 0?
  False -> terminate
  True  -> activate quest and phase
        -> enter external child through In1
             activate reach objective and pin
             wait IsInside reach volume
             retire pin; succeed reach; activate leave
             wait IsOutside leave volume
             succeed leave; terminate child through Out1
        <- parent phase node emits Out1
        -> activate confirmation objective
        -> wait 30 realtime seconds
        -> succeed confirmation and phase
        -> set completed = 1
        -> succeed quest; terminate root

The CutDestination socket exists on the external phase node and other relevant nodes, but every cut socket is deliberately unwired. Lab 4 teaches a normal terminating Out1 handoff only; cut behavior remains Experimental.

Required environment

ComponentExact version
Cyberpunk 2077 for Windows (GOG)2.31a (public patch 2.31)
WolvenKit8.19.0
ArchiveXL1.27.0
RED4ext1.30.0
redscript0.5.31

Other versions may expose different editor wrappers or runtime behavior.

Prerequisites and downloads

Complete Lab 3, then read:

Do not install the two checkpoints together. They register and pack the same depot paths. Use an untouched save created before any Lab 4 candidate was first installed. Uninstalling an earlier candidate or setting cqa004_completed = 0 does not remove save-backed journal, phase, mappin, world, or graph state.

Resource ownership

ResourceDepot pathOwns
Root questphasemod\cqa\cqa004\phases\cqa004.questphaseRoot graph, completion policy, external child call, and root prefab declaration
Boundary child questphasemod\cqa\cqa004\phases\cqa004_boundary.questphaseReach/leave activity and terminating Out1
Journalmod\cqa\cqa004\journal\cqa004.journalQuest, phase, three objectives, and handoff map pin
Onscreen localizationmod\cqa\cqa004\localization\en-us\onscreens\cqa004.jsonQuest title, three objective strings, and pin caption
Streaming blockmod\cqa\cqa004\world\cqa004_handoff.streamingblockQuest and AlwaysLoaded sector descriptors
Quest sectormod\cqa\cqa004\world\cqa004_handoff.streamingsectorReach and leave trigger definitions and placements
AlwaysLoaded sectormod\cqa\cqa004\world\cqa004_always_loaded.streamingsectorStatic handoff marker definition and placement
ArchiveXL registrationCQA_Lab04_HandoffPoint.archive.xlRoot attachment, journal/localization merge, and streaming-block registration

The loose ArchiveXL file is packaging metadata, not an eighth CR2W resource. ArchiveXL registers the streaming block, not its sectors separately.

Registration and child resolution

The ArchiveXL file registers only the root phase:

quest:
  phases:
  - path: mod\cqa\cqa004\phases\cqa004.questphase
    parent: base\quest\cyberpunk2077.quest

journal:
- mod\cqa\cqa004\journal\cqa004.journal

localization:
  onscreens:
    en-us:
    - mod\cqa\cqa004\localization\en-us\onscreens\cqa004.json

streaming:
  blocks:
  - mod\cqa\cqa004\world\cqa004_handoff.streamingblock

Parent phase node 13 resolves the child through:

phaseGraph: null
phaseResource:
  DepotPath: mod\cqa\cqa004\phases\cqa004_boundary.questphase
  Flags: Soft
phaseInstancePrefabs: []
saveLock: 0
unfreezingTriggerNodeRef: 0

The child is packed but not independently ArchiveXL-registered. The supplied validator rejects a child registration entry.

Prefab and NodeRef contract

The registered root declares one local prefab root:

#cqa004_pr_handoff

The external child declares:

phasePrefabs: []

The world-side full root and nested references are:

$/mod/cqa/cqa004/#cqa004_pr_handoff
  #cqa004_tr_reach
  #cqa004_tr_leave
  #cqa004_mp_handoff

The child directly uses the two local trigger refs. Its empty prefab list is intentional: Lab 4 tests root-owned scope across the child boundary. The arrangement is Structurally validated here, Observed in vanilla in the cited street-story pair, and Runtime-proven in the retained four-child GQT003 fixture. Lab 4’s own runtime result remains Experimental.

World and journal scaffold

The world resources reuse Lab 3’s checked geometry under the cqa004 namespace:

OwnerNodePlacementGeometry or orientation
Quest sectorworldTriggerAreaNode reach(-1000.02, 1497.2208, 2.3)16-point regular outline, 25 m circumradius, 12 m high
Quest sectorworldTriggerAreaNode leave(-1000.02, 1497.2208, 0.3)20-point regular outline, 110 m circumradius, 16 m high
AlwaysLoaded sectorworldStaticMarkerNode(-1000.02, 1497.2208, 8.3)yaw 88.6°

The typed journal tree is:

quests/minor_quest/cqa004
└── cqa004_01
    ├── cqa004_01_obj_reach
    │   └── cqa004_01_qmp_handoff -> #cqa004_mp_handoff
    ├── cqa004_01_obj_leave
    └── cqa004_01_obj_confirm

The child owns the first two objectives and map pin. The parent owns the confirmation objective. The only FactsDB name is cqa004_completed.

Start checkpoint contract

The start root already teaches external resolution without the completed behavior:

Root IDRED typePurpose
0questInputNodeDefinitionExpose root In1
13questPhaseNodeDefinitionResolve child and match In1/Out1
1questOutputNodeDefinitionTerminate root through Out1

Its two edges are 0.Out -> 13.In1 and 13.Out1 -> 1.In.

The start child contains [0] Input and [1] Output, connected by 0.Out -> 1.In. Output 1 is Terminating. This pass-through is a checkpoint for inspecting both interface layers; it is not the completed player activity.

Exact root phase

IDRED node typeDecisive payloadPurpose
0questInputNodeDefinitioninterface In1Enter registered root
1questOutputNodeDefinitionterminating Out1End success and bypass routes
10questConditionNodeDefinitioncqa004_completed Equal 0Bypass a completed save
11questJournalNodeDefinitionquest pathActivate Handoff Point
12questJournalNodeDefinitionphase pathActivate phase
13questPhaseNodeDefinitionsoft child path; null inline graph; empty instance prefabsInvoke Boundary child through In1 and receive Out1
14questJournalNodeDefinitionconfirmation objectiveProve parent-only continuation became active
15questPauseConditionNodeDefinition30-second realtime delayKeep the post-return parent window observable
16questJournalNodeDefinitionconfirmation objectiveSucceed confirmation
17questJournalNodeDefinitionphase pathSucceed phase
18questFactsDBManagerNodeDefinitionset cqa004_completed = 1 exactlyPersist one-shot completion
19questJournalNodeDefinitionquest pathSucceed Handoff Point

Root edge contract

SourceDestinationMeaning
0.Out10.InEnter completion guard
10.False1.InCompleted-save bypass
10.True11.ActiveFirst-run activation
11.Out12.ActiveActivate phase
12.Out13.In1Enter external child
13.Out114.ActiveResume parent after normal child return
14.Out15.InBegin visible parent-only window
15.Out16.SucceededEnd confirmation wait
16.Out17.SucceededSucceed phase
17.Out18.InWrite durable completion
18.Out19.SucceededSucceed quest
19.Out1.InTerminate successful root route

Exact boundary child phase

IDRED node typeDecisive payloadPurpose
0questInputNodeDefinitioninterface In1Receive parent invocation
1questOutputNodeDefinitionterminating Out1Return normal completion
10questJournalNodeDefinitionreach objectiveActivate reach objective
11questMappinManagerNodeDefinitionpin path; disable previous 0Activate and track handoff pin
12questPauseConditionNodeDefinitionplayer IsInside #cqa004_tr_reachWait for current inside state
13questMappinManagerNodeDefinitionsame pin path; disable previous 0Inactivate handoff pin
14questJournalNodeDefinitionreach objectiveSucceed reach objective
15questJournalNodeDefinitionleave objectiveActivate leave objective
16questPauseConditionNodeDefinitionplayer IsOutside #cqa004_tr_leaveWait for current outside state
17questJournalNodeDefinitionleave objectiveSucceed leave objective before return

Child edge contract

SourceDestinationMeaning
0.Out10.ActiveBegin child-owned activity
10.Out11.ActiveActivate pin
11.Out12.InArm reach condition
12.Out13.InactiveRetire pin after reach
13.Out14.SucceededSucceed reach objective
14.Out15.ActiveActivate leave objective
15.Out16.InArm leave condition
16.Out17.SucceededSucceed leave objective
17.Out1.InTerminate child through Out1

No root edge reaches a child node directly. No child edge reaches a parent node directly. Phase node 13 and the matching interface names are the handoff.

Common failure modes

SymptomCheck firstBoundary
Quest never appearsRoot path in .archive.xl, installed archive pair, ArchiveXL/RED4ext logsThe child is not an additional root registration
Quest activates but child work never startsNode 13 soft path, archived child, parent In1, child socketName: In1A valid parent CR2W does not prove external resolution
Child finishes but confirmation never appearsChild output reachability, child socketName: Out1, parent 13.Out1 -> 14.ActiveJournal success is not implicit parent continuation
Trigger refs fail only in childRoot prefab entry, empty child/instance lists, full world binding, exact installed buildDo not “fix” by duplicating until the tested arrangement is diagnosed
Reload restarts or skips workSave history, active owner at save time, fact write order, journal stateA console fact reset is not a clean save
An interruption route behaves unpredictablyConfirm every CutDestination remains unwiredLab 4 makes no cut-safety claim

Lab sequence: All labs · Previous topic: Complex cleanup, interruption, and cancellation · Next: Author Handoff Point in WolvenKit.