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

Author Signal Race in WolvenKit

Expand the Lab 2 start checkpoint into the 21-node Signal Race graph in WolvenKit.

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

Use Cyberpunk 2077 2.31a, WolvenKit 8.19.0, ArchiveXL 1.27.0, RED4ext 1.30.0, and redscript 0.5.31. Other versions may expose different editor wrappers or runtime behavior.

1. Open and isolate the start checkpoint

  1. Download and extract the start ZIP.
  2. Open CQA_Lab02_SignalRace_Start.cpmodproj through File > Open Project.
  3. Make an untouched backup of the extracted directory.
  4. Confirm the project contains three cooked resources beneath source\archive, their three review JSON files beneath source\raw, and CQA_Lab02_SignalRace_Start.archive.xl beneath source\resources.
  5. Do not install Lab 1, the completed Lab 2 checkpoint, and this start project as though they were one candidate. Lab 2’s two checkpoints collide on all three cqa002 depot paths.

The phase should contain only [0] Input connected to [1] Output. Verify Input socketName: In1, Output socketName: Out1, and Output type: Terminating before adding nodes.

2. Audit the supplied journal and strings

Open cqa002.journal. Confirm this exact typed tree:

gameJournalRootFolderEntry
└── quests                         gameJournalPrimaryFolderEntry
    └── minor_quest                gameJournalFolderEntry
        └── cqa002                 gameJournalQuest
            └── cqa002_01          gameJournalQuestPhase
                ├── cqa002_01_obj_wait
                └── cqa002_01_obj_stable

The required objective has optional: 0; the stable objective has optional: 1. Both have empty district IDs, zero item/location references, and the quest has no district or recommended-level dependency.

Open the localization resource at mod\cqa\cqa002\localization\en-us\onscreens\cqa002.json. Its localizationPersistenceOnScreenEntries.entries array must join these keys:

secondaryKeyfemaleVariant
cqa_cqa002_titleSignal Race
cqa_cqa002_objective_waitWait for the signal test to resolve.
cqa_cqa002_objective_stableKeep the signal stable.

Each entry uses primary key 0 and an empty male variant. Save, close, and reopen both resources. Do not edit their raw JSON review copies.

3. Add and number the graph nodes

Open cqa002.questphase, right-click an empty graph area, choose Add Node, and add the following nodes in the table’s order. The initial Input and Output already exist.

Target IDAdd Node labelRED type
10ConditionquestConditionNodeDefinition
11FactsDBManagerquestFactsDBManagerNodeDefinition
12JournalquestJournalNodeDefinition
13JournalquestJournalNodeDefinition
14JournalquestJournalNodeDefinition
15PauseConditionquestPauseConditionNodeDefinition
16PauseConditionquestPauseConditionNodeDefinition
17ConditionquestConditionNodeDefinition
18PauseConditionquestPauseConditionNodeDefinition
19FactsDBManagerquestFactsDBManagerNodeDefinition
20PauseConditionquestPauseConditionNodeDefinition
21FactsDBManagerquestFactsDBManagerNodeDefinition
22JournalquestJournalNodeDefinition
23JournalquestJournalNodeDefinition
24FactsDBManagerquestFactsDBManagerNodeDefinition
25LogicalXorquestLogicalXorNodeDefinition
26JournalquestJournalNodeDefinition
27FactsDBManagerquestFactsDBManagerNodeDefinition
28JournalquestJournalNodeDefinition

WolvenKit assigns IDs as nodes are created; a fresh start graph normally uses 2 through 20. Those auto IDs overlap the target range. Do not overwrite a target ID that another node still owns.

After adding all 19 nodes, use the creation order recorded above to renumber in two passes:

  1. move the added nodes to unique temporary IDs 100 through 118, preserving the table order;
  2. move those same nodes from the temporary IDs to target IDs 10 through 28 from the table.

Save, close, and reopen the phase after both passes so the wrappers and connector owners rebind to the serialized IDs. Confirm the inventory is exactly 0, 1, and 10 through 28 before following any ID-addressed step.

Leave the root resource’s inplacePhases and phasePrefabs arrays empty. This lab owns no child phase or world resource. phaseInstancePrefabs belongs to a questPhaseNodeDefinition; it is not a root questQuestPhaseResource property.

4. Configure the immediate conditions

For IDs 10 and 17, add a questFactsDBCondition handle at condition, then add questVarComparison_ConditionType at condition.type.

IDfactNamecomparisonTypevalue
10cqa002_completedEqual0
17cqa002_test_modeEqual1

These nodes sample their facts when a signal enters In and choose True or False. Neither waits for a later value change.

5. Configure the fact writers

Each FactsDBManager node uses questSetVar_NodeType. Set type.setExactValue: 1 on all five nodes:

IDtype.factNametype.value
11cqa002_test_mode2
19cqa002_signal_failed1
21cqa002_signal_stop1
24cqa002_signal_succeeded1
27cqa002_completed1

Exact mode value 2 is canonical. Do not change it while building the graph. Incrementing an old save-backed value would make the test mode depend on prior runs and invalidate the acceptance design.

6. Configure the waiting conditions

Fact listener at ID 15

Add questFactsDBCondition, then questVarComparison_ConditionType:

PropertyValue
factNamecqa002_signal_failed
comparisonTypeGreater
value0

Boolean AND listener at ID 16

Add questLogicalCondition at condition, set operation: AND, and add two handles to its conditions array. Each child is a questFactsDBCondition containing a questVarComparison_ConditionType:

ChildfactNamecomparisonTypevalue
0cqa002_signal_stopGreater0
1cqa002_test_modeEqual2

This is a Boolean tree inside one Pause Condition. Do not replace it with a graph-level Logical AND node.

Realtime delays at IDs 18 and 20

At each node, add questTimeCondition, then questRealtimeDelay_ConditionType. Set hours, minutes, and miliseconds to zero. Set seconds to 30 on ID 18 and 120 on ID 20. These deliberately long human-test windows make the objective state observable after loading and leave time to create a mid-flow manual save.

miliseconds is the native RED spelling. Timer behavior through pause, loading, and save/reload remains part of the runtime test.

7. Configure every journal operation

For each Journal node, add questJournalQuestEntry_NodeType at type, then a gameJournalPath handle at type.path. Set these common properties:

PropertyValue
type.optional0
type.sendNotification1
type.trackQuest1
type.versionInitial
type.path.editorPathempty string
type.path.fileEntryIndex2

Then set paths by target:

IDsclassNamerealPath
12, 28gameJournalQuestquests/minor_quest/cqa002
13, 26gameJournalQuestObjectivequests/minor_quest/cqa002/cqa002_01/cqa002_01_obj_wait
14, 22, 23gameJournalQuestObjectivequests/minor_quest/cqa002/cqa002_01/cqa002_01_obj_stable

The incoming socket chooses state: IDs 12, 13, and 14 receive Active; ID 22 receives Failed; IDs 23, 26, and 28 receive Succeeded. Changing the payload’s path does not compensate for wiring the wrong state socket.

8. Configure the XOR-typed convergence

On ID 25, set:

PropertyValue
inputSocketCount2
outputSocketCount1

After saving and reopening, confirm ordinary sockets In1, In2, and Out1 plus the inherited CutDestination. The node’s name does not prove automatic cancellation or exactly-once behavior; those are acceptance questions.

9. Expose and wire all sockets

Right-click each node and choose Show Unused Sockets. Create these 22 ordinary edges:

SourceDestination
0.Out10.In
10.False1.In
10.True11.In
11.Out12.Active
12.Out13.Active
13.Out14.Active
14.Out15.In
14.Out16.In
14.Out17.In
17.True18.In
18.Out19.In
17.False20.In
20.Out21.In
15.Out22.Failed
22.Out25.In1
16.Out23.Succeeded
23.Out24.In
24.Out25.In2
25.Out126.Succeeded
26.Out27.In
27.Out28.Succeeded
28.Out1.In

The three connections leaving 14.Out are intentional. Do not insert a Hub. The two edges entering 1.In are also valid; they do not require two formal input sockets.

Leave every CutDestination unwired. Lab 2 deliberately avoids claiming cut behavior. Do not connect cut sockets to ordinary flow as a guessed cleanup.

Save, close, reopen, and compare against the exact generated graph. Placement and handle IDs may differ; node IDs, RED types, payloads, socket names, and resolved edges must match.

10. Verify registration and project structure

The start checkpoint already contains ArchiveXL registration. Keep its three sections unchanged while authoring:

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

journal:
- mod\cqa\cqa002\journal\cqa002.journal

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

base\quest\cyberpunk2077.quest is a vanilla reference. Do not include an extracted copy in the project.

Keep the start project filename, <Name>, <ModName>, and CQA_Lab02_SignalRace_Start.archive.xl during the walkthrough. To compare with the supplied result, open CQA_Lab02_SignalRace.cpmodproj separately. Do not partially rename the start project.

11. Validate and build

With every tab saved:

  1. run Project > Scan for broken file references;
  2. run Project > Scan for broken files;
  3. run Project > Run File Validation on the entire project;
  4. resolve all project-owned errors;
  5. close Cyberpunk 2077;
  6. choose Build > Install and wait for packing and installation;
  7. inspect the WolvenKit Log panel and the installed archive plus .archive.xl.

Use the normal ArchiveXL project install, not Install as REDmod. A packed archive without the loose registration file cannot attach the root or merge the journal/localization resources.

The manually authored start project installs CQA_Lab02_SignalRace_Start.archive with its _Start.archive.xl. The supplied canonical completed project installs CQA_Lab02_SignalRace.archive with CQA_Lab02_SignalRace.archive.xl. Remove one pair before installing the other; both pairs register the same three depot paths.

12. Create the controlled failure candidate

Keep a copy of the completed build before editing:

  1. copy the completed project to a separately named working directory;
  2. open node 11;
  3. change only type.value from exact 2 to exact 1;
  4. leave setExactValue: 1 and all other files/properties unchanged;
  5. rebuild and label the edited archive as the mode-1 variant;
  6. install it only after removing the canonical archive;
  7. load a different untouched save created before any Lab 2 candidate was installed.

Do not flip the fact through a console command for acceptance. Together, the controlled source edit and exact graph establish which producer is wired to the route and create a reproducible candidate artifact. The runtime run records the player-visible outcome; it does not directly observe that internal signal.

Common authoring failures

SymptomCheck
Reopening the phase loses or misbinds connectorsRenumber through temporary IDs 100–118, save, close, reopen, and confirm the exact final ID inventory before wiring
A condition branches immediately instead of waitingIDs 15, 16, 18, and 20 must be Pause Condition nodes; IDs 10 and 17 are the only immediate Condition nodes
The stable route never releasesConfirm ID 16 contains one logical AND tree with both fact children and that ID 21 writes cqa002_signal_stop exactly 1
Optional journal state is wrongKeep the journal entry’s optional: 1 separate from each questphase journal operation’s type.optional: 0; wire Failed and Succeeded sockets exactly
Build succeeds but the quest is absentInstall both the packed archive and loose .archive.xl, then inspect ArchiveXL and RED4ext logs for the three depot paths
Canonical hashes no longer matchRestore node 11 to exact value 2 and use the supplied completed project; a manually expanded _Start project is only a comparison candidate

Lab sequence: All labs · Previous: Lab 2: Signal Race · Next: Test both Signal Race routes.