|
1 | 1 | Write P code for the {filename} file. |
2 | 2 |
|
3 | 3 | CRITICAL REQUIREMENTS: |
| 4 | + |
4 | 5 | 1. For EACH scenario in <possible_scenarios>, create a dedicated scenario machine (e.g., Scenario1_XXX) with a start state that instantiates the system. |
5 | 6 | 2. For EACH scenario machine, you MUST write a `test` declaration. Without test declarations, PChecker cannot discover or run any tests. The format is: |
6 | 7 | test tcScenarioName [main=ScenarioMachine]: |
7 | 8 | assert SpecName1, SpecName2 in |
8 | 9 | {{ MachineA, MachineB, ..., ScenarioMachine }}; |
9 | 10 | Use the spec/monitor names from the PSpec files in the assert clause. List ALL machines that participate in the scenario inside the braces. |
10 | | -3. Always create all dependent machines before initializing machines that will send events/messages to them; never use default/null machine references in initialization. |
11 | | -4. The test driver file MUST contain BOTH the scenario machines AND the test declarations. Do NOT put them in separate files. |
12 | | -5. Do NOT re-declare or re-define machines that already exist in PSrc (Broker, Producer, etc.). Only define NEW test-specific machines here (scenario drivers and test_component machines like Consumer if it was listed under <test_components>). |
13 | | -6. You MUST only use events that are already defined in Enums_Types_Events.p. Do NOT invent new events (e.g., eStartProducing, eStartConsuming). If a machine needs to start doing work, trigger it via its constructor payload or entry action — not a custom start event. |
14 | | -7. Scenario machines must be SIMPLE launchers. They create all system components in the correct order and then stop. They should NOT handle any protocol events (no `on eXxx` handlers). If a component like Timer needs a `client: machine` reference, pass the actual component that uses the timer (e.g., the Coordinator), NOT the scenario machine itself (`this`). |
15 | | -8. Ensure every machine is fully initialized before other machines send events to it. Create machines in dependency order: infrastructure first (Timer), then core (Coordinator, Broker), then clients (Client, Producer, Consumer). Pass all required references via constructor payloads — do not leave machine references uninitialized. |
| 11 | +3. The test driver file MUST contain BOTH the scenario machines AND the test declarations. Do NOT put them in separate files. |
| 12 | +4. Do NOT re-declare or re-define machines that already exist in PSrc. Only define NEW scenario-driver machines here. |
| 13 | +5. You MUST only use events that are already defined in Enums_Types_Events.p. Do NOT invent new events. |
| 14 | +6. Scenario machines must be SIMPLE launchers. They create all system components in the correct order and then stop. They should NOT handle any protocol events (no `on eXxx` handlers). |
16 | 15 |
|
17 | | -Example structure for a file with 2 scenarios: |
| 16 | +## CRITICAL: Machine Wiring — Read the Machine Entry Signatures |
18 | 17 |
|
19 | | -machine Scenario1_SingleClient {{ |
20 | | - start state Init {{ |
21 | | - entry {{ |
22 | | - // create system components |
23 | | - }} |
24 | | - }} |
| 18 | +Look at every machine file provided as context. Each machine's start state has an entry function. That entry function's parameter defines EXACTLY what the machine expects when created. You MUST match it. |
| 19 | + |
| 20 | +There are two initialization patterns used by the machines: |
| 21 | + |
| 22 | +### Pattern A: Constructor payload — machine expects config via `new Machine(payload)` |
| 23 | +If a machine's start-state entry function has a parameter, you MUST pass a matching named-tuple payload when creating it with `new`. |
| 24 | + |
| 25 | +Example — if Proposer.p has: |
| 26 | +``` |
| 27 | +start state Init {{ |
| 28 | + entry InitEntry; |
| 29 | + ... |
| 30 | +}} |
| 31 | +fun InitEntry(config: (acceptors: seq[machine], learners: seq[machine], id: int)) {{ |
| 32 | + ... |
25 | 33 | }} |
| 34 | +``` |
| 35 | +Then the test driver MUST create it as: |
| 36 | +``` |
| 37 | +proposer = new Proposer((acceptors = acceptorSeq, learners = learnerSeq, id = 1)); |
| 38 | +``` |
26 | 39 |
|
27 | | -machine Scenario2_MultipleClients {{ |
| 40 | +### Pattern B: Initialization event — machine blocks on a config event |
| 41 | +If a machine's start state waits for an event (e.g., `on eAcceptorConfig goto Ready with Configure;`), you MUST send that event after creating the machine. |
| 42 | + |
| 43 | +Example — if Acceptor.p has: |
| 44 | +``` |
| 45 | +start state WaitForConfig {{ |
| 46 | + on eAcceptorConfig goto Ready with Configure; |
| 47 | + defer ePropose, eAcceptRequest; |
| 48 | +}} |
| 49 | +fun Configure(config: tAcceptorConfig) {{ |
| 50 | + ... |
| 51 | +}} |
| 52 | +``` |
| 53 | +Then the test driver MUST do: |
| 54 | +``` |
| 55 | +acceptor1 = new Acceptor(); |
| 56 | +send acceptor1, eAcceptorConfig, (learners = learnerSeq,); |
| 57 | +``` |
| 58 | + |
| 59 | +### Wiring Rules |
| 60 | +- Create machines in DEPENDENCY ORDER: machines with no dependencies first (e.g., Learner), then machines that reference them (e.g., Acceptor needs learners), then machines that reference those (e.g., Proposer needs acceptors). |
| 61 | +- Build `seq[machine]` or `set[machine]` collections BEFORE passing them to dependent machines. |
| 62 | +- NEVER leave machine-typed variables uninitialized (default/null). Every machine reference must point to a created machine. |
| 63 | +- NEVER pass `this` (the scenario machine) as a protocol participant reference. |
| 64 | +- For each `new` call, verify the payload tuple field names and types match the machine's entry function parameter EXACTLY. |
| 65 | + |
| 66 | +## Complete Example |
| 67 | + |
| 68 | +Given machines with these signatures: |
| 69 | +- Learner: `fun InitEntry()` — no config needed |
| 70 | +- Acceptor: `fun InitEntry(config: (learners: seq[machine],))` — needs learners |
| 71 | +- Proposer: `fun InitEntry(config: (acceptors: seq[machine], learners: seq[machine], id: int))` — needs acceptors + learners |
| 72 | +- Client: `fun InitEntry(config: (proposer: machine, value: int))` — needs proposer |
| 73 | + |
| 74 | +The scenario machine must be: |
| 75 | +``` |
| 76 | +machine Scenario1_BasicPaxos {{ |
28 | 77 | start state Init {{ |
29 | 78 | entry {{ |
30 | | - // create system components |
| 79 | + var learner1: machine; |
| 80 | + var acceptors: seq[machine]; |
| 81 | + var learners: seq[machine]; |
| 82 | + var proposer: machine; |
| 83 | + var client: machine; |
| 84 | + |
| 85 | + // 1. Create machines with no dependencies |
| 86 | + learner1 = new Learner(); |
| 87 | + learners += (0, learner1); |
| 88 | + |
| 89 | + // 2. Create machines that depend on step 1 |
| 90 | + acceptors += (0, new Acceptor((learners = learners,))); |
| 91 | + acceptors += (1, new Acceptor((learners = learners,))); |
| 92 | + acceptors += (2, new Acceptor((learners = learners,))); |
| 93 | + |
| 94 | + // 3. Create machines that depend on steps 1-2 |
| 95 | + proposer = new Proposer((acceptors = acceptors, learners = learners, id = 1)); |
| 96 | + |
| 97 | + // 4. Create clients that depend on proposer |
| 98 | + client = new Client((proposer = proposer, value = 42)); |
31 | 99 | }} |
32 | 100 | }} |
33 | 101 | }} |
34 | 102 |
|
35 | | -test tcSingleClient [main=Scenario1_SingleClient]: |
36 | | - assert SafetySpec in |
37 | | - {{ ComponentA, ComponentB, Scenario1_SingleClient }}; |
38 | | - |
39 | | -test tcMultipleClients [main=Scenario2_MultipleClients]: |
40 | | - assert SafetySpec in |
41 | | - {{ ComponentA, ComponentB, Scenario2_MultipleClients }}; |
| 103 | +test tcBasicPaxos [main=Scenario1_BasicPaxos]: |
| 104 | + assert OnlyOneValueChosen in |
| 105 | + {{ Proposer, Acceptor, Learner, Client, Scenario1_BasicPaxos }}; |
| 106 | +``` |
42 | 107 |
|
43 | 108 | Verify that the generated code strictly follows all the P syntax rules before considering it final. Return only the generated P code without any explanation attached. Return the P code enclosed in XML tags where the tag name is the filename. |
0 commit comments