# Complete independent stages together ## Intent I want one event to complete independent reviews and then join their results. The example does not claim that a force-of-law act contains such a model. ## Wrong form and why it stays silent ```text title="Incorrect form" // Один носитель якобы может и завершить ветви, и выполнить Finish. ``` One atomic step is allowed in independent regions. Finish reads the state before its carrier; a join needs the next event, and join all needs both regions to be completed. ## Correct form ```law language "law.core" version "0.2"; package recipes.k.r04 version "0.1.0"; namespace "urn:recipe:k-procedures:04"; entity Application; event Tick { } procedure ReviewProcess(app: Application) { state Review initial parallel { region Legal { state LegalPending initial; state LegalDone terminal; transition LegalApprove { from LegalPending; to LegalDone; on Tick; } } region Finance { state FinancePending initial; state FinanceDone terminal; transition FinanceApprove { from FinancePending; to FinanceDone; on Tick; } } join all; } state Done terminal; transition Finish { from Review; to Done; on Tick; } } ``` ## Frozen execution scene P and Q in the table are different instances; E1/E2/E3 are carriers with an explicitly given time. All identifiers and instants are pinned in the scenes. | Events and facts | Question | Answer | |---|---|---| | empty parallel history | `truth(current_state(P,LegalPending))` | `truth_status == TRUE_ONLY;` / `COMPUTED` | | one review and a join attempt | `truth(current_state(P,Done))` | `truth_status == NEITHER;` / `COMPUTED` | | branches completed by one event | `truth(current_state(P,FinanceDone))` | `truth_status == TRUE_ONLY;` / `COMPUTED` | | join by the next event | `truth(current_state(P,Done))` | `truth_status == TRUE_ONLY;` / `COMPUTED` | | no data about the second review | `truth(current_state(P,FinanceDone))` | `truth_status == NEITHER;` / `COMPUTED` | | branches and join on one carrier | `truth(current_state(P,Done))` | `issue(CARRIER_REUSED);` / fatal; `results: []`; runner expected FAIL | ```law test "empty parallel history joins nothing" { given { context { legal_time @2026-09-13T09:00:00Z; decision_time @2026-09-13T09:00:00Z; knowledge_time @2026-09-13T09:00:00Z; timezone "UTC"; } assert procedure_instance(entity_ref("urn:recipe:k-procedures:04:p")); } evaluate truth(current_state(entity_ref("urn:recipe:k-procedures:04:p"),LegalPending)); expect truth_status == TRUE_ONLY; expect evaluation_status == COMPUTED; } ``` ```law test "single expertise leaves join undetermined" { given { context { legal_time @2026-09-13T09:00:00Z; decision_time @2026-09-13T09:00:00Z; knowledge_time @2026-09-13T09:00:00Z; timezone "UTC"; } assert procedure_instance(entity_ref("urn:recipe:k-procedures:04:p"));assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), LegalApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z });assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), Finish, Tick { id: "urn:recipe:k-procedures:04:E2", time: @2026-09-03T09:00:00Z }); } evaluate truth(current_state(entity_ref("urn:recipe:k-procedures:04:p"),Done)); expect truth_status == NEITHER; expect evaluation_status == COMPUTED; } ``` ```law test "one event completes both branches" { given { context { legal_time @2026-09-13T09:00:00Z; decision_time @2026-09-13T09:00:00Z; knowledge_time @2026-09-13T09:00:00Z; timezone "UTC"; } assert procedure_instance(entity_ref("urn:recipe:k-procedures:04:p"));assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), LegalApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z });assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), FinanceApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z }); } evaluate truth(current_state(entity_ref("urn:recipe:k-procedures:04:p"),FinanceDone)); expect truth_status == TRUE_ONLY; expect evaluation_status == COMPUTED; } ``` ```law test "follow-up event completes the join" { given { context { legal_time @2026-09-13T09:00:00Z; decision_time @2026-09-13T09:00:00Z; knowledge_time @2026-09-13T09:00:00Z; timezone "UTC"; } assert procedure_instance(entity_ref("urn:recipe:k-procedures:04:p"));assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), LegalApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z });assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), FinanceApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z });assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), Finish, Tick { id: "urn:recipe:k-procedures:04:E2", time: @2026-09-03T09:00:00Z }); } evaluate truth(current_state(entity_ref("urn:recipe:k-procedures:04:p"),Done)); expect truth_status == TRUE_ONLY; expect evaluation_status == COMPUTED; } ``` ```law test "missing second expertise leaves neither" { given { context { legal_time @2026-09-13T09:00:00Z; decision_time @2026-09-13T09:00:00Z; knowledge_time @2026-09-13T09:00:00Z; timezone "UTC"; } assert procedure_instance(entity_ref("urn:recipe:k-procedures:04:p"));assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), LegalApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z }); } evaluate truth(current_state(entity_ref("urn:recipe:k-procedures:04:p"),FinanceDone)); expect truth_status == NEITHER; expect evaluation_status == COMPUTED; } ``` ```law test "branches and join on one carrier refuse" { given { context { legal_time @2026-09-13T09:00:00Z; decision_time @2026-09-13T09:00:00Z; knowledge_time @2026-09-13T09:00:00Z; timezone "UTC"; } assert procedure_instance(entity_ref("urn:recipe:k-procedures:04:p"));assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), LegalApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z });assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), FinanceApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z });assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), Finish, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z }); } evaluate truth(current_state(entity_ref("urn:recipe:k-procedures:04:p"),Done)); expect issue(CARRIER_REUSED); expect evaluation_status == NON_EXECUTABLE; } ``` Counterfactual: `join all;` is replaced with `join any;`. The presented events are the same. ```law test "join any passes after one expertise" { given { context { legal_time @2026-09-13T09:00:00Z; decision_time @2026-09-13T09:00:00Z; knowledge_time @2026-09-13T09:00:00Z; timezone "UTC"; } assert procedure_instance(entity_ref("urn:recipe:k-procedures:04:p"));assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), LegalApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z });assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), Finish, Tick { id: "urn:recipe:k-procedures:04:E2", time: @2026-09-03T09:00:00Z }); } evaluate truth(current_state(entity_ref("urn:recipe:k-procedures:04:p"),Done)); expect truth_status == TRUE_ONLY; expect evaluation_status == COMPUTED; } ``` Swapping two independent attempts does not change the atomic-step node. ```law test "reordered attempts keep step bytes" { given { context { legal_time @2026-09-13T09:00:00Z; decision_time @2026-09-13T09:00:00Z; knowledge_time @2026-09-13T09:00:00Z; timezone "UTC"; } assert procedure_instance(entity_ref("urn:recipe:k-procedures:04:p"));assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), FinanceApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z });assert attempted_transition(entity_ref("urn:recipe:k-procedures:04:p"), LegalApprove, Tick { id: "urn:recipe:k-procedures:04:E1", time: @2026-09-02T09:00:00Z }); } evaluate truth(current_state(entity_ref("urn:recipe:k-procedures:04:p"),FinanceDone)); expect truth_status == TRUE_ONLY; expect evaluation_status == COMPUTED; } ``` ```python >>> import runpy >>> check = runpy.run_path("docs/recipes/k-procedures/resources/check.py") >>> check["check_parallel"](https://github.com/arxohq/law/blob/master/docs/recipes/k-procedures/4) 'К4: общий префикс, атомарный шаг, join any и снятие токенов проверены; lawc = lawref' ``` ```python >>> import runpy >>> check = runpy.run_path("docs/recipes/k-procedures/resources/check.py") >>> check["check_fatal"](https://github.com/arxohq/law/blob/master/docs/recipes/k-procedures/4) 'К4: fatal и пустой results проверены; частичной истории нет; lawc = lawref' ``` ## Counterfactual Mutation check — LDC-E1345. Original fragment: ```text join all; ``` Replacement: ```text join quorum(3); ``` Scenes with a condition removed are marked separately; the same inputs get a different outcome. ## Boundary On join any, exit also removes incomplete tokens, publishing left_state for active nested states. Absence of completion is NEITHER, not a proven failure. An arbitrary custom predicate is not supported in the join. In the scene “branches and join on one carrier” the named expect evaluation_status cannot execute: the document contains fatal CARRIER_REUSED and `results: []`. The sidecar expects a **runner FAIL**, and the adapter requires the exact code, severity fatal, empty results, and absence of procedure_history/step. This is a regular order refusal, not a semantic defect.