Skip to main content

pointlock_ir/
vocab.rs

1//! Closed vocabulary enums (spine Appendix A.4).
2//!
3//! Every enum here is a closed set: adding, removing or renaming a value is a
4//! semantic change of the IR and requires an `irVersion` bump (02 §11).
5//! Wire literals are aligned verbatim with Appendix A.4 via serde renames.
6
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9
10/// Effect classification of a step (full set, spine A.4).
11///
12/// Note: the FlowIR schema restricts action steps to [`EffectClassAction`]
13/// (`pure` never crosses a Provider — pure computation belongs to `let`).
14#[derive(
15    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
16)]
17#[serde(rename_all = "camelCase")]
18pub enum EffectClass {
19    /// Changes the world; replays are only safe when declared idempotent.
20    Mutating,
21    /// Probes the world without changing it; always safe to replay.
22    Readonly,
23    /// Pure computation; never crosses a Provider.
24    Pure,
25}
26
27/// `EffectClass` restricted for action steps; `pure` is excluded because pure
28/// computation never crosses a Provider.
29#[derive(
30    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
31)]
32#[serde(rename_all = "camelCase")]
33pub enum EffectClassAction {
34    /// Changes the world.
35    Mutating,
36    /// Probes the world without changing it.
37    Readonly,
38}
39
40/// Locating/verification channel (full set, spine A.4).
41///
42/// `vision` is verify-only and `coordinate` is act-only; the FlowIR schema
43/// encodes those restrictions structurally via [`ActChannel`] and
44/// [`VerifyChannel`].
45#[derive(
46    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
47)]
48#[serde(rename_all = "camelCase")]
49pub enum Channel {
50    /// Web DOM channel.
51    Dom,
52    /// Native UI-tree channel (requires `observation.uiSnapshot.v1`).
53    UiTree,
54    /// Vision channel (verify-only, principle 7).
55    Vision,
56    /// Static-coordinate channel (act-only).
57    Coordinate,
58}
59
60/// Channel subset legal on the act-chain. `vision` is structurally excluded
61/// (principle 7: vision never locates or acts).
62#[derive(
63    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
64)]
65#[serde(rename_all = "camelCase")]
66pub enum ActChannel {
67    /// Web DOM channel.
68    Dom,
69    /// Native UI-tree channel.
70    UiTree,
71    /// Static-coordinate channel (must carry literal coordinates, bind-phase check).
72    Coordinate,
73}
74
75/// Channel subset legal on the verify-chain. `coordinate` is structurally
76/// excluded (a coordinate cannot verify anything).
77#[derive(
78    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
79)]
80#[serde(rename_all = "camelCase")]
81pub enum VerifyChannel {
82    /// Web DOM channel.
83    Dom,
84    /// Native UI-tree channel.
85    UiTree,
86    /// Vision channel — only legal at the chain tail (bind-phase check).
87    Vision,
88}
89
90/// Actual execution mode reported by the DeviceRail daemon; the whitelist
91/// semantics live on [`crate::BoundAttempt::accept_execution_modes`]
92/// (spine §6.4 R-degrade).
93#[derive(
94    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
95)]
96#[serde(rename_all = "camelCase")]
97pub enum ExecutionMode {
98    /// Native semantic execution.
99    NativeSemantic,
100    /// Web semantic execution.
101    WebSemantic,
102    /// Daemon-internal coordinate fallback (must be whitelisted per attempt).
103    CoordinateFallback,
104}
105
106/// Pointlock-layer closed error taxonomy (spine §5). DeviceRail
107/// `ErrorInfo.code` is an open string set mapped onto this enum.
108///
109/// snake_case on the wire, aligned with DeviceRail error-code style.
110#[derive(
111    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
112)]
113#[serde(rename_all = "snake_case")]
114pub enum ErrorClass {
115    /// Attestation does not match `lockfileDigest`; refuse to start/resume.
116    CapabilityDrift,
117    /// Runtime arguments failed the action inputSchema — a compiler/expression bug signal.
118    BindArgumentsInvalid,
119    /// Action failed with `retryable: true` as reported by the daemon.
120    ActionFailedRetryable,
121    /// Action failed with `retryable: false`; try the next attempt or fail the step.
122    ActionFailedFinal,
123    /// Action timed out; auto-retry only when the step is declared idempotent.
124    ActionTimedOut,
125    /// Action cancelled (user cancellation → run aborted).
126    ActionCancelled,
127    /// `UiNodeRef` documentEpoch invalid or locate miss; re-observe before retry.
128    TargetStale,
129    /// Transport lost / daemon exited; suspend and resume from checkpoint.
130    TransportLost,
131    /// Session degraded; current step yields unknown, flow-level onError fires.
132    SessionDegraded,
133}
134
135/// Canonical verbs — report/metadata only. The runner has no verb switch;
136/// execution is driven exclusively by `BoundAttempt.actionName` (spine R7).
137///
138/// snake_case on the wire (spine A.4).
139#[derive(
140    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
141)]
142#[serde(rename_all = "snake_case")]
143pub enum CanonicalVerb {
144    /// Tap an element.
145    Tap,
146    /// Set an element's value.
147    SetValue,
148    /// Clear an element.
149    Clear,
150    /// Wait for an element condition.
151    WaitFor,
152    /// Find an element.
153    Find,
154    /// Explicit observation.
155    Observe,
156    /// Screenshot capture.
157    Screenshot,
158    /// Escape hatch for provider/driver-specific actions.
159    Invoke,
160}
161
162/// Flow-level verdict folding policy. `strict` folds a degraded pass into
163/// `unknown` (spine §6.3).
164#[derive(
165    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
166)]
167#[serde(rename_all = "camelCase")]
168pub enum VerdictPolicy {
169    /// Degraded passes remain passes (flagged `degraded`).
170    Standard,
171    /// Degraded passes fold to `unknown`.
172    Strict,
173}
174
175/// Interaction mode of a human step (principle 8).
176#[derive(
177    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
178)]
179#[serde(rename_all = "camelCase")]
180pub enum HumanMode {
181    /// Human confirms/rejects; the decision is recorded.
182    Confirm,
183    /// Human produces the step verdict.
184    Judge,
185    /// Human provides typed input (requires `outputSchema`).
186    ProvideInput,
187    /// Human repairs the world; yields a disposition, never a verdict or output.
188    RepairWorld,
189}
190
191/// Handler hook points (spine A.4). Handlers never appear in normal control
192/// flow; they fire on specific state-machine transitions.
193#[derive(
194    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
195)]
196#[serde(rename_all = "camelCase")]
197pub enum HandlerHook {
198    /// Fires when the step verdict folds to fail.
199    OnFail,
200    /// Fires when the step verdict folds to unknown.
201    OnUnknown,
202    /// Fires on an [`ErrorClass`] (optionally filtered via `errorClasses`).
203    OnError,
204    /// Fires when resume preflight probes detect world drift.
205    OnResumeDrift,
206}
207
208/// Element state predicate values — verbatim equal to DeviceRail
209/// `WaitForElementCondition`.
210#[derive(
211    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
212)]
213#[serde(rename_all = "camelCase")]
214pub enum ElementState {
215    /// Element exists in the UI tree.
216    Present,
217    /// Element is visible.
218    Visible,
219    /// Element is enabled.
220    Enabled,
221    /// Element is absent.
222    Absent,
223}
224
225/// Text match mode — isomorphic to DeviceRail `TextMatchMode`.
226#[derive(
227    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
228)]
229#[serde(rename_all = "camelCase")]
230pub enum TextMatchMode {
231    /// Exact match.
232    Exact,
233    /// Substring match.
234    Contains,
235}
236
237/// UI context kind — isomorphic to DeviceRail `UiContextKind`.
238#[derive(
239    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
240)]
241#[serde(rename_all = "camelCase")]
242pub enum UiContextKind {
243    /// Native UI context.
244    Native,
245    /// Web UI context.
246    Web,
247}
248
249/// Which observation of the source action step an assert step reuses.
250#[derive(
251    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
252)]
253#[serde(rename_all = "camelCase")]
254pub enum ObservationWhich {
255    /// The `ActionResult.after` observation.
256    After,
257    /// The `ActionResult.before` observation.
258    Before,
259}
260
261/// Step pipeline phase (spine A.4, used by `PathFrame::Phase`).
262#[derive(
263    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
264)]
265#[serde(rename_all = "camelCase")]
266pub enum Phase {
267    /// Pre-entry world probe.
268    Preflight,
269    /// Action execution.
270    Act,
271    /// Observation capture.
272    Observe,
273    /// Assertion evaluation.
274    Assert,
275}
276
277/// Step lifecycle state (spine §6.2/A.4, closed 14-value set).
278///
279/// `awaitingHuman` doubles as the supervision-gate wait state (R13):
280/// the exit path is discriminated by the pending request's `purpose`.
281#[derive(
282    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
283)]
284#[serde(rename_all = "camelCase")]
285pub enum StepState {
286    /// Not yet reached.
287    Pending,
288    /// Inputs resolved and snapshotted; ready to act.
289    Ready,
290    /// Preflight probes running.
291    Probing,
292    /// Action dispatched (entered only after the actionIntent WAL fsync).
293    Acting,
294    /// Awaiting the four-way terminal outcome.
295    Settling,
296    /// Capturing/localizing observations and evidence.
297    Observing,
298    /// Pure assertion evaluation.
299    Asserting,
300    /// Terminal: verdict folded (or no-verdict for unasserted mutations).
301    Judged,
302    /// Terminal: an `if` branch not taken.
303    Skipped,
304    /// Terminal: upstream failure with halt policy.
305    Blocked,
306    /// Resume probe failed; awaiting onResumeDrift disposition.
307    Drifted,
308    /// Suspended awaiting a human response (step or supervision purpose).
309    AwaitingHuman,
310    /// Run suspended while this step was in flight.
311    Suspended,
312    /// Terminal: aborted by handler or user decision.
313    Aborted,
314}
315
316/// Alignment classification of an old step record against the new IR
317/// (spine §6.7-A, closed five-value set).
318#[derive(
319    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
320)]
321#[serde(rename_all = "camelCase")]
322pub enum AlignmentClass {
323    /// Same effect and judge hash: record adopted as-is.
324    Reusable,
325    /// Judge hash changed only: offline re-judgement over archived evidence.
326    JudgeDirty,
327    /// Effect hash changed: record and its data-dependent downstream invalid.
328    EffectDirty,
329    /// Present in the new IR only; resume point must not pass it.
330    New,
331    /// Present in the old record only; archived, never adopted.
332    Orphaned,
333}
334
335/// Why a human interaction exists (R13, spine §6.1/A.4).
336#[derive(
337    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
338)]
339#[serde(rename_all = "camelCase")]
340pub enum HumanPurpose {
341    /// A `human` step declared in the IR.
342    Step,
343    /// A supervised-run gate before a mutating dispatch.
344    Supervision,
345}
346
347/// Supervised-run policy (R13, spine §6.9/A.4). Recorded per segment in
348/// `runStarted`/`runResumed` payloads; never enters any hash domain.
349#[derive(
350    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
351)]
352#[serde(rename_all = "camelCase")]
353pub enum SupervisePolicy {
354    /// Gate every mutating step.
355    Mutating,
356    /// Gate every action step.
357    All,
358}
359
360/// Human decision at a supervision gate (R13, spine §6.9/A.4; deliberately
361/// no `skip` — skipping a mutating step breaks data dependencies, changes
362/// go through the repair path instead).
363#[derive(
364    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
365)]
366#[serde(rename_all = "camelCase")]
367pub enum SupervisionDecision {
368    /// Write the actionIntent and dispatch.
369    Proceed,
370    /// Abort the run (no handler consulted — the human ruling is final).
371    Abort,
372    /// Suspend the run; the request stays pending across resume.
373    Suspend,
374}
375
376/// Reason DeviceRail fell back to coordinate execution inside the daemon
377/// (transparent passthrough of `CoordinateFallbackReason`, spine A.8).
378#[derive(
379    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
380)]
381#[serde(rename_all = "camelCase")]
382pub enum CoordinateFallbackReason {
383    /// The semantic interaction channel is unavailable for the target.
384    SemanticInteractionUnavailable,
385    /// The platform cannot express the semantic interaction.
386    PlatformLimitation,
387}
388
389/// Three-valued verdict status (spine A.4; `unknown` is never optimistically
390/// folded to `pass`, principle 4).
391#[derive(
392    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
393)]
394#[serde(rename_all = "camelCase")]
395pub enum VerdictStatus {
396    /// The assertion/step is confirmed to hold.
397    Pass,
398    /// The assertion/step is confirmed not to hold.
399    Fail,
400    /// Could not be confirmed either way.
401    Unknown,
402}
403
404/// Reason a screenshot was legitimately omitted from an observation
405/// (DeviceRail `ScreenshotOmissionReason`, spine A.8; omission is data,
406/// not an error — it degrades the verify chain toward `unknown`).
407#[derive(
408    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
409)]
410#[serde(rename_all = "camelCase")]
411pub enum ScreenshotOmissionReason {
412    /// Omitted by daemon policy.
413    Policy,
414    /// Omitted because a protected action was in flight.
415    ProtectedAction,
416}
417
418/// Reason a UI snapshot was legitimately omitted from an observation
419/// (DeviceRail `UiSnapshotOmissionReason`, spine A.8).
420#[derive(
421    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
422)]
423#[serde(rename_all = "camelCase")]
424pub enum UiSnapshotOmissionReason {
425    /// The driver has no semantic UI channel.
426    DriverUnsupported,
427    /// Omitted by daemon policy.
428    Policy,
429    /// Omitted because a protected action was in flight.
430    ProtectedAction,
431}