# The unit address space

> Every point a unit publishes under Process.Model.Unit, its type and meaning, which points are writable commands, and what a Logic script may read from it.

Every unit publishes its run data as ordinary [Logic](logic) addresses under
`Process.<Model>.<Unit>`, so dashboards, Logic expressions, the embedded OPC UA server and
the agent reach it with no extra plumbing. The branch is browsed on the Logic page under
"From other pages" ([From other pages](logic-from-other-pages)) and in every address
picker. Renaming a model, unit, channel, metadata field, evaluation or criterion replaces the
corresponding addresses and rewrites live textual references; recorded files keep the names
frozen when they were written. The segments are the sanitized names: a unit called "Unit 1" of the
model "Climatic chamber" is addressed as `Process.Climatic_chamber.Unit_1`.

| Branch | What it exposes | Writable |
| --- | --- | --- |
| `Channels.<Channel>` | The live bound value of each channel, typed as the channel declares. | A writable channel (Write only or Read and write role) is a writable point through the write funnel; a source a run holds refuses every other writer. |
| `Procedure.<point>` | The run state, one scalar per point (table below). | No. |
| `Commands.<command>` | `Start`, `Hold`, `Resume`, `Stop`, `Abort` and `Comment`. | Yes: writing dispatches (table below). |
| `Next.<point>` | The staging area the next Start consumes. | Manual metadata fields only. |
| `LastRun.<point>` | The record of the latest run the unit finished ([LastRun](#lastrun)). | No. |
| `Productivity.Today.<branch>` and `Productivity.Rolling.<branch>` | The unit's productivity projection for each period. | No. |

## Channels {#channels}

A channel point reads the value behind the unit's binding, projected to the channel's data
type, and reads as a gap when the channel is unbound or its source is unavailable. In a
Logic script the point is a read-only typed projection of the bound tag or variable, never
the tag itself: `Value`, `ValueObject`, `ValueRaw`, `ValueScaled`, `ValueCalibrated`,
`ValueLimited`, `ValueRounded`, the conversions `ValueToBool()`, `ValueToInteger()`,
`ValueToReal()`, `ValueToString()` and `ValueToDateTime()`, the quality `State()`, the
stamps `SourceTimeStamp()` and `ApplicationTimeStamp()`, `Refresh()`, `Name` and
`EngineeringUnit`. The pipeline members answer for a tag binding; a variable binding
answers the value and the application stamp.

## Procedure {#procedure}

Every point is computed from the live run and reads with good quality; a point that has
nothing to say reads a gap.

| Point | Type | Meaning |
| --- | --- | --- |
| `Status` | Text | `Preparing` while the unit is reserved and no run exists yet, `Idle` while nothing owns it, otherwise the run state: `Running`, `Held`, `Saving`, `Completed`, `Aborted`, `Failed`. |
| `Running` | Boolean | Strictly the Running state; never true for preparation, Held, Saving or finalization. |
| `Busy` | Boolean | The whole occupied span: reservation, Running, Held, Saving and the final close of the run file. |
| `Verdict` | Text | `Ok`, `Nok`, `Indeterminate` or `None`, spelled exactly so, whatever word the interface or a printed label shows: a comparison reads `Process.<Model>.<Unit>.Procedure.Verdict == "Nok"`. The judged evidence stays readable after the run ends until the next run starts. |
| `Mode` | Text | The active run's mode, `Instant`, `Temporal` or `Controlled`; a single command (snapshot, evaluate now) reports too. Gap when idle. |
| `ActiveProcedure` | Text | The active run's name ("Procedure · Unit"). Gap when idle. |
| `SegmentIndex` | Integer | The temporal profile's current segment, 0-based. Gap without a profile. |
| `CycleIndex` | Integer | The current cycle, 0-based. Gap when idle. |
| `CycleCount` | Integer | The total cycles of the run (1 for a single pass). Gap when idle. |
| `Cycle` | Text | "2 / 10" for a cyclic run; a gap when the run is not cyclic, so a bound readout shows the gap mark instead of a misleading single pass. |
| `FailedCycles` | Integer | Cycles judged NOK so far. Gap when the run is not cyclic. |
| `SamplesEvaluated`, `SamplesOut`, `SamplesUnavailable`, `SamplesInvalid` | Integer | The evaluation's evidence counters, updated atomically by the evaluation engine. Gap without judged evidence. |
| `Elapsed` | Decimal | Seconds since the run started. Gap when idle. |
| `StartedAt` | Date and time | When the active run started. Gap when idle. |
| `Metadata.<Field>` | Text | One point per metadata field of the model: the value the run in progress froze at Start. Gap when idle and for a field that run does not prompt; a field left blank reads empty text. This is what an action fired at Start reads of the run that starts, since `Next.<Field>` already shows the one after it. |

## Commands {#commands}

Reading a command point answers "can this execute now", so a bound Button disables itself;
writing it dispatches the command through the run console, journaled with the writing
surface's source and recorded with the identity of whoever pressed. A command is a service
call, never a queued point write.

| Point | Reads true when | Writing |
| --- | --- | --- |
| `Start` | The unit is not busy, the runtime accepts operations, the interlock is Normal and a procedure is staged. | Starts the staged procedure with the staged metadata. |
| `Hold` | A run is Running and its procedure is Temporal. | Freezes the window. |
| `Resume` | A run is Held and the interlock is Normal. | Releases the hold. |
| `Stop` | A run is Running. | Ends the run as Completed. |
| `Abort` | A run is Running or Held. | Ends the run as Aborted. |
| `Comment` | Never: the point has no reading. | Appends the written text as a comment to the active run, or as a post-run note on the unit's latest finished run when it is idle. A unit with no run at all refuses ("The unit has no run to comment on."), and so does empty text. |

Every command reads false while the station is refusing writes (the runtime stopped).

## Next {#next}

| Point | Type | Meaning |
| --- | --- | --- |
| `Next.Procedure` | Text | The staged procedure's name. Read-only here: staging is done on the unit panel's Run card. |
| `Next.<Field>` | Text | One point per metadata field the staged procedure prompts; the branch reshapes when the unit is re-staged, and a field of another procedure reads a gap. A manual (text or numeric) field is a writable staging point, which is what an Input component bound to it writes. A sequential field is a read-only prediction of the identifier the counter would compose now; reading never reserves it. |

Staging is station-wide, in-memory and transient: it resets when the application starts
and is consumed, not cleared, by Start.

## Productivity {#productivity}

Two periods, `Today` (since local midnight) and `Rolling` (the window declared on the model
or the unit), each with three branches ([Productivity](process-productivity)):

| Branch | Points | Type |
| --- | --- | --- |
| `Summary` | `ProductivityPercent`, `YieldPercent`, `TypicalElapsedSeconds` | Decimal; a gap until the denominator exists. |
| `Summary` | `Finalized`, `OK`, `NOK`, `Indeterminate`, `Unclassified`, `Aborted`, `Failed` | Integer counts. |
| `Outputs.<key>` | `Quantity`, `RatePerHour` | Decimal; one key per named quantity, or per productive procedure when the model declares no quantity. |
| `Procedures.<key>` | `Quantity`, `RatePerHour` and the summary points above | As above, per productive procedure. |

Keys derive from the stable id and the frozen output unit, not from the display name, so a
rename never moves an expression. Every point is read-only, and the projection is read
from the history index, never from run files.

## LastRun {#lastrun}

The record of the latest run the unit finished: who it was, how it ended, what the operator
entered at Start and how each criterion went. It is what a Logic action fired at Completion reads
([Actions](process-actions#logic-action-commands)), and any other consumer reads it the same way:
a screen showing the last piece, an alarm, the station's servers. Every recorded run of the unit
counts, a Failed one and a Snapshot or Evaluate now included; an imported run never does.

| Point | Type | Meaning |
| --- | --- | --- |
| `RunId` | Text | The run's identifier. |
| `Procedure` | Text | The procedure's name as the run recorded it. |
| `Status` | Text | `Completed`, `Aborted` or `Failed`, spelled exactly so. |
| `Verdict` | Text | `Ok`, `Nok`, `Indeterminate` or `None`, spelled as `Procedure.Verdict`; a Failed run reads `None`. |
| `StartedAt`, `FinishedAt` | Date and time | When the run started and finished. |
| `Elapsed` | Decimal | Seconds from start to finish. |
| `CycleCount` | Integer | The run's cycles (1 for a single pass). |
| `FailedCycles` | Integer | The cycles judged NOK. |
| `Metadata.<Field>` | Text | One point per metadata field of the model: the value the run froze at Start. A field the run did not prompt reads a gap; a field left blank reads empty text. |
| `Evaluations.<Evaluation>.<Criterion>.<point>` | As below | One folder per evaluation of the model and one per criterion under it, named by the criterion's name, or by its channel's when it has none. |

Each criterion carries one result, folded over every cycle it was judged in, so the address is the
same for a single pass and for a run of a hundred cycles:

| Point | Type | Meaning |
| --- | --- | --- |
| `Outcome` | Text | `Ok`, `Nok` or `Indeterminate`, spelled exactly so: any NOK cycle gives `Nok`, otherwise any Indeterminate cycle gives `Indeterminate`, otherwise `Ok`. |
| `Passed` | Boolean | True only when `Outcome` is `Ok`. |
| `Value` | Decimal | The measured value of the watched channel: the last evaluated sample of the window, in One point mode the judged one, from the latest cycle that measured one. |
| `MinValue`, `MaxValue` | Decimal | The lowest and the highest evaluated values, over every cycle. |
| `Limits` | Text | The limits as recorded, such as `5 .. 45`. |
| `WorstExcursion` | Decimal | The largest distance beyond a bound, over every cycle. |
| `FailedCycles` | Integer | The cycles that judged this criterion NOK. |

The branch has the shape of the model, never the shape of the last run: every metadata field of
the catalogue and every criterion of every evaluation is a point, so a script that names one
validates before any run, and after a run of a procedure that judged by another evaluation.

| Situation | What the points read |
| --- | --- |
| No run of the unit has finished yet | A gap with Bad quality, every point. |
| A run ends | The new record, in place before the unit's `Procedure.Status` says the run ended. |
| Another run of the unit is in progress | The previous record, until that run ends. |
| The application starts again | The unit's latest finished run, read back from its run file shortly after start; a gap until it is read. |
| A criterion the last run did not judge (another evaluation, or one added since) | A gap in every point. |
| Two evaluations, or two criteria, whose names read the same | Nothing: the address resolves to neither, and the evaluation's page says so ([Evaluations](process-evaluations#names-are-addresses)). |

Renaming a metadata field, an evaluation, a criterion or the channel of an unnamed criterion moves
these addresses like every other rename on this page.

## What a script may do {#what-a-script-may-do}

Logic variable, alarm and action scripts may **read** everything here: channel values, run
state, command readiness, staged values, the last run and productivity points. They cannot
dispatch a command, write a staging field or append a comment; those writes belong to the explicit
command consumers: the operating panels, dashboard Buttons and
Inputs, the unit automation and the agent tools.

A channel point reads as the typed projection of [Channels](#channels); every other point here
reads as its plain value, with no `.Value` after it, unlike a variable:

```js
if (Process.Oven_soak.Oven_1.LastRun.Verdict === "Ok") {
  Variables.Last_serial = Process.Oven_soak.Oven_1.LastRun.Metadata.Serial;
}
```
