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}