@wowok/agent-mcp 3.1.6 → 3.2.0

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.
Files changed (235) hide show
  1. package/dist/config/exposure.d.ts +10 -10
  2. package/dist/config/judgment.d.ts +25 -25
  3. package/dist/config/rule-engine.d.ts +25 -25
  4. package/dist/customer/user-preferences.d.ts +2 -2
  5. package/dist/evaluation/arbitration-game.js +1 -1
  6. package/dist/evaluation/capability.d.ts +1 -1
  7. package/dist/evaluation/extract.js +1 -1
  8. package/dist/evaluation/match-operation.js +1 -1
  9. package/dist/extensions/industry-pack.d.ts +3 -2
  10. package/dist/extensions/industry-pack.js +1 -1
  11. package/dist/extensions/modes.js +1 -1
  12. package/dist/extensions/registry.js +1 -1
  13. package/dist/extensions/types.d.ts +1 -0
  14. package/dist/graph/onchain/analyze.js +1 -1
  15. package/dist/graph/onchain/analyze.spec.js +1 -1
  16. package/dist/graph/onchain/edge-schema.js +1 -1
  17. package/dist/graph/onchain/extract.js +1 -1
  18. package/dist/graph/onchain/field-manifest.js +1 -1
  19. package/dist/graph/onchain/project-relationship.js +1 -1
  20. package/dist/graph/onchain/types.d.ts +1 -1
  21. package/dist/harness/recover.js +1 -1
  22. package/dist/keeper/KeeperScan.d.ts +2 -1
  23. package/dist/keeper/KeeperScan.js +1 -1
  24. package/dist/keeper/detectors.d.ts +9 -0
  25. package/dist/keeper/detectors.js +1 -1
  26. package/dist/keeper/keeper.spec.js +1 -1
  27. package/dist/keeper/types.d.ts +1 -1
  28. package/dist/keeper/types.js +1 -1
  29. package/dist/knowledge/allocation-ledger.d.ts +4 -1
  30. package/dist/knowledge/allocation-ledger.js +1 -1
  31. package/dist/knowledge/allocation-puzzle.d.ts +2 -0
  32. package/dist/knowledge/allocation-puzzle.js +1 -1
  33. package/dist/knowledge/allocation-risk.d.ts +1 -1
  34. package/dist/knowledge/allocation-risk.js +1 -1
  35. package/dist/knowledge/arb-risk.d.ts +3 -1
  36. package/dist/knowledge/arb-risk.js +1 -1
  37. package/dist/knowledge/arbitration-ledger.js +1 -1
  38. package/dist/knowledge/arbitration-risk.js +1 -1
  39. package/dist/knowledge/arbitration-templates.d.ts +1 -0
  40. package/dist/knowledge/arbitration-templates.js +1 -1
  41. package/dist/knowledge/audit-rules.d.ts +13 -2
  42. package/dist/knowledge/audit-rules.js +1 -1
  43. package/dist/knowledge/baselines/rules/allocation.json +50 -1
  44. package/dist/knowledge/baselines/rules/arb.json +20 -1
  45. package/dist/knowledge/baselines/rules/arbitration.json +27 -0
  46. package/dist/knowledge/baselines/rules/guard.json +75 -2
  47. package/dist/knowledge/baselines/rules/machine.json +38 -13
  48. package/dist/knowledge/baselines/rules/order.json +2 -2
  49. package/dist/knowledge/builtin-templates.d.ts +3 -1
  50. package/dist/knowledge/builtin-templates.js +1 -1
  51. package/dist/knowledge/event-semantics.js +1 -1
  52. package/dist/knowledge/fund-layer.js +1 -1
  53. package/dist/knowledge/getting-started.js +1 -1
  54. package/dist/knowledge/guard-anchor-reach.d.ts +19 -0
  55. package/dist/knowledge/guard-anchor-reach.js +1 -0
  56. package/dist/knowledge/guard-bindings.js +1 -1
  57. package/dist/knowledge/guard-design-patterns.d.ts +1 -1
  58. package/dist/knowledge/guard-design-patterns.js +1 -1
  59. package/dist/knowledge/guard-ledger.js +1 -1
  60. package/dist/knowledge/guard-lint.js +1 -1
  61. package/dist/knowledge/guard-render.d.ts +6 -0
  62. package/dist/knowledge/guard-render.js +1 -1
  63. package/dist/knowledge/guard-risk.js +1 -1
  64. package/dist/knowledge/guard-submission-prompt.d.ts +6 -0
  65. package/dist/knowledge/guard-submission-prompt.js +1 -1
  66. package/dist/knowledge/guard-templates.d.ts +1 -1
  67. package/dist/knowledge/guard-templates.js +1 -1
  68. package/dist/knowledge/index.d.ts +4 -4
  69. package/dist/knowledge/index.js +1 -1
  70. package/dist/knowledge/industry-generalizer.js +1 -1
  71. package/dist/knowledge/industry-registry.d.ts +1 -1
  72. package/dist/knowledge/industry-registry.js +1 -1
  73. package/dist/knowledge/jsonrpc-enum.js +1 -1
  74. package/dist/knowledge/machine-ledger.js +1 -1
  75. package/dist/knowledge/machine-risk.js +1 -1
  76. package/dist/knowledge/machine-templates.js +1 -1
  77. package/dist/knowledge/order-ledger.js +1 -1
  78. package/dist/knowledge/order-templates.js +1 -1
  79. package/dist/knowledge/permission-ledger.js +1 -1
  80. package/dist/knowledge/release-sentinel.d.ts +12 -0
  81. package/dist/knowledge/release-sentinel.js +1 -0
  82. package/dist/knowledge/repository-write-semantics.d.ts +27 -0
  83. package/dist/knowledge/repository-write-semantics.js +1 -0
  84. package/dist/knowledge/rule-node-analyzers.d.ts +6 -0
  85. package/dist/knowledge/rule-node-analyzers.js +1 -1
  86. package/dist/knowledge/safety-rules.d.ts +5 -1
  87. package/dist/knowledge/safety-rules.js +1 -1
  88. package/dist/knowledge/scenario-modes.d.ts +10 -1
  89. package/dist/knowledge/scenario-modes.js +1 -1
  90. package/dist/knowledge/service-allocation-semantics.d.ts +36 -0
  91. package/dist/knowledge/service-allocation-semantics.js +1 -0
  92. package/dist/knowledge/strategy-manuals.d.ts +3 -5
  93. package/dist/knowledge/strategy-manuals.js +1 -1
  94. package/dist/knowledge/template-loader.d.ts +28 -12
  95. package/dist/knowledge/template-loader.js +1 -1
  96. package/dist/knowledge/template-registry.js +1 -1
  97. package/dist/knowledge/template-scanner.js +1 -1
  98. package/dist/knowledge/tools-reference.js +1 -1
  99. package/dist/knowledge/workflow-guidance.d.ts +26 -0
  100. package/dist/knowledge/workflow-guidance.js +1 -1
  101. package/dist/monitor/MonitorLoop.js +1 -1
  102. package/dist/participation/allocation-advice.d.ts +38 -0
  103. package/dist/participation/allocation-advice.js +1 -0
  104. package/dist/participation/radar-core.d.ts +2 -0
  105. package/dist/persona/types.d.ts +3 -2
  106. package/dist/persona/types.js +1 -1
  107. package/dist/playbooks/service-build/business-puzzle.js +1 -1
  108. package/dist/playbooks/service-build/intent-analyzer.js +1 -1
  109. package/dist/playbooks/service-build/merchant-guide.d.ts +70 -63
  110. package/dist/playbooks/service-build/merchant-guide.js +1 -1
  111. package/dist/playbooks/service-build/migration-planner.js +1 -1
  112. package/dist/playbooks/service-build/mode-actions.d.ts +5 -0
  113. package/dist/playbooks/service-build/mode-actions.js +1 -1
  114. package/dist/playbooks/service-build/participation-radar.js +1 -1
  115. package/dist/playbooks/service-build/semantic-graph.d.ts +1 -0
  116. package/dist/playbooks/service-build/semantic-graph.js +1 -1
  117. package/dist/playbooks/service-build/service-quote.d.ts +2 -0
  118. package/dist/playbooks/service-build/service-quote.js +1 -0
  119. package/dist/relationship/derivation.d.ts +1 -1
  120. package/dist/safety/confirm-gate.js +1 -1
  121. package/dist/schema/benchmark-migration/index.d.ts +30 -8
  122. package/dist/schema/benchmark-migration/index.js +1 -1
  123. package/dist/schema/call/allocation.d.ts +6 -3
  124. package/dist/schema/call/arbitration.js +1 -1
  125. package/dist/schema/call/base.d.ts +4 -0
  126. package/dist/schema/call/base.js +1 -1
  127. package/dist/schema/call/bridge.d.ts +1 -0
  128. package/dist/schema/call/error-codes.d.ts +1 -1
  129. package/dist/schema/call/error-codes.js +1 -1
  130. package/dist/schema/call/guard.d.ts +8 -8
  131. package/dist/schema/call/machine.d.ts +56 -0
  132. package/dist/schema/call/machine.js +1 -1
  133. package/dist/schema/call/order.js +1 -1
  134. package/dist/schema/call/payment.js +1 -1
  135. package/dist/schema/call/semantic.js +1 -1
  136. package/dist/schema/call/service.d.ts +84 -22
  137. package/dist/schema/call/service.js +1 -1
  138. package/dist/schema/common/index.js +1 -1
  139. package/dist/schema/common/tokentype-short-probe.spec.js +1 -0
  140. package/dist/schema/evaluation/index.d.ts +8 -80
  141. package/dist/schema/evaluation/index.js +1 -1
  142. package/dist/schema/goal/index.d.ts +9 -42
  143. package/dist/schema/goal/planning.d.ts +25 -60
  144. package/dist/schema/goal/planning.js +1 -1
  145. package/dist/schema/intent-radar/index.d.ts +2 -20
  146. package/dist/schema/intent-radar/index.js +1 -1
  147. package/dist/schema/interaction/index.d.ts +1 -1
  148. package/dist/schema/keeper/index.d.ts +3 -0
  149. package/dist/schema/keeper/index.js +1 -1
  150. package/dist/schema/local/index.d.ts +8 -0
  151. package/dist/schema/local/index.js +1 -1
  152. package/dist/schema/local/wip.d.ts +73 -0
  153. package/dist/schema/local/wip.js +1 -1
  154. package/dist/schema/operations.d.ts +92 -14
  155. package/dist/schema/operations.js +1 -1
  156. package/dist/schema/persona/index.d.ts +279 -384
  157. package/dist/schema/persona/index.js +1 -1
  158. package/dist/schema/query/bi.d.ts +149 -10
  159. package/dist/schema/query/bi.js +1 -1
  160. package/dist/schema/query/index.d.ts +38 -19
  161. package/dist/schema/query/index.js +1 -1
  162. package/dist/schema/schema-query/index.d.ts +4 -4
  163. package/dist/schema/schema-version.js +1 -1
  164. package/dist/schema/watch/index.d.ts +2 -2
  165. package/dist/schema-query-impl/index.d.ts +1 -0
  166. package/dist/schema-query-impl/index.js +1 -1
  167. package/dist/schemas/account_operation.output.json +3 -2
  168. package/dist/schemas/benchmark_migration_operation.output.json +116 -2
  169. package/dist/schemas/benchmark_migration_operation.schema.json +2 -10
  170. package/dist/schemas/bridge_operation.output.json +3 -2
  171. package/dist/schemas/evaluation_operation.schema.json +7 -70
  172. package/dist/schemas/goal_operation.schema.json +6 -39
  173. package/dist/schemas/index.json +1 -1
  174. package/dist/schemas/intent_radar.output.json +4 -20
  175. package/dist/schemas/keeper_operation.output.json +2 -2
  176. package/dist/schemas/keeper_operation.schema.json +9 -4
  177. package/dist/schemas/local_history_operation.output.json +3 -2
  178. package/dist/schemas/local_info_operation.output.json +3 -2
  179. package/dist/schemas/local_mark_operation.output.json +3 -2
  180. package/dist/schemas/messenger_operation.output.json +2 -2
  181. package/dist/schemas/monitor_events.output.json +2 -2
  182. package/dist/schemas/monitor_subscription.output.json +2 -2
  183. package/dist/schemas/onchain_events.output.json +2 -2
  184. package/dist/schemas/onchain_operations.output.json +7 -6
  185. package/dist/schemas/onchain_operations.schema.json +227 -54
  186. package/dist/schemas/onchain_operations_allocation.schema.json +11 -10
  187. package/dist/schemas/onchain_operations_arbitration.schema.json +13 -13
  188. package/dist/schemas/onchain_operations_machine.schema.json +27 -5
  189. package/dist/schemas/onchain_operations_order.schema.json +1 -1
  190. package/dist/schemas/onchain_operations_payment.schema.json +2 -2
  191. package/dist/schemas/onchain_operations_reward.schema.json +1 -1
  192. package/dist/schemas/onchain_operations_service.schema.json +171 -21
  193. package/dist/schemas/onchain_operations_treasury.schema.json +1 -1
  194. package/dist/schemas/onchain_table_data.output.json +57 -4
  195. package/dist/schemas/persona_operation.output.json +11 -88
  196. package/dist/schemas/persona_operation.schema.json +4 -32
  197. package/dist/schemas/query_toolkit.output.json +320 -22
  198. package/dist/schemas/query_toolkit.schema.json +53 -0
  199. package/dist/schemas/wip_file.output.json +221 -0
  200. package/dist/schemas/wip_file.schema.json +125 -0
  201. package/dist/tools/handlers/benchmark-migration.js +1 -1
  202. package/dist/tools/handlers/config.js +1 -1
  203. package/dist/tools/handlers/dispatch-expectations.spec.js +1 -1
  204. package/dist/tools/handlers/keeper.d.ts +1 -1
  205. package/dist/tools/handlers/onchain.js +1 -1
  206. package/dist/tools/handlers/query.js +1 -1
  207. package/dist/tools/handlers/schema-query.js +1 -1
  208. package/dist/tools/handlers/wip-upload.d.ts +22 -0
  209. package/dist/tools/handlers/wip-upload.js +1 -0
  210. package/dist/tools/handlers/wip.js +1 -1
  211. package/dist/tools/index.js +1 -1
  212. package/dist/tools/move-fn-index.gen.js +1 -1
  213. package/dist/tools/registry/business.js +1 -1
  214. package/dist/tools/registry/files.js +1 -1
  215. package/dist/tools/wip-deploy-assist.js +1 -1
  216. package/dist/tools/wrap.js +1 -1
  217. package/package.json +2 -2
  218. package/dist/knowledge/alloc-audit-policy.spec.js +0 -1
  219. package/dist/knowledge/event-semantics.spec.d.ts +0 -1
  220. package/dist/knowledge/event-semantics.spec.js +0 -1
  221. package/dist/knowledge/facts-sync.spec.d.ts +0 -1
  222. package/dist/knowledge/facts-sync.spec.js +0 -1
  223. package/dist/knowledge/guard-design-patterns.spec.d.ts +0 -1
  224. package/dist/knowledge/guard-design-patterns.spec.js +0 -1
  225. package/dist/knowledge/guard-eval.spec.d.ts +0 -1
  226. package/dist/knowledge/guard-eval.spec.js +0 -1
  227. package/dist/knowledge/rule-node-analyzers.spec.d.ts +0 -1
  228. package/dist/knowledge/rule-node-analyzers.spec.js +0 -1
  229. package/dist/knowledge/safety-rules.extract-amount.spec.d.ts +0 -1
  230. package/dist/knowledge/safety-rules.extract-amount.spec.js +0 -1
  231. package/dist/knowledge/template-loader.spec.d.ts +0 -1
  232. package/dist/knowledge/template-loader.spec.js +0 -1
  233. package/dist/knowledge/template-scanner.spec.d.ts +0 -1
  234. package/dist/knowledge/template-scanner.spec.js +0 -1
  235. /package/dist/{knowledge/alloc-audit-policy.spec.d.ts → schema/common/tokentype-short-probe.spec.d.ts} +0 -0
@@ -12,6 +12,15 @@
12
12
  "rate_rule_pure": "Pure Rate mode (no Surplus) with sum > 0 and sum != RATE_TOTAL_FULL.",
13
13
  "rate_rule_exceed": "Rate + Surplus mode with rate sum > RATE_TOTAL_FULL.",
14
14
  "rate_total_full": "KERNEL CONSTANT — full rate denominator (RATE_TOTAL_FULL = 10000).",
15
+ "rate_gross_branch": "First pure-RateGross allocator (no NET Rate) whose gross plan cannot be paid: 'sum_exceeds_10000' | 'cap_fit' | 'fixed_full' (undefined when none).",
16
+ "rate_gross_index": "Allocator index of the RateGross-rule offender.",
17
+ "rate_gross_guard": "Guard address of the RateGross-rule offender.",
18
+ "rate_gross_sum": "Sum of RateGross-mode sharing values (Number()) for the offender.",
19
+ "rate_gross_fix": "Fixed Amount total (fix) of the RateGross-rule offender.",
20
+ "rate_gross_max": "Number(allocator.max) for the offender (only set on the cap_fit branch).",
21
+ "mixed_rate_bases_present": "An allocator mixes NET Rate and RateGross entries while carrying a fixed Amount total (fix > 0) — rejected on-chain with EMIXED_RATE_BASES (17). With fix == 0 the two rate bases coincide and mixing is allowed, so no offender is reported.",
22
+ "mixed_rate_bases_index": "Allocator index of the mixed-rate-bases offender.",
23
+ "mixed_rate_bases_guard": "Guard address of the mixed-rate-bases offender.",
15
24
  "amount_rule_branch": "First amount-rule violation branch for the first offending allocator: 'multiple_surplus' | 'below_threshold' | 'exceeds_max' (undefined when none).",
16
25
  "amount_rule_index": "Allocator index of the amount-rule offender.",
17
26
  "amount_rule_guard": "Guard address of the amount-rule offender.",
@@ -103,7 +112,7 @@
103
112
  {
104
113
  "rule_id": "R-A-1-02",
105
114
  "dimension": "structural",
106
- "trigger": "Pure Rate mode sum != 10000 or Rate+Surplus sum > 10000",
115
+ "trigger": "Pure NET Rate sum != 10000, NET Rate+Surplus sum > 10000, a RateGross plan that cannot be paid, or NET Rate mixed with RateGross under a fixed total",
107
116
  "cases": [
108
117
  {
109
118
  "when": { "field": "rate_rule_pure", "op": "eq", "value": true },
@@ -131,6 +140,46 @@
131
140
  "mitigation": "Reduce sum(rates) to ≤ ${rate_total_full}.",
132
141
  "evidence": "rateSum=${rate_rule_sum}, max=${rate_total_full}",
133
142
  "stakeholders": ["owner"]
143
+ },
144
+ {
145
+ "when": { "field": "rate_gross_branch", "op": "eq", "value": "sum_exceeds_10000" },
146
+ "level": "high",
147
+ "title": "RateGross sum ${rate_gross_sum} > ${rate_total_full}",
148
+ "description": "Allocator ${rate_gross_index} (guard=${rate_gross_guard}) uses RateGross mode off the full pool, but sum(rates)=${rate_gross_sum} > ${rate_total_full}. Move will abort with ERATE_EXCEEDS_10000.",
149
+ "scenario": "RateGross percentages exceed 100% of the full pool",
150
+ "mitigation": "Reduce sum(RateGross rates) to ≤ ${rate_total_full}.",
151
+ "evidence": "grossRateSum=${rate_gross_sum}, max=${rate_total_full}",
152
+ "stakeholders": ["owner"]
153
+ },
154
+ {
155
+ "when": { "field": "rate_gross_branch", "op": "eq", "value": "cap_fit" },
156
+ "level": "high",
157
+ "title": "RateGross plan does not fit the max cap ${rate_gross_max}",
158
+ "description": "Allocator ${rate_gross_index} (guard=${rate_gross_guard}) uses RateGross mode with `max` set, but the plan overdraws the cap: fix×10000 + sum(rates)×max = ${rate_gross_fix}×10000 + ${rate_gross_sum}×${rate_gross_max} > ${rate_gross_max}×10000. Move will abort with ERATE_EXCEEDS_10000.",
159
+ "scenario": "Fixed Amount total plus gross rates overdraw the max cap",
160
+ "mitigation": "Lower the fixed Amount total, lower sum(RateGross rates), or raise `max` so fix×10000 + sum(rates)×max ≤ max×10000.",
161
+ "evidence": "fix=${rate_gross_fix}, rateSum=${rate_gross_sum}, max=${rate_gross_max}",
162
+ "stakeholders": ["owner"]
163
+ },
164
+ {
165
+ "when": { "field": "rate_gross_branch", "op": "eq", "value": "fixed_full" },
166
+ "level": "high",
167
+ "title": "RateGross sum ${rate_gross_sum} leaves no room for the fixed total",
168
+ "description": "Allocator ${rate_gross_index} (guard=${rate_gross_guard}) uses RateGross mode with a fixed Amount total (fix=${rate_gross_fix}) and no `max`: sum(rates)=${rate_gross_sum} ≥ ${rate_total_full} can never be paid on top of the fixed total. Move will abort with ERATE_EXCEEDS_10000.",
169
+ "scenario": "Gross rates at 100% plus a fixed Amount total with no cap",
170
+ "mitigation": "Reduce sum(RateGross rates) below ${rate_total_full}, or set a `max` cap that fits fix + rates×max.",
171
+ "evidence": "fix=${rate_gross_fix}, rateSum=${rate_gross_sum}",
172
+ "stakeholders": ["owner"]
173
+ },
174
+ {
175
+ "when": { "field": "mixed_rate_bases_present", "op": "eq", "value": true },
176
+ "level": "high",
177
+ "title": "Allocator ${mixed_rate_bases_index} mixes NET Rate and RateGross with a fixed total",
178
+ "description": "Allocator ${mixed_rate_bases_index} (guard=${mixed_rate_bases_guard}) carries both NET Rate and RateGross entries while also carrying a fixed Amount total. The two modes are measured against different rate bases (pool minus fix vs the full pool / max cap), so the sharing semantics are ambiguous. Move will abort with EMIXED_RATE_BASES (17).",
179
+ "scenario": "One Allocator combining NET Rate and RateGross entries with a fixed Amount total",
180
+ "mitigation": "Split the rate entries into separate Allocators (one for NET Rate, one for RateGross), or drop the fixed Amount total — with fix = 0 the two bases coincide and mixing is allowed.",
181
+ "evidence": "allocator=${mixed_rate_bases_index}, guard=${mixed_rate_bases_guard}",
182
+ "stakeholders": ["owner"]
134
183
  }
135
184
  ]
136
185
  },
@@ -11,6 +11,8 @@
11
11
  "indemnity_none": "indemnity is None (the ruling carries no compensation).",
12
12
  "weight_concentrated": "The Arbitration rule gives disproportionate voting weight to one voter.",
13
13
  "expects_status_enum": "The caller expects status fields to be a Move enum (they are u8 constants).",
14
+ "escrow_released_before_case": "Escrow refunds on the case's order predate the case filing (refund→claim ordering) — caller supplies from escrow forensics (allocation balance vs order amount; refund event timestamps vs case creation time).",
15
+ "escrow_deficit_display": "Rendered escrow deficit — the order principal that already flowed out of the escrow ('?' when unknown).",
14
16
  "max_votor_count": "KERNEL CONSTANT — maximum voters per Arb (MAX_VOTOR_COUNT).",
15
17
  "withdraw_duration_time_ms": "KERNEL CONSTANT — post-arbitration withdraw lock in milliseconds (WITHDRAW_DURATION_TIME)."
16
18
  },
@@ -24,7 +26,7 @@
24
26
  "when": { "field": "invalid_transition", "op": "eq", "value": true },
25
27
  "level": "high",
26
28
  "title": "7-state machine — invalid transitions can deadlock the arbitration",
27
- "description": "Arb has a 7-state machine: Principal_confirming(0) → Arbitrator_confirming(1) → Voting(2) → Arbitrated(3) → Objectionable(4) → Finished(5) → Withdrawn(6). reset() can revert from {1, 4} back to 0. Each op asserts the current status; calling an op out of order aborts with E_STATUS_NOT_MATCH (3). Repeated mis-calls leave the Arb stuck in a non-terminal state with no automatic recovery.",
29
+ "description": "Arb has a 7-state machine (u8 constants, not an enum). A NEW case starts at Arbitrator_confirming(1) — Principal_confirming(0) is ONLY reachable via reset(). Forward path: 1 → Voting(2) via arbitrator_confirm → Arbitrated(3) via the ruling (indemnity set, capped at 3x order amount, enforced at award time) → Finished(5) via the compensation claim, or Objectionable(4) via objection. reset() reverts {1, 4} back to 0 and CLEARS indemnity + votes. withdraw (fee sweep) goes 5→6 immediately, or 3→6 after WITHDRAW_DURATION_TIME when no objection was filed. Each op asserts the current status; calling an op out of order aborts with E_STATUS_NOT_MATCH (3). Repeated mis-calls leave the Arb stuck in a non-terminal state with no automatic recovery.",
28
30
  "scenario": "Caller calls vote() when status is still Arbitrator_confirming; abort blocks progress",
29
31
  "mitigation": "Strictly validate the current status before submitting any Arb op. The SDK should expose a status-aware state machine helper. Provide a recovery path (reset) for Arbitrator_confirming and Objectionable states.",
30
32
  "evidence": "invalid_transition=true (status=${status_display})",
@@ -150,6 +152,23 @@
150
152
  "stakeholders": ["system"]
151
153
  }
152
154
  ]
155
+ },
156
+ {
157
+ "rule_id": "R-ARB-09",
158
+ "dimension": "semantic",
159
+ "trigger": "escrow refunds on the case's order predate the case filing",
160
+ "cases": [
161
+ {
162
+ "when": { "field": "escrow_released_before_case", "op": "eq", "value": true },
163
+ "level": "high",
164
+ "title": "Refund-then-claim ordering — the principal may recover twice",
165
+ "description": "The order's escrow was already released BEFORE this case was filed (deficit ${escrow_deficit_display}). The claim→refund direction is on-chain closed — the order seals itself once a claim settles — but the reverse ordering is NOT: the principal can still claim the indemnity on top of the refunded principal. The discriminating evidence is fully on-chain: (1) refund/alloc event timestamps vs the case creation time — the decisive ordering signal; (2) escrow balance vs order amount (the deficit); (3) the order's progress path (visited refund terminals); (4) the owner receive history.",
166
+ "scenario": "Buyer collects a refund via the refund track, then files a dispute and claims the indemnity on top",
167
+ "mitigation": "At ruling time, net the indemnity against the principal already refunded — compensate the delta, not the full loss. The defendant attaches the escrow forensics to the case statement; tooling refuses to drive the claim for an order whose escrow was already released to the buyer.",
168
+ "evidence": "escrow_released_before_case=true (deficit=${escrow_deficit_display})",
169
+ "stakeholders": ["principal", "arbitrator", "voter"]
170
+ }
171
+ ]
153
172
  }
154
173
  ]
155
174
  }
@@ -14,6 +14,7 @@
14
14
  "current_timestamp_ms": "Echo of the current clock reading used for the deadline comparison.",
15
15
  "voting_deadline_in_past": "True when the selected voting_deadline is already elapsed at the current timestamp.",
16
16
  "vote_voting_guard": "The Guard id the vote claims (vote.voting_guard).",
17
+ "vote_present": "The context carries a vote op payload (plain or weighted).",
17
18
  "voting_guard_list_empty": "True when the on-chain Arbitration.voting_guard list is missing or empty.",
18
19
  "vote_guard_registered": "True when the claimed vote Guard is found in the on-chain voting_guard list.",
19
20
  "registered_voting_guards": "Comma-joined on-chain voting_guard address list (display form).",
@@ -184,6 +185,32 @@
184
185
  }
185
186
  ]
186
187
  },
188
+ {
189
+ "rule_id": "R-AB-2-04",
190
+ "dimension": "semantic",
191
+ "trigger": "Plain (open) vote on an Arbitration with an empty voting_guard — NOT permissionless",
192
+ "cases": [
193
+ {
194
+ "when": { "all": [
195
+ { "field": "vote_present", "op": "eq", "value": true },
196
+ { "field": "voting_guard_list_empty", "op": "eq", "value": true }
197
+ ] },
198
+ "level": "medium",
199
+ "title": "Open vote is permission-gated (358), not permissionless",
200
+ "description": "voting_guard is empty (equal weight, 1 person 1 vote) but vote() still asserts ARBITRATION_VOTE=358 — an account without 358 is rejected with E_PERMISSION_DENIED (code 5)",
201
+ "scenario": "Assuming 'empty voting_guard' means anyone can vote",
202
+ "mitigation": "Grant ARBITRATION_VOTE=358 to every intended voter via the Arbitration's Permission object; or configure a voting_guard list (354) for weighted voting",
203
+ "evidence": "voting_guard=empty",
204
+ "stakeholders": ["voter", "arbiter", "disputant"],
205
+ "exposure": {
206
+ "loss_parties": [
207
+ { "role": "buyer", "basis": "If 358 is not granted to the disputant, the disputant cannot vote in their own case — the ruling proceeds without their input." }
208
+ ],
209
+ "gain_paths": []
210
+ }
211
+ }
212
+ ]
213
+ },
187
214
  {
188
215
  "rule_id": "R-AB-3-01",
189
216
  "dimension": "authority",
@@ -1,5 +1,5 @@
1
1
  {
2
- "comment": "Guard rule pack (R-C/R-X) — declarative form of the retired in-code Guard risk rules (the guard condition-tree lint pack: 32 rules over the serialized root, table classification and the scene ledger). Facts are produced by the kernel extractor (guard-risk.ts, bound to the GUARDQUERY invariant catalog, the witness chain table and the per-scene reentrancy specs); rules only reference fact names. Levels/wording can be retuned per rule and rules can be disabled (enabled=false, trace left) via the judgment document — factory rules can never be deleted or invented here.",
2
+ "comment": "Guard rule pack (R-C/R-X) — declarative form of the retired in-code Guard risk rules (the guard condition-tree lint pack: 34 rules over the serialized root, table classification and the scene ledger). Facts are produced by the kernel extractor (guard-risk.ts, bound to the GUARDQUERY invariant catalog, the witness chain table, the certain-outcome folder and the per-scene reentrancy specs); rules only reference fact names. Levels/wording can be retuned per rule and rules can be disabled (enabled=false, trace left) via the judgment document — factory rules can never be deleted or invented here.",
3
3
  "facts": {
4
4
  "has_signer_check": "KERNEL — the serialized root contains a context(Signer) check.",
5
5
  "has_clock_check": "KERNEL — the serialized root contains a context(Clock) node.",
@@ -20,6 +20,8 @@
20
20
  "root_identifier_is_submission": "KERNEL — when the root is an identifier, the referenced table entry has b_submission=true (false when the entry is missing or constant).",
21
21
  "root_query_ids_csv": "KERNEL — all GUARDQUERY ids referenced in the root (numeric ids and resolved names), comma-space joined.",
22
22
  "root_has_progress_current_query": "KERNEL — the root queries progress.current (query id 1253).",
23
+ "queries_arb_status": "KERNEL — the serialized root mentions arb.status (Arb case state query).",
24
+ "arb_status_transient_gate": "KERNEL — the root queries arb.status AND the table pins a constant numeric value of 5 (Finished): a transient-state gate that arb_withdraw (5→6 Withdrawn) will permanently overtake (testnet o10 refund-edge deadlock).",
23
25
  "logic_and_count": "KERNEL — number of logic_and markers in the serialized root.",
24
26
  "const_addr_list": "KERNEL — constant Address table entries (b_submission=false, value set) rendered as '#id=value', comma joined.",
25
27
  "const_addr_count": "KERNEL — number of constant Address table entries (b_submission=false, value set).",
@@ -87,9 +89,80 @@
87
89
  "reentry_found_primitive": "KERNEL — GUARDQUERY name of the anti-reentrancy primitive found in the root.",
88
90
  "reentry_evidence": "KERNEL — final detection evidence of the reentrancy scan.",
89
91
  "reentry_rationale": "KERNEL — per-scene reentrancy rationale (spec table, Move-verified).",
90
- "reentry_mitigation": "KERNEL — per-scene reentrancy mitigation (spec table, Move-verified)."
92
+ "reentry_mitigation": "KERNEL — per-scene reentrancy mitigation (spec table, Move-verified).",
93
+ "tree_folds_always_true": "KERNEL — the condition tree provably evaluates to TRUE for every submission and every on-chain state (certain-outcome folder in guard-risk.ts: constant-true table leaf, reflexive comparison of the same operand, unsigned value compared >= the constant 0, or an and/or/logic_not fold of such).",
94
+ "tree_folds_always_true_reason": "KERNEL — the decisive tautology pattern rendered for the evidence line.",
95
+ "tree_folds_always_false": "KERNEL — the condition tree provably evaluates to FALSE (always denies: legitimate dead-edge / frozen-service pattern, reported as a notice, not as open access).",
96
+ "tree_folds_always_false_reason": "KERNEL — the decisive always-false pattern rendered for the evidence line.",
97
+ "write_guard_scene": "KERNEL — the Guard is bound as a Repository policy write_guard (scene binding_field=write_guard / id repository_write_guard).",
98
+ "write_guard_no_identity_check": "KERNEL — write_guard scene AND no context(Signer) leaf anywhere in the root: the gate binds a STATE, never the WRITER, so any caller satisfying it may write or overwrite any row.",
99
+ "write_guard_open": "KERNEL — write_guard scene AND (the tree folds true OR it binds no caller identity): the Repository write is effectively unauthenticated even though the policy has a guard."
91
100
  },
92
101
  "rules": [
102
+ {
103
+ "rule_id": "R-X1-16",
104
+ "dimension": "data_source_trust",
105
+ "trigger": "Guard queries arb.status and pins a constant numeric table entry to 5 (Finished) — a transient state that arb_withdraw overtakes (5→6 Withdrawn)",
106
+ "cases": [
107
+ {
108
+ "when": { "field": "arb_status_transient_gate", "op": "eq", "value": true },
109
+ "level": "high",
110
+ "title": "arb.status==5 gate is transient: fee withdrawal permanently kills the refund edge",
111
+ "description": "arb.status is a U8 lifecycle state. After a ruling the case sits at 5 (Finished), but a legitimate arb_withdraw by the arbitrator advances it to 6 (Withdrawn) — the gate silently flips false and never returns. Guard AND Machine are immutable after publish (IMMUT-001), so any forward gated on ==5 dies permanently and strands its funds (verified on testnet, booking o10: 1.5 WOW locked with no on-chain exit).",
112
+ "scenario": "Arbitration refund forward gated on arb.status==5: the arbitrator withdraws the case fee before the refund executes — the forward aborts forever",
113
+ "mitigation": "Gate on the withdraw-stable ruling signal instead: arb.indemnity some == true (Bool — set by the ruling, never cleared by arb_withdraw; cleared by reset, which correctly re-gates). Template: tpl_forward_arb_ruling_won. Time-bounded variant: arb.indemnity.time (U64 ruling timestamp).",
114
+ "evidence": "Root queries arb.status; table pins a constant numeric value of 5 (Finished).",
115
+ "stakeholders": ["provider", "customer"]
116
+ }
117
+ ]
118
+ },
119
+ {
120
+ "rule_id": "R-X1-17",
121
+ "dimension": "logic_gap",
122
+ "trigger": "The condition tree folds to TRUE for every input (tautology), or a Repository write_guard binds no caller identity — the chain checks that a write_guard EXISTS, never that it PROVES anything",
123
+ "cases": [
124
+ {
125
+ "when": { "all": [{ "field": "write_guard_scene", "op": "eq", "value": true }, { "field": "tree_folds_always_true", "op": "eq", "value": true }] },
126
+ "level": "critical",
127
+ "title": "Repository write_guard is a tautology — evidence writes are open to every address",
128
+ "description": "policy_add_imp asserts only that the write_guard LIST IS NON-EMPTY when a policy's id_from is NONE (repository.move L511-536, E_POLICY_WRITE_GUARD_REQUIRED = 22); nothing on chain evaluates what the Guard authorizes. A Guard that returns true for every caller is therefore accepted silently and is exactly the open door an empty list would have been — the schema warning for 'write_guard missing' does not fire, so the misconfiguration is invisible until exploited. Verified on testnet (test-14, HIGH-04): a NON-merchant signer wrote a forged tracking row for another buyer's order (tx BLA7F62r…), then the merchant's legitimate write simply upserted over it (tx DaZaPn6o…). Every downstream Guard that gates a forward on repository.data EXISTENCE (repository.data has / count where) is satisfied by the forged row, so shipping/return evidence stops being evidence; Repository rows carry no author field, so a signed WTS Proof (proof.signer / proof.about / proof.time) is the only on-chain provenance.",
129
+ "scenario": "Merchant binds a 'true' placeholder as the evidence Repository write_guard to satisfy the schema; a stranger (or the counterparty in a dispute) pre-writes the shipping/return receipt row and the delivery forward's evidence gate passes on forged data",
130
+ "mitigation": "Delete the placeholder: bind the writer. Minimum = context(Signer) equality against a constant Address or a vec_contains_address allowlist entry; better = the merchant Permission entity (permission index) or the Order holder via witness, so the row is attributable to the party that owns the order. For evidence that must survive a dispute, store a signed WTS Proof (Prover+Time+Content, repository.move L160-171) instead of a bare string. If genuinely open writes are intended, use id_from=Signer/Clock instead of a write_guard — that is the protocol's declared way to allow anyone.",
131
+ "evidence": "Tautology: ${tree_folds_always_true_reason}",
132
+ "stakeholders": ["customer", "provider", "arbitrator"]
133
+ },
134
+ {
135
+ "when": { "all": [{ "field": "write_guard_scene", "op": "eq", "value": true }, { "field": "tree_folds_always_true", "op": "eq", "value": false }, { "field": "write_guard_no_identity_check", "op": "eq", "value": true }] },
136
+ "level": "high",
137
+ "title": "Repository write_guard gates a state, not a writer — any qualifying caller may overwrite any row",
138
+ "description": "The policy has a write_guard, but the tree contains no context(Signer) leaf, so it never asks WHO is writing. The gate can be satisfied by anyone who can present the referenced objects (or who simply owns them), and once satisfied the writer may add OR OVERWRITE any data ID under that policy — Repository rows carry no author. Downstream Guards that check existence (repository.data has) then trust data with no provenance.",
139
+ "scenario": "Ship-evidence policy guarded only by 'the submitted Order exists': the buyer writes the seller-side shipping receipt themselves, and the deliver forward's evidence check passes",
140
+ "mitigation": "Add the identity leaf: context(Signer) == a constant merchant Address, or vec_contains_address against an allowlist / permission entity table, or the Order holder derived by witness. Where the row must be provably authored, write a signed WTS Proof rather than a bare value, and have the consuming Guard check proof.attestation == the expected party instead of mere existence.",
141
+ "evidence": "write_guard scene with no context(Signer) leaf in the root",
142
+ "stakeholders": ["customer", "provider", "arbitrator"]
143
+ },
144
+ {
145
+ "when": { "all": [{ "field": "tree_folds_always_true", "op": "eq", "value": true }, { "field": "write_guard_scene", "op": "eq", "value": false }] },
146
+ "level": "high",
147
+ "title": "Guard is a tautology — whatever it gates is unrestricted",
148
+ "description": "The condition tree evaluates to true for every submission and every on-chain state, so binding it to a Forward / buy / allocator / usage slot authorizes every caller while LOOKING guarded. Guards are immutable once published (IMMUT-001): the binding cannot be repaired in place, only by standing up new objects and rebinding what is still mutable (L3 fields).",
149
+ "scenario": "A placeholder guard (constant-true entry, self-comparison, x >= 0) shipped as 'to be filled in later' gets bound to a forward; the workflow accepts any caller from day one and can never be tightened after publish",
150
+ "mitigation": "Before publishing the host object, replace the placeholder with a real predicate; if the intent is genuinely 'no gate', leave the binding EMPTY instead of binding an always-true Guard (an empty binding is honest; a tautology is a false assurance). Re-check with the Guard analyzer after every edit.",
151
+ "evidence": "Tautology: ${tree_folds_always_true_reason}",
152
+ "stakeholders": ["customer", "provider"]
153
+ },
154
+ {
155
+ "when": { "field": "tree_folds_always_false", "op": "eq", "value": true },
156
+ "level": "low",
157
+ "title": "Guard is always false — nothing it gates can ever run",
158
+ "description": "The tree folds to false for every input (the certain-outcome folder found a decisive always-false expression). This is the safe direction of error — it denies rather than opens — and is sometimes intentional (a deliberately frozen edge), but it is far more often a polarity or identifier mistake, and after publish the gated path is dead permanently (IMMUT-001).",
159
+ "scenario": "Merchant wants 'not yet shipped' and writes logic_equal[current_node, shipped_constant] inside a forward that only runs AFTER shipping; the forward can never fire",
160
+ "mitigation": "Confirm the intent. If the edge must ever run, fix the predicate before publishing; if it is a permanent block, prefer NOT binding a Guard at all and instead leaving the edge unreachable in the Machine graph (clearer to readers and to the workflow analyzer).",
161
+ "evidence": "Always-false: ${tree_folds_always_false_reason}",
162
+ "stakeholders": ["provider"]
163
+ }
164
+ ]
165
+ },
93
166
  {
94
167
  "rule_id": "R-C1-01",
95
168
  "dimension": "data_source_trust",
@@ -1,8 +1,11 @@
1
1
  {
2
- "comment": "Machine rule pack (R-M) — declarative form of the retired in-code Machine risk rules (43 rules across 5 dimensions). Facts are produced by the kernel extractor (machine-risk.ts, bound to MAX_NODE_COUNT and USER_DEFINED_PERM_INDEX_START); rules only reference fact names. Graph walks (entry/terminal/orphan scan, per-node pair counting, per-pair forward counting, duplicate names, unachievable-threshold classification, per-forward permission scans, published-object cross-checks) are sunk into the extractor as first-offender facts. Rules whose retired check had no runtime detection (design guidance only) are catalog stubs: they carry the full wording but a never-true condition, so the finding set matches the retired code exactly. Levels/wording can be retuned per rule and rules can be disabled (enabled=false, trace left) via the judgment document — factory rules can never be deleted or invented here.",
2
+ "comment": "Machine rule pack (R-M) — declarative form of the retired in-code Machine risk rules (44 rules across 5 dimensions). Facts are produced by the kernel extractor (machine-risk.ts, bound to MAX_NODE_COUNT and USER_DEFINED_PERM_INDEX_START); rules only reference fact names. Graph walks (entry/terminal/orphan scan, per-node pair counting, per-pair forward counting, duplicate names, unachievable-threshold classification, per-forward permission scans, published-object cross-checks) are sunk into the extractor as first-offender facts. Rules whose retired check had no runtime detection (design guidance only) are catalog stubs: they carry the full wording but a never-true condition, so the finding set matches the retired code exactly. Levels/wording can be retuned per rule and rules can be disabled (enabled=false, trace left) via the judgment document — factory rules can never be deleted or invented here.",
3
3
  "facts": {
4
4
  "has_entry": "At least one Pair has prev_node='' (the workflow entry point).",
5
5
  "has_terminal": "At least one node has no outgoing Pair (a terminal exists).",
6
+ "terminal_nodes_display": "Stop nodes — nodes with NO outgoing Pair (never appear as prev_node), ', '-joined; orders rest here forever.",
7
+ "no_allocator_published": "The project context is allocator-aware (published_allocators provided) and the set is EMPTY — no Allocator published. Unknown (context without the set, e.g. design-time scans) never fires.",
8
+ "terminal_fund_exit_uncovered": "At least one stop node exists AND the allocator-aware project context shows no Allocator published — fund-exit coverage gap (R-M5-03).",
6
9
  "first_orphaned_node_name": "First-offender — name of the first node with neither an entry/prev reference nor any incoming Pair (absent when none).",
7
10
  "node_count": "Number of nodes in the Machine JSON.",
8
11
  "node_count_over_limit": "node_count exceeds MAX_NODE_COUNT (chain-limit comparison sunk into the extractor).",
@@ -19,7 +22,7 @@
19
22
  "first_missing_guard_forward_name": "First-offender — name of the first Forward referencing a Guard outside the published set (absent when none).",
20
23
  "first_missing_guard_guard": "That Forward's Guard address.",
21
24
  "first_retained_no_guard_forward_name": "First-offender — name of the first Forward carrying retained_submission without any Guard (absent when none).",
22
- "first_noperm_forward_name": "First-offender — name of the first Forward with neither namedOperator nor permissionIndex (absent when none).",
25
+ "first_noperm_forward_name": "First-offender — name of the first Forward with NONE of namedOperator, permissionIndex, or Guard (absent when none). A Guard-only forward IS executable: the verified Guard replaces both identity pre-checks through the Passport path.",
23
26
  "first_noperm_prev": "That Forward's Pair prev_node.",
24
27
  "first_noperm_next": "That Forward's Pair next_node.",
25
28
  "first_both_forward_name": "First-offender — name of the first Forward with BOTH namedOperator and permissionIndex set (absent when none).",
@@ -199,14 +202,14 @@
199
202
  {
200
203
  "rule_id": "R-M1-11",
201
204
  "dimension": "structural",
202
- "trigger": "Match node names against regex /(^|_)(disputed?|refund(?:ed)?|arbitration|arb)(_|$)/i (catches both exact names like 'refunded' and compound fund-flow terminals like 'deposit_refunded'/'deposit_deducted'; business states like 'return_approved'/'damage_confirmed'/'cancelled'/'returned' do NOT match) — catalog stub: the retired check was not implemented",
205
+ "trigger": "Two-tier node-name match, identical to the template-scanner / mode-actions / audit-rules enforcement regex /(^|_)(disputed?|arbitration|arb)(_|$)|^(refund|refunded|deposit_refunded|deposit_deducted|cancel|cancelled)$/i — dispute family matches any underscore segment (a dispute never lives inside the Machine); fund terminals match EXACT names only. Business states that ROUTE allocator refunds ('closed_cancel', 'cancel_requested', 'refund_requested', 'return_approved', 'returned') do NOT match. — catalog stub: the retired check was not implemented",
203
206
  "cases": [
204
207
  {
205
208
  "when": { "field": "always_true", "op": "eq", "value": false },
206
209
  "level": "critical",
207
210
  "title": "Dispute anti-pattern — machine illegally models dispute flow",
208
- "description": "Machine contains nodes named 'disputed', 'refunded', 'arb', 'arbitration', 'dispute', or 'refund'. This is a CRITICAL design anti-pattern because dispute is INDEPENDENT of the machine workflow. Dispute flows through: Order → dispute filed on the Arbitration → Arb case → arbiter ruling → fee withdrawal by order holder. Arbitrators are configured in the Arbitration's voting_guard list, NOT in Permission. Merchants who model dispute in the machine (e.g., 'disputed → refunded' forward guarded by Permission index 1500) create dead-end paths because no one has Permission 1500 — arbitrators are NOT Permission holders.",
209
- "mitigation": "Remove all dispute/refund nodes from the machine. Instead: (1) bind an Arbitration object to the Service via Service.arbitrations, (2) configure arbitrators via Arbitration.voting_guard_add, (3) deposit compensation_fund to the Service. Disputes are then filed against the order within the Arbitration object — completely independent of the machine workflow."
211
+ "description": "Machine contains nodes named 'disputed', 'refunded', 'arb', 'arbitration', 'dispute', or 'refund'. This is a CRITICAL design anti-pattern because dispute resolution is a SEPARATE system from the Machine workflow. Dispute flows through: Order → dispute filed on the Arbitration (Arb case created, dispute fee escrowed in the case) → arbitrator confirm → voting → ruling (indemnity capped at 3x order amount, enforced at award time) → compensation claim pays the awarded amount from the Service's compensation_fund to the ORDER OWNER (the call itself is permissionless — any keeper/agent can drive it, the recipient is hard-bound to the order owner) → the case fee is released to the Arbitration via arb_withdraw (permission 364, the arbitration operator — NOT the order holder). Arbitrators are configured in the Arbitration's voting_guard list, NOT in Permission. Merchants who model dispute in the machine (e.g., 'disputed → refunded' forward guarded by Permission index 1500) create dead-end paths because no one has Permission 1500 — arbitrators are NOT Permission holders.",
212
+ "mitigation": "Remove all dispute/refund nodes from the machine. Instead: (1) bind an Arbitration object to the Service via Service.arbitrations, (2) configure arbitrators via Arbitration.voting_guard_add, (3) deposit compensation_fund to the Service. Disputes are then filed against the order within the Arbitration object — completely independent of the machine workflow. BOUNDARY (design intent, never 'fix' it): Arbitration (compensation_fund payouts) and Allocator (escrow distribution) keep independent fund sources and lifecycles by design. Cross-system checks belong in allocator Guards as READ-ONLY evidence (order.claimed_by / arb.indemnity — see pattern.arb_status_escrow_holdback), NOT in arb-linked Machine nodes/forwards or protocol state sync — coupling the two systems opens the refund+compensation double-payout path."
210
213
  }
211
214
  ]
212
215
  },
@@ -384,15 +387,15 @@
384
387
  {
385
388
  "rule_id": "R-M3-01",
386
389
  "dimension": "permission",
387
- "trigger": "Check each forward has at least one of namedOperator or permissionIndex",
390
+ "trigger": "Check each forward has at least one executor binding: namedOperator, permissionIndex, or Guard (Guard-only is valid — verified via Passport)",
388
391
  "cases": [
389
392
  {
390
393
  "when": { "field": "first_noperm_forward_name", "op": "present" },
391
394
  "level": "critical",
392
395
  "title": "Forward without permission",
393
- "description": "Forward has neither namedOperator nor permissionIndex. Cannot be executed.",
394
- "mitigation": "Set namedOperator='' for OrderHolder, or set permissionIndex.",
395
- "evidence": "Forward \"${first_noperm_forward_name}\" in Pair (${first_noperm_prev} -> ${first_noperm_next}) has no permission.",
396
+ "description": "Forward has no executor binding at all — neither namedOperator, permissionIndex, nor Guard. Cannot be executed (the plain forward constructor aborts E_PERMISSION_NOT_DEFINED).",
397
+ "mitigation": "Set namedOperator='' for OrderHolder, set permissionIndex, or bind a Guard (a Guard-only forward is executable through the Passport path — the verified Guard replaces both identity pre-checks).",
398
+ "evidence": "Forward \"${first_noperm_forward_name}\" in Pair (${first_noperm_prev} -> ${first_noperm_next}) has no executor binding.",
396
399
  "exposure": {
397
400
  "loss_parties": [
398
401
  { "role": "buyer", "basis": "The affected forward has no executor — orders that route through this Pair can never advance past it and their escrowed funds freeze." },
@@ -620,14 +623,22 @@
620
623
  {
621
624
  "rule_id": "R-M5-03",
622
625
  "dimension": "environment",
623
- "trigger": "Check if Service.order_allocators is configured for each terminal node — catalog stub: the retired check was not implemented",
626
+ "trigger": "Check if Service.order_allocators is configured for each terminal node (stop-node fund-exit coverage)",
624
627
  "cases": [
625
628
  {
626
- "when": { "field": "always_true", "op": "eq", "value": false },
629
+ "when": { "field": "terminal_fund_exit_uncovered", "op": "eq", "value": true },
627
630
  "level": "high",
628
631
  "title": "Allocation configuration incomplete",
629
- "description": "Service's order_allocators not configured or misconfigured. Terminal node funds cannot be distributed.",
630
- "mitigation": "Configure Service.order_allocators, one Allocator per terminal node."
632
+ "description": "Machine has stop nodes (no outgoing Pair) but no Allocator is published in the project. Funds at those nodes can be neither distributed nor refunded — and Machine + Allocator are immutable after publish (IMMUT-001), so an uncovered stop node strands escrowed funds permanently.",
633
+ "mitigation": "Before Service publish, bind Service.order_allocators fund-exit rules to EVERY stop node: withdrawal (release) AND refund paths. Review-dependent release is a TIME-GATE on the same exit (reviewed, OR unreviewed after T) — never a parallel edge or a separate node without its own exit.",
634
+ "evidence": "Stop nodes without allocation coverage: ${terminal_nodes_display} (no Allocator published).",
635
+ "exposure": {
636
+ "loss_parties": [
637
+ { "role": "buyer", "basis": "Escrowed order funds resting at an uncovered stop node can never be refunded to the buyer after publish (immutable topology)." },
638
+ { "role": "merchant", "basis": "The merchant release share at the same node can never be withdrawn." }
639
+ ],
640
+ "gain_paths": []
641
+ }
631
642
  }
632
643
  ]
633
644
  },
@@ -701,6 +712,20 @@
701
712
  "evidence": "Object dependency table incomplete. Missing Guards: ${missing_guards_display}"
702
713
  }
703
714
  ]
715
+ },
716
+ {
717
+ "rule_id": "R-M5-09",
718
+ "dimension": "environment",
719
+ "trigger": "Design-time review: allocator coverage over ALL stop nodes incl. review-gated and dispute exits — catalog stub: requires cross-object (Service x Machine) evaluation; enforced via publish schema guidance + pattern.fund_flow_stop_node_coverage",
720
+ "cases": [
721
+ {
722
+ "when": { "field": "always_true", "op": "eq", "value": false },
723
+ "level": "high",
724
+ "title": "Stop-node fund-exit coverage not reviewed",
725
+ "description": "Every node where an order can rest — terminal nodes AND waiting states such as review windows or open disputes — must have BOTH a withdrawal and a refund allocation rule evaluated at Service publish. Review-gated release is a time variant of the completed exit; dispute release is an arb.indemnity-gated edge (R-X1-16). The stop-node list is derived from THIS business's rest states, not a fixed vocabulary: wowok grows arbitrary commerce systems from Move-native primitives.",
726
+ "mitigation": "Run the coverage checklist of pattern.fund_flow_stop_node_coverage (guard-design-patterns) against the planned Machine before publishing Service; publish is irreversible (IMMUT-001)."
727
+ }
728
+ ]
704
729
  }
705
730
  ]
706
731
  }
@@ -236,7 +236,7 @@
236
236
  "when": { "field": "operation", "op": "eq", "value": "arb_claim_compensation" },
237
237
  "level": "high",
238
238
  "title": "arb_claim_compensation is IRREVERSIBLE (claimed_by one-time set)",
239
- "description": "Setting claimed_by is permanent. After this call: (1) claimed_by cannot be reset, (2) NO new disputes can be filed (E_ORDER_ALREADY_CLAIMED), (3) all unresolved disputes become unactionable. If first compensation is insufficient, buyer has no recourse.",
239
+ "description": "Setting claimed_by is permanent. After this call: (1) claimed_by cannot be reset, (2) NO new disputes can be filed (E_ORDER_ALREADY_CLAIMED), (3) all unresolved disputes become unactionable, (4) the order seals itself — the owner receive entries abort, so any escrow balance still on the order becomes unclaimable. If first compensation is insufficient, buyer has no recourse.",
240
240
  "scenario": "Buyer claims partial compensation, then discovers additional damages",
241
241
  "mitigation": "BEFORE claiming: (1) enumerate ALL disputes, (2) ensure proposition covers all damages, (3) confirm Arb ruling is final. Add explicit user confirmation (C-O-08).",
242
242
  "evidence": "operation=arb_claim_compensation, current_claimed_by=${claimed_by_display}",
@@ -262,7 +262,7 @@
262
262
  ] },
263
263
  "level": "high",
264
264
  "title": "Cannot file new dispute after claimed_by is set",
265
- "description": "Order.claimed_by is set — any new dispute() call aborts E_ORDER_ALREADY_CLAIMED. arb_confirm/arb_objection trigger dispute() internally.",
265
+ "description": "Order.claimed_by is set — any new dispute() call and any further payout claim on the order abort E_ORDER_ALREADY_CLAIMED. arb_confirm/arb_objection trigger dispute() internally; the owner receive entries abort for escrow payouts (the provider release track pays direct and stays usable).",
266
266
  "scenario": "Buyer claims compensation then tries to file additional dispute",
267
267
  "mitigation": "Resolve ALL disputes BEFORE calling arb_claim_compensation. claimed_by is terminal for dispute flow.",
268
268
  "evidence": "operation=${operation}, claimed_by_set=true",
@@ -4,6 +4,7 @@ export interface ArchetypeTemplate {
4
4
  id: string;
5
5
  industry: Industry;
6
6
  variant: string;
7
+ product_ref: string;
7
8
  archetype: "leader" | "challenger";
8
9
  phase: 1 | 2 | 3;
9
10
  machine_shape: ModeMachineNode[];
@@ -18,8 +19,9 @@ export interface ArchetypeTemplate {
18
19
  user_inputs: string[];
19
20
  key_risk: string;
20
21
  build_notes: string[];
22
+ time_anchors?: Record<string, string>;
21
23
  }
22
- export declare const BUILTIN_TEMPLATES_VERSION = 2;
24
+ export declare const BUILTIN_TEMPLATES_VERSION = 17;
23
25
  export declare const BUILTIN_TEMPLATES: ArchetypeTemplate[];
24
26
  export declare const TEMPLATE_KEYWORDS: Record<string, string[]>;
25
27
  export declare function getBuiltinTemplate(id: string): ArchetypeTemplate | undefined;