@fluentcommerce/ai-skills 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +622 -0
  3. package/bin/cli.mjs +1973 -0
  4. package/content/cli/agents/fluent-cli/agent.json +149 -0
  5. package/content/cli/agents/fluent-cli.md +132 -0
  6. package/content/cli/skills/fluent-bootstrap/SKILL.md +181 -0
  7. package/content/cli/skills/fluent-cli-index/SKILL.md +63 -0
  8. package/content/cli/skills/fluent-cli-mcp-cicd/SKILL.md +77 -0
  9. package/content/cli/skills/fluent-cli-reference/SKILL.md +1031 -0
  10. package/content/cli/skills/fluent-cli-retailer/SKILL.md +85 -0
  11. package/content/cli/skills/fluent-cli-settings/SKILL.md +106 -0
  12. package/content/cli/skills/fluent-connect/SKILL.md +886 -0
  13. package/content/cli/skills/fluent-module-deploy/SKILL.md +349 -0
  14. package/content/cli/skills/fluent-profile/SKILL.md +180 -0
  15. package/content/cli/skills/fluent-workflow/SKILL.md +310 -0
  16. package/content/dev/agents/fluent-dev/agent.json +88 -0
  17. package/content/dev/agents/fluent-dev.md +525 -0
  18. package/content/dev/reference-modules/catalog.json +4754 -0
  19. package/content/dev/skills/fluent-build/SKILL.md +192 -0
  20. package/content/dev/skills/fluent-connection-analysis/SKILL.md +386 -0
  21. package/content/dev/skills/fluent-custom-code/SKILL.md +895 -0
  22. package/content/dev/skills/fluent-data-module-scaffold/SKILL.md +714 -0
  23. package/content/dev/skills/fluent-e2e-test/SKILL.md +394 -0
  24. package/content/dev/skills/fluent-event-api/SKILL.md +945 -0
  25. package/content/dev/skills/fluent-feature-explain/SKILL.md +603 -0
  26. package/content/dev/skills/fluent-feature-plan/PLAN_TEMPLATE.md +695 -0
  27. package/content/dev/skills/fluent-feature-plan/SKILL.md +227 -0
  28. package/content/dev/skills/fluent-job-batch/SKILL.md +138 -0
  29. package/content/dev/skills/fluent-mermaid-validate/SKILL.md +86 -0
  30. package/content/dev/skills/fluent-module-scaffold/SKILL.md +1928 -0
  31. package/content/dev/skills/fluent-module-validate/SKILL.md +775 -0
  32. package/content/dev/skills/fluent-pre-deploy-check/SKILL.md +1108 -0
  33. package/content/dev/skills/fluent-retailer-config/SKILL.md +1111 -0
  34. package/content/dev/skills/fluent-rule-scaffold/SKILL.md +385 -0
  35. package/content/dev/skills/fluent-scope-decompose/SKILL.md +1021 -0
  36. package/content/dev/skills/fluent-session-audit-export/SKILL.md +632 -0
  37. package/content/dev/skills/fluent-session-summary/SKILL.md +195 -0
  38. package/content/dev/skills/fluent-settings/SKILL.md +1058 -0
  39. package/content/dev/skills/fluent-source-onboard/SKILL.md +632 -0
  40. package/content/dev/skills/fluent-system-monitoring/SKILL.md +767 -0
  41. package/content/dev/skills/fluent-test-data/SKILL.md +513 -0
  42. package/content/dev/skills/fluent-trace/SKILL.md +1143 -0
  43. package/content/dev/skills/fluent-transition-api/SKILL.md +346 -0
  44. package/content/dev/skills/fluent-version-manage/SKILL.md +744 -0
  45. package/content/dev/skills/fluent-workflow-analyzer/SKILL.md +959 -0
  46. package/content/dev/skills/fluent-workflow-builder/SKILL.md +319 -0
  47. package/content/dev/skills/fluent-workflow-deploy/SKILL.md +267 -0
  48. package/content/mcp-extn/agents/fluent-mcp.md +69 -0
  49. package/content/mcp-extn/skills/fluent-mcp-tools/SKILL.md +461 -0
  50. package/content/mcp-official/agents/fluent-mcp-core.md +91 -0
  51. package/content/mcp-official/skills/fluent-mcp-core/SKILL.md +94 -0
  52. package/content/rfl/agents/fluent-rfl.md +56 -0
  53. package/content/rfl/skills/fluent-rfl-assess/SKILL.md +172 -0
  54. package/docs/CAPABILITY_MAP.md +77 -0
  55. package/docs/CLI_COVERAGE.md +47 -0
  56. package/docs/DEV_WORKFLOW.md +802 -0
  57. package/docs/FLOW_RUN.md +142 -0
  58. package/docs/USE_CASES.md +404 -0
  59. package/metadata.json +156 -0
  60. package/package.json +51 -0
@@ -0,0 +1,1143 @@
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) MISSED → setting "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 #1 — ORDER 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 #2 — FULFILMENT 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