@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,959 @@
1
+ ---
2
+ name: fluent-workflow-analyzer
3
+ description: Analyze Fluent Commerce workflow JSON definitions. Map status graphs, trace event chains, detect orphaned rulesets, validate trigger coverage, and generate dependency reports. Triggers on "analyze workflow", "workflow analysis", "workflow graph", "workflow dependencies", "workflow review".
4
+ user-invocable: true
5
+ allowed-tools: Bash, Read, Write, Edit, Glob, Grep
6
+ argument-hint: <workflow-file-or-name> [--deep] [--mermaid] [--explain-rules] [--output <path>]
7
+ ---
8
+
9
+ # Workflow Analyzer
10
+
11
+ Analyze existing Fluent Commerce workflow definitions to understand structure, trace event chains, detect issues, and generate comprehensive reports.
12
+
13
+ ## Ownership Boundary
14
+
15
+ This skill owns workflow structural analysis, dependency mapping, and quality assessment.
16
+
17
+ Operational workflow commands are owned by `/fluent-workflow`.
18
+ Workflow creation and editing guidance is owned by `/fluent-workflow-builder`.
19
+ Runtime event tracing is owned by `/fluent-trace`.
20
+
21
+ ## Pre-Check: Load Source Analysis
22
+
23
+ Before analyzing, check if `/fluent-custom-code` analysis artifacts exist:
24
+
25
+ ```
26
+ accounts/<PROFILE>/analysis/custom-code/source-map.json
27
+ accounts/<PROFILE>/analysis/custom-code/workflow-rule-map.json
28
+ ```
29
+
30
+ If found, use them to:
31
+ - Annotate workflow graph nodes with rule descriptions from `source-map.json`
32
+ - Identify which rules are custom vs core (custom rules appear in `source-map.json`)
33
+ - Report test coverage per rule from `source-map.json` → `modules[].rules[].hasTest`
34
+
35
+ If not found, analyze workflow structure only (no source-level annotations). Treat artifact-gate failures as "not found" (for example missing required files, missing hashes, or blocking `missingSources` in `constraints.json`).
36
+
37
+ ## When to Use
38
+
39
+ - Understanding an unfamiliar workflow before modifying it
40
+ - Auditing a workflow for structural issues (orphans, dead-ends, unreachable statuses)
41
+ - Mapping the complete event chain from entity creation to terminal states
42
+ - Generating Mermaid diagrams for workflow walkthroughs and handovers
43
+ - Explaining which rules/rulesets run, what each consumes, and what each emits
44
+ - Generating documentation for a workflow's state machine
45
+ - Pre-deployment validation beyond basic JSON syntax
46
+ - Comparing workflow complexity across entity types
47
+
48
+ ## Analysis Framework
49
+
50
+ ### Step 1: Load and Parse
51
+
52
+ Load the workflow JSON (from file or download via `/fluent-workflow`):
53
+
54
+ ```
55
+ 1. Read the workflow JSON file
56
+ 2. Extract metadata: name, version, entityType, entitySubtype, retailerId
57
+ 3. Separate statuses by entityType (ORDER vs FULFILMENT vs ARTICLE etc.)
58
+ 4. Index rulesets by name and type
59
+ ```
60
+
61
+ ### Step 2: Build Status Graph
62
+
63
+ Map all status transitions by tracing `SetState` rules:
64
+
65
+ ```
66
+ For each ruleset:
67
+ 1. Find all SetState rules → extract target status
68
+ 2. Find all triggers → extract source statuses
69
+ 3. If no triggers → ruleset fires on named event (ruleset name = event name)
70
+ 4. Map: source_status → [event_name] → target_status
71
+ ```
72
+
73
+ **Output format — Status Transition Table:**
74
+
75
+ ```
76
+ Source Status Event/Ruleset Target Status
77
+ -------------------------------------------------------------
78
+ (new entity) CREATE CREATED
79
+ CREATED ProcessOrder ON_VALIDATION
80
+ ON_VALIDATION ConfirmValidation IN_PROGRESS
81
+ IN_PROGRESS OrderComplete COMPLETE
82
+ BOOKED OrderCancel CANCELLED
83
+ ```
84
+
85
+ ### Step 3: Trace Event Chains
86
+
87
+ Map cascading events — when one ruleset fires `SendEvent`, trace to the receiving ruleset:
88
+
89
+ ```
90
+ For each ruleset:
91
+ For each SendEvent rule:
92
+ 1. Extract eventName prop
93
+ 2. Find matching ruleset (name == eventName)
94
+ 3. Record chain: RulesetA -> SendEvent(X) -> RulesetX
95
+ 4. Recurse into RulesetX
96
+ ```
97
+
98
+ **Output format — Event Chain:**
99
+
100
+ ```
101
+ CREATE
102
+ +-> SendEvent("CheckOrderCoordinates")
103
+ +-> CheckOrderCoordinates
104
+ |-> ForwardIfOrderCoordinatesPresent -> SendEvent("ProcessOrder")
105
+ | +-> ProcessOrder
106
+ | +-> SetState(ON_VALIDATION)
107
+ | +-> SendEvent("FindAndCreateOrderFulfilment")
108
+ +-> ForwardIfOrderCoordinatesNotPresent -> SendEvent("ResolveOrderCoordinates")
109
+ +-> ResolveOrderCoordinates
110
+ +-> SendEvent("UpdateOrderCoordinates")
111
+ ```
112
+
113
+ ### 3A: Event-to-Ruleset Mapping Heuristics
114
+
115
+ Use these heuristics when mapping runtime events back to workflow intent:
116
+
117
+ 1. **Direct name match (highest confidence)**
118
+ `event.name == ruleset.name` on same entity type/subtype.
119
+ 2. **Status-trigger fallback**
120
+ If no name match, map by `triggers[].status` against entity status at event time.
121
+ 3. **Entity scope check**
122
+ Validate `context.entityType` and `context.rootEntityType` alignment before concluding ownership.
123
+ 4. **SendEvent bridge inference**
124
+ For downstream events, map `SendEvent(eventName)` producer ruleset -> target ruleset named `eventName`.
125
+ 5. **Audit evidence confirmation**
126
+ Confirm inferred mapping with `ORCHESTRATION_AUDIT` evidence (`category=ruleSet|rule|ACTION|exception`) from `/fluent-trace`.
127
+
128
+ Confidence levels:
129
+ - **Confirmed:** name match + audit evidence
130
+ - **Strong inference:** status-trigger + consistent audit timeline
131
+ - **Weak inference:** no audit evidence; mark explicitly and avoid hard conclusions
132
+
133
+ ### Step 3B: Mermaid Diagram Output (--mermaid)
134
+
135
+ When `--mermaid` is requested, generate copy-pasteable Mermaid diagram blocks. Generate **all four diagram types** by default; the user can request a subset. **Validate all blocks against `/fluent-mermaid-validate` rules before output** (no colons in free text, no unicode arrows, quoted special-char labels).
136
+
137
+ #### Diagram 1 — Status State Machine (`stateDiagram-v2`)
138
+
139
+ Generate one state diagram **per entity type** in the workflow (ORDER, FULFILMENT_CHOICE, FULFILMENT, etc.).
140
+
141
+ **Generation algorithm:**
142
+ ```
143
+ For each entity type in the workflow:
144
+ 1. Collect all statuses for this entity type from statuses[]
145
+ 2. Identify DONE-category statuses (terminal states)
146
+ 3. For each ruleset scoped to this entity type:
147
+ a. Find trigger status (from triggers[].status) -> this is the source state
148
+ b. Find all SetState rules -> extract target status
149
+ c. Edge = source -> target, labeled with ruleset name
150
+ 4. For rulesets with NO trigger status (event-name match):
151
+ a. Infer source status from the event chain (which ruleset sends this event, what status it runs in)
152
+ b. If ambiguous, label edge with "via {eventName}"
153
+ 5. [*] -> CREATED for the initial transition
154
+ 6. Terminal states -> [*] for DONE-category statuses
155
+ ```
156
+
157
+ **Styling rules:**
158
+ - Use `classDef terminal fill:#d4edda` for completed states, `fill:#f8d7da` for cancelled/failed
159
+ - Add notes for statuses that have ScheduleEvent rules (timeouts)
160
+ - Group subtypes separately if the workflow has subtype-specific rulesets
161
+
162
+ **Example — ORDER entity:**
163
+ ```mermaid
164
+ stateDiagram-v2
165
+ [*] --> CREATED: CREATE
166
+ CREATED --> ON_VALIDATION: ProcessOrder
167
+ ON_VALIDATION --> IN_PROGRESS: ConfirmValidation
168
+ ON_VALIDATION --> IN_PROGRESS: ValidationGraceExpired
169
+ IN_PROGRESS --> SHIPPED: NotifyFulfilmentShipped
170
+ SHIPPED --> COMPLETED: NotifyFulfilmentDelivered
171
+ IN_PROGRESS --> COMPLETED: NotifyFulfilmentCollected
172
+ CREATED --> CANCELLED: CancelOrder
173
+ ON_VALIDATION --> CANCELLED: CancelOrder
174
+ COMPLETED --> [*]
175
+ CANCELLED --> [*]
176
+
177
+ note right of ON_VALIDATION: ScheduleEvent: ValidationGraceExpired (30s)
178
+ ```
179
+
180
+ **Example — FULFILMENT entity (with subtype branching):**
181
+ ```mermaid
182
+ stateDiagram-v2
183
+ [*] --> CREATED: CREATE
184
+ CREATED --> READY: ProcessFulfilment
185
+ READY --> PICKPACK: ConfirmPick
186
+ PICKPACK --> SHIPPED: ConfirmShipment
187
+ PICKPACK --> READY_FOR_PICKUP: ReadyForPickup [CC_PFS only]
188
+ SHIPPED --> DELIVERED: ConfirmDelivery
189
+ READY_FOR_PICKUP --> COLLECTED: ConfirmCollection [CC_PFS only]
190
+ DELIVERED --> [*]
191
+ COLLECTED --> [*]
192
+ ```
193
+
194
+ #### Diagram 2 — Event Chain Flowchart (`flowchart TD`)
195
+
196
+ Shows how events cascade through rulesets. Use subgraphs to group by entity type.
197
+
198
+ **Generation algorithm:**
199
+ ```
200
+ For each ruleset:
201
+ 1. Create a node with shape based on trigger type
202
+ 2. For each rule in the ruleset:
203
+ a. SendEvent -> event node (circle) -> edge to target ruleset
204
+ b. SetState -> state node (trapezoid)
205
+ 3. Group by entity type using subgraph blocks
206
+ 4. Cross-entity bridges use dashed arrows with label
207
+ ```
208
+
209
+ **Node shapes:**
210
+ - `["name"]` — status-triggered ruleset (rectangle)
211
+ - `[/"name"/]` — event-triggered ruleset (parallelogram)
212
+ - `(("eventName"))` — emitted event (circle)
213
+ - `[/STATUS/]` — status change (trapezoid)
214
+ - `{{"condition"}}` — gate/decision rule (hexagon)
215
+
216
+ **Example — Combined flowchart:**
217
+ ```mermaid
218
+ flowchart TD
219
+ subgraph ORDER
220
+ CREATE_RS["CREATE<br/><small>trigger: new entity</small>"]
221
+ CREATE_RS --> evt_validate(("ValidateOrder"))
222
+ evt_validate --> VALIDATE_RS[/"ValidateOrder"/]
223
+ VALIDATE_RS --> state_onval[/ON_VALIDATION/]
224
+
225
+ CONFIRM_VAL[/"ConfirmValidation"/]
226
+ CONFIRM_VAL --> evt_process(("ProcessOrder"))
227
+ evt_process --> PROCESS_RS[/"ProcessOrder"/]
228
+ PROCESS_RS --> state_inprog[/IN_PROGRESS/]
229
+ PROCESS_RS --> evt_route(("RouteFulfilmentChoice"))
230
+ end
231
+
232
+ subgraph FULFILMENT_CHOICE
233
+ ROUTE_FC[/"RouteFulfilmentChoice"/]
234
+ evt_route --> ROUTE_FC
235
+ ROUTE_FC --> evt_hd(("ProcessHDFulfilmentChoice"))
236
+ ROUTE_FC --> evt_cc(("ProcessCCFulfilmentChoice"))
237
+ evt_hd --> HD_FC[/"ProcessHDFulfilmentChoice"/]
238
+ evt_cc --> CC_FC[/"ProcessCCFulfilmentChoice"/]
239
+ end
240
+
241
+ subgraph FULFILMENT
242
+ HD_FC -.->|CreateFulfilment| FUL_CREATE["CREATE"]
243
+ CC_FC -.->|CreateFulfilment| FUL_CREATE
244
+ FUL_CREATE --> FUL_READY[/READY/]
245
+ CONFIRM_PICK[/"ConfirmPick"/] --> FUL_PICKPACK[/PICKPACK/]
246
+ CONFIRM_SHIP[/"ConfirmShipment"/] --> FUL_SHIPPED[/SHIPPED/]
247
+ end
248
+
249
+ style HD_FC fill:#fff3cd,stroke:#856404
250
+ style CC_FC fill:#fff3cd,stroke:#856404
251
+ ```
252
+
253
+ #### Diagram 3 — Cross-Entity Lifecycle (`flowchart LR`)
254
+
255
+ Shows the full lifecycle across ALL entity types on a single horizontal timeline. This is the "big picture" diagram for stakeholder walkthroughs and handovers.
256
+
257
+ **Generation algorithm:**
258
+ ```
259
+ 1. ORDER statuses as the main spine (left to right)
260
+ 2. At each status where child entities are created or events cross entities:
261
+ a. Branch down to FULFILMENT_CHOICE statuses
262
+ b. Branch further down to FULFILMENT statuses
263
+ 3. Cross-entity events shown as dashed arrows
264
+ 4. User actions (events with userActions config) shown with bold borders
265
+ 5. Webhooks shown as external callout nodes
266
+ ```
267
+
268
+ **Example:**
269
+ ```mermaid
270
+ flowchart LR
271
+ subgraph Order
272
+ O_CREATED([CREATED]) -->|ProcessOrder| O_ONVAL([ON_VALIDATION])
273
+ O_ONVAL -->|ConfirmValidation| O_INPROG([IN_PROGRESS])
274
+ O_INPROG -->|all fulfilments done| O_SHIPPED([SHIPPED])
275
+ O_SHIPPED -->|all delivered| O_COMPLETE([COMPLETED])
276
+ end
277
+
278
+ subgraph FulfilmentChoice
279
+ O_INPROG -.->|RouteFulfilmentChoice| FC_CREATED([FC:CREATED])
280
+ FC_CREATED -->|ProcessHD/CC| FC_ASSIGNED([FC:ASSIGNED])
281
+ end
282
+
283
+ subgraph Fulfilment
284
+ FC_ASSIGNED -.->|CreateFulfilment| FUL_CREATE([FUL:CREATED])
285
+ FUL_CREATE --> FUL_READY([READY])
286
+ FUL_READY -->|ConfirmPick| FUL_PICK([PICKPACK])
287
+ FUL_PICK -->|Ship| FUL_SHIPPED([SHIPPED])
288
+ FUL_SHIPPED -->|Deliver| FUL_DELIVERED([DELIVERED])
289
+ FUL_PICK -->|CC path| FUL_RFP([READY_FOR_PICKUP])
290
+ FUL_RFP -->|Collect| FUL_COLLECTED([COLLECTED])
291
+ end
292
+
293
+ FUL_SHIPPED -.->|NotifyShipped| O_SHIPPED
294
+ FUL_DELIVERED -.->|NotifyDelivered| O_COMPLETE
295
+
296
+ style O_COMPLETE fill:#d4edda
297
+ style FUL_DELIVERED fill:#d4edda
298
+ style FUL_COLLECTED fill:#d4edda
299
+ ```
300
+
301
+ #### Diagram 4 — Rule Dependency Graph (`flowchart TD`)
302
+
303
+ Shows what each rule in a ruleset consumes (settings, event attributes, entity fields) and produces (state changes, events, mutations). Use `--deep` to generate for all rulesets, otherwise generate for a specific ruleset on request.
304
+
305
+ **Generation algorithm:**
306
+ ```
307
+ For a specific ruleset:
308
+ 1. For each rule, look up metadata via plugin.list (see Step 3D)
309
+ 2. From rule props, identify: settings referenced, event attributes consumed
310
+ 3. From rule metadata, identify: events produced, mutations performed
311
+ 4. Create nodes: settings (cylinder), events (circle), states (trapezoid), rules (rectangle)
312
+ 5. Draw edges: setting --> rule --> event/state
313
+ ```
314
+
315
+ **Example — single ruleset:**
316
+ ```mermaid
317
+ flowchart TD
318
+ setting_wh[("webhook.order.created")] --> rule_webhook["SendWebhookWithDynamicAttributes"]
319
+ rule_webhook --> ext_call>"External webhook POST"]
320
+ rule_upsert["UpsertAttribute"] --> attr["statusHistory attribute"]
321
+ rule_setState["SetState"] --> state[/ON_VALIDATION/]
322
+ rule_schedule["ScheduleEvent"] --> timer["ValidationGraceExpired (30s)"]
323
+ rule_sendEvt["SendEvent"] --> evt(("ValidateOrder"))
324
+
325
+ style setting_wh fill:#e2e3f1
326
+ style ext_call fill:#fff3cd
327
+ style timer fill:#fce4ec
328
+ ```
329
+
330
+ ### Step 3C: Rule Execution Narrative (--explain-rules)
331
+
332
+ When `--explain-rules` is requested, produce a detailed execution narrative per ruleset. This answers "what happens when this event fires?" in plain language with verified data.
333
+
334
+ #### Rule Lookup Strategy (MANDATORY — never guess what a rule does)
335
+
336
+ To explain a rule, you MUST look it up. Use these sources in priority order:
337
+
338
+ **1. Live rule registry — `plugin.list` (covers ALL deployed rules):**
339
+ ```
340
+ plugin.list({ name: "RuleShortName" })
341
+ ```
342
+ Returns: description, parameters (with types/defaults), accepted entity types, produced events, exceptions. Extract short name from `ACCOUNT.bundle.RuleName` -> search for `RuleName`.
343
+
344
+ **2. Custom rule source code (if cloned under SOURCE/):**
345
+ ```
346
+ accounts/<PROFILE>/SOURCE/<repo>/src/main/java/.../<RuleName>.java
347
+ ```
348
+ Look for `@RuleInfo`, `@ParamString`/`@ParamInteger` annotations, `run()` method logic, GraphQL queries/mutations, `sendEvent()` calls.
349
+
350
+ **3. Reference module JARs (for core/order/fulfilment module rules):**
351
+ If `plugin.list` returns a description but you need implementation details for a reference module rule (core, order, fulfilment, commonv2, globalinventory), the user can provide the deployed JAR. Decompile it to inspect the rule's actual logic:
352
+ ```
353
+ # Get JAR from Fluent module artifacts or ask user to supply it
354
+ # Decompile with cfr, procyon, or IntelliJ's built-in decompiler
355
+ java -jar cfr.jar <module>.jar --outputdir decompiled/
356
+ # Then search for the rule class — use the Glob tool with pattern
357
+ # decompiled/**/*RuleName* instead of shell find for cross-platform compatibility
358
+ ```
359
+
360
+ This is useful when `plugin.list` gives you "what" but you need "how" — the actual algorithm, edge cases, and failure modes. Store decompiled output under `accounts/<PROFILE>/SOURCE/.decompiled/<jar-basename>/`.
361
+
362
+ **4. Cached analysis artifacts (from `/fluent-custom-code`):**
363
+ ```
364
+ accounts/<PROFILE>/analysis/custom-code/source-map.json -> modules[].rules[]
365
+ ```
366
+
367
+ **5. Name pattern inference (LAST RESORT — always label as inferred):**
368
+ Only if all above fail. Infer from name: `*SetState` -> state change, `*SendEvent` -> emit event, etc. Always mark as `(inferred from name — not verified)`.
369
+
370
+ #### Narrative Format
371
+
372
+ For each ruleset, produce:
373
+
374
+ **1. Header:**
375
+ ```
376
+ ### [RulesetName] — {entityType} @ {triggerStatus or "event: {eventName}"}
377
+ {One-sentence business summary of what this ruleset accomplishes}
378
+ ```
379
+
380
+ **2. Rules table (descriptions from plugin.list, NOT invented):**
381
+
382
+ | # | Rule | Description | Props | Reads | Produces |
383
+ |---|------|-------------|-------|-------|----------|
384
+ | 1 | `ACCT.bundle.RuleName` | *{from plugin.list}* | `prop=value` | event.attr.X | SetState(STATUS) |
385
+ | 2 | `ACCT.core.SendEvent` | *Sends named event* | `eventName=Foo` | — | Event: Foo |
386
+
387
+ **3. Data flow summary:**
388
+ ```
389
+ Inputs: event.attributes.items, setting:fulfilment.pick.config
390
+ Actions: Update item quantities, transition to PICKPACK
391
+ Outputs: SendEvent(RequestShipment), SendEvent(ReadyForPickup)
392
+ ```
393
+
394
+ **4. Failure modes (from rule metadata + props):**
395
+ ```
396
+ - Missing setting "fulfilment.pick.config" -> SettingNotFoundException
397
+ - Event attribute "items" empty -> rule skips (no error)
398
+ - Entity not in expected status -> ruleset no-match (silent skip)
399
+ ```
400
+
401
+ #### Full Walkthrough Example
402
+
403
+ ```markdown
404
+ ### CREATE — ORDER @ new entity
405
+ Initializes a new order: ensures product variants exist, records status history,
406
+ fires webhook to external system, and routes to validation.
407
+
408
+ | # | Rule | Description | Props | Produces |
409
+ |---|------|-------------|-------|----------|
410
+ | 1 | `*.CreateMissingVariantProducts` | Creates variants that don't exist for order items | `productCatalogueRef=PC:MASTER:2` | Product mutations |
411
+ | 2 | `*.UpdateStatusHistory` | Records status transition in entity attributes | — | Attribute upsert |
412
+ | 3 | `*.SendWebhookWithDynamicAttributes` | POSTs to URL from settings | `settingName=webhook.order.created` | HTTP POST |
413
+ | 4 | `*.SendEvent` | Sends named event | `eventName=ValidateOrder` | Event: ValidateOrder |
414
+
415
+ Data flow: New order -> product variants ensured -> status logged -> webhook fired -> ValidateOrder emitted.
416
+ ```
417
+
418
+ ### Step 3D: Rule Resolution (Understanding What a Rule Does)
419
+
420
+ When you encounter a rule in a workflow and need to understand its behavior, follow this resolution chain in order:
421
+
422
+ #### 1. Parse the Rule Name
423
+
424
+ Rule names follow `<ACCOUNT>.<MODULE>.<RuleName>`. The module segment tells you the origin:
425
+
426
+ | Module | Origin | Example |
427
+ |--------|--------|---------|
428
+ | `core` | Fluent platform core module | `ACCT.core.SetState`, `ACCT.core.SendEvent` |
429
+ | `order`, `fulfilment` | Fluent reference modules | `ACCT.order.SendEventForAllFulfilments` |
430
+ | `commonv2`, `globalinventory` | Fluent shared/inventory modules | `ACCT.globalinventory.ValidateIncomingProduct` |
431
+ | `reporting` | Fluent reporting module | `ACCT.reporting.SetState` |
432
+ | Any other name | **Custom extension module** | `ACCT.myextensions.CreateFulfilmentFromSourcingLocation` |
433
+
434
+ #### 2. Query the Live Rule Registry (`plugin.list`)
435
+
436
+ The `plugin.list` MCP tool returns the live registry of every rule deployed on the platform. This is the fastest way to understand any rule:
437
+
438
+ ```
439
+ plugin.list({ name: "CreateFulfilmentFromSourcingLocation" })
440
+ ```
441
+
442
+ **Returns:**
443
+ - `description` — what the rule does in plain language
444
+ - `parameters[]` — configurable props (`name`, `description`, `type`) that map to the `props` object in workflow JSON
445
+ - `ruleInfo.accepts[]` — entity types the rule works with
446
+ - `ruleInfo.produces[]` — events the rule can emit
447
+ - `ruleInfo.ruleException[]` — exceptions it can throw
448
+
449
+ **Example response (live from SAGIRISH):**
450
+ ```json
451
+ {
452
+ "name": "CreateFulfilmentFromSourcingLocation",
453
+ "description": "Creates a Fulfilment at a location dynamically sourced from a configurable JSON path.",
454
+ "parameters": [
455
+ { "name": "sourcingLocationPath", "description": "JSON path to extract location ref", "type": "STRING" },
456
+ { "name": "fulfilmentType", "description": "Fulfilment type (default: HD)", "type": "STRING" },
457
+ { "name": "fulfilmentRefPrefix", "description": "Static fallback prefix (default: FUL)", "type": "STRING" }
458
+ ]
459
+ }
460
+ ```
461
+
462
+ This tells you: the `props` in the workflow JSON (`sourcingLocationPath`, `fulfilmentType`, etc.) map directly to these parameters.
463
+
464
+ #### 3. Read Source Code or Decompiled JAR
465
+
466
+ For **any** rule where you need implementation details (not just the description from `plugin.list`), look at the actual code:
467
+
468
+ **Custom extension modules** — original source:
469
+ ```
470
+ accounts/<PROFILE>/SOURCE/<repo>/src/main/java/.../CreateFulfilmentFromSourcingLocation.java
471
+ ```
472
+
473
+ **Reference modules** (core, order, fulfilment, commonv2, globalinventory) — decompiled from JAR:
474
+ ```
475
+ accounts/<PROFILE>/SOURCE/.decompiled/<jar-basename>/com/fluentcommerce/rule/.../SetState.java
476
+ ```
477
+
478
+ Reference modules ship as JARs. If the user has placed the JAR under `accounts/<PROFILE>/SOURCE/`, `/fluent-connect` or `/fluent-custom-code` will decompile it. If no decompiled source exists yet, ask the user to provide the module JAR:
479
+
480
+ > I need to see the implementation of `<ACCOUNT>.order.SendEventForAllFulfilments`.
481
+ > This is a reference module rule — the source isn't open, but if you have the JAR
482
+ > (e.g., `fc-module-order-<version>.jar`), place it under `accounts/<PROFILE>/SOURCE/`
483
+ > and I can decompile it.
484
+
485
+ **What to look for in source or decompiled code:**
486
+ - `@RuleInfo` annotation — description, accepts, produces (mirrors `plugin.list`)
487
+ - `@ParamString` / `@ParamInteger` annotations — rule parameters
488
+ - `run()` method — the actual execution logic
489
+ - GraphQL queries/mutations — what entity data the rule reads or writes
490
+ - `context.action().sendEvent()` calls — events it emits at runtime
491
+ - Exception patterns — what causes failures
492
+
493
+ **Confidence by source type:**
494
+
495
+ | Source | Confidence | Editable? |
496
+ |--------|-----------|-----------|
497
+ | Original repo source | High | Yes |
498
+ | Decompiled JAR | Medium (synthetic var names, missing comments) | No (read-only) |
499
+ | `plugin.list` only | Description-level (no implementation detail) | N/A |
500
+
501
+ Use `/fluent-custom-code` to generate a pre-computed analysis (`source-map.json`) that indexes all rules — both custom and decompiled — with descriptions, parameters, test coverage, and complexity metrics.
502
+
503
+ #### 4. Check Cached Analysis Artifacts
504
+
505
+ If `/fluent-custom-code` has been run:
506
+
507
+ - `source-map.json` -> `modules[].rules[]` — every rule with `className`, `description`, `parameters`, `hasTest`
508
+ - `workflow-rule-map.json` — which rules are used in which workflows and rulesets
509
+ - `constraints.json` — extension risks and recommendations
510
+
511
+ #### Resolution Priority
512
+
513
+ ```
514
+ plugin.list (live, always available, covers ALL deployed rules)
515
+ | need implementation details?
516
+ Original source (custom rules with repos cloned to SOURCE/)
517
+ | no source repo?
518
+ Decompiled JAR (reference or custom modules, under SOURCE/.decompiled/)
519
+ | no JAR available?
520
+ Ask user to provide JAR -> place under SOURCE/ -> decompile
521
+ | need pre-computed batch analysis?
522
+ source-map.json (from /fluent-custom-code, covers both source + decompiled)
523
+ | rule not found anywhere?
524
+ Likely undeployed or from a module not installed on this account
525
+ ```
526
+
527
+ ### Step 4: Detect Issues
528
+
529
+ Run these checks against the parsed workflow:
530
+
531
+ #### 4.1 Orphaned Rulesets
532
+ Rulesets that can never be reached:
533
+ - No status trigger AND
534
+ - No other ruleset sends an event matching this ruleset's name
535
+
536
+ ```
537
+ For each ruleset R:
538
+ if R has no status triggers:
539
+ if no other ruleset contains SendEvent(R.name):
540
+ WARN: Orphaned ruleset "{R.name}" — never triggered
541
+ ```
542
+
543
+ #### 4.2 Dead-End Statuses
544
+ Statuses with no outgoing transitions (no ruleset triggers from them):
545
+
546
+ ```
547
+ For each status S:
548
+ if no ruleset has trigger.status == S.name:
549
+ if S.category != "DONE":
550
+ WARN: Dead-end status "{S.name}" (category={S.category}) — no transitions out
551
+ ```
552
+
553
+ Note: DONE-category statuses are expected terminal states and should NOT be flagged.
554
+
555
+ #### 4.3 Unreachable Statuses
556
+ Statuses that no `SetState` rule targets:
557
+
558
+ ```
559
+ For each status S:
560
+ if no ruleset contains SetState(S.name):
561
+ if S.name != "CREATED": # CREATED is set by platform on entity creation
562
+ WARN: Unreachable status "{S.name}" — no SetState targets it
563
+ ```
564
+
565
+ #### 4.4 Missing SendEvent Targets
566
+ Events fired by `SendEvent` that have no matching ruleset:
567
+
568
+ ```
569
+ For each SendEvent(eventName):
570
+ if no ruleset.name == eventName:
571
+ WARN: SendEvent("{eventName}") has no matching ruleset
572
+ ```
573
+
574
+ Note: Some events are intentionally sent to child/parent entities or external systems. Cross-reference with entity types.
575
+
576
+ #### 4.5 Same-Name Ruleset Collision Analysis
577
+ ```
578
+ For each pair of rulesets (R1, R2) where R1.name == R2.name and R1.type == R2.type:
579
+ key = (type, subtype-or-*, name)
580
+
581
+ if key matches and trigger statuses overlap:
582
+ HIGH: Ambiguous same-name rulesets with overlapping trigger scopes
583
+ else if key matches and trigger statuses do not overlap:
584
+ MEDIUM: Same-name multi-trigger pattern (often intentional, review for clarity)
585
+ else if subtype differs:
586
+ INFO: Same-name subtype-partitioned rulesets (usually intentional)
587
+ ```
588
+
589
+ Notes:
590
+ - Same name with different entity types (ORDER vs FULFILMENT) is normal.
591
+ - Same name + same type is not automatically an error; subtype and trigger overlap decide severity.
592
+
593
+ #### 4.6 Trigger Conflicts
594
+ Multiple rulesets with the same status trigger for the same entity type:
595
+
596
+ ```
597
+ For each status S:
598
+ rulesets = all rulesets with trigger.status == S AND same type
599
+ if len(rulesets) > 1:
600
+ WARN: Multiple rulesets trigger on status "{S}": {ruleset names}
601
+ (Only the first match fires — order matters)
602
+ ```
603
+
604
+ #### 4.7 Rule Pattern Detection
605
+
606
+ Detect rule types, integration touchpoints, and setting dependencies by static analysis of rule names and props:
607
+
608
+ **Direct event-name match:**
609
+ - Ruleset name = expected event name (primary matching mechanism)
610
+ - Example: Ruleset `ConfirmValidation` fires when event `ConfirmValidation` arrives
611
+
612
+ **Status-trigger match:**
613
+ - Rulesets with `triggers: [{ "status": "BOOKED" }]` fire when the entity enters that status
614
+ - Check for conflicts: multiple rulesets triggering on the same status (only first match fires)
615
+
616
+ **Cross-entity event mapping:**
617
+ - `SendEvent` rules in one entity type often target rulesets in a different entity type
618
+ - Example: ORDER ruleset sends `CreateFulfilment` -> FULFILMENT entity's `CREATE` ruleset fires
619
+ - Track: source entity type + event name -> target entity type + matching ruleset
620
+
621
+ **Rule pattern detection for status transitions:**
622
+ ```
623
+ Status transition rules (use endsWith for namespaced matching):
624
+ - *SetState -> sets entity status
625
+ - *ChangeState -> state change rule
626
+ - *ChangeStateGQL -> GraphQL-based state change
627
+ Example: "ACCOUNT.core.SetState" matches via endsWith("SetState")
628
+ ```
629
+
630
+ **Webhook pattern detection:**
631
+ ```
632
+ Rules whose names contain (case-insensitive):
633
+ webhook, hook, callback, notify, notification, trigger, publish
634
+ Or whose props reference webhook setting names.
635
+ Mark these rulesets as integration touchpoints.
636
+ ```
637
+
638
+ **Setting dependency detection:**
639
+ ```
640
+ Rules whose props contain keys matching:
641
+ setting, config, param, parameter, option, preference
642
+ Extract the setting name from the prop value.
643
+ Cross-reference with /fluent-settings to verify settings exist.
644
+ ```
645
+
646
+ #### 4.8 Settings Validation (Live Cross-Reference)
647
+
648
+ Verify that all settings referenced by workflow rule props actually exist in the live environment. Missing settings are the #1 cause of silent rule failures — the event processes as SUCCESS but the rule does nothing, leaving entities stuck.
649
+
650
+ ##### Extraction
651
+
652
+ Parse all rulesets and extract setting references from rule props:
653
+
654
+ ```
655
+ For each ruleset:
656
+ For each rule in ruleset.rules:
657
+ For each prop key/value in rule.props:
658
+ If key matches: setting, settingName, settingRef, settingsKey,
659
+ webhookSettingName, configSetting, configName
660
+ → Record: { settingName: value, ruleset, rule, propKey }
661
+
662
+ If rule.name endsWith "SendWebhook" or "SendWebhookWithDynamicAttributes":
663
+ → Mark as webhook setting (expect LOB valueType with "url" field)
664
+
665
+ If rule.name endsWith "UpdateEntityFromSetting" or "GetSettingValue":
666
+ → Mark as config setting
667
+ ```
668
+
669
+ Additionally, query `plugin.list` for each rule to discover settings that aren't obvious from prop names:
670
+
671
+ ```
672
+ plugin.list({ name: "<RuleShortName>" })
673
+ → Check parameters[].description for mentions of "setting" or "config"
674
+ → Cross-reference parameter names with the rule's props to identify the actual setting name
675
+ ```
676
+
677
+ ##### Validation
678
+
679
+ For each extracted setting reference, query the live environment:
680
+
681
+ ```graphql
682
+ {
683
+ settings(first: 1, name: ["<SETTING_NAME>"], context: "RETAILER") {
684
+ edges {
685
+ node { id name value lobValue valueType context contextId }
686
+ }
687
+ }
688
+ }
689
+ ```
690
+
691
+ Check:
692
+ 1. **Exists** — edges array is non-empty
693
+ 2. **Value type** — webhook settings should be LOB; simple config should be STRING/BOOLEAN
694
+ 3. **Value content** — LOB webhook settings should contain a `url` field in `lobValue`
695
+ 4. **Context scope** — setting context matches rule expectation (usually RETAILER)
696
+ 5. **Non-empty** — `value` or `lobValue` is not null/empty
697
+
698
+ ##### Report
699
+
700
+ ```
701
+ === Settings Validation: ORDER::HD (v1.50) ===
702
+
703
+ Ruleset Rule Setting Ref Status
704
+ ──────────────────────────────────────────────────────────────────────────────────────────────────────
705
+ OrderCreatedWebhook *.SendWebhookWithDynamicAttributes webhook.order.created OK (LOB)
706
+ OrderCancelledWebhook *.SendWebhookWithDynamicAttributes webhook.order.cancelled OK (LOB)
707
+ FulfilmentShippedNotify *.SendWebhookWithDynamicAttributes webhook.fulfilment.shipped MISSING
708
+ UpdateOrderConfig *.UpdateEntityFromSetting order.update.mapping MISSING
709
+ ConsignmentCreate *.GetSettingValue consignment.prefix OK (STRING)
710
+ CarrierRouting *.GetSettingValue carrier.hd.config TYPE_MISMATCH
711
+ → Expected: LOB (JSON config), Actual: STRING
712
+
713
+ Summary: 3/6 valid, 2 MISSING, 1 TYPE_MISMATCH
714
+ Action: Create missing settings before go-live → /fluent-settings
715
+ ```
716
+
717
+ ##### Severity
718
+
719
+ | Status | Severity | Impact |
720
+ |--------|----------|--------|
721
+ | OK | None | Setting will be read correctly |
722
+ | MISSING | HIGH | Rule will fail silently — entity gets stuck |
723
+ | TYPE_MISMATCH | MEDIUM | Rule may read empty value (e.g., reads `lobValue` but type is STRING) |
724
+ | EMPTY_VALUE | LOW | Setting exists but value is null/empty — rule behavior depends on implementation |
725
+
726
+ ##### Orphaned Settings Detection
727
+
728
+ Optionally, compare all live settings against all setting references extracted from workflows:
729
+
730
+ ```
731
+ For each setting in the environment:
732
+ If setting.name does NOT appear in any workflow rule prop:
733
+ → ORPHANED (exists but no rule uses it — candidate for cleanup)
734
+ ```
735
+
736
+ Report orphaned settings separately. These are low priority but indicate configuration drift.
737
+
738
+ #### 4.9 Rule Props Audit (Runtime vs Static)
739
+
740
+ Compare rule props as defined in the workflow JSON against the actual props observed at runtime via ORCHESTRATION_AUDIT events. Drift between static config and runtime evidence indicates workflow version mismatches, environment-specific overrides, or deployment issues.
741
+
742
+ ##### Static Props Extraction
743
+
744
+ From the workflow JSON, extract all rule props for each ruleset:
745
+
746
+ ```
747
+ For each ruleset:
748
+ For each rule in ruleset.rules:
749
+ Record: { rulesetName, ruleName, props: { key: value, ... } }
750
+ ```
751
+
752
+ ##### Runtime Props Extraction
753
+
754
+ Query ORCHESTRATION_AUDIT events with `category=rule` for the target entity:
755
+
756
+ ```
757
+ event.list({
758
+ "eventType": "ORCHESTRATION_AUDIT",
759
+ "context.rootEntityRef": "<ENTITY_REF>",
760
+ "count": 200
761
+ })
762
+ ```
763
+
764
+ Filter results where `category == "rule"`. Each rule audit event contains:
765
+ - `name` — the rule's short name (e.g., `SendWebhookWithDynamicAttributes`)
766
+ - `ruleSet` — the ruleset it belongs to (e.g., `OrderCreatedWebhook`)
767
+ - `props` — the actual props object as passed by the workflow engine at execution time
768
+
769
+ ##### Comparison
770
+
771
+ ```
772
+ For each rule execution from runtime:
773
+ 1. Find the matching rule in the static workflow JSON (by ruleSet + rule name)
774
+ 2. Compare static props vs runtime props:
775
+ - MATCH: all keys and values identical
776
+ - EXTRA_PROP: runtime has a prop not in static JSON (injected by platform or module)
777
+ - MISSING_PROP: static JSON has a prop not seen at runtime (stripped or defaulted)
778
+ - VALUE_DRIFT: same key, different value (version mismatch or override)
779
+ 3. Flag VALUE_DRIFT as HIGH — this means the deployed workflow differs from the JSON file
780
+ ```
781
+
782
+ ##### Report Format
783
+
784
+ ```
785
+ === Rule Props Audit: ORDER::HD ===
786
+
787
+ Ruleset Rule Prop Static Value Runtime Value Status
788
+ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
789
+ OrderCreatedWebhook *.SendWebhookWithDynamicAttributes setting webhook.order.created webhook.order.created MATCH
790
+ ProcessOrder *.SetState status ON_VALIDATION ON_VALIDATION MATCH
791
+ ConfirmShipment *.SendWebhookWithDynamicAttributes setting webhook.ful.shipped webhook.shipped VALUE_DRIFT
792
+ CreateFulfilment *.CreateFulfilmentFromSourcingLocation fulfilmentType HD HD MATCH
793
+ CreateFulfilment *.CreateFulfilmentFromSourcingLocation maxRetries (not in JSON) 3 EXTRA_PROP
794
+
795
+ Summary: 4/5 MATCH, 0 MISSING, 1 VALUE_DRIFT, 1 EXTRA_PROP
796
+ Action: VALUE_DRIFT on "ConfirmShipment" setting prop → re-download workflow or check deployment version
797
+ ```
798
+
799
+ ##### Severity
800
+
801
+ | Status | Severity | Meaning |
802
+ |--------|----------|---------|
803
+ | MATCH | None | Static and runtime agree |
804
+ | VALUE_DRIFT | HIGH | Deployed workflow differs from local JSON — re-download or re-deploy |
805
+ | MISSING_PROP | MEDIUM | Prop exists in JSON but was not observed — rule may not have fired, or platform stripped it |
806
+ | EXTRA_PROP | LOW | Platform or module injected a default prop not in the JSON — usually harmless |
807
+
808
+ ##### Integration
809
+
810
+ - Use runtime props data from `/fluent-trace` Step 8A–8F event extraction
811
+ - Feed VALUE_DRIFT findings into `/fluent-workflow` for re-download
812
+ - Feed MISSING_PROP findings into `/fluent-trace` for investigation of why the rule didn't fire
813
+
814
+ ### Step 5: Generate Report
815
+
816
+ Produce a structured analysis report:
817
+
818
+ ```
819
+ === Workflow Analysis: ORDER::HD (v1.50) ===
820
+
821
+ Metadata:
822
+ Entity Type: ORDER
823
+ Entity Subtype: HD
824
+ Retailer ID: 2
825
+ Total Statuses: 29 (ORDER=8, FULFILMENT=11, ARTICLE=5, CONSIGNMENT=5)
826
+ Total Rulesets: 61
827
+
828
+ Status Graph (ORDER):
829
+ CREATED -> ON_VALIDATION -> BOOKED -> PICK_PACK -> AWAITING_COURIER_COLLECTION -> COMPLETE
830
+ -> CANCELLED
831
+ -> ESCALATED
832
+
833
+ Entity Type Breakdown:
834
+ ORDER: 8 statuses, 12 rulesets
835
+ FULFILMENT: 11 statuses, 20 rulesets
836
+ ARTICLE: 5 statuses, 15 rulesets
837
+ CONSIGNMENT: 5 statuses, 14 rulesets
838
+
839
+ Issues Found:
840
+ [WARN] Orphaned ruleset "UpsertEventAttributes" — no trigger, no SendEvent targets it
841
+ [WARN] Dead-end status "ESCALATED" is category DONE — OK (terminal)
842
+ [INFO] 4 cross-entity SendEvent calls (ORDER -> FULFILMENT events)
843
+
844
+ Event Chain Depth:
845
+ Longest chain: CREATE -> ... -> OrderComplete (12 hops)
846
+ Deepest cascade: ConfirmValidation triggers 8 downstream rulesets
847
+
848
+ Rule Module Usage:
849
+ <ACCOUNT>.core: 45 usages (SetState, SendEvent, ScheduleEvent, SendWebhook)
850
+ <ACCOUNT>.order: 38 usages (domain-specific rules)
851
+ <ACCOUNT>.metrics: 20 usages (UpdateStatusHistory, ComputeMetrics)
852
+
853
+ Process Flow Classification:
854
+ CREATE (1): CREATE
855
+ USER_ACTION (3): CancelOrder, ConfirmPick, ConfirmShipment
856
+ INTEGRATION_EVENT (2): PaymentCallback, InventoryUpdate
857
+ SCHEDULED_EVENT (1): ValidationGraceExpired
858
+ CROSS_WORKFLOW (4): CreateFulfilment, NotifyFulfilmentShipped, ...
859
+ INTERNAL (51): ProcessOrder, ConfirmValidation, ...
860
+ ```
861
+
862
+ ### Step 5A: Process Flow Classification
863
+
864
+ Classify each ruleset by its role in the business process. This reveals how work enters and flows through the system.
865
+
866
+ | Flow Type | Detection Rule | Priority |
867
+ |-----------|---------------|----------|
868
+ | **CREATE** | Ruleset name is exactly `CREATE` | 1 (highest) |
869
+ | **USER_ACTION** | Ruleset has `userActions` defined (UI button triggers) | 2 |
870
+ | **SCHEDULED_EVENT** | Ruleset is the target of a `ScheduleEvent` rule (has delay/schedule props) | 3 |
871
+ | **CROSS_WORKFLOW** | Ruleset receives events from a different workflow type (cross-workflow incoming connection) | 4 |
872
+ | **INTEGRATION_EVENT** | Ruleset has no internal or cross-workflow incoming connections (external API/webhook entry point) | 5 |
873
+ | **INTERNAL** | All other rulesets — triggered internally via `SendEvent` chains or status triggers | 6 (default) |
874
+
875
+ **Classification algorithm:**
876
+ ```
877
+ For each ruleset R:
878
+ if R.name == "CREATE" -> CREATE
879
+ else if R.userActions is non-empty -> USER_ACTION
880
+ else if any other ruleset has ScheduleEvent rule with eventName == R.name -> SCHEDULED_EVENT
881
+ else if R has cross-workflow incoming connections -> CROSS_WORKFLOW
882
+ else if R has no incoming connections from within same workflow -> INTEGRATION_EVENT
883
+ else -> INTERNAL
884
+ ```
885
+
886
+ **Why this matters:**
887
+ - **CREATE** — entity generation rate and initialization quality
888
+ - **USER_ACTION** — manual intervention points (bottleneck candidates)
889
+ - **SCHEDULED_EVENT** — time-dependent automation (monitor for stale timers)
890
+ - **CROSS_WORKFLOW** — inter-workflow dependencies (failure propagation risk)
891
+ - **INTEGRATION_EVENT** — external system entry points (webhook health)
892
+ - **INTERNAL** — core orchestration logic (event chain depth)
893
+
894
+ ## Cross-Workflow Connection Analysis
895
+
896
+ ### Connection Types
897
+
898
+ | Type | Definition | Detection |
899
+ |------|-----------|-----------|
900
+ | **Internal** | Events within the same workflow (ruleset A -> SendEvent -> ruleset B within ORDER::HD) | SendEvent target entityType matches workflow's own entityType |
901
+ | **Cross-Entity** | Events targeting child entities (ORDER workflow -> SendEvent -> FULFILMENT entity) | SendEvent target entityType differs from workflow's entityType |
902
+ | **Cross-Workflow** | Events bridging workflow types (ORDER::HD -> FULFILMENT::HD_WH) | Target flexType differs from source flexType; creates new execution thread |
903
+
904
+ ### Detection Pattern
905
+
906
+ For each SendEvent rule in the workflow:
907
+ 1. Extract target `entityType` from rule props or event attributes
908
+ 2. Compare with the workflow's own `entityType`
909
+ 3. If same -> **internal connection**
910
+ 4. If different -> **cross-entity connection**
911
+ 5. Look up target workflow by flexType (entityType::subtype) -> if found, map the bridge -> **cross-workflow connection**
912
+ 6. If target workflow not found -> potential **orphan connection** (event will get NO_MATCH)
913
+
914
+ ### Cross-Workflow Bridge Report
915
+
916
+ When analyzing workflows, report bridges between them:
917
+
918
+ ```
919
+ ORDER::HD -> FULFILMENT::HD_WH
920
+ Bridge event: CreateFulfilment (sent by CreateFulfilmentFromSourcingLocation rule)
921
+ Source ruleset: ProcessHDFulfilmentChoice
922
+ Target workflow: FULFILMENT::HD_WH (CREATE ruleset)
923
+ Thread boundary: YES (different execution context)
924
+ ```
925
+
926
+ ## Deep Analysis Mode (--deep)
927
+
928
+ When `--deep` is specified, additionally:
929
+
930
+ 1. **Cross-workflow analysis** — Download ALL workflows for the retailer and check for cross-entity event consistency (e.g., ORDER workflow sends events that FULFILMENT workflow expects)
931
+ 2. **Rule module inventory** — List all unique rule names used, grouped by module
932
+ 3. **User action audit** — List all rulesets with `userActions` defined, map to UI button labels
933
+ 4. **Attribute flow** — Track attributes set by rules across the event chain
934
+ 5. **Webhook mapping** — List all SendWebhook rules and their target settings
935
+
936
+ ## Integration with Other Skills
937
+
938
+ | Task | Skill / Tool |
939
+ |------|-------------|
940
+ | Download workflow to analyze | `/fluent-workflow` |
941
+ | Connection-centric dependency mapping | `/fluent-connection-analysis` |
942
+ | Understand what a rule does (live registry) | `plugin.list` MCP tool |
943
+ | Read custom rule source code | `/fluent-custom-code` |
944
+ | Decompile reference module JARs | `/fluent-custom-code` or manual `cfr`/`procyon` |
945
+ | Fix issues found by analyzer | `/fluent-workflow-builder` |
946
+ | Deploy fixed workflow | `/fluent-module-deploy` or `/fluent-workflow` |
947
+ | Test after deployment | `/fluent-e2e-test` |
948
+ | Trace runtime failures | `/fluent-trace` |
949
+ | Query available user actions | `/fluent-transition-api` |
950
+ | Check rule settings dependencies | `/fluent-settings` |
951
+
952
+ ## Tips
953
+
954
+ - **Always download the latest version** before analyzing. Prefer MCP-based download (`workflow.list` then `workflow.download` for each, saving with `::` replaced by `__` in filenames). On macOS/Linux, `fluent workflow download -w all` also works. On Windows, the CLI fails on `::` filenames — use `--json` export and split to sanitized filenames with `workflow-file-map.json`.
955
+ - **Composite workflows** contain multiple entity types (ORDER + FULFILMENT + ARTICLE + CONSIGNMENT) — analyze each entity type's status graph separately
956
+ - **SendEvent across entity types** is normal — ORDER rulesets often send events to FULFILMENT entities and vice versa
957
+ - **Rule names reveal module ownership** — `<ACCOUNT>.core.*` are platform module rules, `<ACCOUNT>.order.*` are from the order module, custom modules use their own prefix
958
+ - **Gate rulesets** (e.g., `SendEventOnVerifyingAllFcStatus`) wait for child entities before advancing parent — trace these carefully
959
+ - **Never guess what a rule does** — always use `plugin.list` first, then source/decompiled code if you need implementation details