---
name: fluent-connection-analysis
description: Analyze workflow connection topology across rulesets and workflows. Produces internal/cross-entity/cross-workflow maps, static-vs-dynamic runtime diffs, and webhook/setting conformance inventories with Mermaid output. Triggers on "connection analysis", "workflow connections", "cross workflow dependencies", "orphaned rulesets", "process flow classification", "webhook dependency map", "expected vs observed rulesets", "runtime workflow diff".
user-invocable: true
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
argument-hint: <workflow-file-or-name> [--deep] [--mermaid] [--output <path>] [--validate <entity-ref> --entity-type ORDER|FULFILMENT] [--from <iso> --to <iso>]
cursor-tier: auto
---

# Fluent Connection Analysis

Connection-focused analysis for Fluent workflows. Use this when the main question is not just "what statuses exist?" but "how does work move between rulesets/workflows and where are the risky dependency points?"

## Ownership Boundary

This skill owns:
- connection topology (internal, cross-entity, cross-workflow)
- orphan/missing-target detection
- process-flow type classification
- webhook and setting dependency extraction

Related skills:
- Workflow structure baseline -> `/fluent-workflow-analyzer`
- Workflow edits/fixes -> `/fluent-workflow-builder`
- Runtime failure correlation -> `/fluent-trace`
- Settings validation -> `/fluent-settings`

## When to Use

- Mapping dependencies before changing a workflow
- Explaining "what triggers what" across entities
- Finding orphaned rulesets and missing SendEvent targets
- Auditing integration/webhook touchpoints
- Producing architecture handover docs with Mermaid diagrams
- Comparing static expected paths vs runtime observed execution after an event/mutation
- Verifying rule-referenced settings exist and are valid in live context

## Progress

Emit this block at each phase transition to show progress:

```
▸ /fluent-connection-analysis [1/7]
  ✓ Gather workflow set      → Build connection graph
  ○ Detect risks             ○ Process flow classification
  ○ Webhook/setting deps     ○ Produce deliverables
  ○ Validate vs live data
```

Update the block as each phase completes — mark completed phases with `✓`, the active phase with `→`, and remaining phases with `○`. Replace `[1/7]` with the current phase number.

## Seamless Default Bundle

Run this skill as a single-pass bundle by default:

1. Static connection topology + risk checks
2. Settings conformance (`rule props -> live setting status`)
3. Runtime diff (when `--validate` inputs are provided)

If `--validate` is not provided, still emit sections 1-2 and explicitly mark runtime diff as `NOT_RUN`.

## Pre-flight: Project Knowledge Check

Check for project-specific knowledge that should inform connection analysis:

1. Check if `accounts/<PROFILE>/knowledge/` exists
2. If yes, read it and find files where `relevant-skills` includes `fluent-connection-analysis`
   **Account knowledge:** Read from `accounts/<PROFILE>/knowledge/` when `FLUENT_PROFILE` is set. These contain project-specific conventions.

3. Read matching knowledge files — typically:
   - `knowledge/platform/domain-model.md` — use for entity edges, cross-domain topology, valid connection paths
   - `accounts/<PROFILE>/knowledge/client/data-model.md` — use for entity types, subtypes, expected relationships
4. Apply knowledge silently — do NOT show raw knowledge to user, just use it to validate topology findings

## Connection Analysis Procedure

### 1) Gather Workflow Set

1. Resolve target workflow(s) (local file or via `/fluent-workflow` download).
2. For dependency analysis, load adjacent workflows in the same retailer (ORDER + FULFILMENT + child types).
3. Build indexes:
   - rulesets by `(type, name)`
   - statuses by `(entityType, name)`
   - event emitters by `eventName` — scan ALL rules with `eventName` or `noMatchEventName` props (SendEvent, ScheduleEvent, ForwardEvent*, SendEventOnVerifying*, and any other event-emitting rule)

### 2) Build Connection Graph

For each ruleset:
1. Identify incoming edges:
   - event-name match (`event.name == ruleset.name`)
   - status-trigger match (`triggers[].status`)
2. Identify outgoing edges:
   - `SendEvent(eventName)` -> target ruleset(s)
   - `SetState(status)` -> status transition edges
3. Classify each edge:
   - `internal`: same workflow/entity scope
   - `cross-entity`: different entity type
   - `cross-workflow`: target flexType/workflow differs
4. Annotate conditional edges:
   - If a ruleset has a `subtype` field (e.g. `"subtype": "HD_WH"`), mark all its incoming edges as **conditional on subtype**. The event fires for all subtypes but only this ruleset's trigger scope matches the specific subtype.
   - In the report, label conditional edges: `ConfirmPick --(HD_WH only)--> RequestShipment`

### 3) Detect Risks

Run these checks:
- orphaned rulesets (no trigger and no inbound SendEvent)
- missing SendEvent targets (no ruleset receives emitted event)
- trigger conflicts (multiple rulesets for same status in same type)
- dead-end non-terminal statuses
- unreachable statuses (never targeted by SetState)

**Duplicate ruleset severity calibration:**
- Same name + same entity type + same subtype (or both subtype-empty) + **overlapping trigger statuses** = **HIGH** (ambiguous runtime behavior)
- Same name + same entity type + same subtype (or both subtype-empty) + **non-overlapping trigger statuses** = **MEDIUM** (maintenance ambiguity; often intentional normal-vs-late variants)
- Same name + same entity type + **different subtype filters** = **INFO** (usually intentional subtype partitioning; document explicitly)

### 4) Process Flow Classification

Classify each ruleset into one flow type. There are 6 categories (not 5):

| Type | Condition | Examples |
|------|-----------|---------|
| `CREATE` | Ruleset name is `CREATE` | ORDER.CREATE, FULFILMENT.CREATE |
| `SCHEDULED_EVENT` | Ruleset receives event fired by `ScheduleEvent` | ValidationGraceExpired |
| `CROSS_ENTITY_EVENT` | Ruleset receives event fired by `SendEventForOrder`, `SendEventForAllFulfilmentChoices`, `SendEventForAllFulfilments`, or other cross-entity Send rules | NotifyFCComplete, RouteFulfilmentChoice, CancelFulfilment |
| `USER_ACTION` | Ruleset has non-empty `userActions[]` | CancelOrder, EscalateFulfilmentChoice |
| `INTERNAL_EVENT` | Ruleset receives event fired by `SendEvent` or `ForwardEvent*` from another ruleset **within the same entity type** | ValidateOrder (from CREATE), ProcessOrder (from ConfirmValidation), TransitionToShipped (from NotifyFulfilmentShipped) |
| `INTEGRATION_EVENT` | No inbound SendEvent from any ruleset in the workflow; event arrives from external system | ConfirmValidation, ConfirmPick, ConfirmShipment, ConfirmDelivery |

**How to distinguish INTERNAL_EVENT from INTEGRATION_EVENT:**
1. Build the emitter index by scanning ALL event-emitting rule patterns in the workflow:
   - `core.SendEvent` → `eventName` prop
   - `core.ScheduleEvent` → `eventName` prop
   - `ForwardEventBy*` (e.g. `ForwardEventByFulfilmentChoiceType`) → `eventName` prop
   - `SendEventOnVerifying*` (e.g. `SendEventOnVerifyingAttributeValue`) → both `eventName` AND `noMatchEventName` props
   - `SendEventOnVerifyingAllFulfilment*States` → `eventName` prop
   - **Catch-all:** Any rule with an `eventName` or `noMatchEventName` prop emits events — include it.
   Record each emitted event name and which ruleset emits it.
2. If a ruleset's name appears as an emitted `eventName` from another ruleset in the same entity type → `INTERNAL_EVENT`.
3. If a ruleset's name does NOT appear as any emitted `eventName` in the workflow → `INTEGRATION_EVENT` (external inbound).
4. Conditional emitters count: `noMatchEventName` targets, scheduled event targets, and gate-pattern event targets (from `SendEventOnVerifyingAll*`) are all internal emitters.
5. **Dual classification:** A ruleset can be both a USER_ACTION (has `userActions[]`) and an INTERNAL_EVENT target (e.g. `CancelOrder` is a user action but also sent by `GracePeriodTimeoutCancel`). Use the primary classification per priority order, but note dual roles in the report.

Priority for deterministic classification (first match wins):
1. `CREATE`
2. `SCHEDULED_EVENT`
3. `CROSS_ENTITY_EVENT`
4. `USER_ACTION`
5. `INTERNAL_EVENT`
6. `INTEGRATION_EVENT`

### 4A) Strict User Action Contract Checks (Anti-Hallucination)

When a ruleset is classified as `USER_ACTION`, enforce these checks:

1. `userActions` must exist at the ruleset level (never inside rule props).
2. Every action must have explicit `eventName` (no inferred defaults).
3. Ruleset `subtype` must match the intended workflow branch for that action.
4. `context[]` entries must include `label`, `type` (`PRIMARY` or `SECONDARY`), and non-empty `modules[]`.
5. `attributes[]` entries must only use documented fields (`name`, `type`, `mandatory`, optional `source`, `options`).
6. If expected actions are missing, verify ALL THREE mandatory Transition API params: `module` (specific name — `"all"` returns NOTHING), `flexType`, and `flexVersion`. All rules treated equally regardless of plugin origin.

For canonical authoring and diagnostics, cross-check `/fluent-workflow-builder` and `/fluent-transition-api`.

### 5) Webhook + Setting Dependency Mapping

Detect webhook/integration patterns by:
- rule name patterns (`webhook`, `notify`, `callback`, `publish`, `subscribe`)
- rule props referencing webhook/setting keys

Detect setting usage by prop-key/value patterns:
- `setting`, `config`, `parameter`, `option`, `property`

Output:
- ruleset -> webhook touchpoints
- ruleset -> setting keys
- setting -> dependent rulesets/workflows
- setting runtime contract status (`FOUND`, `MISSING`, `EMPTY`, `INVALID_FORMAT`)

Runtime setting verification:
1. For each extracted setting key, query live settings using **cascading scope resolution**:
   - First: `RETAILER` + retailer `contextId`
   - Then: `ACCOUNT` + `contextId=0`
   - Use the first scope where the setting is found.
   Module-installed settings often default to `ACCOUNT` scope. Always check both before reporting `MISSING`.
2. Validate existence and value shape:
   - `MISSING`: no setting found.
   - `EMPTY`: found but `value` and `lobValue` are empty.
   - `INVALID_FORMAT`: value exists but does not match expected shape (for example webhook JSON missing `url`).
   - `FOUND`: exists with plausible value shape.
3. Emit a contract table: `setting -> referencedByRulesets -> runtimeStatus -> notes`.

For full CRUD/migration workflows, hand off to `/fluent-settings`.

### 6) Produce Deliverables

Always generate:
1. Connection Summary (counts by internal/cross-entity/cross-workflow)
2. Risk Findings (ordered by severity)
3. Process Flow Table (ruleset -> flow type)
4. Integration Dependency Table (webhook + settings)

When `--mermaid` is enabled, generate:
- state machine per entity (`stateDiagram-v2`)
- event/connection flow (`flowchart TD`)
- cross-entity lifecycle (`flowchart LR`)

**Mermaid syntax:** Validate all generated diagrams against `knowledge/mermaid-syntax-rules.md` rules before output (no colons in free text, no unicode arrows, quoted special-char labels).

> **Diagram validation:** All Mermaid blocks must pass `knowledge/mermaid-syntax-rules.md` rules before writing to the plan file.

**Mermaid accuracy rules:**
- Dotted-line labels between entities must use **event names**, not rule names. If a rule (e.g. `CreateFulfilmentFromSourcingLocation`) creates a child entity, label the edge as "creates entity" or the subsequent CREATE event, not the rule class name.
- Cross-entity lifecycle must show **intermediate statuses** when an entity transitions through multiple states. E.g. if ReportShortpick sends both NotifyFulfilmentShipped and NotifyFulfilmentDelivered, show the ORDER transitioning through SHIPPED before COMPLETED, not skipping directly to COMPLETED.
- Annotate subtype-conditional paths in diagrams: `RequestShipment [HD_WH]`, `ReadyForPickup [CC_PFS]`.

### 7) Validate Against Live Data (`--validate`)

Use this when you have a real entity and want to compare "what the static connection graph predicts" vs "what actually executed at runtime". Requires `--validate <entity-ref> --entity-type <TYPE>`.

#### 7a) Resolve Entity and Determine Scope

1. Accept entity ref and type from CLI arguments. Supported types: `ORDER`, `FULFILMENT`, `FULFILMENT_CHOICE`, `ARTICLE`.
2. Query the entity to confirm it exists and retrieve its current status and subtype:
   ```
   graphql.query: { orders(ref: ["<REF>"]) { edges { node { id ref type status } } } }
   ```
   (Adjust root field for entity type: `orders`, `fulfilments`, etc.)
3. Determine the workflow flexType from entity type + subtype (e.g. `ORDER::HD`, `FULFILMENT::HD_WH`).
4. Load the matching workflow JSON from the local workflow set (Steps 1-2 of the main procedure). If not found locally, download it.
5. Run Steps 2-4 (Build Connection Graph, Detect Risks, Process Flow Classification) on the workflow to produce the **expected connection graph** — the full set of rulesets, edges, and conditional branches.

#### 7b) Query Live Orchestration Events

Fetch all orchestration events for the entity:

> **Event filter reference:** For complete filter syntax, see `/fluent-event-api`. The examples below show connection-analysis-specific patterns.

```
event.list({
  "context.entityRef": "<ENTITY_REF>",
  "context.entityType": "<ENTITY_TYPE>",
  "eventType": "ORCHESTRATION_AUDIT",
  "count": 200
})
```

Also collect business orchestration events for name-level matching:
```
event.list({
  "context.entityRef": "<ENTITY_REF>",
  "context.entityType": "<ENTITY_TYPE>",
  "eventType": "ORCHESTRATION",
  "count": 200
})
```

If more than 200 events exist, paginate using `start` offset until all events are collected for both queries.

For each returned event, extract:
- `name` — the event/ruleset name that fired
- `status` — event status (SUCCESS, FAILED, etc.)
- `createdOn` — timestamp for timing analysis
- `entityId`, `entityRef`, `entityType` — confirm entity scope
- `attributes` — any rule-specific attributes (subtype, status transitions)
- `category` — especially `ruleSet`, `rule`, `ACTION`, `exception` from `ORCHESTRATION_AUDIT`

#### 7c) Cross-Entity Event Tracing

For entity types that spawn or interact with child entities, also query child events:

- **ORDER** entities: query events for related fulfilment choices and fulfilments:
  ```
  event.list({
    "context.rootEntityRef": "<ORDER_REF>",
    "context.rootEntityType": "ORDER",
    "context.entityType": "FULFILMENT_CHOICE",
    "eventType": "ORCHESTRATION",
    "count": 200
  })
  ```
  Repeat for `context.entityType: "FULFILMENT"`.

- **FULFILMENT** entities: query events for the parent order:
  ```
  event.list({
    "context.entityRef": "<FULFILMENT_REF>",
    "context.entityType": "FULFILMENT",
    "eventType": "ORCHESTRATION",
    "count": 200
  })
  ```
  Also query any articles linked to the fulfilment.

Collect all cross-entity events into a separate list for cross-entity edge validation.

#### 7d) Map Actual Events to Expected Rulesets

For each ruleset in the expected connection graph:

1. **Direct match**: Check if an ORCHESTRATION event with the same `name` as the ruleset name exists in the collected events. If found, mark as **MATCHED**.
2. **Conditional branch check**: If the ruleset has a `subtype` filter (e.g. `HD_WH` only), check whether the entity's actual subtype matches. If the subtype does not match, mark as **SKIPPED (subtype mismatch: entity is <actual>, ruleset requires <expected>)**.
3. **Gate ruleset check**: For gate-pattern rulesets (e.g. `SendEventOnVerifyingAllFulfilmentStates`), check if the gate event was emitted by looking for the gate's `eventName` in the event list. If the gate condition was not met, mark as **SKIPPED (gate condition not met)**.
4. **Cross-entity event check**: For rulesets that emit cross-entity events (via `SendEventForOrder`, `SendEventForAllFulfilmentChoices`, `SendEventForAllFulfilments`), verify the target event appears in the cross-entity event list. If found, mark as **MATCHED (cross-entity)**. If not found, mark as **SKIPPED (cross-entity event not propagated)**.
5. **Status precondition check**: If a ruleset triggers on a specific status and the entity never reached that status (based on observed SetState transitions), mark as **SKIPPED (status <STATUS> never reached)**.

For each observed event that does NOT correspond to any expected ruleset, mark as **UNEXPECTED**.

#### 7e) Timing Analysis

Sort all matched events by `createdOn` timestamp and compute:
- **Duration between consecutive events**: time from one ruleset completion to the next
- **Total execution span**: time from first event to last event
- **Slowest transition**: the largest gap between consecutive events (potential bottleneck)
- **Gate wait time**: for gate rulesets, time between the last contributing child event and the gate event firing

Flag any gap exceeding 5 seconds as a potential delay indicator.

#### 7f) Produce Validate Report

Generate the report with these sections:

**Expected Path vs Actual Path Table:**
```
| Ruleset | Flow Type | Expected | Observed | Status | Evidence |
|---------|-----------|----------|----------|--------|----------|
| CREATE | CREATE | yes | yes | MATCHED | evt-001 |
| ValidateOrder | INTERNAL_EVENT | yes | yes | MATCHED | evt-002 |
| ConfirmValidation | INTEGRATION_EVENT | yes | yes | MATCHED | evt-003 |
| RequestShipment | INTERNAL_EVENT | yes | no | SKIPPED | subtype mismatch: entity is CC, ruleset requires HD_WH |
| ReadyForPickup | INTERNAL_EVENT | yes | yes | MATCHED | evt-004 |
| UnknownExternalEvt | - | no | yes | UNEXPECTED | evt-099 |
```

**Summary Counts:**
```
MATCHED: <N> rulesets executed as expected
SKIPPED: <N> rulesets not executed (with reasons)
UNEXPECTED: <N> events observed but not in expected path
```

**Skipped Rulesets Detail:**
For each SKIPPED ruleset, explain the skip reason:
- `subtype mismatch` — entity subtype does not match ruleset filter
- `status never reached` — prerequisite status was never set
- `gate condition not met` — gate ruleset waiting on child entities that are not all in required state
- `cross-entity event not propagated` — expected cross-entity event was not observed on child/parent
- `conditional guard` — rule-level guard/attribute condition not satisfied

**Conditional Branch Report:**
```
Branch Point: <ruleset with multiple outgoing conditional edges>
  Taken: <branch that was observed> (subtype: HD_WH)
  Not taken: <branch not observed> (subtype: CC_PFS) — SKIPPED
```

**Timing Analysis:**
```
| From | To | Duration | Flag |
|------|----|----------|------|
| CREATE | ValidateOrder | 120ms | |
| ValidateOrder | ConfirmValidation | 45200ms | SLOW (>5s) |
| ConfirmValidation | ReadyForPickup | 340ms | |
Total span: 45.66s | Slowest: ValidateOrder -> ConfirmValidation (45.2s)
```

**Cross-Entity Propagation:**
```
| Source Entity | Event Emitted | Target Entity Type | Target Event | Status |
|--------------|---------------|--------------------|--------------|--------|
| ORDER:ORD-001 | NotifyFCComplete | FULFILMENT_CHOICE | RouteFulfilmentChoice | MATCHED |
| ORDER:ORD-001 | CancelFulfilment | FULFILMENT | CancelFulfilment | NOT FOUND |
```

**Default output path:** `accounts/<PROFILE>/analysis/topology/`. When `--output <path>` is specified, write the full report to the given file instead. When `--mermaid` is also enabled, annotate the connection graph diagram with color-coded edges: green for MATCHED, grey for SKIPPED, red for UNEXPECTED.

#### 7g) Runtime Settings Conformance (required in validate mode)

In `--validate` mode, always add a settings conformance section:

1. Reuse extracted setting refs from Step 5 (webhook + non-webhook settings).
2. Query live settings for each key using **cascading scope resolution**:
   - First: `RETAILER` (contextId = retailer id)
   - Then: `ACCOUNT` (contextId = 0)
   - Use the first scope where the setting is found.
   Record which scope the setting was found at — this is important for the conformance table.
3. Evaluate status:
   - `FOUND`
   - `MISSING`
   - `EMPTY`
   - `INVALID_FORMAT` (for example webhook JSON without `url`)
   - `CONTRACT_MISMATCH` (exists but runtime evidence suggests wrong value; for example webhook request endpoint differs from configured setting URL)
4. If `ORCHESTRATION_AUDIT` contains webhook action evidence, compare:
   - configured webhook URL from setting
   - observed `Request Endpoint` in audit attributes
   and emit mismatch findings.

Settings conformance table:
```
| Setting | Referenced By | Runtime Status | Evidence |
|---------|----------------|----------------|----------|
| webhook.order.created | ORDER.CREATE | FOUND | setting id=... |
| webhook.carrier.shipment.request | FULFILMENT.RequestShipment | CONTRACT_MISMATCH | configured=https://x, observed=https://y |
| update.fulfilment.confirmPick | FULFILMENT.ConfirmPick | MISSING | no settings edge |
```

## Output Template

```text
=== Connection Analysis: <WORKFLOW_NAME> ===

Topology:
  Internal edges: <N>
  Cross-entity edges: <N>
  Cross-workflow edges: <N>

Findings:
  [CRITICAL|HIGH|MEDIUM] <finding>

Process Flow Classification:
  <Ruleset> -> <FlowType>

Webhook/Setting Dependencies:
  <Ruleset> -> webhook:<keys> setting:<keys>
```

## Learning Capture

This is an analysis skill — follow the **Learning Capture Protocol** (see CLAUDE.md Cross-Skill Conventions). After topology analysis, when the user confirms or corrects findings about cross-workflow connections, event routing, or webhook dependencies, write the confirmed learning to the `implementation-learnings.md` auto-memory file under the relevant account heading.

## Decision Rules

- If the user needs full state machine quality checks -> include `/fluent-workflow-analyzer`.
- If gaps are found and user asks for fixes -> switch to `/fluent-workflow-builder`.
- If runtime behavior differs from static analysis -> pivot to `/fluent-trace`.

