@fluentcommerce/ai-skills 0.1.0 → 0.3.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.

Potentially problematic release.


This version of @fluentcommerce/ai-skills might be problematic. Click here for more details.

Files changed (168) hide show
  1. package/README.md +866 -622
  2. package/bin/cli.mjs +2112 -1973
  3. package/content/cli/agents/fluent-cli/agent.json +149 -149
  4. package/content/cli/agents/fluent-cli.md +132 -132
  5. package/content/cli/skills/fluent-bootstrap/SKILL.md +214 -181
  6. package/content/cli/skills/fluent-cli-index/SKILL.md +1 -1
  7. package/content/cli/skills/fluent-cli-mcp-cicd/SKILL.md +117 -1
  8. package/content/cli/skills/fluent-cli-reference/SKILL.md +1040 -1031
  9. package/content/cli/skills/fluent-cli-retailer/SKILL.md +27 -2
  10. package/content/cli/skills/fluent-cli-settings/SKILL.md +21 -1
  11. package/content/cli/skills/fluent-connect/SKILL.md +937 -886
  12. package/content/cli/skills/fluent-module-deploy/SKILL.md +63 -5
  13. package/content/cli/skills/fluent-profile/SKILL.md +73 -0
  14. package/content/cli/skills/fluent-workflow/SKILL.md +360 -310
  15. package/content/dev/agents/fluent-backend-dev/AGENT.md +58 -0
  16. package/content/dev/agents/fluent-backend-dev/agent.json +69 -0
  17. package/content/dev/agents/fluent-backend-dev.md +287 -0
  18. package/content/dev/agents/fluent-dev/AGENT.md +98 -0
  19. package/content/dev/agents/fluent-dev/agent.json +14 -2
  20. package/content/dev/agents/fluent-dev.md +194 -525
  21. package/content/dev/agents/fluent-frontend-dev/AGENT.md +63 -0
  22. package/content/dev/agents/fluent-frontend-dev/agent.json +52 -0
  23. package/content/dev/agents/fluent-frontend-dev.md +323 -0
  24. package/content/dev/skills/fluent-archive/SKILL.md +234 -0
  25. package/content/dev/skills/fluent-build/SKILL.md +312 -192
  26. package/content/dev/skills/fluent-connection-analysis/SKILL.md +422 -386
  27. package/content/dev/skills/fluent-custom-code/SKILL.md +15 -9
  28. package/content/dev/skills/fluent-data-module-scaffold/SKILL.md +19 -2
  29. package/content/dev/skills/fluent-e2e-test/SKILL.md +501 -394
  30. package/content/dev/skills/fluent-event-api/SKILL.md +962 -945
  31. package/content/dev/skills/fluent-feature-explain/SKILL.md +680 -603
  32. package/content/dev/skills/fluent-feature-plan/PLAN_TEMPLATE.md +27 -2
  33. package/content/dev/skills/fluent-feature-plan/SKILL.md +478 -227
  34. package/content/dev/skills/fluent-feature-status/SKILL.md +335 -0
  35. package/content/dev/skills/fluent-feedback/SKILL.md +221 -0
  36. package/content/dev/skills/fluent-implementation-map/SKILL.md +644 -0
  37. package/content/dev/skills/fluent-job-batch/SKILL.md +10 -0
  38. package/content/dev/skills/fluent-module-scaffold/SKILL.md +64 -2
  39. package/content/dev/skills/fluent-module-validate/SKILL.md +778 -775
  40. package/content/dev/skills/fluent-mystique-analyze/SKILL.md +817 -0
  41. package/content/dev/skills/fluent-mystique-builder/COMPONENT_TEMPLATE.md +81 -0
  42. package/content/dev/skills/fluent-mystique-builder/README.md +63 -0
  43. package/content/dev/skills/fluent-mystique-builder/SKILL.md +1294 -0
  44. package/content/dev/skills/fluent-mystique-builder/components/INDEX.md +92 -0
  45. package/content/dev/skills/fluent-mystique-builder/components/fc.accordion.md +48 -0
  46. package/content/dev/skills/fluent-mystique-builder/components/fc.action.field.fulfilmentpack.md +20 -0
  47. package/content/dev/skills/fluent-mystique-builder/components/fc.action.field.multiparcel.md +21 -0
  48. package/content/dev/skills/fluent-mystique-builder/components/fc.action.field.returnitems.md +21 -0
  49. package/content/dev/skills/fluent-mystique-builder/components/fc.action.field.wavepick.md +21 -0
  50. package/content/dev/skills/fluent-mystique-builder/components/fc.action.inline.md +24 -0
  51. package/content/dev/skills/fluent-mystique-builder/components/fc.activity.entity.md +25 -0
  52. package/content/dev/skills/fluent-mystique-builder/components/fc.analytics.viz.md +20 -0
  53. package/content/dev/skills/fluent-mystique-builder/components/fc.attribute.column.md +111 -0
  54. package/content/dev/skills/fluent-mystique-builder/components/fc.attribute.json.md +20 -0
  55. package/content/dev/skills/fluent-mystique-builder/components/fc.attribute.jsoneditor.md +54 -0
  56. package/content/dev/skills/fluent-mystique-builder/components/fc.attribute.locationId.md +51 -0
  57. package/content/dev/skills/fluent-mystique-builder/components/fc.attribute.retailerId.md +52 -0
  58. package/content/dev/skills/fluent-mystique-builder/components/fc.button.bar.md +57 -0
  59. package/content/dev/skills/fluent-mystique-builder/components/fc.button.print.download.md +53 -0
  60. package/content/dev/skills/fluent-mystique-builder/components/fc.button.print.inline.compatibility.md +60 -0
  61. package/content/dev/skills/fluent-mystique-builder/components/fc.button.print.inline.md +53 -0
  62. package/content/dev/skills/fluent-mystique-builder/components/fc.button.print.md +24 -0
  63. package/content/dev/skills/fluent-mystique-builder/components/fc.button.print.pick.md +61 -0
  64. package/content/dev/skills/fluent-mystique-builder/components/fc.buttons.add.reject.md +20 -0
  65. package/content/dev/skills/fluent-mystique-builder/components/fc.card.attribute.md +73 -0
  66. package/content/dev/skills/fluent-mystique-builder/components/fc.card.attributes.grid.md +40 -0
  67. package/content/dev/skills/fluent-mystique-builder/components/fc.card.image.md +37 -0
  68. package/content/dev/skills/fluent-mystique-builder/components/fc.card.map.point.md +24 -0
  69. package/content/dev/skills/fluent-mystique-builder/components/fc.card.multi.md +79 -0
  70. package/content/dev/skills/fluent-mystique-builder/components/fc.card.product.md +27 -0
  71. package/content/dev/skills/fluent-mystique-builder/components/fc.chart.area.md +34 -0
  72. package/content/dev/skills/fluent-mystique-builder/components/fc.chart.area.wrapper.feed.md +98 -0
  73. package/content/dev/skills/fluent-mystique-builder/components/fc.chart.bar.md +52 -0
  74. package/content/dev/skills/fluent-mystique-builder/components/fc.chart.bar.wrapper.source.md +104 -0
  75. package/content/dev/skills/fluent-mystique-builder/components/fc.chart.gauge.md +28 -0
  76. package/content/dev/skills/fluent-mystique-builder/components/fc.chart.gauge.wrapper.threshold.md +118 -0
  77. package/content/dev/skills/fluent-mystique-builder/components/fc.chart.line.md +32 -0
  78. package/content/dev/skills/fluent-mystique-builder/components/fc.conditional.md +62 -0
  79. package/content/dev/skills/fluent-mystique-builder/components/fc.dashboard.threshold.md +65 -0
  80. package/content/dev/skills/fluent-mystique-builder/components/fc.daterange.wrapper.forwarder.md +56 -0
  81. package/content/dev/skills/fluent-mystique-builder/components/fc.drawer.button.md +21 -0
  82. package/content/dev/skills/fluent-mystique-builder/components/fc.event.detail.md +20 -0
  83. package/content/dev/skills/fluent-mystique-builder/components/fc.events.search.md +21 -0
  84. package/content/dev/skills/fluent-mystique-builder/components/fc.field.daterange.md +83 -0
  85. package/content/dev/skills/fluent-mystique-builder/components/fc.field.filterComplex.md +106 -0
  86. package/content/dev/skills/fluent-mystique-builder/components/fc.field.intrange.md +82 -0
  87. package/content/dev/skills/fluent-mystique-builder/components/fc.field.multistring.md +50 -0
  88. package/content/dev/skills/fluent-mystique-builder/components/fc.filterPanel.md +53 -0
  89. package/content/dev/skills/fluent-mystique-builder/components/fc.json.editor.md +22 -0
  90. package/content/dev/skills/fluent-mystique-builder/components/fc.json.viewer.md +21 -0
  91. package/content/dev/skills/fluent-mystique-builder/components/fc.list.customAction.md +79 -0
  92. package/content/dev/skills/fluent-mystique-builder/components/fc.list.md +116 -0
  93. package/content/dev/skills/fluent-mystique-builder/components/fc.list.wrapper.bppmetrics.md +69 -0
  94. package/content/dev/skills/fluent-mystique-builder/components/fc.list.wrapper.feed.md +65 -0
  95. package/content/dev/skills/fluent-mystique-builder/components/fc.list.wrapper.source.md +64 -0
  96. package/content/dev/skills/fluent-mystique-builder/components/fc.modal.button.addItem.md +60 -0
  97. package/content/dev/skills/fluent-mystique-builder/components/fc.modal.button.md +21 -0
  98. package/content/dev/skills/fluent-mystique-builder/components/fc.mutation.inline.md +88 -0
  99. package/content/dev/skills/fluent-mystique-builder/components/fc.mystique.collapsible.attributes.md +83 -0
  100. package/content/dev/skills/fluent-mystique-builder/components/fc.mystique.collapsible.text.md +33 -0
  101. package/content/dev/skills/fluent-mystique-builder/components/fc.mystique.link.md +30 -0
  102. package/content/dev/skills/fluent-mystique-builder/components/fc.order.itemDetails.md +20 -0
  103. package/content/dev/skills/fluent-mystique-builder/components/fc.order.shipmentDetails.md +20 -0
  104. package/content/dev/skills/fluent-mystique-builder/components/fc.page.filter.select.md +87 -0
  105. package/content/dev/skills/fluent-mystique-builder/components/fc.page.md +64 -0
  106. package/content/dev/skills/fluent-mystique-builder/components/fc.page.refresh.md +48 -0
  107. package/content/dev/skills/fluent-mystique-builder/components/fc.page.section.column.md +71 -0
  108. package/content/dev/skills/fluent-mystique-builder/components/fc.page.section.header.md +61 -0
  109. package/content/dev/skills/fluent-mystique-builder/components/fc.page.section.md +59 -0
  110. package/content/dev/skills/fluent-mystique-builder/components/fc.page.wizard.md +45 -0
  111. package/content/dev/skills/fluent-mystique-builder/components/fc.page.wizard.summary.md +56 -0
  112. package/content/dev/skills/fluent-mystique-builder/components/fc.progress.circular.md +20 -0
  113. package/content/dev/skills/fluent-mystique-builder/components/fc.provider.graphql.md +71 -0
  114. package/content/dev/skills/fluent-mystique-builder/components/fc.quantity.list.md +87 -0
  115. package/content/dev/skills/fluent-mystique-builder/components/fc.repeater.md +56 -0
  116. package/content/dev/skills/fluent-mystique-builder/components/fc.reports.ipuipc.md +54 -0
  117. package/content/dev/skills/fluent-mystique-builder/components/fc.return.rowExpansion.md +19 -0
  118. package/content/dev/skills/fluent-mystique-builder/components/fc.scanner.barcode.md +21 -0
  119. package/content/dev/skills/fluent-mystique-builder/components/fc.scanner.barcodeFilter.md +72 -0
  120. package/content/dev/skills/fluent-mystique-builder/components/fc.scanner.camera.md +20 -0
  121. package/content/dev/skills/fluent-mystique-builder/components/fc.settingForm.md +64 -0
  122. package/content/dev/skills/fluent-mystique-builder/components/fc.sourcing.profile.drawer.button.md +19 -0
  123. package/content/dev/skills/fluent-mystique-builder/components/fc.sourcing.profile.modal.button.md +64 -0
  124. package/content/dev/skills/fluent-mystique-builder/components/fc.sourcing.strategy.modal.button.md +20 -0
  125. package/content/dev/skills/fluent-mystique-builder/components/fc.stepper.md +20 -0
  126. package/content/dev/skills/fluent-mystique-builder/components/fc.tab.content.md +56 -0
  127. package/content/dev/skills/fluent-mystique-builder/components/fc.tabs.card.md +64 -0
  128. package/content/dev/skills/fluent-mystique-builder/components/fc.tabs.md +69 -0
  129. package/content/dev/skills/fluent-mystique-builder/components/fc.tile.metric.md +73 -0
  130. package/content/dev/skills/fluent-mystique-builder/components/fc.workflow.provider.md +77 -0
  131. package/content/dev/skills/fluent-mystique-builder/validate-docs.ps1 +260 -0
  132. package/content/dev/skills/fluent-mystique-scaffold/SKILL.md +1830 -0
  133. package/content/dev/skills/fluent-mystique-validate/SKILL.md +646 -0
  134. package/content/dev/skills/fluent-pre-deploy-check/SKILL.md +1144 -1108
  135. package/content/dev/skills/fluent-retailer-config/SKILL.md +1162 -1111
  136. package/content/dev/skills/fluent-rollback/SKILL.md +387 -0
  137. package/content/dev/skills/fluent-rule-scaffold/SKILL.md +515 -385
  138. package/content/dev/skills/fluent-scope-decompose/SKILL.md +1123 -1021
  139. package/content/dev/skills/fluent-session-audit-export/SKILL.md +880 -632
  140. package/content/dev/skills/fluent-session-summary/SKILL.md +320 -195
  141. package/content/dev/skills/fluent-settings/SKILL.md +160 -1
  142. package/content/dev/skills/fluent-source-onboard/SKILL.md +31 -3
  143. package/content/dev/skills/fluent-sourcing/SKILL.md +1185 -0
  144. package/content/dev/skills/fluent-system-monitoring/SKILL.md +771 -767
  145. package/content/dev/skills/fluent-test-data/SKILL.md +514 -513
  146. package/content/dev/skills/fluent-trace/SKILL.md +1169 -1143
  147. package/content/dev/skills/fluent-transition-api/SKILL.md +364 -346
  148. package/content/dev/skills/fluent-use-case-discover/SKILL.md +593 -0
  149. package/content/dev/skills/fluent-use-case-discover/SPEC_TEMPLATE.md +281 -0
  150. package/content/dev/skills/fluent-version-manage/SKILL.md +53 -2
  151. package/content/dev/skills/fluent-workflow-analyzer/SKILL.md +995 -959
  152. package/content/dev/skills/fluent-workflow-builder/SKILL.md +668 -319
  153. package/content/dev/skills/fluent-workflow-deploy/SKILL.md +480 -267
  154. package/content/dev/skills/fluent-workspace-tree/SKILL.md +281 -0
  155. package/content/mcp-extn/agents/fluent-mcp.md +133 -69
  156. package/content/mcp-extn/skills/fluent-mcp-tools/SKILL.md +812 -461
  157. package/content/mcp-official/agents/fluent-mcp-core.md +91 -91
  158. package/content/mcp-official/skills/fluent-mcp-core/SKILL.md +94 -94
  159. package/content/rfl/skills/fluent-rfl-assess/SKILL.md +172 -172
  160. package/docs/CAPABILITY_MAP.md +106 -77
  161. package/docs/DEPLOYMENT_PROMOTION_RUNBOOK.md +218 -0
  162. package/docs/DESIGN-implementation-map.md +698 -0
  163. package/docs/DEV_WORKFLOW.md +814 -802
  164. package/docs/FLOW_RUN.md +142 -142
  165. package/docs/GETTING_STARTED.md +427 -0
  166. package/docs/USE_CASES.md +909 -52
  167. package/metadata.json +184 -156
  168. package/package.json +3 -2
@@ -1,1143 +1,1169 @@
1
- ---
2
- name: fluent-trace
3
- description: Trace and debug Fluent Commerce event processing. Analyze failed events, correlate with workflows and rules, identify root causes. Triggers on "trace event", "debug order", "why did event fail", "event trace", "debug fulfilment".
4
- user-invocable: true
5
- allowed-tools: Bash, Read, Write, Edit, Glob, Grep
6
- argument-hint: <entity-ref> [--entity-type ORDER|FULFILMENT] [--status FAILED]
7
- ---
8
-
9
- # Event Trace & Debug
10
-
11
- Trace Fluent Commerce event processing to diagnose failures, identify root causes, and correlate events with workflow rulesets and rules.
12
-
13
- ## Ownership Boundary
14
-
15
- This skill owns diagnostic workflow, correlation logic, and decision trees.
16
-
17
- Canonical MCP extension tool syntax/limits are owned by `/fluent-mcp-tools`. Reuse that skill for exact request payload patterns.
18
-
19
- ## Pre-Check: Load Source Analysis
20
-
21
- Before tracing, check if `/fluent-custom-code` analysis artifacts exist:
22
-
23
- ```
24
- accounts/<PROFILE>/analysis/custom-code/workflow-rule-map.json
25
- accounts/<PROFILE>/analysis/custom-code/source-map.json
26
- ```
27
-
28
- If found, use them to:
29
- - Map rule names in event traces to actual source classes and file paths
30
- - Understand rule parameters and expected behavior
31
- - Identify confidence level of rule mappings (exact vs inferred)
32
- - Jump directly to source when a rule fails
33
-
34
- If not found, fall back to workflow JSON analysis and runtime evidence only. Treat artifact-gate failures as "not found" (for example missing required files, missing hashes, or blocking `missingSources` in `constraints.json`).
35
-
36
- ## When to Use
37
-
38
- - An event was sent but the entity didn't change state
39
- - Event processing returned FAILED status
40
- - Need to understand why an order/fulfilment is stuck
41
- - Investigating which ruleset processed (or didn't process) an event
42
- - Debugging rule execution errors
43
-
44
- ### Handoff from `/fluent-e2e-test`
45
-
46
- When invoked after a failed E2E step, accept and reuse the handoff payload when provided:
47
- - `entityRef`, `entityType`
48
- - `eventId` (optional)
49
- - expected vs actual status
50
-
51
- If `eventId` is already known, go straight to `event.get` and avoid redundant listing.
52
-
53
- ### API Constraints to Remember
54
-
55
- - **Archival window:** Events are retained for ~4 months. Queries beyond this return empty results.
56
- - **Rate limiting:** ~100 requests/minute per user. When paginating large audit trails, add brief pauses between calls.
57
- - **Max count:** MCP `event.list` caps at 500 per request; REST API supports up to 5,000 but may timeout.
58
- - **Recommended time range:** 5 minutes per query for high-volume entities. Use narrow `from`/`to` windows.
59
-
60
- ## Quick Start: One-Call Forensics
61
-
62
- For most debugging scenarios, start with `event.flowInspect`:
63
-
64
- ```
65
- event.flowInspect({
66
- rootEntityRef: "<ORDER_REF>",
67
- rootEntityType: "ORDER"
68
- })
69
- ```
70
-
71
- **Compact mode (default):** Returns a pre-analyzed summary (~2-3k tokens) with an `analysis` section containing `statusFlow`, `findings` (anomaly detection), `failedWebhookEndpoints`, and `slowestRulesets`. Audit arrays are stripped to essentials — only failed webhooks, top 5 mutations by name (count only), and top 5 slowest rulesets. Diagnostics show summary inspected events (id, name, status, closeMatch count).
72
-
73
- **IMPORTANT Context budget discipline:**
74
- - ALWAYS start with compact mode (the default). The ~2-3k token summary is sufficient for 90% of debugging.
75
- - NEVER call `compact: false` as a first step — it returns ~24-30k tokens and fills context.
76
- - If compact findings point to a specific issue, drill down with ONE targeted flag at a time (keep `compact: true`):
77
- - Rule timing issue → add `includeRuleDetails: true`
78
- - Need custom log messages → add `includeCustomLogs: true`
79
- - Need entity state snapshots → add `includeSnapshots: true`
80
- - Need child entity events → add `includeCrossEntity: true`
81
- - Only use `compact: false` as a last resort when you need raw arrays and have already identified what to look for.
82
-
83
- Example (targeted drill-down for rule timing — keeps compact summary, adds rule details):
84
- ```
85
- event.flowInspect({
86
- rootEntityRef: "<ORDER_REF>",
87
- rootEntityType: "ORDER",
88
- includeRuleDetails: true
89
- })
90
- ```
91
-
92
- **Response sections (compact mode):**
93
- - `totals` raw event counts (always present)
94
- - `analysis` local findings: `statusFlow`, `entityTypes`, `timespan`, `failedWebhookEndpoints`, `slowestRulesets`, `findings[]`
95
- - `orchestration` — statusCounts, entityTypeCounts, topNames (top 10, no events array)
96
- - `audit.exceptions`rule exceptions (critical, always included)
97
- - `audit.webhookActions` — only failures (responseCode >= 400)
98
- - `audit.mutationActions` — top 5 by queryName (name + count only)
99
- - `audit.sendEventActions` — count + scheduledCount only
100
- - `diagnostics` — summary inspected events (no full event payload)
101
-
102
- **Additional sections (available via targeted flags, all work with compact: true):**
103
- - `audit.ruleEvents` — per-rule execution details (add `includeRuleDetails: true`)
104
- - `audit.customLogs` — custom plugin logs (add `includeCustomLogs: true`)
105
- - `audit.snapshots` — entity snapshots (add `includeSnapshots: true`)
106
- - `diagnostics.noMatchAuditDetails` — closeMatches from ruleSet audit (add `includeNoMatchDetails: true`, on by default)
107
- - `crossEntity` — child entity events (add `includeCrossEntity: true`)
108
-
109
- See `/fluent-mcp-tools` for full parameter reference.
110
-
111
- Use the manual step-by-step workflow below when you need finer control over individual queries or when investigating a specific event ID.
112
-
113
- ## Diagnostic Workflow (Manual)
114
-
115
- ### Step 1: Get Entity Current State
116
-
117
- Use MCP `graphql.query` to fetch the entity's current status and key attributes:
118
-
119
- **For an ORDER:**
120
- ```graphql
121
- {
122
- orders(ref: ["<ORDER_REF>"], first: 1) {
123
- edges {
124
- node {
125
- id
126
- ref
127
- type
128
- status
129
- createdOn
130
- updatedOn
131
- attributes {
132
- name
133
- type
134
- value
135
- }
136
- fulfilmentChoice {
137
- edges {
138
- node {
139
- id
140
- ref
141
- type
142
- status
143
- deliveryType
144
- }
145
- }
146
- }
147
- items {
148
- edges {
149
- node {
150
- ref
151
- quantity
152
- status
153
- fulfilmentChoiceRef
154
- }
155
- }
156
- }
157
- }
158
- }
159
- }
160
- }
161
- ```
162
-
163
- **For a FULFILMENT:**
164
- ```graphql
165
- {
166
- fulfilments(ref: ["<FULFILMENT_REF>"], first: 1) {
167
- edges {
168
- node {
169
- id
170
- ref
171
- type
172
- status
173
- createdOn
174
- updatedOn
175
- attributes {
176
- name
177
- type
178
- value
179
- }
180
- items {
181
- edges {
182
- node {
183
- ref
184
- status
185
- requestedQuantity
186
- filledQuantity
187
- }
188
- }
189
- }
190
- order {
191
- id
192
- ref
193
- status
194
- }
195
- fromLocation {
196
- ref
197
- name
198
- }
199
- }
200
- }
201
- }
202
- }
203
- ```
204
-
205
- ### Step 2: Fetch Event History
206
-
207
- Use MCP `event.list` to get all events for this entity:
208
-
209
- ```
210
- event.list({
211
- "context.entityRef": "<ENTITY_REF>",
212
- "context.entityType": "ORDER",
213
- "count": 50
214
- })
215
- ```
216
-
217
- **Filter by failed events:**
218
- ```
219
- event.list({
220
- "context.entityRef": "<ENTITY_REF>",
221
- "context.entityType": "ORDER",
222
- "eventStatus": "FAILED",
223
- "count": 50
224
- })
225
- ```
226
-
227
- **Filter by time window:**
228
- ```
229
- event.list({
230
- "context.entityRef": "<ENTITY_REF>",
231
- "from": "2026-02-20T00:00:00Z",
232
- "to": "2026-02-20T23:59:59Z",
233
- "count": 100
234
- })
235
- ```
236
-
237
- For full event-model/filter semantics and causality patterns (`context.sourceEvents`, root-entity tracing), use `/fluent-event-api`.
238
-
239
- ### Step 3: Inspect Failed Event
240
-
241
- Use MCP `event.get` with the event ID from step 2:
242
-
243
- ```
244
- event.get({ "eventId": "<EVENT_ID>" })
245
- ```
246
-
247
- Look for:
248
- - `status` — FAILED, PENDING, SUCCESS
249
- - `response.errors` — Error messages from rule execution
250
- - `context.entityType` + `context.entityRef` — Which entity was targeted
251
- - `context.rootEntityType` + `context.rootEntityRef` — Parent entity context
252
- - `attributes` — What data was sent with the event
253
-
254
- ### Step 4: Correlate with Workflow
255
-
256
- Given the event name and entity status at time of event, identify which ruleset should have processed it:
257
-
258
- 1. **Download the workflow** via MCP `workflow.download` or read local copy
259
- 2. **Find the matching ruleset:**
260
- - If the event name matches a ruleset name → that ruleset should fire
261
- - If the entity just entered a new status → find ruleset with `triggers: [{ "status": "<STATUS>" }]`
262
- 3. **Check the rules** in that ruleset — identify which rule likely failed
263
-
264
- ### Step 5: Identify Root Cause
265
-
266
- Common failure patterns:
267
-
268
- | Symptom | Likely Cause | How to Verify |
269
- |---------|-------------|---------------|
270
- | Event FAILED, no state change | Rule threw exception | Check event response errors |
271
- | Event SUCCESS but no state change | Rule ran but SetState was conditional | Check gate conditions, verify child entity statuses |
272
- | Event PENDING for a long time | Async processing queue backlog | Wait and re-check, or send again |
273
- | Event NO_MATCH | No ruleset matched event name or status trigger | Verify event name matches a ruleset name in the workflow; check entity subtype matches workflow flexType |
274
- | Event SUCCESS but wrong state | Ruleset executed unexpected rules | Check trigger status matches expected |
275
- | Entity stuck in intermediate state | Gate condition not met | Query all child entities (FCs, fulfilments) and check their statuses |
276
- | Event not found at all | Event sent to wrong entity/ref | Verify entityRef, entityType, retailerId |
277
- | retailerId mismatch | Event sent with wrong retailerId | Check user scope — account-level users get retailerId=0 |
278
-
279
- ### Step 5B: Causal Chain Reconstruction
280
-
281
- > **Shortcut:** `event.flowInspect` with `includeRuleDetails: true` returns the full audit chain (ruleSet durations, rule-level execution with props/timing, ACTION payloads) in one call. Use the manual approach below only when you need per-event-ID granularity.
282
-
283
- When `sourceEvents` is sparse or missing, reconstruct the causal chain using correlation:
284
-
285
- ```
286
- 1. Get the ORCHESTRATION event that was sent:
287
- event.get({ eventId: "<EVENT_ID>" })
288
-
289
- 2. Find all audit events it spawned (time-window correlation):
290
- event.list({
291
- eventType: "ORCHESTRATION_AUDIT",
292
- "context.entityRef": "<ENTITY_REF>",
293
- from: "<event_generatedOn_minus_1s>",
294
- to: "<event_generatedOn_plus_30s>",
295
- count: 100
296
- })
297
-
298
- 3. Group audit events by category:
299
- - category=ruleSet → ruleset start/stop (check startTimer/stopTimer)
300
- - category=rule individual rule execution
301
- - category=ACTION → rule actions (SendEvent, SetState, Send Webhook)
302
- - category=exception → failure point
303
-
304
- 4. Build execution timeline:
305
- ORCHESTRATION event → ruleSet audit → rule audits → ACTION audits → next ORCHESTRATION (if SendEvent)
306
-
307
- 5. Identify the break point:
308
- - Last successful rule before exception
309
- - Missing expected ACTION (e.g., no SetState audit = state didn't change)
310
- - ORCHESTRATION_AUDIT with category=exception = the failure
311
- ```
312
-
313
- **When sourceEvents IS available:** Follow `sourceEvents[0]` upward to find the parent event. Repeat until you reach an event with empty `sourceEvents` (the root cause event).
314
-
315
- ### Step 5C: Correlation Confidence Ladder
316
-
317
- When multiple candidate links exist, rank correlation confidence in this order:
318
-
319
- 1. **Direct reference (highest confidence, score ~0.80)**
320
- Child event `context.sourceEvents[]` contains the parent event ID.
321
- 2. **Entity + timing match (medium confidence, score ~0.15)**
322
- Same `entityType` + same entity identifier (`entityId`/`entityRef`) within **1ms timing gap**.
323
- 3. **Root-context + sequence match (medium-low confidence, score ~0.05)**
324
- Same `rootEntityType/rootEntityRef` and expected sequence (`ruleSet` -> `rule` -> `ACTION`).
325
- 4. **Name-only inference (low confidence, score 0)**
326
- Event/ruleset names suggest linkage but no causal pointer.
327
-
328
- **Scoring:** When scoring multiple candidates, sum applicable factors (max 1.0). Direct reference (0.80) + entity match (0.15) + timing proximity within 100μs (0.05) = 1.0 (perfect). Use this to pick the best match when multiple candidates exist.
329
-
330
- **Timing threshold:** Use **1 millisecond** as the maximum gap for timing-based correlation. Events further apart than 1ms on the same entity are unlikely to be causally linked via the same rule execution.
331
-
332
- Always tag conclusions as **confirmed** (1) or **inferred** (2-4), and include the evidence used.
333
-
334
- For full event model and filter semantics `/fluent-event-api`.
335
-
336
- ### Step 5D: Payload Evidence Bundle (Mutations, Webhooks, Scheduled)
337
-
338
- > **Shortcut:** `event.flowInspect` extracts all three categories below automatically: `audit.mutationActions`, `audit.webhookActions`, `audit.sendEventActions` / `audit.scheduledActions`. Use the manual approach below only for targeted queries outside the root-entity scope.
339
-
340
- After reconstructing the chain, extract payload evidence from `category=ACTION` events:
341
-
342
- 1. Query:
343
- ```
344
- event.list({
345
- "eventType": "ORCHESTRATION_AUDIT",
346
- "category": "ACTION",
347
- "context.rootEntityRef": "<ENTITY_REF>",
348
- "count": 200
349
- })
350
- ```
351
- 2. Mutation extraction (often from ACTION events with missing `name`):
352
- - `attributes.request.queryType` (look for `DynamicUpdateMutation`)
353
- - `attributes.request.queryName`
354
- - `attributes.request.queryString`
355
- - `attributes.request.variables.values.input` (actual mutation payload)
356
- - `attributes.response.inner`
357
- 3. Webhook extraction:
358
- - `Request Endpoint`, `Request Headers`
359
- - `Response code`, `Response reason`, `Response Body`, `Response Headers`
360
- 4. Scheduled/future-dated extraction:
361
- - `attributes["Future Dated"]`
362
- - `attributes.Event.scheduledOn`
363
- - `event.get(eventId).event.meta.scheduledOn`
364
- 5. Diagnose event-status mismatches:
365
- - If `ORCHESTRATION` shows `PENDING` but downstream ACTION/ruleSet audit completed, treat audit chain as runtime truth and flag status-lag behavior.
366
-
367
- ### Step 6: Deep Dive — Rule-Level Analysis
368
-
369
- ### Step 6A: Evidence Escalation When Logic Is Vague
370
-
371
- Do not rely on ruleset descriptions alone when rule intent is unclear.
372
- Escalate evidence in this order:
373
-
374
- 1. **Ask focused clarification questions** (event name, expected state, actual state, and where it diverged)
375
- 2. **Request source first** (`module.json` + Java rule classes)
376
- 3. **If source is unavailable, request compiled artifacts** (module ZIP/JAR)
377
- 4. **Decompile candidate rule classes** and map behavior back to workflow props and event errors
378
- 5. **Correlate with runtime evidence** (`event.get`, `event.list`, entity GraphQL state)
379
- 6. **Report confidence explicitly** (confirmed vs inferred behavior)
380
-
381
- Use this escalation whenever:
382
- - rule/ruleset descriptions are generic ("validation", "process", "update")
383
- - multiple rules can match the same symptom
384
- - event error output does not directly identify the failing line of logic
385
-
386
- ### Step 6B: Rule Source Analysis
387
-
388
- If you identified the failing rule, check its source code:
389
-
390
- 1. **Find the rule class** — Map rule name to Java file:
391
- - `ACCT.MODULE.RuleName` `rule/<package>/RuleName.java`
392
- 2. **Check required props** Does the workflow supply all props the rule expects?
393
- - `@ParamString(name = "xxx")` annotations define expected props
394
- - Props are CASE-SENSITIVE
395
- 3. **Check dynamic query paths** If rule uses `DynamicUtils.query()`, are the paths valid?
396
- 4. **Check mutation types** If rule uses `DynamicUtils.mutate()`, is the input type correct?
397
- 5. **Check setting references** — If rule reads a Setting, does the Setting exist with correct data?
398
- - Query via MCP: `graphql.query` with `settings(first: 1, context: "RETAILER", contextId: <RETAILER_ID>, name: ["<setting-name>"])`
399
-
400
- ### Step 6C: Decompiled Analysis (No Source Case)
401
-
402
- **Prerequisite:** Check if decompiled output exists at `accounts/<PROFILE>/SOURCE/.decompiled/`. If empty or missing:
403
- - Run `/fluent-custom-code <PROFILE>` it will decompile any JARs found under `SOURCE/`
404
- - If no JARs are available either, ask the user:
405
- > "To analyze this rule's implementation, I need the module JAR. You can:
406
- > 1. Copy the JAR to `accounts/<PROFILE>/SOURCE/` and re-run `/fluent-custom-code <PROFILE>`
407
- > 2. Run `/fluent-connect` which will guide you through full workspace preparation including JAR decompilation
408
- > 3. Continue with `plugin.list` data only (rule description and parameters, no implementation detail)"
409
- - For reference modules (core, order, fulfilment, commonv2, globalinventory, reporting), the JAR can typically be obtained from the Fluent module distribution or build artifacts
410
-
411
- When only JAR/ZIP artifacts are available:
412
-
413
- 1. Extract class names and identify likely rule classes from `module.json` rule mappings.
414
- 2. Decompile only the suspected classes first (avoid whole-jar noise).
415
- 3. Confirm:
416
- - which props are read
417
- - what GraphQL mutations/queries/events are invoked
418
- - what status transitions or guards are enforced
419
- 4. Reconcile decompiled findings with workflow ruleset props and observed event failures.
420
- 5. Mark any uncertain interpretation (obfuscation/inlined code) before recommending fixes.
421
- 6. Use `accounts/<PROFILE>/SOURCE/.decompiled/<artifact-name>/` and write `DECOMPILED.md` with source artifact path + decompiler used.
422
- 7. Treat JAR/ZIP artifacts and `.decompiled/` output as read-only evidence. Do not recommend editing decompiled code; recommend source onboarding for implementation changes.
423
-
424
- ### Step 6D: Performance Bottleneck Detection
425
-
426
- When investigating slow processing (not failures), calculate execution duration per step from event timestamps:
427
-
428
- 1. **Collect timing data** For each event in the causal chain, extract `eventTime` (ISO-8601 with microsecond precision when available).
429
- 2. **Calculate step durations** — Duration between consecutive events in the chain (parent → child).
430
- 3. **Identify bottlenecks** Flag any step whose duration exceeds **2× the average** step duration.
431
- 4. **Classify severity**:
432
- - Processing time <1s = normal
433
- - Processing time 1–5s = slow (investigate rule complexity, external calls)
434
- - Processing time >5s = critical bottleneck (likely external system wait: webhook, inventory query, payment gateway)
435
- 5. **Report** List steps ranked by duration, flag bottlenecks, and correlate with rule source if available.
436
-
437
- ### Step 7: Workflow Coverage Analysis (Static vs Dynamic)
438
-
439
- After tracing an entity's events (Steps 1–6), overlay the trace against the workflow definition to find divergence rulesets that should have fired but didn't, or unexpected rulesets that appeared.
440
-
441
- #### When to Use
442
-
443
- - After tracing an entity that's stuck or behaved unexpectedly
444
- - After E2E test pass/fail to verify the full expected path was executed
445
- - During go-live readiness to confirm workflow coverage on real orders
446
-
447
- #### Coverage Algorithm
448
-
449
- 1. **Reconstruct the entity's status path** from the event trace (Step 2 data):
450
- ```
451
- Extract all status transitions from events:
452
- CREATED ON_VALIDATION BOOKED PICK_PACK COMPLETE
453
- Record which event name triggered each transition.
454
- ```
455
-
456
- 2. **Load the workflow definition** (local file or `workflow.download`):
457
- ```
458
- Parse all rulesets for this entity type.
459
- For each status in the entity's actual path, collect:
460
- a. Status-triggered rulesets (triggers[].status matches the status)
461
- b. Event-name-triggered rulesets (name matches a SendEvent from the previous ruleset's rules)
462
- ```
463
-
464
- 3. **Build expected ruleset sequence** from static analysis:
465
- ```
466
- Status: CREATED
467
- Expected: CREATE ruleset → rules: [CreateVariants, UpdateStatusHistory, SendWebhook, SendEvent(ValidateOrder)]
468
- Expected downstream: ValidateOrder ruleset
469
-
470
- Status: ON_VALIDATION
471
- Expected: status-triggered rulesets + event-triggered rulesets from previous step's SendEvents
472
- ```
473
-
474
- 4. **Compare expected vs actual**:
475
- ```
476
- For each expected ruleset:
477
- Search event trace for ORCHESTRATION_AUDIT with category=ruleSet matching this name
478
- If found MATCHED
479
- If not found → MISSED
480
-
481
- For each ruleset in the event trace:
482
- Check if it appears in the expected sequence
483
- If not → UNEXPECTED
484
- ```
485
-
486
- 5. **Analyze missed rulesets** — for each MISSED ruleset, determine why:
487
- - Triggering event never sent → upstream rule didn't fire `SendEvent`
488
- - Status trigger never reached entity took a different branch
489
- - Conditional rule (ForwardIf*, gate) evaluated to false → check condition props
490
- - Setting missing caused the rule to skip → cross-reference with `/fluent-settings` audit
491
- - Entity subtype mismatch → ruleset scoped to a different flexType
492
-
493
- #### Coverage Report Format
494
-
495
- ```
496
- === Workflow Coverage: ORDER ref=HD-20260222-001 ===
497
-
498
- Status Path: CREATED ON_VALIDATION BOOKED → PICK_PACK → COMPLETE
499
-
500
- Expected Rulesets Actual (from trace) Status
501
- ──────────────────────────────────────────────────────────────
502
- CREATE CREATE MATCHED
503
- ValidateOrder ValidateOrder MATCHED
504
- ConfirmValidation ConfirmValidation MATCHED
505
- ProcessOrder ProcessOrder MATCHED
506
- BookOrder BookOrder MATCHED
507
- NotifyOrderBooked (not found) MISSEDsetting "webhook.order.booked" not found
508
- ConfirmPick ConfirmPick MATCHED
509
- ConfirmShipment ConfirmShipment MATCHED
510
-
511
- Unexpected:
512
- RetryValidation → fired at ON_VALIDATION (ScheduleEvent timeout handler)
513
-
514
- Coverage: 7/8 expected rulesets matched (87.5%)
515
- Missed: 1 (setting dependency fixable via /fluent-settings)
516
- Unexpected: 1 (timeout handler — normal for slow processing)
517
- ```
518
-
519
- #### Interpreting Results
520
-
521
- | Result | Meaning | Action |
522
- |--------|---------|--------|
523
- | **High coverage (>90%)** | Workflow executing as designed | No action needed |
524
- | **Missed rulesets with setting cause** | Settings gap — rule skipped silently | Run `/fluent-settings --audit` and create missing settings |
525
- | **Missed rulesets with condition cause** | Conditional branch not taken | Verify entity data meets the condition (attributes, child statuses) |
526
- | **Unexpected rulesets** | Timer/retry handlers or misconfigured triggers | Check if ruleset is a ScheduleEvent target (normal) or a trigger conflict (bug) |
527
- | **Low coverage (<70%)** | Workflow path fundamentally different from expected | Re-examine entity subtype, workflow version, and event sequence |
528
-
529
- #### Integration
530
-
531
- - Use `/fluent-workflow-analyzer` output for the expected ruleset sequence (static analysis)
532
- - Use Steps 1–5 event trace data for actual execution evidence (dynamic analysis)
533
- - Use `/fluent-settings --audit` to explain missing-setting causes for MISSED rulesets
534
- - Hand off MISSED rulesets to `/fluent-settings` for remediation or `/fluent-workflow-builder` for workflow fixes
535
-
536
- ## Detailed Event Data Extraction
537
-
538
- After diagnosing an issue or completing an E2E test, extract specific data types from the event audit trail for comprehensive analysis. These sections go beyond root-cause diagnosis — they produce structured inventories of what the orchestration engine actually did.
539
-
540
- > **One-call alternative:** Use `event.flowInspect` to extract all sections below (8A–8F) in a single API call. It returns mutations, webhooks, scheduled dispatches, NO_MATCH diagnostics with closeMatches, custom rule logs, entity snapshots, rule execution props, and exception details — all keyed by root entity. The manual patterns below remain useful when you need to customize extraction or filter beyond what flowInspect provides.
541
-
542
- ### 8A: Mutation Audit Trail
543
-
544
- Extract every GraphQL mutation the workflow executed, with the exact query string and input variables. Mutation ACTION events have a **null name** and contain the full mutation payload.
545
-
546
- #### Query
547
-
548
- ```
549
- event.list({
550
- "eventType": "ORCHESTRATION_AUDIT",
551
- "context.rootEntityRef": "<ENTITY_REF>",
552
- "count": 200
553
- })
554
- ```
555
-
556
- Filter results where `name` is null and `attributes` contains `request.queryString`.
557
-
558
- #### Data Fields
559
-
560
- | Attribute | Description |
561
- |-----------|-------------|
562
- | `request.queryString` | Full GraphQL mutation string (e.g., `mutation updateFulfilment($input: UpdateFulfilmentInput!) { ... }`) |
563
- | `request.inputName` | Input type name (e.g., `UpdateFulfilmentInput`) |
564
- | `request.queryType` | Mutation classification (e.g., `DynamicUpdateMutation`) |
565
- | `request.variables.values.input` | Exact input payload — entity ID, status changes, attribute updates |
566
-
567
- #### Report Format
568
-
569
- ```
570
- === Mutation Audit Trail: ORDER ref=HD-20260222-001 ===
571
-
572
- # Entity Mutation Type Target Status Attributes Changed
573
- ─────────────────────────────────────────────────────────────────────────────────
574
- 1 ORDER:143 updateOrder ORDER_SPLIT status
575
- 2 FC:89 updateFulfilmentChoice AWAITING_FC status
576
- 3 FULFILMENT:201 updateFulfilment CREATED status, fromAddress, toAddress, deliveryType
577
- 4 FULFILMENT:201 updateFulfilment RECEIVED status, attributes[allocatedAt]
578
- 5 ORDER:143 updateOrder IN_PROGRESS status
579
- 6 FULFILMENT:201 updateFulfilment PICKPACK status, attributes[pickedAt]
580
- 7 FULFILMENT:201 updateFulfilment SHIPPED status, attributes[trackingNumber, carrierRef]
581
-
582
- Total: 7 mutations across 3 entity types
583
- ```
584
-
585
- #### Use Cases
586
-
587
- - **Audit compliance**: Verify every state change has a corresponding mutation record
588
- - **Debugging stuck entities**: Identify if a SetState mutation was attempted but failed
589
- - **Change impact analysis**: See exactly which attributes were modified and in what order
590
- - **Rule behavior verification**: Confirm a rule is constructing the correct mutation input
591
-
592
- ### 8B: Webhook Delivery Report
593
-
594
- Extract full webhook request/response round-trips from ACTION events named "Send Webhook". This supplements the existing Webhook Failure Triage section with a comprehensive delivery inventory.
595
-
596
- #### Query
597
-
598
- ```
599
- event.list({
600
- "eventType": "ORCHESTRATION_AUDIT",
601
- "context.rootEntityRef": "<ENTITY_REF>",
602
- "count": 200
603
- })
604
- ```
605
-
606
- Filter results where `name == "Send Webhook"`.
607
-
608
- #### Data Fields
609
-
610
- | Attribute | Description |
611
- |-----------|-------------|
612
- | `Request Endpoint` | Target URL the webhook was sent to |
613
- | `Request Headers` | HTTP headers sent (may include auth tokens) |
614
- | `Response code` | HTTP response status (200=OK, 404=not found, 0=timeout) |
615
- | `Response Body` | Full response body from the target server |
616
- | `Response Headers` | Response headers (rate-limit, content-type) |
617
- | `Response reason` | HTTP status text (e.g., "Not Found", "OK") |
618
- | Dynamic attributes | Rule-injected attributes (e.g., `orderType`, `orderId`, `orderStatus`, `eventName`, `fulfilmentId`) |
619
-
620
- #### Report Format
621
-
622
- ```
623
- === Webhook Delivery Report: ORDER ref=HD-20260222-001 ===
624
-
625
- # Ruleset Endpoint Status Duration
626
- ────────────────────────────────────────────────────────────────────────────────────────────────────
627
- 1 OrderCreatedWebhook https://api.example.com/order/created 200 OK 120ms
628
- 2 FulfilmentCreatedWebhook https://api.example.com/fulfilment/created 200 OK 95ms
629
- 3 FulfilmentShippedWebhook https://api.example.com/fulfilment/shipped 404 NF 45ms ← FAIL
630
- 4 OrderCompletedWebhook https://api.example.com/order/completed 200 OK 110ms
631
-
632
- Summary: 3/4 delivered successfully, 1 FAILED (404)
633
- Failed webhooks: FulfilmentShippedWebhook check setting "webhook.fulfilment.shipped"
634
- ```
635
-
636
- #### Dynamic Attributes Extraction
637
-
638
- Webhook ACTION events also contain dynamic attributes injected by the rule at execution time. These represent the payload data sent alongside the webhook:
639
-
640
- ```
641
- Dynamic attributes for webhook #1 (OrderCreatedWebhook):
642
- orderType: HD
643
- orderId: 143
644
- orderStatus: CREATED
645
- eventName: CREATE
646
- fulfilmentChoiceRef: FC-HD-20260222-001
647
- sourceSystem: E2E_TEST
648
- ```
649
-
650
- These dynamic attributes are valuable for:
651
- - Reconstructing what the external system received
652
- - Verifying the correct data was included in the webhook payload
653
- - Debugging webhook receiver failures when the response body is unhelpful
654
-
655
- #### Cross-Reference with Settings
656
-
657
- Compare each webhook's `Request Endpoint` with the configured setting value:
658
-
659
- ```
660
- 1. Extract setting name from workflow rule props (e.g., "webhook.order.created")
661
- 2. Query: settings(name: ["webhook.order.created"], context: "RETAILER")
662
- 3. Parse lobValue.url from the setting
663
- 4. Compare with Request Endpoint from the ACTION event
664
- 5. If different → CONTRACT_MISMATCH (setting was changed after the event was processed, or wrong setting was loaded)
665
- ```
666
-
667
- ### 8C: Scheduled Event Inventory
668
-
669
- Extract all scheduled (future-dated) events from ACTION events named "Send Event". These are events dispatched by `ScheduleEvent` rules with a time delay.
670
-
671
- #### Query
672
-
673
- ```
674
- event.list({
675
- "eventType": "ORCHESTRATION_AUDIT",
676
- "context.rootEntityRef": "<ENTITY_REF>",
677
- "count": 200
678
- })
679
- ```
680
-
681
- Filter results where `name == "Send Event"`.
682
-
683
- #### Data Fields
684
-
685
- | Attribute | Description |
686
- |-----------|-------------|
687
- | `Event Name` | Name of the scheduled event (e.g., `ValidationGraceExpired`) |
688
- | `Event` | Full event object: ID, meta, attributes, entityType, rootEntity info |
689
- | `Future Dated` | `true` if the event is scheduled for the future, `false` if immediate |
690
- | `scheduledOn` | Epoch milliseconds when the event will fire (only present when Future Dated is true) |
691
-
692
- #### Report Format
693
-
694
- ```
695
- === Scheduled Event Inventory: ORDER ref=HD-20260222-001 ===
696
-
697
- # Event Name Entity Type Future Dated Scheduled For Delay
698
- ───────────────────────────────────────────────────────────────────────────────────────────────
699
- 1 ValidateOrder ORDER false (immediate) 0s
700
- 2 ValidationGraceExpired ORDER true 2026-02-22T13:43:30Z 30s
701
- 3 ProcessOrder ORDER false (immediate) 0s
702
- 4 NotifyFCComplete FC false (immediate) 0s
703
- 5 SourceOrder ORDER false (immediate) 0s
704
-
705
- Future-dated events: 1 of 5
706
- Scheduled timers: ValidationGraceExpired (30s delay)
707
- ```
708
-
709
- #### Scheduled Event Analysis
710
-
711
- For each future-dated event:
712
- 1. **Calculate actual delay** `scheduledOn` minus the parent event's `generatedOn` timestamp
713
- 2. **Check if it fired** — Search for the matching ORCHESTRATION event after `scheduledOn`
714
- 3. **Check if it was pre-empted** — If a status change occurred before `scheduledOn`, the scheduled event may arrive at a status where no ruleset matches (NO_MATCH is expected)
715
- 4. **Timer health** — Summarize which scheduled events fired vs were pre-empted
716
-
717
- ### 8D: NO_MATCH Deep Diagnostics
718
-
719
- When a ruleset evaluates but no rule matches (NO_MATCH), the ruleSet audit event contains structured diagnostic data explaining why. This goes beyond the simple "NO_MATCH" detection in Step 5.
720
-
721
- #### Query
722
-
723
- ```
724
- event.list({
725
- "eventType": "ORCHESTRATION_AUDIT",
726
- "context.rootEntityRef": "<ENTITY_REF>",
727
- "count": 200
728
- })
729
- ```
730
-
731
- Filter results where `category == "ruleSet"` and attributes contain `message` with "no match" or where `closeMatches` is present.
732
-
733
- #### Data Fields
734
-
735
- | Attribute | Description |
736
- |-----------|-------------|
737
- | `message` | Summary: "No rules matched for the event and its entity" |
738
- | `entityStatus` | Entity status when the ruleset was evaluated |
739
- | `closeMatches` | Array of rulesets that almost matched, with structured mismatch reasons |
740
- | `closeMatches[].name` | Ruleset name that almost matched |
741
- | `closeMatches[].mismatchReasons` | Array of specific reasons: subtype mismatch, status mismatch, etc. |
742
- | `lastRule` | Last rule that was evaluated before NO_MATCH |
743
- | `lastRuleSet` | Last ruleset that was evaluated |
744
-
745
- #### Report Format
746
-
747
- ```
748
- === NO_MATCH Diagnostics: ORDER ref=HD-20260222-001 ===
749
-
750
- Event: ValidationGraceExpired → NO_MATCH
751
-
752
- Entity status at evaluation: ON_VALIDATION
753
- Close matches:
754
- 1. ProcessOrder
755
- Mismatch: subtype=HD required, entity subtype=CC
756
- 2. CancelValidation
757
- Mismatch: status=CANCELLED required, entity status=ON_VALIDATION
758
-
759
- Diagnosis: ValidationGraceExpired fired after the entity already advanced past ON_VALIDATION
760
- (pre-empted by ConfirmValidation). This is EXPECTED for timer events.
761
-
762
- ---
763
- Event: RetryFulfilment → NO_MATCH
764
-
765
- Entity status at evaluation: SHIPPED
766
- Close matches:
767
- 1. ProcessFulfilment
768
- Mismatch: status=CREATED required, entity status=SHIPPED
769
-
770
- Diagnosis: Retry event arrived too late — fulfilment already shipped.
771
- Review: is the ScheduleEvent delay too long?
772
- ```
773
-
774
- #### NO_MATCH Classification
775
-
776
- | Pattern | Severity | Meaning |
777
- |---------|----------|---------|
778
- | Timer event + entity already advanced | INFO | Normal — scheduled event pre-empted by faster progression |
779
- | Event name has no matching ruleset | HIGH | Misconfigured workflow — event fired but no ruleset exists to handle it |
780
- | Subtype mismatch in closeMatches | MEDIUM | Event sent to wrong subtype — check SendEvent props |
781
- | Status mismatch in closeMatches | LOW | Race condition or ordering issue — usually self-resolving |
782
-
783
- ### 8E: Custom Rule Log Extraction
784
-
785
- Custom rules can emit structured diagnostic logs during execution. These appear as CUSTOM category events with `LogCollection` and `EventAttribute` data.
786
-
787
- #### Query
788
-
789
- ```
790
- event.list({
791
- "eventType": "ORCHESTRATION_AUDIT",
792
- "context.rootEntityRef": "<ENTITY_REF>",
793
- "count": 200
794
- })
795
- ```
796
-
797
- Filter results where `category == "CUSTOM"`.
798
-
799
- #### Data Fields
800
-
801
- | Attribute | Description |
802
- |-----------|-------------|
803
- | `LogCollection` | JSON string containing `logs[]` array: `{ level, source, message, timestamp }` |
804
- | `EventAttribute` | JSON string containing the triggering event's full attributes |
805
-
806
- #### Log Structure
807
-
808
- Each log entry in `LogCollection.logs[]`:
809
-
810
- ```json
811
- {
812
- "level": "INFO",
813
- "source": "ACCT.ext.CreateFulfilmentFromSourcingLocation",
814
- "message": "Creating fulfilment at location WH-MAIN for order HD-20260222-001",
815
- "timestamp": "2026-02-22T13:43:05.123Z"
816
- }
817
- ```
818
-
819
- #### Report Format
820
-
821
- ```
822
- === Custom Rule Logs: ORDER ref=HD-20260222-001 ===
823
-
824
- Timestamp Level Source Rule Message
825
- ──────────────────────────────────────────────────────────────────────────────────────────────────
826
- 2026-02-22T13:43:05.123Z INFO CreateFulfilmentFromSourcingLocation Creating fulfilment at WH-MAIN
827
- 2026-02-22T13:43:05.456Z INFO CreateFulfilmentFromSourcingLocation Fulfilment ref: FUL-HD-001
828
- 2026-02-22T13:43:06.789Z WARN ValidateInventoryAvailability Low stock: SKU-001 has 2 units
829
- 2026-02-22T13:43:07.012Z INFO SendWebhookWithDynamicAttributes Webhook sent to order.created endpoint
830
-
831
- Total: 4 log entries (3 INFO, 1 WARN, 0 ERROR)
832
- ```
833
-
834
- #### Use Cases
835
-
836
- - **Rule execution visibility**: See exactly what a custom rule decided and why
837
- - **Debugging silent failures**: When a rule "succeeds" but does something unexpected, logs reveal the internal logic path
838
- - **Performance profiling**: Log timestamps show how long each rule's internal processing took
839
- - **Regression detection**: Compare log output between test runs to spot behavioral changes
840
-
841
- ### 8F: Entity Snapshot Extraction
842
-
843
- Snapshot events capture the full entity state at the moment orchestration begins. These are emitted as `snapshot` category audit events and contain the complete entity (all fields, attributes, items, relationships).
844
-
845
- #### Query
846
-
847
- ```
848
- event.list({
849
- "eventType": "ORCHESTRATION_AUDIT",
850
- "context.rootEntityRef": "<ENTITY_REF>",
851
- "count": 200
852
- })
853
- ```
854
-
855
- Filter results where `category == "snapshot"`.
856
-
857
- #### Data Content by Entity Type
858
-
859
- **ORDER snapshot includes:**
860
- - `id`, `ref`, `type`, `subtype`, `status`
861
- - `customer` — full customer object (firstName, lastName, username)
862
- - `items[]` — order items with ref, quantity, status, productRef, fulfilmentChoiceRef
863
- - `fulfilmentChoice` — FC details (ref, deliveryType, deliveryAddress)
864
- - `attributes[]` — all entity attributes at that moment
865
- - `createdOn`, `updatedOn`
866
-
867
- **FULFILMENT snapshot includes:**
868
- - `id`, `ref`, `type`, `subtype`, `status`
869
- - `items[]` — fulfilment items with ref, requestedQuantity, filledQuantity
870
- - `toAddress`, `fromAddress` — shipping addresses
871
- - `attributes[]` — including trackingNumber, carrierRef, pickedAt, etc.
872
- - `consignment` consignment details if created
873
- - `deliveryType`
874
-
875
- #### Report Format
876
-
877
- ```
878
- === Entity Snapshots: ORDER ref=HD-20260222-001 ===
879
-
880
- Snapshot #1ORDER at CREATED (2026-02-22T13:43:01Z)
881
- Status: CREATED
882
- Items: 2 (SKU-001 x1, SKU-002 x2)
883
- Customer: john.doe
884
- Delivery: HD to 123 Main St
885
- Attributes: sourceSystem=E2E_TEST, testRunId=E2E_MULTI_202602221343
886
-
887
- Snapshot #2FULFILMENT at CREATED (2026-02-22T13:43:06Z)
888
- Status: CREATED
889
- Items: 2 (SKU-001 x1, SKU-002 x2)
890
- From: WH-MAIN (Warehouse Main)
891
- To: 123 Main St
892
- Delivery Type: HD
893
- Attributes: (none yet)
894
-
895
- Snapshot #3 FULFILMENT at PICKPACK (2026-02-22T13:43:15Z)
896
- Status: PICKPACK
897
- Items: 2 (SKU-001 filled:1, SKU-002 filled:2)
898
- Attributes: pickedAt=2026-02-22T13:43:14Z
899
- ```
900
-
901
- #### Use Cases
902
-
903
- - **State verification in E2E tests**: Compare expected entity state at each step against the snapshot — no need to query entity separately
904
- - **Before/after comparison**: Diff consecutive snapshots to see exactly what changed during a status transition
905
- - **Attribute tracking**: Verify attributes like `trackingNumber`, `pickedAt`, `deliveredAt` were set at the right time
906
- - **Customer data audit**: Confirm customer information was correctly attached at order creation
907
-
908
- #### Integration with `/fluent-e2e-test`
909
-
910
- After an E2E test completes, snapshots can be used as assertion evidence:
911
-
912
- ```
913
- For each test step:
914
- 1. Extract snapshot for the entity at the expected status
915
- 2. Verify expected fields are present and correct
916
- 3. Compare with previous snapshot to confirm the transition changed the right fields
917
- 4. Include snapshot diffs in the test report for documentation
918
- ```
919
-
920
- ## Quick Diagnostic Queries
921
-
922
- ### Order lifecycle summary (all events for an order)
923
- ```
924
- event.list({
925
- "context.entityRef": "<ORDER_REF>",
926
- "context.entityType": "ORDER",
927
- "count": 100
928
- })
929
- ```
930
-
931
- ### All fulfilments for an order
932
- ```graphql
933
- {
934
- fulfilments(orderId: [<ORDER_ID>], first: 50) {
935
- edges {
936
- node { id ref type status fromLocation { ref } }
937
- }
938
- }
939
- }
940
- ```
941
-
942
- ### All fulfilment choices for an order
943
- ```graphql
944
- {
945
- fulfilmentChoices(orderId: [<ORDER_ID>], first: 50) {
946
- edges {
947
- node { id ref type status deliveryType }
948
- }
949
- }
950
- }
951
- ```
952
-
953
- ### Check a setting value
954
- ```graphql
955
- {
956
- settings(first: 1, context: "RETAILER", contextId: <RETAILER_ID>, name: ["<SETTING_NAME>"]) {
957
- edges {
958
- node { id name value lobValue }
959
- }
960
- }
961
- }
962
- ```
963
-
964
- ### Check workflow version deployed
965
- Use MCP `workflow.list` to verify the expected version is active.
966
-
967
- ## Entity State Stuck — Decision Tree
968
-
969
- ```
970
- Entity not advancing?
971
-
972
- ├─ Check event.list for the entity
973
- ├─ No events found Event was never sent, or wrong entityRef/entityType
974
- │ ├─ Events all SUCCESS → State changed but maybe to unexpected status
975
- │ │ └─ Query entity status Check workflow state machine
976
- │ └─ Event FAILED → Inspect event.get for error details
977
- │ ├─ "Rule exception" → Check rule source code + props
978
- │ ├─ "No matching ruleset" / NO_MATCH → Event name doesn't match any ruleset; check flexType
979
- │ ├─ "Entity not found" → Wrong entityRef or entity deleted
980
- │ └─ "Permission denied" → Check user/retailer scope
981
-
982
- ├─ Entity in gate state (waiting for children)?
983
- │ └─ Query all child entities
984
- │ ├─ All children in terminal state → Gate ruleset bug (check statuses prop)
985
- │ └─ Some children not terminal → Wait for children to complete
986
-
987
- └─ Event sent but still PENDING?
988
- └─ Async queue delay — wait 15-30s and re-check
989
- ```
990
-
991
- ## Manual Intervention Options
992
-
993
- After identifying the root cause, choose the appropriate intervention:
994
-
995
- ### Option 1: Re-send the Event
996
-
997
- If the root cause is fixed (e.g., workflow deployed, setting created, data corrected), re-send the original event:
998
-
999
- ```
1000
- event.send({
1001
- "name": "<EVENT_NAME>",
1002
- "entityType": "<ENTITY_TYPE>",
1003
- "entityRef": "<ENTITY_REF>",
1004
- "retailerId": "<RETAILER_ID>"
1005
- })
1006
- ```
1007
-
1008
- ### Option 2: Run-Once Workflow (Targeted Rule Execution)
1009
-
1010
- Execute specific rules without triggering the full workflow. Useful for re-triggering a failed webhook, running a data correction rule, or executing a rule that isn't in the current deployed workflow.
1011
-
1012
- Send to `POST /api/v4.1/event/sync` with the workflow attached in `meta`:
1013
-
1014
- ```json
1015
- {
1016
- "name": "FixEvent",
1017
- "retailerId": "1",
1018
- "entityType": "FULFILMENT",
1019
- "entityId": "143",
1020
- "meta": {
1021
- "workflow": {
1022
- "retailerId": "1",
1023
- "version": "1.0",
1024
- "rulesets": [{
1025
- "name": "FixEvent",
1026
- "type": "FULFILMENT",
1027
- "eventType": "NORMAL",
1028
- "rules": [{ "name": "ACCOUNT.module.RuleName", "props": { "key": "value" } }],
1029
- "triggers": [],
1030
- "userActions": []
1031
- }]
1032
- }
1033
- }
1034
- }
1035
- ```
1036
-
1037
- **Key:** The event `name` must match the ruleset `name`. Any rule in the account can be used — it doesn't need to exist in the deployed workflow. Webhooks and mutations execute; inline events are ignored.
1038
-
1039
- For full run-once workflow reference → `/fluent-event-api`.
1040
-
1041
- ### Option 3: Direct GraphQL Mutation
1042
-
1043
- For data corrections that don't require workflow logic, use `graphql.query` with a mutation directly.
1044
-
1045
- ## Causal Chain Playbook
1046
-
1047
- Compact playbook for tracing event causality when diagnosing failures.
1048
-
1049
- ### Principle: One ORCHESTRATION Event = One Execution Journey
1050
-
1051
- Every ORCHESTRATION event triggers a chain of ORCHESTRATION_AUDIT events. The audit events contain the detailed execution (rulesets, rules, actions) linked via `sourceEvents`.
1052
-
1053
- ### Step-by-Step Chain Reconstruction
1054
-
1055
- 1. **Find the ORCHESTRATION event** that triggered execution:
1056
- ```
1057
- event.list({ "context.entityRef": "<REF>", "eventType": "ORCHESTRATION", "count": 50 })
1058
- ```
1059
-
1060
- 2. **Find all audit events it spawned** (linked by sourceEvents):
1061
- ```
1062
- event.list({
1063
- "eventType": "ORCHESTRATION_AUDIT",
1064
- "context.entityRef": "<REF>",
1065
- "from": "<orchestration_event_timestamp_minus_1s>",
1066
- "to": "<orchestration_event_timestamp_plus_60s>",
1067
- "count": 200
1068
- })
1069
- ```
1070
- Match: audit events whose `context.sourceEvents` array contains the ORCHESTRATION event ID.
1071
-
1072
- 3. **Classify audit events by category:**
1073
- - `snapshot` entity state before execution
1074
- - `ruleSet` — ruleset-level timing (`startTimer`/`stopTimer`)
1075
- - `rule` — individual rule execution
1076
- - `ACTION` — actions performed (SetState, SendEvent, Send Webhook)
1077
- - `exception` error with stack trace
1078
- - `CUSTOM` — custom log output from rules
1079
-
1080
- 4. **Trace the failure point:**
1081
- - Find first `exception` category event → check `attributes.message` and `attributes.exception.stackTrace`
1082
- - Check the `ruleSet` event its `name` is the ruleset that was executing
1083
- - Check the `ACTION` events → see what actions completed before the failure
1084
-
1085
- 5. **If sourceEvents is sparse:** fall back to entity context + time window correlation (see `/fluent-event-api` → Causality Correlation Workflow)
1086
-
1087
- ### Webhook Failure Triage
1088
-
1089
- When a webhook fails during event processing:
1090
-
1091
- 1. **Find the webhook ACTION event:**
1092
- ```
1093
- event.list({
1094
- "category": "ACTION",
1095
- "name": "Send Webhook",
1096
- "context.rootEntityRef": "<REF>",
1097
- "count": 50
1098
- })
1099
- ```
1100
-
1101
- 2. **Inspect webhook attributes:**
1102
- - `Request Endpoint` — the target URL
1103
- - `Response code` HTTP status (4xx = client error, 5xx = server error, 0 = connection timeout)
1104
- - `Response Body` error details from the remote server
1105
- - `Response Headers` may reveal rate limiting or auth issues
1106
-
1107
- 3. **Check the webhook setting:**
1108
- ```graphql
1109
- {
1110
- settings(first: 1, context: "RETAILER", contextId: <ID>, name: ["<webhook-setting-name>"]) {
1111
- edges { node { id name value lobValue } }
1112
- }
1113
- }
1114
- ```
1115
-
1116
- 4. **Common webhook failures:**
1117
-
1118
- | Response Code | Likely Cause | Action |
1119
- |--------------|--------------|--------|
1120
- | 0 | Connection timeout / DNS failure | Check endpoint URL and network |
1121
- | 401/403 | Auth credentials invalid or expired | Update webhook setting credentials |
1122
- | 404 | Endpoint URL changed | Update webhook setting URL |
1123
- | 429 | Rate limited | Implement retry/backoff or reduce event frequency |
1124
- | 500+ | Remote server error | Check target system logs |
1125
-
1126
- ## Integration with Other Skills
1127
-
1128
- | Task | Skill |
1129
- |------|-------|
1130
- | Event model, filter parameters, causality chains | `/fluent-event-api` |
1131
- | MCP payload syntax and tool limits | `/fluent-mcp-tools` |
1132
- | Rule/source correlation | `/fluent-custom-code` |
1133
- | Workflow topology and trigger intent | `/fluent-workflow-analyzer` |
1134
-
1135
- ## Reporting
1136
-
1137
- After diagnosis, report:
1138
-
1139
- 1. **Entity:** ref, type, current status, expected status
1140
- 2. **Failing event:** name, ID, status, error message
1141
- 3. **Root cause:** which ruleset/rule failed and why
1142
- 4. **Fix:** what needs to change (code, workflow, setting, data)
1143
- 5. **Recommendation:** specific file/line/config to modify
1
+ ---
2
+ name: fluent-trace
3
+ description: Trace and debug Fluent Commerce event processing. Analyze failed events, correlate with workflows and rules, identify root causes. Triggers on "trace event", "debug order", "why did event fail", "event trace", "debug fulfilment".
4
+ user-invocable: true
5
+ allowed-tools: Bash, Read, Write, Edit, Glob, Grep
6
+ argument-hint: <entity-ref> [--entity-type ORDER|FULFILMENT] [--status FAILED]
7
+ ---
8
+
9
+ # Event Trace & Debug
10
+
11
+ Trace Fluent Commerce event processing to diagnose failures, identify root causes, and correlate events with workflow rulesets and rules.
12
+
13
+ ## Ownership Boundary
14
+
15
+ This skill owns diagnostic workflow, correlation logic, and decision trees.
16
+
17
+ Canonical MCP extension tool syntax/limits are owned by `/fluent-mcp-tools`. Reuse that skill for exact request payload patterns.
18
+
19
+ ## Pre-Check: Load Source Analysis
20
+
21
+ Before tracing, check if `/fluent-custom-code` analysis artifacts exist:
22
+
23
+ ```
24
+ accounts/<PROFILE>/analysis/code/workflow-rule-map.json
25
+ accounts/<PROFILE>/analysis/code/source-map.json
26
+ ```
27
+
28
+ If found, use them to:
29
+ - Map rule names in event traces to actual source classes and file paths
30
+ - Understand rule parameters and expected behavior
31
+ - Identify confidence level of rule mappings (exact vs inferred)
32
+ - Jump directly to source when a rule fails
33
+
34
+ If not found, fall back to workflow JSON analysis and runtime evidence only. Treat artifact-gate failures as "not found" (for example missing required files, missing hashes, or blocking `missingSources` in `constraints.json`).
35
+
36
+ ## When to Use
37
+
38
+ - An event was sent but the entity didn't change state
39
+ - Event processing returned FAILED status
40
+ - Need to understand why an order/fulfilment is stuck
41
+ - Investigating which ruleset processed (or didn't process) an event
42
+ - Debugging rule execution errors
43
+
44
+ ### Handoff from `/fluent-e2e-test`
45
+
46
+ When invoked after a failed E2E step, accept and reuse the handoff payload when provided:
47
+ - `entityRef`, `entityType`
48
+ - `eventId` (optional)
49
+ - expected vs actual status
50
+
51
+ If `eventId` is already known, go straight to `event.get` and avoid redundant listing.
52
+
53
+ ### API Constraints to Remember
54
+
55
+ - **Archival window:** Events are retained for ~4 months. Queries beyond this return empty results.
56
+ - **Rate limiting:** ~100 requests/minute per user. When paginating large audit trails, add brief pauses between calls.
57
+ - **Max count:** MCP `event.list` caps at 500 per request; REST API supports up to 5,000 but may timeout.
58
+ - **Recommended time range:** 5 minutes per query for high-volume entities. Use narrow `from`/`to` windows.
59
+
60
+ ## Progress
61
+
62
+ Emit this block at each phase transition to show progress:
63
+
64
+ ```
65
+ ▸ /fluent-trace [1/5]
66
+ Load context → Query events
67
+ Inspect failed event ○ Correlate with workflow
68
+ ○ Root cause & remediation
69
+ ```
70
+
71
+ Update the block as each phase completes mark completed phases with `✓`, the active phase with `→`, and remaining phases with `○`. Replace `[1/5]` with the current phase number.
72
+
73
+ ## Quick Start: One-Call Forensics
74
+
75
+ For most debugging scenarios, start with `event.flowInspect`:
76
+
77
+ ```
78
+ event.flowInspect({
79
+ rootEntityRef: "<ORDER_REF>",
80
+ rootEntityType: "ORDER"
81
+ })
82
+ ```
83
+
84
+ **Compact mode (default):** Returns a pre-analyzed summary (~2-3k tokens) with an `analysis` section containing `statusFlow`, `findings` (anomaly detection), `failedWebhookEndpoints`, and `slowestRulesets`. Audit arrays are stripped to essentials — only failed webhooks, top 5 mutations by name (count only), and top 5 slowest rulesets. Diagnostics show summary inspected events (id, name, status, closeMatch count).
85
+
86
+ **IMPORTANT — Context budget discipline:**
87
+ - ALWAYS start with compact mode (the default). The ~2-3k token summary is sufficient for 90% of debugging.
88
+ - NEVER call `compact: false` as a first step — it returns ~24-30k tokens and fills context.
89
+ - If compact findings point to a specific issue, drill down with ONE targeted flag at a time (keep `compact: true`):
90
+ - Rule timing issue → add `includeRuleDetails: true`
91
+ - Need custom log messages → add `includeCustomLogs: true`
92
+ - Need entity state snapshots → add `includeSnapshots: true`
93
+ - Need child entity events add `includeCrossEntity: true`
94
+ - Only use `compact: false` as a last resort when you need raw arrays and have already identified what to look for.
95
+
96
+ Example (targeted drill-down for rule timing keeps compact summary, adds rule details):
97
+ ```
98
+ event.flowInspect({
99
+ rootEntityRef: "<ORDER_REF>",
100
+ rootEntityType: "ORDER",
101
+ includeRuleDetails: true
102
+ })
103
+ ```
104
+
105
+ **Response sections (compact mode):**
106
+ - `totals` — raw event counts (always present)
107
+ - `analysis` — local findings: `statusFlow`, `entityTypes`, `timespan`, `failedWebhookEndpoints`, `slowestRulesets`, `findings[]`
108
+ - `orchestration` — statusCounts, entityTypeCounts, topNames (top 10, no events array)
109
+ - `audit.exceptions` rule exceptions (critical, always included)
110
+ - `audit.webhookActions` — only failures (responseCode >= 400)
111
+ - `audit.mutationActions` top 5 by queryName (name + count only)
112
+ - `audit.sendEventActions` — count + scheduledCount only
113
+ - `diagnostics` summary inspected events (no full event payload)
114
+
115
+ **Additional sections (available via targeted flags, all work with compact: true):**
116
+ - `audit.ruleEvents` — per-rule execution details (add `includeRuleDetails: true`)
117
+ - `audit.customLogs` custom plugin logs (add `includeCustomLogs: true`)
118
+ - `audit.snapshots` — entity snapshots (add `includeSnapshots: true`)
119
+ - `diagnostics.noMatchAuditDetails` — closeMatches from ruleSet audit (add `includeNoMatchDetails: true`, on by default)
120
+ - `crossEntity` — child entity events (add `includeCrossEntity: true`)
121
+
122
+ See `/fluent-mcp-tools` for full parameter reference.
123
+
124
+ Use the manual step-by-step workflow below when you need finer control over individual queries or when investigating a specific event ID.
125
+
126
+ ## Diagnostic Workflow (Manual)
127
+
128
+ ### Step 1: Get Entity Current State
129
+
130
+ Use MCP `graphql.query` to fetch the entity's current status and key attributes:
131
+
132
+ **For an ORDER:**
133
+ ```graphql
134
+ {
135
+ orders(ref: ["<ORDER_REF>"], first: 1) {
136
+ edges {
137
+ node {
138
+ id
139
+ ref
140
+ type
141
+ status
142
+ createdOn
143
+ updatedOn
144
+ attributes {
145
+ name
146
+ type
147
+ value
148
+ }
149
+ fulfilmentChoice {
150
+ edges {
151
+ node {
152
+ id
153
+ ref
154
+ type
155
+ status
156
+ deliveryType
157
+ }
158
+ }
159
+ }
160
+ items {
161
+ edges {
162
+ node {
163
+ ref
164
+ quantity
165
+ status
166
+ fulfilmentChoiceRef
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
176
+ **For a FULFILMENT:**
177
+ ```graphql
178
+ {
179
+ fulfilments(ref: ["<FULFILMENT_REF>"], first: 1) {
180
+ edges {
181
+ node {
182
+ id
183
+ ref
184
+ type
185
+ status
186
+ createdOn
187
+ updatedOn
188
+ attributes {
189
+ name
190
+ type
191
+ value
192
+ }
193
+ items {
194
+ edges {
195
+ node {
196
+ ref
197
+ status
198
+ requestedQuantity
199
+ filledQuantity
200
+ }
201
+ }
202
+ }
203
+ order {
204
+ id
205
+ ref
206
+ status
207
+ }
208
+ fromLocation {
209
+ ref
210
+ name
211
+ }
212
+ }
213
+ }
214
+ }
215
+ }
216
+ ```
217
+
218
+ ### Step 2: Fetch Event History
219
+
220
+ > **Event filter reference:** For the complete event filter parameter syntax, status codes, category values, and advanced query patterns, see `/fluent-event-api`. The examples below show trace-specific usage patterns.
221
+
222
+ Use MCP `event.list` to get all events for this entity:
223
+
224
+ ```
225
+ event.list({
226
+ "context.entityRef": "<ENTITY_REF>",
227
+ "context.entityType": "ORDER",
228
+ "count": 50
229
+ })
230
+ ```
231
+
232
+ **Filter by failed events:**
233
+ ```
234
+ event.list({
235
+ "context.entityRef": "<ENTITY_REF>",
236
+ "context.entityType": "ORDER",
237
+ "eventStatus": "FAILED",
238
+ "count": 50
239
+ })
240
+ ```
241
+
242
+ > **Canonical reference:** See `/fluent-event-api` for complete event status values, filter syntax, and query patterns.
243
+
244
+ **Filter by time window:**
245
+ ```
246
+ event.list({
247
+ "context.entityRef": "<ENTITY_REF>",
248
+ "from": "2026-02-20T00:00:00Z",
249
+ "to": "2026-02-20T23:59:59Z",
250
+ "count": 100
251
+ })
252
+ ```
253
+
254
+ For full event-model/filter semantics and causality patterns (`context.sourceEvents`, root-entity tracing), use `/fluent-event-api`.
255
+
256
+ ### Step 3: Inspect Failed Event
257
+
258
+ Use MCP `event.get` with the event ID from step 2:
259
+
260
+ ```
261
+ event.get({ "eventId": "<EVENT_ID>" })
262
+ ```
263
+
264
+ Look for:
265
+ - `status` — FAILED, PENDING, SUCCESS
266
+ - `response.errors` — Error messages from rule execution
267
+ - `context.entityType` + `context.entityRef` — Which entity was targeted
268
+ - `context.rootEntityType` + `context.rootEntityRef` Parent entity context
269
+ - `attributes` — What data was sent with the event
270
+
271
+ ### Step 4: Correlate with Workflow
272
+
273
+ Given the event name and entity status at time of event, identify which ruleset should have processed it:
274
+
275
+ 1. **Download the workflow** via MCP `workflow.download` or read local copy
276
+ 2. **Find the matching ruleset:**
277
+ - If the event name matches a ruleset name that ruleset should fire
278
+ - If the entity just entered a new status → find ruleset with `triggers: [{ "status": "<STATUS>" }]`
279
+ 3. **Check the rules** in that ruleset — identify which rule likely failed
280
+
281
+ ### Step 5: Identify Root Cause
282
+
283
+ Common failure patterns:
284
+
285
+ | Symptom | Likely Cause | How to Verify |
286
+ |---------|-------------|---------------|
287
+ | Event FAILED, no state change | Rule threw exception | Check event response errors |
288
+ | Event SUCCESS but no state change | Rule ran but SetState was conditional | Check gate conditions, verify child entity statuses |
289
+ | Event PENDING for a long time | Async processing queue backlog | Wait and re-check, or send again |
290
+ | Event NO_MATCH | No ruleset matched event name or status trigger | Verify event name matches a ruleset name in the workflow; check entity subtype matches workflow flexType |
291
+ | Event SUCCESS but wrong state | Ruleset executed unexpected rules | Check trigger status matches expected |
292
+ | Entity stuck in intermediate state | Gate condition not met | Query all child entities (FCs, fulfilments) and check their statuses |
293
+ | Event not found at all | Event sent to wrong entity/ref | Verify entityRef, entityType, retailerId |
294
+ | retailerId mismatch | Event sent with wrong retailerId | Check user scope — account-level users get retailerId=0 |
295
+
296
+ ### Step 5B: Causal Chain Reconstruction
297
+
298
+ > **Shortcut:** `event.flowInspect` with `includeRuleDetails: true` returns the full audit chain (ruleSet durations, rule-level execution with props/timing, ACTION payloads) in one call. Use the manual approach below only when you need per-event-ID granularity.
299
+
300
+ When `sourceEvents` is sparse or missing, reconstruct the causal chain using correlation:
301
+
302
+ ```
303
+ 1. Get the ORCHESTRATION event that was sent:
304
+ event.get({ eventId: "<EVENT_ID>" })
305
+
306
+ 2. Find all audit events it spawned (time-window correlation):
307
+ event.list({
308
+ eventType: "ORCHESTRATION_AUDIT",
309
+ "context.entityRef": "<ENTITY_REF>",
310
+ from: "<event_generatedOn_minus_1s>",
311
+ to: "<event_generatedOn_plus_30s>",
312
+ count: 100
313
+ })
314
+
315
+ 3. Group audit events by category:
316
+ - category=ruleSet → ruleset start/stop (check startTimer/stopTimer)
317
+ - category=rule individual rule execution
318
+ - category=ACTION → rule actions (SendEvent, SetState, Send Webhook)
319
+ - category=exception failure point
320
+
321
+ 4. Build execution timeline:
322
+ ORCHESTRATION event ruleSet audit rule audits ACTION audits → next ORCHESTRATION (if SendEvent)
323
+
324
+ 5. Identify the break point:
325
+ - Last successful rule before exception
326
+ - Missing expected ACTION (e.g., no SetState audit = state didn't change)
327
+ - ORCHESTRATION_AUDIT with category=exception = the failure
328
+ ```
329
+
330
+ **When sourceEvents IS available:** Follow `sourceEvents[0]` upward to find the parent event. Repeat until you reach an event with empty `sourceEvents` (the root cause event).
331
+
332
+ ### Step 5C: Correlation Confidence Ladder
333
+
334
+ When multiple candidate links exist, rank correlation confidence in this order:
335
+
336
+ 1. **Direct reference (highest confidence, score ~0.80)**
337
+ Child event `context.sourceEvents[]` contains the parent event ID.
338
+ 2. **Entity + timing match (medium confidence, score ~0.15)**
339
+ Same `entityType` + same entity identifier (`entityId`/`entityRef`) within **1ms timing gap**.
340
+ 3. **Root-context + sequence match (medium-low confidence, score ~0.05)**
341
+ Same `rootEntityType/rootEntityRef` and expected sequence (`ruleSet` -> `rule` -> `ACTION`).
342
+ 4. **Name-only inference (low confidence, score 0)**
343
+ Event/ruleset names suggest linkage but no causal pointer.
344
+
345
+ **Scoring:** When scoring multiple candidates, sum applicable factors (max 1.0). Direct reference (0.80) + entity match (0.15) + timing proximity within 100μs (0.05) = 1.0 (perfect). Use this to pick the best match when multiple candidates exist.
346
+
347
+ **Timing threshold:** Use **1 millisecond** as the maximum gap for timing-based correlation. Events further apart than 1ms on the same entity are unlikely to be causally linked via the same rule execution.
348
+
349
+ Always tag conclusions as **confirmed** (1) or **inferred** (2-4), and include the evidence used.
350
+
351
+ For full event model and filter semantics `/fluent-event-api`.
352
+
353
+ ### Step 5D: Payload Evidence Bundle (Mutations, Webhooks, Scheduled)
354
+
355
+ > **Shortcut:** `event.flowInspect` extracts all three categories below automatically: `audit.mutationActions`, `audit.webhookActions`, `audit.sendEventActions` / `audit.scheduledActions`. Use the manual approach below only for targeted queries outside the root-entity scope.
356
+
357
+ After reconstructing the chain, extract payload evidence from `category=ACTION` events:
358
+
359
+ 1. Query:
360
+ ```
361
+ event.list({
362
+ "eventType": "ORCHESTRATION_AUDIT",
363
+ "category": "ACTION",
364
+ "context.rootEntityRef": "<ENTITY_REF>",
365
+ "count": 200
366
+ })
367
+ ```
368
+ 2. Mutation extraction (often from ACTION events with missing `name`):
369
+ - `attributes.request.queryType` (look for `DynamicUpdateMutation`)
370
+ - `attributes.request.queryName`
371
+ - `attributes.request.queryString`
372
+ - `attributes.request.variables.values.input` (actual mutation payload)
373
+ - `attributes.response.inner`
374
+ 3. Webhook extraction:
375
+ - `Request Endpoint`, `Request Headers`
376
+ - `Response code`, `Response reason`, `Response Body`, `Response Headers`
377
+ 4. Scheduled/future-dated extraction:
378
+ - `attributes["Future Dated"]`
379
+ - `attributes.Event.scheduledOn`
380
+ - `event.get(eventId).event.meta.scheduledOn`
381
+ 5. Diagnose event-status mismatches:
382
+ - If `ORCHESTRATION` shows `PENDING` but downstream ACTION/ruleSet audit completed, treat audit chain as runtime truth and flag status-lag behavior.
383
+
384
+ ### Step 6: Deep Dive Rule-Level Analysis
385
+
386
+ ### Step 6A: Evidence Escalation When Logic Is Vague
387
+
388
+ Do not rely on ruleset descriptions alone when rule intent is unclear.
389
+ Escalate evidence in this order:
390
+
391
+ 1. **Ask focused clarification questions** (event name, expected state, actual state, and where it diverged)
392
+ 2. **Request source first** (`module.json` + Java rule classes)
393
+ 3. **If source is unavailable, request compiled artifacts** (module ZIP/JAR)
394
+ 4. **Decompile candidate rule classes** and map behavior back to workflow props and event errors
395
+ 5. **Correlate with runtime evidence** (`event.get`, `event.list`, entity GraphQL state)
396
+ 6. **Report confidence explicitly** (confirmed vs inferred behavior)
397
+
398
+ Use this escalation whenever:
399
+ - rule/ruleset descriptions are generic ("validation", "process", "update")
400
+ - multiple rules can match the same symptom
401
+ - event error output does not directly identify the failing line of logic
402
+
403
+ ### Step 6B: Rule Source Analysis
404
+
405
+ If you identified the failing rule, check its source code:
406
+
407
+ 1. **Find the rule class** Map rule name to Java file:
408
+ - `ACCT.MODULE.RuleName` `rule/<package>/RuleName.java`
409
+ 2. **Check required props** Does the workflow supply all props the rule expects?
410
+ - `@ParamString(name = "xxx")` annotations define expected props
411
+ - Props are CASE-SENSITIVE
412
+ 3. **Check dynamic query paths** — If rule uses `DynamicUtils.query()`, are the paths valid?
413
+ 4. **Check mutation types** If rule uses `DynamicUtils.mutate()`, is the input type correct?
414
+ 5. **Check setting references** — If rule reads a Setting, does the Setting exist with correct data?
415
+ - Query via MCP: `graphql.query` with `settings(first: 1, context: "RETAILER", contextId: <RETAILER_ID>, name: ["<setting-name>"])`
416
+
417
+ ### Step 6C: Decompiled Analysis (No Source Case)
418
+
419
+ **Prerequisite:** Check if decompiled output exists at `accounts/<PROFILE>/SOURCE/.decompiled/`. If empty or missing:
420
+ - Run `/fluent-custom-code <PROFILE>` it will decompile any JARs found under `SOURCE/`
421
+ - If no JARs are available either, ask the user:
422
+ > "To analyze this rule's implementation, I need the module JAR. You can:
423
+ > 1. Copy the JAR to `accounts/<PROFILE>/SOURCE/` and re-run `/fluent-custom-code <PROFILE>`
424
+ > 2. Run `/fluent-connect` which will guide you through full workspace preparation including JAR decompilation
425
+ > 3. Continue with `plugin.list` data only (rule description and parameters, no implementation detail)"
426
+ - For reference modules (core, order, fulfilment, commonv2, globalinventory, reporting), the JAR can typically be obtained from the Fluent module distribution or build artifacts
427
+
428
+ When only JAR/ZIP artifacts are available:
429
+
430
+ 1. Extract class names and identify likely rule classes from `module.json` rule mappings.
431
+ 2. Decompile only the suspected classes first (avoid whole-jar noise).
432
+ 3. Confirm:
433
+ - which props are read
434
+ - what GraphQL mutations/queries/events are invoked
435
+ - what status transitions or guards are enforced
436
+ 4. Reconcile decompiled findings with workflow ruleset props and observed event failures.
437
+ 5. Mark any uncertain interpretation (obfuscation/inlined code) before recommending fixes.
438
+ 6. Use `accounts/<PROFILE>/SOURCE/.decompiled/<artifact-name>/` and write `DECOMPILED.md` with source artifact path + decompiler used.
439
+ 7. Treat JAR/ZIP artifacts and `.decompiled/` output as read-only evidence. Do not recommend editing decompiled code; recommend source onboarding for implementation changes.
440
+
441
+ ### Step 6D: Performance Bottleneck Detection
442
+
443
+ When investigating slow processing (not failures), calculate execution duration per step from event timestamps:
444
+
445
+ 1. **Collect timing data** For each event in the causal chain, extract `eventTime` (ISO-8601 with microsecond precision when available).
446
+ 2. **Calculate step durations** — Duration between consecutive events in the chain (parent → child).
447
+ 3. **Identify bottlenecks** — Flag any step whose duration exceeds **2× the average** step duration.
448
+ 4. **Classify severity**:
449
+ - Processing time <1s = normal
450
+ - Processing time 1–5s = slow (investigate rule complexity, external calls)
451
+ - Processing time >5s = critical bottleneck (likely external system wait: webhook, inventory query, payment gateway)
452
+ 5. **Report** List steps ranked by duration, flag bottlenecks, and correlate with rule source if available.
453
+
454
+ ### Step 7: Workflow Coverage Analysis (Static vs Dynamic)
455
+
456
+ After tracing an entity's events (Steps 1–6), overlay the trace against the workflow definition to find divergence — rulesets that should have fired but didn't, or unexpected rulesets that appeared.
457
+
458
+ #### When to Use
459
+
460
+ - After tracing an entity that's stuck or behaved unexpectedly
461
+ - After E2E test pass/fail to verify the full expected path was executed
462
+ - During go-live readiness to confirm workflow coverage on real orders
463
+
464
+ #### Coverage Algorithm
465
+
466
+ 1. **Reconstruct the entity's status path** from the event trace (Step 2 data):
467
+ ```
468
+ Extract all status transitions from events:
469
+ CREATED → ON_VALIDATION → BOOKED → PICK_PACK → COMPLETE
470
+ Record which event name triggered each transition.
471
+ ```
472
+
473
+ 2. **Load the workflow definition** (local file or `workflow.download`):
474
+ ```
475
+ Parse all rulesets for this entity type.
476
+ For each status in the entity's actual path, collect:
477
+ a. Status-triggered rulesets (triggers[].status matches the status)
478
+ b. Event-name-triggered rulesets (name matches a SendEvent from the previous ruleset's rules)
479
+ ```
480
+
481
+ 3. **Build expected ruleset sequence** from static analysis:
482
+ ```
483
+ Status: CREATED
484
+ Expected: CREATE ruleset → rules: [CreateVariants, UpdateStatusHistory, SendWebhook, SendEvent(ValidateOrder)]
485
+ Expected downstream: ValidateOrder ruleset
486
+
487
+ Status: ON_VALIDATION
488
+ Expected: status-triggered rulesets + event-triggered rulesets from previous step's SendEvents
489
+ ```
490
+
491
+ 4. **Compare expected vs actual**:
492
+ ```
493
+ For each expected ruleset:
494
+ Search event trace for ORCHESTRATION_AUDIT with category=ruleSet matching this name
495
+ If found → MATCHED
496
+ If not found MISSED
497
+
498
+ For each ruleset in the event trace:
499
+ Check if it appears in the expected sequence
500
+ If not → UNEXPECTED
501
+ ```
502
+
503
+ 5. **Analyze missed rulesets** — for each MISSED ruleset, determine why:
504
+ - Triggering event never sent → upstream rule didn't fire `SendEvent`
505
+ - Status trigger never reached → entity took a different branch
506
+ - Conditional rule (ForwardIf*, gate) evaluated to false → check condition props
507
+ - Setting missing caused the rule to skip cross-reference with `/fluent-settings` audit
508
+ - Entity subtype mismatch → ruleset scoped to a different flexType
509
+
510
+ #### Coverage Report Format
511
+
512
+ ```
513
+ === Workflow Coverage: ORDER ref=HD-20260222-001 ===
514
+
515
+ Status Path: CREATED ON_VALIDATION BOOKED PICK_PACK → COMPLETE
516
+
517
+ Expected Rulesets Actual (from trace) Status
518
+ ──────────────────────────────────────────────────────────────
519
+ CREATE CREATE MATCHED
520
+ ValidateOrder ValidateOrder MATCHED
521
+ ConfirmValidation ConfirmValidation MATCHED
522
+ ProcessOrder ProcessOrder MATCHED
523
+ BookOrder BookOrder MATCHED
524
+ NotifyOrderBooked (not found) MISSED setting "webhook.order.booked" not found
525
+ ConfirmPick ConfirmPick MATCHED
526
+ ConfirmShipment ConfirmShipment MATCHED
527
+
528
+ Unexpected:
529
+ RetryValidation → fired at ON_VALIDATION (ScheduleEvent timeout handler)
530
+
531
+ Coverage: 7/8 expected rulesets matched (87.5%)
532
+ Missed: 1 (setting dependency fixable via /fluent-settings)
533
+ Unexpected: 1 (timeout handler normal for slow processing)
534
+ ```
535
+
536
+ #### Interpreting Results
537
+
538
+ | Result | Meaning | Action |
539
+ |--------|---------|--------|
540
+ | **High coverage (>90%)** | Workflow executing as designed | No action needed |
541
+ | **Missed rulesets with setting cause** | Settings gap — rule skipped silently | Run `/fluent-settings --audit` and create missing settings |
542
+ | **Missed rulesets with condition cause** | Conditional branch not taken | Verify entity data meets the condition (attributes, child statuses) |
543
+ | **Unexpected rulesets** | Timer/retry handlers or misconfigured triggers | Check if ruleset is a ScheduleEvent target (normal) or a trigger conflict (bug) |
544
+ | **Low coverage (<70%)** | Workflow path fundamentally different from expected | Re-examine entity subtype, workflow version, and event sequence |
545
+
546
+ #### Integration
547
+
548
+ - Use `/fluent-workflow-analyzer` output for the expected ruleset sequence (static analysis)
549
+ - Use Steps 1–5 event trace data for actual execution evidence (dynamic analysis)
550
+ - Use `/fluent-settings --audit` to explain missing-setting causes for MISSED rulesets
551
+ - Hand off MISSED rulesets to `/fluent-settings` for remediation or `/fluent-workflow-builder` for workflow fixes
552
+
553
+ ## Detailed Event Data Extraction
554
+
555
+ After diagnosing an issue or completing an E2E test, extract specific data types from the event audit trail for comprehensive analysis. These sections go beyond root-cause diagnosis — they produce structured inventories of what the orchestration engine actually did.
556
+
557
+ > **One-call alternative:** Use `event.flowInspect` to extract all sections below (8A–8F) in a single API call. It returns mutations, webhooks, scheduled dispatches, NO_MATCH diagnostics with closeMatches, custom rule logs, entity snapshots, rule execution props, and exception details — all keyed by root entity. The manual patterns below remain useful when you need to customize extraction or filter beyond what flowInspect provides.
558
+
559
+ ### 8A: Mutation Audit Trail
560
+
561
+ Extract every GraphQL mutation the workflow executed, with the exact query string and input variables. Mutation ACTION events have a **null name** and contain the full mutation payload.
562
+
563
+ #### Query
564
+
565
+ ```
566
+ event.list({
567
+ "eventType": "ORCHESTRATION_AUDIT",
568
+ "context.rootEntityRef": "<ENTITY_REF>",
569
+ "count": 200
570
+ })
571
+ ```
572
+
573
+ Filter results where `name` is null and `attributes` contains `request.queryString`.
574
+
575
+ #### Data Fields
576
+
577
+ | Attribute | Description |
578
+ |-----------|-------------|
579
+ | `request.queryString` | Full GraphQL mutation string (e.g., `mutation updateFulfilment($input: UpdateFulfilmentInput!) { ... }`) |
580
+ | `request.inputName` | Input type name (e.g., `UpdateFulfilmentInput`) |
581
+ | `request.queryType` | Mutation classification (e.g., `DynamicUpdateMutation`) |
582
+ | `request.variables.values.input` | Exact input payload — entity ID, status changes, attribute updates |
583
+
584
+ #### Report Format
585
+
586
+ ```
587
+ === Mutation Audit Trail: ORDER ref=HD-20260222-001 ===
588
+
589
+ # Entity Mutation Type Target Status Attributes Changed
590
+ ─────────────────────────────────────────────────────────────────────────────────
591
+ 1 ORDER:143 updateOrder ORDER_SPLIT status
592
+ 2 FC:89 updateFulfilmentChoice AWAITING_FC status
593
+ 3 FULFILMENT:201 updateFulfilment CREATED status, fromAddress, toAddress, deliveryType
594
+ 4 FULFILMENT:201 updateFulfilment RECEIVED status, attributes[allocatedAt]
595
+ 5 ORDER:143 updateOrder IN_PROGRESS status
596
+ 6 FULFILMENT:201 updateFulfilment PICKPACK status, attributes[pickedAt]
597
+ 7 FULFILMENT:201 updateFulfilment SHIPPED status, attributes[trackingNumber, carrierRef]
598
+
599
+ Total: 7 mutations across 3 entity types
600
+ ```
601
+
602
+ #### Use Cases
603
+
604
+ - **Audit compliance**: Verify every state change has a corresponding mutation record
605
+ - **Debugging stuck entities**: Identify if a SetState mutation was attempted but failed
606
+ - **Change impact analysis**: See exactly which attributes were modified and in what order
607
+ - **Rule behavior verification**: Confirm a rule is constructing the correct mutation input
608
+
609
+ ### 8B: Webhook Delivery Report
610
+
611
+ Extract full webhook request/response round-trips from ACTION events named "Send Webhook". This supplements the existing Webhook Failure Triage section with a comprehensive delivery inventory.
612
+
613
+ #### Query
614
+
615
+ ```
616
+ event.list({
617
+ "eventType": "ORCHESTRATION_AUDIT",
618
+ "context.rootEntityRef": "<ENTITY_REF>",
619
+ "count": 200
620
+ })
621
+ ```
622
+
623
+ Filter results where `name == "Send Webhook"`.
624
+
625
+ #### Data Fields
626
+
627
+ | Attribute | Description |
628
+ |-----------|-------------|
629
+ | `Request Endpoint` | Target URL the webhook was sent to |
630
+ | `Request Headers` | HTTP headers sent (may include auth tokens) |
631
+ | `Response code` | HTTP response status (200=OK, 404=not found, 0=timeout) |
632
+ | `Response Body` | Full response body from the target server |
633
+ | `Response Headers` | Response headers (rate-limit, content-type) |
634
+ | `Response reason` | HTTP status text (e.g., "Not Found", "OK") |
635
+ | Dynamic attributes | Rule-injected attributes (e.g., `orderType`, `orderId`, `orderStatus`, `eventName`, `fulfilmentId`) |
636
+
637
+ #### Report Format
638
+
639
+ ```
640
+ === Webhook Delivery Report: ORDER ref=HD-20260222-001 ===
641
+
642
+ # Ruleset Endpoint Status Duration
643
+ ────────────────────────────────────────────────────────────────────────────────────────────────────
644
+ 1 OrderCreatedWebhook https://api.example.com/order/created 200 OK 120ms
645
+ 2 FulfilmentCreatedWebhook https://api.example.com/fulfilment/created 200 OK 95ms
646
+ 3 FulfilmentShippedWebhook https://api.example.com/fulfilment/shipped 404 NF 45ms FAIL
647
+ 4 OrderCompletedWebhook https://api.example.com/order/completed 200 OK 110ms
648
+
649
+ Summary: 3/4 delivered successfully, 1 FAILED (404)
650
+ Failed webhooks: FulfilmentShippedWebhook check setting "webhook.fulfilment.shipped"
651
+ ```
652
+
653
+ #### Dynamic Attributes Extraction
654
+
655
+ Webhook ACTION events also contain dynamic attributes injected by the rule at execution time. These represent the payload data sent alongside the webhook:
656
+
657
+ ```
658
+ Dynamic attributes for webhook #1 (OrderCreatedWebhook):
659
+ orderType: HD
660
+ orderId: 143
661
+ orderStatus: CREATED
662
+ eventName: CREATE
663
+ fulfilmentChoiceRef: FC-HD-20260222-001
664
+ sourceSystem: E2E_TEST
665
+ ```
666
+
667
+ These dynamic attributes are valuable for:
668
+ - Reconstructing what the external system received
669
+ - Verifying the correct data was included in the webhook payload
670
+ - Debugging webhook receiver failures when the response body is unhelpful
671
+
672
+ #### Cross-Reference with Settings
673
+
674
+ Compare each webhook's `Request Endpoint` with the configured setting value:
675
+
676
+ ```
677
+ 1. Extract setting name from workflow rule props (e.g., "webhook.order.created")
678
+ 2. Query: settings(name: ["webhook.order.created"], context: "RETAILER")
679
+ 3. Parse lobValue.url from the setting
680
+ 4. Compare with Request Endpoint from the ACTION event
681
+ 5. If different CONTRACT_MISMATCH (setting was changed after the event was processed, or wrong setting was loaded)
682
+ ```
683
+
684
+ ### 8C: Scheduled Event Inventory
685
+
686
+ Extract all scheduled (future-dated) events from ACTION events named "Send Event". These are events dispatched by `ScheduleEvent` rules with a time delay.
687
+
688
+ #### Query
689
+
690
+ ```
691
+ event.list({
692
+ "eventType": "ORCHESTRATION_AUDIT",
693
+ "context.rootEntityRef": "<ENTITY_REF>",
694
+ "count": 200
695
+ })
696
+ ```
697
+
698
+ Filter results where `name == "Send Event"`.
699
+
700
+ #### Data Fields
701
+
702
+ | Attribute | Description |
703
+ |-----------|-------------|
704
+ | `Event Name` | Name of the scheduled event (e.g., `ValidationGraceExpired`) |
705
+ | `Event` | Full event object: ID, meta, attributes, entityType, rootEntity info |
706
+ | `Future Dated` | `true` if the event is scheduled for the future, `false` if immediate |
707
+ | `scheduledOn` | Epoch milliseconds when the event will fire (only present when Future Dated is true) |
708
+
709
+ #### Report Format
710
+
711
+ ```
712
+ === Scheduled Event Inventory: ORDER ref=HD-20260222-001 ===
713
+
714
+ # Event Name Entity Type Future Dated Scheduled For Delay
715
+ ───────────────────────────────────────────────────────────────────────────────────────────────
716
+ 1 ValidateOrder ORDER false (immediate) 0s
717
+ 2 ValidationGraceExpired ORDER true 2026-02-22T13:43:30Z 30s
718
+ 3 ProcessOrder ORDER false (immediate) 0s
719
+ 4 NotifyFCComplete FC false (immediate) 0s
720
+ 5 SourceOrder ORDER false (immediate) 0s
721
+
722
+ Future-dated events: 1 of 5
723
+ Scheduled timers: ValidationGraceExpired (30s delay)
724
+ ```
725
+
726
+ #### Scheduled Event Analysis
727
+
728
+ For each future-dated event:
729
+ 1. **Calculate actual delay** — `scheduledOn` minus the parent event's `generatedOn` timestamp
730
+ 2. **Check if it fired** — Search for the matching ORCHESTRATION event after `scheduledOn`
731
+ 3. **Check if it was pre-empted** If a status change occurred before `scheduledOn`, the scheduled event may arrive at a status where no ruleset matches (NO_MATCH is expected)
732
+ 4. **Timer health** — Summarize which scheduled events fired vs were pre-empted
733
+
734
+ ### 8D: NO_MATCH Deep Diagnostics
735
+
736
+ When a ruleset evaluates but no rule matches (NO_MATCH), the ruleSet audit event contains structured diagnostic data explaining why. This goes beyond the simple "NO_MATCH" detection in Step 5.
737
+
738
+ #### Query
739
+
740
+ ```
741
+ event.list({
742
+ "eventType": "ORCHESTRATION_AUDIT",
743
+ "context.rootEntityRef": "<ENTITY_REF>",
744
+ "count": 200
745
+ })
746
+ ```
747
+
748
+ Filter results where `category == "ruleSet"` and attributes contain `message` with "no match" or where `closeMatches` is present.
749
+
750
+ #### Data Fields
751
+
752
+ | Attribute | Description |
753
+ |-----------|-------------|
754
+ | `message` | Summary: "No rules matched for the event and its entity" |
755
+ | `entityStatus` | Entity status when the ruleset was evaluated |
756
+ | `closeMatches` | Array of rulesets that almost matched, with structured mismatch reasons |
757
+ | `closeMatches[].name` | Ruleset name that almost matched |
758
+ | `closeMatches[].mismatchReasons` | Array of specific reasons: subtype mismatch, status mismatch, etc. |
759
+ | `lastRule` | Last rule that was evaluated before NO_MATCH |
760
+ | `lastRuleSet` | Last ruleset that was evaluated |
761
+
762
+ #### Report Format
763
+
764
+ ```
765
+ === NO_MATCH Diagnostics: ORDER ref=HD-20260222-001 ===
766
+
767
+ Event: ValidationGraceExpired → NO_MATCH
768
+
769
+ Entity status at evaluation: ON_VALIDATION
770
+ Close matches:
771
+ 1. ProcessOrder
772
+ Mismatch: subtype=HD required, entity subtype=CC
773
+ 2. CancelValidation
774
+ Mismatch: status=CANCELLED required, entity status=ON_VALIDATION
775
+
776
+ Diagnosis: ValidationGraceExpired fired after the entity already advanced past ON_VALIDATION
777
+ (pre-empted by ConfirmValidation). This is EXPECTED for timer events.
778
+
779
+ ---
780
+ Event: RetryFulfilment NO_MATCH
781
+
782
+ Entity status at evaluation: SHIPPED
783
+ Close matches:
784
+ 1. ProcessFulfilment
785
+ Mismatch: status=CREATED required, entity status=SHIPPED
786
+
787
+ Diagnosis: Retry event arrived too late — fulfilment already shipped.
788
+ Review: is the ScheduleEvent delay too long?
789
+ ```
790
+
791
+ #### NO_MATCH Classification
792
+
793
+ | Pattern | Severity | Meaning |
794
+ |---------|----------|---------|
795
+ | Timer event + entity already advanced | INFO | Normal — scheduled event pre-empted by faster progression |
796
+ | Event name has no matching ruleset | HIGH | Misconfigured workflow — event fired but no ruleset exists to handle it |
797
+ | Subtype mismatch in closeMatches | MEDIUM | Event sent to wrong subtype — check SendEvent props |
798
+ | Status mismatch in closeMatches | LOW | Race condition or ordering issue — usually self-resolving |
799
+
800
+ ### 8E: Custom Rule Log Extraction
801
+
802
+ Custom rules can emit structured diagnostic logs during execution. These appear as CUSTOM category events with `LogCollection` and `EventAttribute` data.
803
+
804
+ #### Query
805
+
806
+ ```
807
+ event.list({
808
+ "eventType": "ORCHESTRATION_AUDIT",
809
+ "context.rootEntityRef": "<ENTITY_REF>",
810
+ "count": 200
811
+ })
812
+ ```
813
+
814
+ Filter results where `category == "CUSTOM"`.
815
+
816
+ #### Data Fields
817
+
818
+ | Attribute | Description |
819
+ |-----------|-------------|
820
+ | `LogCollection` | JSON string containing `logs[]` array: `{ level, source, message, timestamp }` |
821
+ | `EventAttribute` | JSON string containing the triggering event's full attributes |
822
+
823
+ #### Log Structure
824
+
825
+ Each log entry in `LogCollection.logs[]`:
826
+
827
+ ```json
828
+ {
829
+ "level": "INFO",
830
+ "source": "ACCT.ext.CreateFulfilmentFromSourcingLocation",
831
+ "message": "Creating fulfilment at location WH-MAIN for order HD-20260222-001",
832
+ "timestamp": "2026-02-22T13:43:05.123Z"
833
+ }
834
+ ```
835
+
836
+ #### Report Format
837
+
838
+ ```
839
+ === Custom Rule Logs: ORDER ref=HD-20260222-001 ===
840
+
841
+ Timestamp Level Source Rule Message
842
+ ──────────────────────────────────────────────────────────────────────────────────────────────────
843
+ 2026-02-22T13:43:05.123Z INFO CreateFulfilmentFromSourcingLocation Creating fulfilment at WH-MAIN
844
+ 2026-02-22T13:43:05.456Z INFO CreateFulfilmentFromSourcingLocation Fulfilment ref: FUL-HD-001
845
+ 2026-02-22T13:43:06.789Z WARN ValidateInventoryAvailability Low stock: SKU-001 has 2 units
846
+ 2026-02-22T13:43:07.012Z INFO SendWebhookWithDynamicAttributes Webhook sent to order.created endpoint
847
+
848
+ Total: 4 log entries (3 INFO, 1 WARN, 0 ERROR)
849
+ ```
850
+
851
+ #### Use Cases
852
+
853
+ - **Rule execution visibility**: See exactly what a custom rule decided and why
854
+ - **Debugging silent failures**: When a rule "succeeds" but does something unexpected, logs reveal the internal logic path
855
+ - **Performance profiling**: Log timestamps show how long each rule's internal processing took
856
+ - **Regression detection**: Compare log output between test runs to spot behavioral changes
857
+
858
+ ### 8F: Entity Snapshot Extraction
859
+
860
+ Snapshot events capture the full entity state at the moment orchestration begins. These are emitted as `snapshot` category audit events and contain the complete entity (all fields, attributes, items, relationships).
861
+
862
+ #### Query
863
+
864
+ ```
865
+ event.list({
866
+ "eventType": "ORCHESTRATION_AUDIT",
867
+ "context.rootEntityRef": "<ENTITY_REF>",
868
+ "count": 200
869
+ })
870
+ ```
871
+
872
+ Filter results where `category == "snapshot"`.
873
+
874
+ #### Data Content by Entity Type
875
+
876
+ **ORDER snapshot includes:**
877
+ - `id`, `ref`, `type`, `subtype`, `status`
878
+ - `customer` full customer object (firstName, lastName, username)
879
+ - `items[]` — order items with ref, quantity, status, productRef, fulfilmentChoiceRef
880
+ - `fulfilmentChoice`FC details (ref, deliveryType, deliveryAddress)
881
+ - `attributes[]` — all entity attributes at that moment
882
+ - `createdOn`, `updatedOn`
883
+
884
+ **FULFILMENT snapshot includes:**
885
+ - `id`, `ref`, `type`, `subtype`, `status`
886
+ - `items[]` — fulfilment items with ref, requestedQuantity, filledQuantity
887
+ - `toAddress`, `fromAddress` shipping addresses
888
+ - `attributes[]` — including trackingNumber, carrierRef, pickedAt, etc.
889
+ - `consignment` consignment details if created
890
+ - `deliveryType`
891
+
892
+ #### Report Format
893
+
894
+ ```
895
+ === Entity Snapshots: ORDER ref=HD-20260222-001 ===
896
+
897
+ Snapshot #1 ORDER at CREATED (2026-02-22T13:43:01Z)
898
+ Status: CREATED
899
+ Items: 2 (SKU-001 x1, SKU-002 x2)
900
+ Customer: john.doe
901
+ Delivery: HD to 123 Main St
902
+ Attributes: sourceSystem=E2E_TEST, testRunId=E2E_MULTI_202602221343
903
+
904
+ Snapshot #2 FULFILMENT at CREATED (2026-02-22T13:43:06Z)
905
+ Status: CREATED
906
+ Items: 2 (SKU-001 x1, SKU-002 x2)
907
+ From: WH-MAIN (Warehouse Main)
908
+ To: 123 Main St
909
+ Delivery Type: HD
910
+ Attributes: (none yet)
911
+
912
+ Snapshot #3 — FULFILMENT at PICKPACK (2026-02-22T13:43:15Z)
913
+ Status: PICKPACK
914
+ Items: 2 (SKU-001 filled:1, SKU-002 filled:2)
915
+ Attributes: pickedAt=2026-02-22T13:43:14Z
916
+ ```
917
+
918
+ #### Use Cases
919
+
920
+ - **State verification in E2E tests**: Compare expected entity state at each step against the snapshot — no need to query entity separately
921
+ - **Before/after comparison**: Diff consecutive snapshots to see exactly what changed during a status transition
922
+ - **Attribute tracking**: Verify attributes like `trackingNumber`, `pickedAt`, `deliveredAt` were set at the right time
923
+ - **Customer data audit**: Confirm customer information was correctly attached at order creation
924
+
925
+ #### Integration with `/fluent-e2e-test`
926
+
927
+ After an E2E test completes, snapshots can be used as assertion evidence:
928
+
929
+ ```
930
+ For each test step:
931
+ 1. Extract snapshot for the entity at the expected status
932
+ 2. Verify expected fields are present and correct
933
+ 3. Compare with previous snapshot to confirm the transition changed the right fields
934
+ 4. Include snapshot diffs in the test report for documentation
935
+ ```
936
+
937
+ ## Quick Diagnostic Queries
938
+
939
+ ### Order lifecycle summary (all events for an order)
940
+ ```
941
+ event.list({
942
+ "context.entityRef": "<ORDER_REF>",
943
+ "context.entityType": "ORDER",
944
+ "count": 100
945
+ })
946
+ ```
947
+
948
+ ### All fulfilments for an order
949
+ ```graphql
950
+ {
951
+ fulfilments(orderId: [<ORDER_ID>], first: 50) {
952
+ edges {
953
+ node { id ref type status fromLocation { ref } }
954
+ }
955
+ }
956
+ }
957
+ ```
958
+
959
+ ### All fulfilment choices for an order
960
+ ```graphql
961
+ {
962
+ fulfilmentChoices(orderId: [<ORDER_ID>], first: 50) {
963
+ edges {
964
+ node { id ref type status deliveryType }
965
+ }
966
+ }
967
+ }
968
+ ```
969
+
970
+ ### Check a setting value
971
+ ```graphql
972
+ {
973
+ settings(first: 1, context: "RETAILER", contextId: <RETAILER_ID>, name: ["<SETTING_NAME>"]) {
974
+ edges {
975
+ node { id name value lobValue }
976
+ }
977
+ }
978
+ }
979
+ ```
980
+
981
+ ### Check workflow version deployed
982
+ Use MCP `workflow.list` to verify the expected version is active.
983
+
984
+ ## Entity State Stuck Decision Tree
985
+
986
+ ```
987
+ Entity not advancing?
988
+
989
+ ├─ Check event.list for the entity
990
+ │ ├─ No events found → Event was never sent, or wrong entityRef/entityType
991
+ │ ├─ Events all SUCCESS → State changed but maybe to unexpected status
992
+ │ │ └─ Query entity status → Check workflow state machine
993
+ │ └─ Event FAILED Inspect event.get for error details
994
+ │ ├─ "Rule exception" → Check rule source code + props
995
+ │ ├─ "No matching ruleset" / NO_MATCH → Event name doesn't match any ruleset; check flexType
996
+ │ ├─ "Entity not found" → Wrong entityRef or entity deleted
997
+ │ └─ "Permission denied" Check user/retailer scope
998
+
999
+ ├─ Entity in gate state (waiting for children)?
1000
+ │ └─ Query all child entities
1001
+ │ ├─ All children in terminal state → Gate ruleset bug (check statuses prop)
1002
+ │ └─ Some children not terminal → Wait for children to complete
1003
+
1004
+ └─ Event sent but still PENDING?
1005
+ └─ Async queue delay — wait 15-30s and re-check
1006
+ ```
1007
+
1008
+ ## Manual Intervention Options
1009
+
1010
+ After identifying the root cause, choose the appropriate intervention:
1011
+
1012
+ ### Option 1: Re-send the Event
1013
+
1014
+ If the root cause is fixed (e.g., workflow deployed, setting created, data corrected), re-send the original event:
1015
+
1016
+ ```
1017
+ event.send({
1018
+ "name": "<EVENT_NAME>",
1019
+ "entityType": "<ENTITY_TYPE>",
1020
+ "entityRef": "<ENTITY_REF>",
1021
+ "retailerId": "<RETAILER_ID>"
1022
+ })
1023
+ ```
1024
+
1025
+ ### Option 2: Run-Once Workflow (Targeted Rule Execution)
1026
+
1027
+ Execute specific rules without triggering the full workflow. Useful for re-triggering a failed webhook, running a data correction rule, or executing a rule that isn't in the current deployed workflow.
1028
+
1029
+ Send to `POST /api/v4.1/event/sync` with the workflow attached in `meta`:
1030
+
1031
+ ```json
1032
+ {
1033
+ "name": "FixEvent",
1034
+ "retailerId": "1",
1035
+ "entityType": "FULFILMENT",
1036
+ "entityId": "143",
1037
+ "meta": {
1038
+ "workflow": {
1039
+ "retailerId": "1",
1040
+ "version": "1.0",
1041
+ "rulesets": [{
1042
+ "name": "FixEvent",
1043
+ "type": "FULFILMENT",
1044
+ "eventType": "NORMAL",
1045
+ "rules": [{ "name": "ACCOUNT.module.RuleName", "props": { "key": "value" } }],
1046
+ "triggers": [],
1047
+ "userActions": []
1048
+ }]
1049
+ }
1050
+ }
1051
+ }
1052
+ ```
1053
+
1054
+ **Key:** The event `name` must match the ruleset `name`. Any rule in the account can be used — it doesn't need to exist in the deployed workflow. Webhooks and mutations execute; inline events are ignored.
1055
+
1056
+ Strict user-action note:
1057
+ - This run-once pattern is primarily backend/event driven and typically keeps `userActions: []`.
1058
+ - If user actions are introduced, keep explicit `eventName` and documented `context`/`attributes` fields only (no invented schema keys), and validate visibility with `workflow.transitions` (`module` vs `module: "all"`).
1059
+ - For canonical schema and diagnostics, use `/fluent-workflow-builder` and `/fluent-transition-api`.
1060
+
1061
+ For full run-once workflow reference → `/fluent-event-api`.
1062
+
1063
+ ### Option 3: Direct GraphQL Mutation
1064
+
1065
+ For data corrections that don't require workflow logic, use `graphql.query` with a mutation directly.
1066
+
1067
+ ## Causal Chain Playbook
1068
+
1069
+ Compact playbook for tracing event causality when diagnosing failures.
1070
+
1071
+ ### Principle: One ORCHESTRATION Event = One Execution Journey
1072
+
1073
+ Every ORCHESTRATION event triggers a chain of ORCHESTRATION_AUDIT events. The audit events contain the detailed execution (rulesets, rules, actions) linked via `sourceEvents`.
1074
+
1075
+ ### Step-by-Step Chain Reconstruction
1076
+
1077
+ 1. **Find the ORCHESTRATION event** that triggered execution:
1078
+ ```
1079
+ event.list({ "context.entityRef": "<REF>", "eventType": "ORCHESTRATION", "count": 50 })
1080
+ ```
1081
+
1082
+ 2. **Find all audit events it spawned** (linked by sourceEvents):
1083
+ ```
1084
+ event.list({
1085
+ "eventType": "ORCHESTRATION_AUDIT",
1086
+ "context.entityRef": "<REF>",
1087
+ "from": "<orchestration_event_timestamp_minus_1s>",
1088
+ "to": "<orchestration_event_timestamp_plus_60s>",
1089
+ "count": 200
1090
+ })
1091
+ ```
1092
+ Match: audit events whose `context.sourceEvents` array contains the ORCHESTRATION event ID.
1093
+
1094
+ 3. **Classify audit events by category:**
1095
+ - `snapshot` — entity state before execution
1096
+ - `ruleSet` — ruleset-level timing (`startTimer`/`stopTimer`)
1097
+ - `rule` — individual rule execution
1098
+ - `ACTION` — actions performed (SetState, SendEvent, Send Webhook)
1099
+ - `exception` — error with stack trace
1100
+ - `CUSTOM` — custom log output from rules
1101
+
1102
+ 4. **Trace the failure point:**
1103
+ - Find first `exception` category event check `attributes.message` and `attributes.exception.stackTrace`
1104
+ - Check the `ruleSet` event its `name` is the ruleset that was executing
1105
+ - Check the `ACTION` events see what actions completed before the failure
1106
+
1107
+ 5. **If sourceEvents is sparse:** fall back to entity context + time window correlation (see `/fluent-event-api` → Causality Correlation Workflow)
1108
+
1109
+ ### Webhook Failure Triage
1110
+
1111
+ When a webhook fails during event processing:
1112
+
1113
+ 1. **Find the webhook ACTION event:**
1114
+ ```
1115
+ event.list({
1116
+ "category": "ACTION",
1117
+ "name": "Send Webhook",
1118
+ "context.rootEntityRef": "<REF>",
1119
+ "count": 50
1120
+ })
1121
+ ```
1122
+
1123
+ 2. **Inspect webhook attributes:**
1124
+ - `Request Endpoint` the target URL
1125
+ - `Response code` — HTTP status (4xx = client error, 5xx = server error, 0 = connection timeout)
1126
+ - `Response Body` error details from the remote server
1127
+ - `Response Headers` — may reveal rate limiting or auth issues
1128
+
1129
+ 3. **Check the webhook setting:**
1130
+ ```graphql
1131
+ {
1132
+ settings(first: 1, context: "RETAILER", contextId: <ID>, name: ["<webhook-setting-name>"]) {
1133
+ edges { node { id name value lobValue } }
1134
+ }
1135
+ }
1136
+ ```
1137
+
1138
+ 4. **Common webhook failures:**
1139
+
1140
+ | Response Code | Likely Cause | Action |
1141
+ |--------------|--------------|--------|
1142
+ | 0 | Connection timeout / DNS failure | Check endpoint URL and network |
1143
+ | 401/403 | Auth credentials invalid or expired | Update webhook setting credentials |
1144
+ | 404 | Endpoint URL changed | Update webhook setting URL |
1145
+ | 429 | Rate limited | Implement retry/backoff or reduce event frequency |
1146
+ | 500+ | Remote server error | Check target system logs |
1147
+
1148
+ ## Integration with Other Skills
1149
+
1150
+ | Task | Skill |
1151
+ |------|-------|
1152
+ | Event model, filter parameters, causality chains | `/fluent-event-api` |
1153
+ | MCP payload syntax and tool limits | `/fluent-mcp-tools` |
1154
+ | Rule/source correlation | `/fluent-custom-code` |
1155
+ | Workflow topology and trigger intent | `/fluent-workflow-analyzer` |
1156
+
1157
+ ## Learning Capture
1158
+
1159
+ This is an analysis skill — follow the **Learning Capture Protocol** (see CLAUDE.md Cross-Skill Conventions). After tracing events, when the user confirms or corrects findings about runtime behavior, event ordering, rule failures, or unexpected state transitions, write the confirmed learning to the `implementation-learnings.md` auto-memory file under the relevant account heading.
1160
+
1161
+ ## Reporting
1162
+
1163
+ After diagnosis, report:
1164
+
1165
+ 1. **Entity:** ref, type, current status, expected status
1166
+ 2. **Failing event:** name, ID, status, error message
1167
+ 3. **Root cause:** which ruleset/rule failed and why
1168
+ 4. **Fix:** what needs to change (code, workflow, setting, data)
1169
+ 5. **Recommendation:** specific file/line/config to modify