# Procedure: attempt, admissible transition, reached state Accreditation from the first tutorials was a fact: an entry exists, the researcher is admitted. But between the application and the entry lies the case's course: the request composed, filed, examined, decided. Each step has its conditions, and "filed" does not mean "the filing took place". For this the core has the procedures profile `law.procedure/0.1`. The corpus holds 98 procedures in 69 packages and 468 transitions (measured 05.09.2026 over `.law` text); the complaint-examination procedure `ProizvodstvoPoZhalobe` in the `complaints-106` package has seven states and six transitions. This page's legal frame: an attempted procedural action is a fact of the world and remains one even when no legal effect arose. The profile tells three things apart, deriving none from another: the attempt, the transition's admissibility, and the reached state. An attempt carries a THIRD argument — the carrier: the very event by which the attempt was undertaken. It carries the `id` and the `time`, and time gives history its order: the history fold reads one instance's attempts in ascending time, not in the case's line order. ```law language "law.core" version "0.2"; package tutorial.archive version "0.12.0"; namespace "urn:law:tutorial:archive"; entity Person; entity Application; relation application_of(app: Application, p: Person) kind empirical; relation application_complete(app: Application) kind empirical; relation committee_approved(app: Application) kind empirical; relation committee_refused(app: Application) kind empirical; relation accredited(p: Person) kind institutional; ``` ## The automaton An accreditation application passes four steps. Only a complete application may be filed; examination starts on handover to the committee; the committee either accredits or refuses, both outcomes final. ```law procedure Accreditation(app: Application) { state Draft initial; state Submitted; state UnderReview; state Accredited terminal; state Refused terminal; transition Submit { from Draft; to Submitted; when application_complete(app); } transition Review { from Submitted; to UnderReview; } transition Grant { from UnderReview; to Accredited; when committee_approved(app); } transition Refuse { from UnderReview; to Refused; when committee_refused(app); } } ``` The procedure parameter is the instance undergoing it: the single variable visible to all transitions' guards. Exactly one state is `initial`; `terminal` states have no outgoing transitions. A transition requires `from` and `to`; the `when` guard is an ordinary formula over the instance, and `Review` has none: there an attempt from the right state suffices. ## What this lowers into The automaton is DATA, not a set of rules: the compiler produces a `procedure` node, state and transition declaration-constants under qualified `

/` names, the `AccreditationStep` carrier type (this procedure's transitions do not name `on`), and the profile predicate declarations. ```text $ lawc expand 20-procedure.law.md --symbol Accreditation procedure Accreditation (20-procedure.law.md:…) procedure …#Accreditation type_decl …#AccreditationStep symbol_decl …#Accreditation/Draft … …#Accreditation/Refuse symbol_decl …#procedure_instance … …#current_state ``` The command names the page file; on this page run it with the `.en.law.md` filename. | Relation | Arity | Kind | Who establishes | |---|---|---|---| | `procedure_instance(app)` | 1 | empirical | case: the application exists | | `attempted_transition(app, Submit, e)` | 3 | empirical | case: the attempt undertaken by event `e` | | `valid_transition(app, Submit, e)` | 3 | institutional | history fold: attempt, source state, guard | | `initial_state(app, Draft)` | 2 | institutional | fold: the stage declared initial | | `entered_state(app, Submitted, e)` | 3 | institutional | fold: entered the stage BY exactly this event | | `left_state(app, Draft, e)` | 3 | institutional | fold: the stage left by this event | | `current_state(app, Submitted)` | 2 | institutional | fold: the case stands here NOW | The former two-argument `entered_state` answered four questions at once — "initial", "entered by this event", "standing now", "left" — and the author could not separate them. Now each has its own predicate, and the choice between them is a norm's choice: "while the application is in draft" is `current_state`, while "the application was ever filed" is `entered_state` with that attempt's carrier. Two empirical inputs and institutional conclusions — that is the procedure frame. No one derives an attempt: the case feeds it together with its carrier, like any observed fact. No one feeds a state: the fold of history derives it — attempts ordered by carrier time. ## Attempt and effect The same filing attempt with a complete and an incomplete application. | Facts beyond the instance | `entered_state(Submitted, e)` | `attempted_transition(Submit, e)` | `valid_transition(Submit, e)` | |---|---|---|---| | filing attempt, application complete | `TRUE_ONLY` | `TRUE_ONLY` | `TRUE_ONLY` | | filing attempt, application incomplete | `NEITHER` | `TRUE_ONLY` | `NEITHER` | | application complete, no attempt | `NEITHER` | `NEITHER` | `NEITHER` | The first row is the test from this page, byte for byte: ```law test "попытка подачи при полной заявке — подача состоялась" { given { context { decision_time @2026-04-15T09:00:00+05:00; knowledge_time @2026-04-15T09:00:00+05:00; legal_time @2026-04-15; timezone "Asia/Almaty"; } assert procedure_instance(entity_ref("urn:tutorial:application1")) { id "assert-instance"; origin case_input; } assert application_complete(entity_ref("urn:tutorial:application1")) { id "assert-complete"; origin case_input; } assert attempted_transition(entity_ref("urn:tutorial:application1"), Submit, AccreditationStep { id: "urn:tutorial:application1#submit", time: @2026-04-14T10:00:00+05:00 }) { id "assert-attempt-submit"; origin case_input; } } evaluate truth(current_state(entity_ref("urn:tutorial:application1"), Submitted)); expect truth_status == TRUE_ONLY; expect evaluation_status == COMPUTED; } ``` The test name reads: "A filing attempt with a complete application — the filing took place." The `AccreditationStep` carrier is synthetic: this procedure's transitions do not name `on`, and the profile gives them a step type by procedure name. Both its fields are mandatory: without the `id` an event has no identity, without the `time` no place in history, and the compiler refuses `LDC-E1343`. The carrier time is 14 April. The history fold reads ALL of the instance's attempts and orders them only relative to each other: the case's `decision_time` and `legal_time` do not cut carrier time off (one law for the whole history), and the case's record order does not affect history — `time` gives the order. The second row is the point of the page. Ivanova brought an incomplete application and tried to file it. The attempt exists — `attempted_transition` is established by the case and stays `TRUE_ONLY`. There is no effect: no transition happened, no state reached. The answer to "did the filing take place" is `NEITHER`, not `FALSE_ONLY`: the profile does not claim the filing did not take place; it merely finds no grounds to count it as having taken place. The third row is symmetric: a complete application nobody filed does not become filed — a guard without an attempt starts nothing. ## Where state comes from | Facts | question | answer | |---|---|---| | instance declared | `initial_state(Draft)` | `TRUE_ONLY` | | no instance declared, application complete, filing attempt | `current_state(Submitted)` | `NEITHER` | | instance, committee approval, decision attempt without filing and review | `current_state(Accredited)` | `NEITHER` | | instance, complete application, approval, filing, review, and decision attempts | `current_state(Accredited)` | `TRUE_ONLY` | | the same full chain | `current_state(Draft)` | `NEITHER` | | the same full chain | `entered_state(Draft, e)` | `NEITHER`: nothing entered `Draft` | | the same full chain | `left_state(Draft, e_submit)` | `TRUE_ONLY` | The initial state is "reached" by nothing: it is declared, and `initial_state` reads the declaration at the instance. Without an instance there is no initial state and hence no transition: second row. The third is a jump attempt: the committee approved, a decision attempt was undertaken, but the `UnderReview` source state was not reached, and there is no transition. Step order is held by the source state's reachedness AT the carrier's moment. The last three rows are what the separated predicates are for. Before, `entered_state` meant "ever entered", and after accreditation `Draft` stayed "reached": returning to a state was indistinguishable from never leaving it, while the "while the application is in draft" norm had to be written through a case fact or `not_known` over a later state. Now such a norm is written directly — `current_state(app, Draft)` — and "ever entered" is asked with `entered_state` carrying that very attempt. The initial stage was "entered" by nothing: it has no carrier, and its question is `initial_state`. ## A norm reads the reached state A researcher's accreditation is an ordinary institutional fact, derived by an ordinary norm from the reached state and the application-to-person link. ```law rule AccreditationGranted strict { for app: Application; for p: Person; when application_of(app, p) and current_state(app, Accredited); then accredited(p); } ``` | Facts | `accredited(Ivanova)` | |---|---| | Ivanova's application, full chain to decision | `TRUE_ONLY` | So a procedure links to the rest of the package: its conclusions are literals, norms read them, and the same norms may carry duties with terms for each step, as in [the deadlines tutorial](/tutorials/deadlines/). ## Two outcomes from one state | Facts | `current_state` | |---|---| | chain to review, committee refusal, refusal attempt | `Refused`: `TRUE_ONLY` | | chain to review, approval and refusal, decision attempt EARLIER than refusal attempt | `Accredited`: `TRUE_ONLY`, `Refused`: `NEITHER` | The second row is what changed with the event model. Before, the profile knew no mutual exclusion of transitions at all: a case asserting approval and refusal and both attempts reached BOTH terminal states at once, because no order existed between attempts. Now there is order — carrier time — and the history fold reads attempts in ascending order: `Grant` took place from `UnderReview`, the instance stands in `Accredited`, and for `Refuse` the `from UnderReview` condition no longer holds. The refusal attempt remains a fact of the world (`attempted_transition` is `TRUE_ONLY`) but yields no legal effect, and the proof node names the cause: `from`. This does not replace mutual exclusion: swap the carrier times and refusal takes place, not accreditation. A norm indifferent to the presentation order is still written with guards (`not committee_refused` in `Grant`'s guard) or a constraint — and that is the act's norm, not the profile. ## What the profile does not promise Two earlier boundaries were removed; a third remains and is honestly named here. **`on Event` is now a condition, not a declared intention.** Before, the event name did not reach CLIR: two procedures differing only by event produced byte-identical CLIR, and `check` stayed green with an `LDC-E1323` warning. Now the name must resolve into an event or action declaration — else a refusal, not a warning: ```text error LDC-E1344: переход: имя `AccreditationRequested` в клаузе `on` не разрешается в объявление события §79 либо действия §80 — носителя такого типа не существует, и переход не состоялся бы ни при какой истории (§160.1) ``` The diagnostic reads: "transition: the name `AccreditationRequested` in the `on` clause resolves into neither an event nor an action declaration — no carrier of such a type exists, and the transition would not have taken place under any history". A declared event becomes the carrier TYPE: a transition with `on E` carries an `E` instance in its attempt; one without `on` a synthetic `

Step`, like `AccreditationStep` on this page. **An event journal and a current state exist.** The `law_process` and `law_process_run` tools read the `procedure` node — no more restoring the automaton from the shape of produced ids — and run the case's attempt journal through an ordinary `evaluate`. An `ATTEMPT_WITHOUT_EFFECT` find in their report is the regular subject of attempted actions, not a defect of the statute. **Terminality lives in the node.** The `terminal` marker stopped being a source property: it is a state field in the `procedure` node, and to a tool over CLIR a lawful terminal shows as a terminal, not as `SINK_STATE` in notes. Left outside the page's slice are parallel branches and `join`: they exist in the language but have not yet received their own page. ## Compiler refusals Exactly one initial state. Remove `initial` from `Draft` and the procedure does not lower at all, followed down by the norm that read its constant: ```text error LDC-E1311: процедура "Accreditation": ровно одно состояние обязано быть `initial` (§160), объявлено 0 ``` The diagnostic reads: 'procedure "Accreditation": exactly one state must be `initial`, 0 declared'. A transition from a terminal state is a record under which terminality would be a comment. Point `Submit` from `Accredited`: ```text error LDC-E1313: переход "Submit" выходит из терминального состояния "Accredited" — терминальность иначе была бы комментарием (§160) ``` The diagnostic reads: 'transition "Submit" leaves the terminal state "Accredited" — otherwise terminality would be a comment'. Both refusals belong to the language. A state missing from the procedure, and a transition without `from` or `to`, are `LDC-E1312`: ```text error LDC-E1312: переход "Review": состояние "Committee" не объявлено в процедуре (§160) ``` The diagnostic reads: 'transition "Review": state "Committee" is not declared in the procedure'. And `LDC-E1344` is already a refusal, not a warning: a variant with `on AccreditationRequested` must NOT compile. Before, this place held an `LDC-E1323` warning with a zero exit code, and the compiler's silence would have cost the author false confidence that the event counted. ## Next The track's A2 step closes here: source, definitions, presumptions, time, terms, positions, readings, evidence, and procedure. Next is the package-in-corpus step: several packages in one world, shared computation as a dependency, tables, answer investigation, and acceptance. Its pages await the package practicum and are not yet written. The exercise for this page is [/tutorials/exercise-procedure/](/tutorials/exercise-procedure/).