@wowok/skills 1.1.12 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -90,6 +90,21 @@ Before running this example, ensure you have:
90
90
 
91
91
  ---
92
92
 
93
+ ## Environment Parameters
94
+
95
+ All on-chain operations in this example use the following `env` fields:
96
+
97
+ | Field | Value | Purpose |
98
+ |-------|-------|---------|
99
+ | `network` | `"testnet"` | Target network |
100
+ | `account` | Account name | Signer account for the transaction |
101
+ | `no_cache` | `true` | Bypass local cache to avoid stale reads during sequential object creation. Without this, operations that depend on recently created objects may fail with "object not found". |
102
+ | `confirmed` | `true` | Explicitly confirm the on-chain transaction (MCP ConfirmGate). Required for all write operations. |
103
+
104
+ Additionally, `onChain: true` is required when an object's name needs to be resolved across different accounts (see Step 0.3).
105
+
106
+ ---
107
+
93
108
  ## Step 0: Setup Weather Data
94
109
 
95
110
  Before creating the travel service, set up the weather Repository with the next 5 days of weather data. The weather data is keyed by timestamp, and the `weather_check_guard` (Step 3.1) will query this repository at runtime when the customer enters the "Ice Scooting" node (Step 7.3). You must use timestamps that are valid at the time you run this example.
@@ -139,7 +154,9 @@ Day 5: 1783900800000 (2026-07-13T00:00:00.000Z)
139
154
  },
140
155
  "env": {
141
156
  "account": "weather_provider",
142
- "network": "testnet"
157
+ "network": "testnet",
158
+ "no_cache": true,
159
+ "confirmed": true
143
160
  }
144
161
  }
145
162
  ```
@@ -155,7 +172,8 @@ Day 5: 1783900800000 (2026-07-13T00:00:00.000Z)
155
172
  "object": {
156
173
  "name": "weather_repo",
157
174
  "permission": "weather_permission",
158
- "replaceExistName": true
175
+ "replaceExistName": true,
176
+ "onChain": true
159
177
  },
160
178
  "description": "Weather data repository for Iceland travel activities",
161
179
  "policies": {
@@ -173,11 +191,15 @@ Day 5: 1783900800000 (2026-07-13T00:00:00.000Z)
173
191
  },
174
192
  "env": {
175
193
  "account": "weather_provider",
176
- "network": "testnet"
194
+ "network": "testnet",
195
+ "no_cache": true,
196
+ "confirmed": true
177
197
  }
178
198
  }
179
199
  ```
180
200
 
201
+ > **Note**: `onChain: true` is required here because `weather_repo` is created by the `weather_provider` account, but its name will be referenced in the Guard table (Step 3.1) by the `travel_provider` account. Without `onChain: true`, the name is stored locally only on `weather_provider`'s device and cannot be resolved by `travel_provider`. When `onChain: true` is set, the name is published on-chain and becomes publicly visible, allowing cross-account name resolution.
202
+
181
203
  ### 0.4 Add Weather Data
182
204
 
183
205
  Add 5 days of weather data. The `weather_check_guard` (Step 3.1) only verifies that a record **exists** for the activity date (via `repository.data has`), so all 5 days will pass the Guard regardless of the condition value. The "rainy" value on Day 5 is informational only — to actually reject based on weather condition, you would need a Guard that queries `repository.data` and compares the value, which is more complex and not used in this example.
@@ -206,7 +228,9 @@ Add 5 days of weather data. The `weather_check_guard` (Step 3.1) only verifies t
206
228
  },
207
229
  "env": {
208
230
  "account": "weather_provider",
209
- "network": "testnet"
231
+ "network": "testnet",
232
+ "no_cache": true,
233
+ "confirmed": true
210
234
  }
211
235
  }
212
236
  ```
@@ -239,7 +263,9 @@ Create a Permission object to manage access control for the travel service. Add
239
263
  },
240
264
  "env": {
241
265
  "account": "travel_provider",
242
- "network": "testnet"
266
+ "network": "testnet",
267
+ "no_cache": true,
268
+ "confirmed": true
243
269
  }
244
270
  }
245
271
  ```
@@ -267,7 +293,9 @@ Create an Arbitration object for dispute resolution.
267
293
  },
268
294
  "env": {
269
295
  "account": "travel_provider",
270
- "network": "testnet"
296
+ "network": "testnet",
297
+ "no_cache": true,
298
+ "confirmed": true
271
299
  }
272
300
  }
273
301
  ```
@@ -337,7 +365,9 @@ repository.data has("Condition", convert_number_address(activity_date))
337
365
  },
338
366
  "env": {
339
367
  "account": "travel_provider",
340
- "network": "testnet"
368
+ "network": "testnet",
369
+ "no_cache": true,
370
+ "confirmed": true
341
371
  }
342
372
  }
343
373
  ```
@@ -409,7 +439,9 @@ clock > progress.current_time + 1000
409
439
  },
410
440
  "env": {
411
441
  "account": "travel_provider",
412
- "network": "testnet"
442
+ "network": "testnet",
443
+ "no_cache": true,
444
+ "confirmed": true
413
445
  }
414
446
  }
415
447
  ```
@@ -455,7 +487,9 @@ Creates a Guard that allows order cancellation. This Guard always passes (return
455
487
  },
456
488
  "env": {
457
489
  "account": "travel_provider",
458
- "network": "testnet"
490
+ "network": "testnet",
491
+ "no_cache": true,
492
+ "confirmed": true
459
493
  }
460
494
  }
461
495
  ```
@@ -507,7 +541,9 @@ Checks if order progress current node is "Complete". If passed, merchant receive
507
541
  },
508
542
  "env": {
509
543
  "account": "travel_provider",
510
- "network": "testnet"
544
+ "network": "testnet",
545
+ "no_cache": true,
546
+ "confirmed": true
511
547
  }
512
548
  }
513
549
  ```
@@ -583,7 +619,9 @@ Checks if progress current is "Cancel" or "Ice Scooting". If passed, merchant ge
583
619
  },
584
620
  "env": {
585
621
  "account": "travel_provider",
586
- "network": "testnet"
622
+ "network": "testnet",
623
+ "no_cache": true,
624
+ "confirmed": true
587
625
  }
588
626
  }
589
627
  ```
@@ -635,7 +673,9 @@ Checks if progress current is "SPA". If passed, merchant gets 5%, user gets 95%
635
673
  },
636
674
  "env": {
637
675
  "account": "travel_provider",
638
- "network": "testnet"
676
+ "network": "testnet",
677
+ "no_cache": true,
678
+ "confirmed": true
639
679
  }
640
680
  }
641
681
  ```
@@ -762,7 +802,9 @@ Create a Machine to define the travel service workflow with all nodes and forwar
762
802
  },
763
803
  "env": {
764
804
  "account": "travel_provider",
765
- "network": "testnet"
805
+ "network": "testnet",
806
+ "no_cache": true,
807
+ "confirmed": true
766
808
  }
767
809
  }
768
810
  ```
@@ -883,7 +925,9 @@ Create the travel service with all configurations and publish it in one operatio
883
925
  },
884
926
  "env": {
885
927
  "account": "travel_provider",
886
- "network": "testnet"
928
+ "network": "testnet",
929
+ "no_cache": true,
930
+ "confirmed": true
887
931
  }
888
932
  }
889
933
  ```
@@ -960,7 +1004,9 @@ The customer (Alice) purchases the travel package. This creates an Order, a Prog
960
1004
  },
961
1005
  "env": {
962
1006
  "account": "alice",
963
- "network": "testnet"
1007
+ "network": "testnet",
1008
+ "no_cache": true,
1009
+ "confirmed": true
964
1010
  }
965
1011
  }
966
1012
  ```
@@ -1284,7 +1330,7 @@ For refund scenarios (Cancel or SPA), use the corresponding Guard. The same subm
1284
1330
  "submission": [{"identifier": 0, "b_submission": true, "value_type": "Address", "value": "<ORDER_OBJECT_ID>", "name": "Order ID"}]
1285
1331
  }]
1286
1332
  },
1287
- "env": {"account": "travel_provider", "network": "testnet", "no_cache": true}
1333
+ "env": {"account": "travel_provider", "network": "testnet", "no_cache": true, "confirmed": true}
1288
1334
  }
1289
1335
  ```
1290
1336
 
@@ -1305,7 +1351,7 @@ For refund scenarios (Cancel or SPA), use the corresponding Guard. The same subm
1305
1351
  "submission": [{"identifier": 0, "b_submission": true, "value_type": "Address", "value": "<ORDER_OBJECT_ID>", "name": "Order ID"}]
1306
1352
  }]
1307
1353
  },
1308
- "env": {"account": "travel_provider", "network": "testnet", "no_cache": true}
1354
+ "env": {"account": "travel_provider", "network": "testnet", "no_cache": true, "confirmed": true}
1309
1355
  }
1310
1356
  ```
1311
1357
 
@@ -1440,6 +1486,6 @@ Customers place orders using the `order_new` field in the Service operation. Thi
1440
1486
  "namedNewAllocation": {"name": "allocation_name", "replaceExistName": true}
1441
1487
  }
1442
1488
  },
1443
- "env": {"account": "customer", "network": "testnet"}
1489
+ "env": {"account": "customer", "network": "testnet", "no_cache": true, "confirmed": true}
1444
1490
  }
1445
1491
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wowok/skills",
3
- "version": "1.1.12",
3
+ "version": "1.1.13",
4
4
  "description": "WoWok AI Skills for Claude and other AI assistants - Helping AI use WoWok MCP tools correctly",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -53,7 +53,30 @@ Every Guard is built from three layers, each with a distinct role:
53
53
 
54
54
  **The root is the question**: It must return Bool. Intermediate nodes return numbers, strings, addresses, or vectors. Guard is **strongly typed** — the type system is strictly enforced at creation time. Type mismatches (e.g., passing a string to a numeric comparison node) will cause validation errors and prevent Guard creation.
55
55
 
56
- **The rely is composition**: Up to 4 dependent Guards. When `rely.logic_or` is false (default), all dependencies must pass (AND). When true, any passing is sufficient (OR). A Guard can only depend on Guards with `rep: true` — `rep` is the Guard's internal flag indicating it has no external Repository dependency and can serve as a dependency. Guards with `rep: false` cannot appear in `rely` lists. Violations are caught by the contract layer at creation time.
56
+ **The rely is composition**: Up to 4 dependent Guards. When `rely.logic_or` is false (default), all dependencies must pass (AND). When true, any passing is sufficient (OR). A Guard can only depend on Guards with `rep: true` — `rep` indicates the Guard's `repository.data` queries (query 1167) do not depend on runtime submissions, so results are deterministic and the Guard can serve as a dependency. Guards with `rep: false` cannot appear in `rely` lists. Violations are caught by the contract layer at creation time.
57
+
58
+ ### Data Source 4 Classification — The Foundation of Guard Semantics
59
+
60
+ A Guard is fundamentally a **data computation tree**: deterministic data (on-chain constants + system context) + submitted data (runtime, semi-open) → derived through finite operation rules → a single boolean result. Every leaf node in the computation tree draws data from one of **4 data source classifications**. Understanding these 4 classifications is essential for designing and interpreting Guards.
61
+
62
+ | Type | Name | SDK Manifestation | Native Opcode | Trust Level | Typical Scenario |
63
+ |------|------|-------------------|---------------|-------------|------------------|
64
+ | **Type 1** | OnChainConstant | `query` + `identifier` (`b_submission: false`, no witness) | TYPE_QUERY + TYPE_CONSTANT | Highest | Query fields of already-published Service/Machine/Reward objects |
65
+ | **Type 2** | WitnessDerived | `query` + `identifier` + `convert_witness` (100-108) | TYPE_QUERY + witness_byte | High (source trusted + deterministic derivation) | Order → Progress query via witness=100 |
66
+ | **Type 3** | SubmittedObject | `query` + `identifier` (`b_submission: true`, no witness) | TYPE_QUERY + TYPE_CONSTANT | Medium (requires constraint rules) | User submits Order address for field query |
67
+ | **Type 4** | SystemContext | `context` (Signer/Clock/Guard) | TYPE_SIGNER / TYPE_CLOCK / TYPE_GUARD | Highest | Identity verification, time-locks |
68
+
69
+ **Key insights**:
70
+ 1. **Type 1 and Type 3 are isomorphic at the native layer** — both use TYPE_QUERY+TYPE_CONSTANT; the only difference is the `b_submission` flag (false vs true)
71
+ 2. **Type 2 can overlay on Type 1 or Type 3** — the source object can be a constant (Type 1) or a submission (Type 3), then witness derives the target object
72
+ 3. **Type 4 is fully independent** — does not depend on the table
73
+ 4. **Except for Type 4, all data must be declared in the table** — the table is the complete data contract between Guard and caller
74
+
75
+ **The table as data contract**: The table declares:
76
+ - **Deterministic data** (`b_submission: false`): type + value, baked at creation, immutable
77
+ - **Submitted data** (`b_submission: true`): type only (1-byte placeholder), value provided by caller at runtime — **must have constraint rules designed, otherwise empty data is meaningless**
78
+
79
+ **Guard essence**: A deterministic data set (Type 1 + Type 4) + submitted data (Type 3, must have constraint rules and defined types) → derived through finite operation rules → a single boolean result. The semantics are deterministic — you only need to fill in the "data object source meaning" and "field meaning" (e.g., "the permission address of service A", "the current node time of workflow B").
57
80
 
58
81
  ### Where Guards Attach in the Ecosystem
59
82
 
@@ -148,26 +171,43 @@ The Guard table is the **complete declaration of information** the Guard consume
148
171
  - **No duplicate identifiers.** Each index number must appear exactly once.
149
172
  - **Non-submission entries must have a value.** These are baked into the Guard immutably.
150
173
  - **Submission entries use placeholder values.** The actual value is provided by the caller at runtime.
151
- - **Query target objects must be of type Address in the table.** Their `object_type` field should match the expected query target type (Progress, Order, Machine, Reward, etc.).
174
+ - **Query target objects must be of type Address in the table.** The `object_type` field is **automatically filled by the SDK** based on the first query node referencing this identifier (it is NOT a user-provided field). The SDK infers the object type from the query instruction's target object type (Progress, Order, Machine, Reward, etc.).
152
175
  - **Querying EntityRegistrar or EntityLinker requires system address table entries.** Add entries for `ENTITY_REGISTRAR_ADDRESS` (`0xaab`) or `ENTITY_LINKER_ADDRESS` (`0xaaa`) to the table as Address-type constants when your query instruction targets these global registries. Without them, creation fails.
153
176
  - **Maximum 256 table entries** (identifiers 0–255). The total serialized table size must not exceed 40000 bytes.
154
177
  - **Submission entries must have descriptive `name` values.** For `b_submission: true` entries, `name` is the contract between Guard and caller — it tells callers what data they must provide. Use natural language that explains the purpose and necessity: "The order ID that identifies the target Order for verification" not `"order_id"`, "The signer's account address that will be compared against the authorized list" not `"addr"`. This is critical because callers see only this name when submitting data.
155
178
 
156
179
  ### The convert_witness Mechanism
157
180
 
158
- `convert_witness` transforms a submitted object ID into its associated object — enabling queries across object relationships without requiring the caller to submit multiple IDs.
181
+ `convert_witness` transforms a source object ID into its associated target object — enabling queries across object relationships without requiring the caller to submit multiple IDs. This is the **Type 2 (WitnessDerived)** data source.
159
182
 
160
- **Core principle**: Caller submits what they have (e.g., Order ID); Guard queries what it needs (e.g., Progress state) via witness conversion.
183
+ **Core principle**: Witness is a "read the source object's associated field" mechanism (not a lookup table, not an independent index). It is a one-to-one deterministic derivation of object relationships with only 9 derivation types. Caller submits what they have (e.g., Order ID); Guard queries what it needs (e.g., Progress state) via witness conversion.
161
184
 
162
185
  **Rules**:
163
186
  - Witness type encodes source→target transformation
164
- - Table entry's `object_type` must match witness source type
187
+ - Table entry's `object_type` (auto-filled by SDK) must match witness source type
165
188
  - Query instruction's object type must match witness target type
166
189
  - Type mismatches cause Guard creation to fail
167
-
168
- **Available witness types** are defined in the schema — query `wowok_buildin_info` with info `"guard instructions"` for the complete list with use cases.
169
-
170
- **Notable**: `TypeArbArbitration (105)`: Arb and Arbitration are **different on-chain objects**. The witness queries the Arbitration (parent service) from an Arb (case) address — the binding is set when Arbitration creates the Arb. Schema describes this as "access arbitration configuration or fee settings."
190
+ - Multi-hop witnesses (106-108) require intermediate objects to exist
191
+
192
+ **Complete 9 witness types** (defined in `guard.rs#L34-L65`):
193
+
194
+ | Code | Name | Source → Target | Derivation | Hops |
195
+ |------|------|-----------------|------------|------|
196
+ | 100 | TypeOrderProgress | Order → Progress | read order.progress field | 1 |
197
+ | 101 | TypeOrderMachine | Order → Machine | read order.machine field | 1 |
198
+ | 102 | TypeOrderService | Order → Service | read order.service field | 1 |
199
+ | 103 | TypeProgressMachine | Progress → Machine | read progress.machine field | 1 |
200
+ | 104 | TypeArbOrder | Arb → Order | read arb.order field | 1 |
201
+ | 105 | TypeArbArbitration | Arb → Arbitration | read arb.arbitration field | 1 |
202
+ | 106 | TypeArbProgress | Arb → Progress | arb.order → order.progress | 2 (multi-hop) |
203
+ | 107 | TypeArbMachine | Arb → Machine | arb.order → order.machine | 2 (multi-hop) |
204
+ | 108 | TypeArbService | Arb → Service | arb.order → order.service | 2 (multi-hop) |
205
+
206
+ **Key notes**:
207
+ - **Type 2 can overlay on Type 1 or Type 3**: The source object can be a constant (Type 1, `b_submission: false`) or a submission (Type 3, `b_submission: true`). The witness then derives the target object.
208
+ - **Multi-hop witnesses (106-108)**: Arb → Progress/Machine/Service uses two hops (Arb → Order → target). The intermediate Order object must exist for the derivation to succeed.
209
+ - **TypeArbArbitration (105)**: Arb and Arbitration are **different on-chain objects**. The witness queries the Arbitration (parent service) from an Arb (case) address — the binding is set when Arbitration creates the Arb.
210
+ - **Available witness types** are also discoverable via `wowok_buildin_info` with info `"guard instructions"`.
171
211
 
172
212
  ---
173
213
 
@@ -281,6 +321,8 @@ Machine's forward `guard` validates state transitions. If `retained_submission`
281
321
 
282
322
  Repository's `write_guard` validates writes. If `id_from_submission` is set, reads entity ID from that submission index — **the index must be Address type**. If `data_from_submission` is set, reads data value from that index — **the value type must match the Repository's declared value_type**. Guard table must include entries for the data being extracted.
283
323
 
324
+ **Important — impack_list semantics in verify phase**: When a Guard queries Repository data (query 1167 `repository.data`) with a policy that has a `quote_guard` set, the verification checks whether the quote_guard address is in the `impack_list`. However, `impack_list` is **always empty during the `verify_guard` phase** — `Passport.new()` initializes `impack:vector[]` and the verify loop never modifies it; `impack` is only populated in `result_for_permission` (after verify completes). This means a Repository query with `quote_guard = Some(addr)` will always fail with `IMPACK_GUARD_NOT_FOUND` in the gen_passport flow; only `quote_guard = None` passes. Verify the quote_guard mechanism's design intent before relying on it.
325
+
284
326
  ---
285
327
 
286
328
  **Key Principle**: Design your Guard table based on what data the target object needs to read. Objects don't just validate — they consume Guard submissions as structured data inputs.
@@ -303,25 +345,89 @@ Each object extracts Guard data with precise type expectations. Mismatches cause
303
345
 
304
346
  ### Common Pitfalls
305
347
 
306
- 1. **Undefined table identifiers**: Every `identifier` node in the tree must match an entry in the table. Missing entries cause creation failure validate your tree against your table before submitting.
348
+ > The full constraint system has **33 rules: 22 creation-phase + 11 runtime-phase**. The 22 creation-phase constraints below are all enforced by SDK + native `validate_guard_data`; runtime constraints are enforced by native `verify_guard`.
349
+
350
+ #### Creation-Phase Constraints (22 items, enforced by SDK + native `validate_guard_data`)
351
+
352
+ **Root (1 item)**
353
+
354
+ 1. **ROOT_01 — Root must return Bool**: The outermost node of the tree must produce Bool. Logic and comparison nodes return Bool; arithmetic, conversion, and string operation nodes do not. Ensure your tree terminates at a logic or comparison node — the creation validation will reject non-Bool roots.
355
+
356
+ **Table (5 items)**
357
+
358
+ 2. **TABLE_01 — Identifier uniqueness**: Every `identifier` in the table must be unique (0–255). Duplicate identifiers cause creation failure. SDK uses `lodash.groupBy` to detect duplicates.
359
+
360
+ 3. **TABLE_02 — Identifier referential integrity**: Every `identifier` node in the computation tree must match an entry in the table. Missing entries cause creation failure — validate your tree against your table before submitting.
361
+
362
+ 4. **TABLE_03 — Constant value non-empty**: When `b_submission=false`, the `value` field must be non-empty. These values are baked into the Guard immutably at creation time.
363
+
364
+ 5. **TABLE_04 — Table size limits**: Maximum 256 table entries (identifiers 0–255), and the total serialized table size must not exceed 40000 bytes (BCS). Enforced by Move `guard::new`.
365
+
366
+ 6. **TABLE_05 — Submission value is 1-byte type code**: When `b_submission=true`, the `value` field is only a 1-byte type code placeholder (the actual value is provided at runtime). Enforced by native `deserialize_constants`.
367
+
368
+ **Query (4 items)**
369
+
370
+ 7. **QUERY_01 — Query instruction ID valid**: Query instruction IDs are system-defined. Always discover them through `wowok_buildin_info` with info `"guard instructions"`. Invalid IDs cause creation failure.
371
+
372
+ 8. **QUERY_02 — Parameter count matches**: The parameter count and types in your query node must match the instruction exactly — off-by-one parameter counts are a common failure.
373
+
374
+ 9. **QUERY_03 — Return type compatible**: The query node's return type must be compatible with the parent node's expected input. A `logic_equal` comparing a String to a U64 fails validation. Use explicit conversion nodes (`convert_string_number`, `convert_number_string`) when types differ. Numeric comparisons use `logic_as_u256_*` variants which auto-widen to U256.
375
+
376
+ 10. **QUERY_04 — Object identifier is Address type**: The table entry referenced by a query node's `object.identifier` must have `value_type: Address`. SDK `buildNode` validates this at L603-609.
377
+
378
+ **Witness (3 items)**
379
+
380
+ 11. **WITNESS_01 — Witness type valid (100-108)**: The `convert_witness` value must be one of the 9 valid witness types (100-108). Invalid witness types cause creation failure.
381
+
382
+ 12. **WITNESS_02 — Witness target matches query objectType**: The witness's target object type must match the query instruction's expected object type. For example, `TypeOrderProgress` (100) derives a Progress, so the query must target a Progress object. SDK `buildNode` validates this at L613-619.
383
+
384
+ 13. **WITNESS_03 — Witness source matches table object_type**: If the table entry has an `object_type` declared (auto-filled by SDK), it must match the witness's source object type. For example, `TypeOrderProgress` (100) expects an Order source, so the table entry's `object_type` must be Order. SDK `buildNode` validates this at L622-631. **Missing convert_witness** is a related failure: when accessing Progress data from an Order ID, the query node needs `convert_witness` with the appropriate witness type. Without it, the runtime looks for a Progress at the Order's address — which does not exist as a Progress object.
385
+
386
+ **Rely (3 items)**
387
+
388
+ 14. **RELY_01 — Dependency count ≤ 4**: A Guard can depend on at most 4 other Guards (`MAX_DEPENDED_COUNT`). SDK `reliesAdd` enforces this limit.
389
+
390
+ 15. **RELY_02 — Dependencies must have rep=true**: A Guard's `rely` entries must reference Guards with `rep: true` — meaning their `repository.data` queries do not depend on runtime submissions. Guards that depend on a Repository via submitted addresses (`rep: false`) cannot serve as dependencies. Move `guard::relies_add` catches violations at creation time.
391
+
392
+ 16. **RELY_03 — No self-reference**: A Guard cannot depend on itself. SDK `reliesAdd` prevents self-referential rely entries.
393
+
394
+ **Binding (3 items)**
395
+
396
+ 17. **BINDING_01 — voting_guard GuardIdentifier must be numeric**: When using `GuardIdentifier` for Arbitration `voting_guard`, the referenced table entry must have a numeric `value_type` (U8–U256). The system checks this when the VotingGuard is added to the Arbitration — if the identifier does not exist or is non-numeric, the operation reverts with `E_GUARD_IDENTIFIER_NOT_NUMBER`.
397
+
398
+ 18. **BINDING_02 — Repository id_from_submission must be Address**: When a Repository `write_guard` uses `id_from_submission`, the referenced table entry must have `value_type: Address`. Move Repository enforces this at binding time.
399
+
400
+ 19. **BINDING_03 — Repository data_from_submission type must match**: When a Repository `write_guard` uses `data_from_submission`, the referenced table entry's `value_type` must match the Repository's declared `value_type`. Move Repository enforces this at binding time.
401
+
402
+ **Input (2 items)**
307
403
 
308
- 2. **Type mismatches in comparison nodes**: A `logic_equal` comparing a String to a U64 fails validation. Use explicit conversion nodes (`convert_string_number`, `convert_number_string`) when types differ. Numeric comparisons use `logic_as_u256_*` variants which auto-widen to U256.
404
+ 20. **INPUT_01 Root bytecode non-empty**: The serialized root computation tree must not be empty. SDK `newGuard` validates this before submission.
309
405
 
310
- 3. **Wrong query instruction IDs or parameter counts**: Query instructions are system-defined. Always discover them through `wowok_buildin_info` with info `"guard instructions"`. The parameter count and types in your query node must match the instruction exactly — off-by-one parameter counts are a common failure.
406
+ 21. **INPUT_02 Root bytecode size MAX_INPUT_SIZE**: The serialized root computation tree must not exceed `MAX_INPUT_SIZE`. SDK `newGuard` validates this before submission.
311
407
 
312
- 4. **Missing convert_witness**: When accessing Progress data from an Order ID in the table, the query node needs `convert_witness` with the appropriate witness type. Without it, the runtime looks for a Progress at the Order's address — which does not exist as a Progress object. The creation-time validation catches this mismatch.
408
+ **Immutable (1 item)**
313
409
 
314
- 5. **Testing with production durations**: Set time-lock durations to small values (e.g., 1000 milliseconds) during testing. Increase to production values only after verifying the logic works correctly. A Guard with a 30-day lock tested with real durations cannot produce results for a month.
410
+ 22. **IMMUTABLE_01 Guard becomes immutable after creation**: Once `guard::create` is called, the Guard's `immutable` flag is set to `true` and no further modifications are possible. This is the foundation of the immutability contract to change a Guard, export via `guard2file`, create a new Guard, and update all references.
315
411
 
316
- 6. **Forgetting to export before recreating**: Guards are immutable. If you need to change one, export it first with `guard2file` so you have the exact on-chain definition as a reference. Then create a new Guard with a versioned name and update all references.
412
+ #### Practical Tips (not strict constraints, but strongly recommended)
317
413
 
318
- 7. **Root not returning Bool**: The outermost node of the tree must produce Bool. Logic and comparison nodes return Bool; arithmetic, conversion, and string operation nodes do not. Ensure your tree terminates at a logic or comparison node the creation validation will reject non-Bool roots.
414
+ - **Testing with production durations**: Set time-lock durations to small values (e.g., 1000 milliseconds) during testing. Increase to production values only after verifying the logic works correctly. A Guard with a 30-day lock tested with real durations cannot produce results for a month.
415
+ - **Forgetting to export before recreating**: Guards are immutable. If you need to change one, export it first with `guard2file` so you have the exact on-chain definition as a reference. Then create a new Guard with a versioned name and update all references.
416
+ - **Not checking Arbitration pause state**: Even with a valid usage_guard Passport, the dispute fails if the Arbitration is paused (`bPaused: true`). The pause check happens before the guard check — advise customers to verify the Arbitration is active before generating Passports.
319
417
 
320
- 8. **Dependency on non-standalone Guards**: A Guard's `rely` entries must reference Guards with `rep: true` — meaning they have no external Repository dependency. Guards that depend on a Repository (`rep: false`) cannot serve as dependencies. The contract layer catches violations at creation time.
418
+ #### Runtime-Phase Constraints (enforced by native `verify_guard`)
321
419
 
322
- 9. **Forgetting voting_guard weight type validation**: When using `GuardIdentifier`, the referenced identifier must exist in the guard's table and its value type must be numeric. The system checks this when the VotingGuard is added to the Arbitration — if the identifier does not exist or is non-numeric, the operation reverts with `E_GUARD_IDENTIFIER_NOT_NUMBER`.
420
+ These constraints are checked at Guard verification time (gen_passport or actual usage), not at creation. They are often overlooked because creation succeeds but runtime fails:
323
421
 
324
- 10. **Not checking Arbitration pause state**: Even with a valid usage_guard Passport, the dispute fails if the Arbitration is paused (`bPaused: true`). The pause check happens before the guard check advise customers to verify the Arbitration is active before generating Passports.
422
+ - **RUN_IMMUTABLE_01**: Guard must have `immutable=true` to be verified. A Guard that hasn't been finalized via `guard::create` cannot be used.
423
+ - **RUN_SUB_01**: The submission's `value[0]` (type byte) must match the table declaration. A submission with the wrong type byte is rejected.
424
+ - **RUN_SUB_02**: Every table entry with `b_submission=true` must have a corresponding submission value. Missing submissions cause failure.
425
+ - **RUN_SUB_03**: Total submission bytes must be ≤ `MAX_SUBMISSION_SIZE` (256).
426
+ - **RUN_WITNESS_01/02**: When witness conversion runs, the source object must have the associated field, and the derived target object must exist. Multi-hop witnesses (106-108) require the intermediate Order object to exist.
427
+ - **RUN_QUERY_01**: The query target object must exist and its type must match.
428
+ - **RUN_IMPACK_01/02**: At least one impack guard is required; an impack guard failure fails the entire passport. **Note**: `impack_list` is always empty during verify (see Repository section above), so quote_guard queries will fail unless `quote_guard = None`.
429
+ - **RUN_TX_01**: The Passport's `tx_hash` must match the current transaction.
430
+ - **RUN_RELY_01**: Rely guards must have been added to the passport.
325
431
 
326
432
  ---
327
433