---
name: fluent-e2e-test
description: Run end-to-end test sequences for Fluent Commerce workflows. Discover environment, create entities dynamically, fire events, poll statuses, assert state transitions, and report results. Triggers on "run e2e test", "test order flow", "test workflow", "e2e test", "integration test".
user-invocable: true
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
argument-hint: [scenario-name] [--order-ref <ref>] [--entity-type ORDER|FULFILMENT]
cursor-tier: auto
---

# End-to-End Test Runner

Run automated test sequences against Fluent Commerce workflows. Discover environment configuration, create entities with real refs, fire events in sequence, poll for state transitions, and report pass/fail results.

**Knowledge dependency:** For the full `createOrder` input schema, mutation patterns (HD, CC, MULTI, mixed), fulfilmentChoice wiring, and query gotchas, see `knowledge/platform/create-order-reference.md`.

## Pre-flight: Feedback Check

Before starting, check for past learnings from this skill:

1. Check if `accounts/<PROFILE>/feedback/fluent-e2e-test.jsonl` exists
2. If yes, read last 20 records
3. Filter to: FAILURE or USER_CORRECTED outcomes, confidence = CONFIRMED or PROMOTED
4. Extract top 3 relevant learnings — use as internal guidance during execution
5. Do NOT show raw feedback to the user — silently adjust approach based on past issues

## Ownership Boundary

This skill owns test scenario choreography, polling strategy, and pass/fail reporting.

Environment discovery and entity creation payloads are owned by `/fluent-test-data`.
Canonical MCP extension tool syntax/limits are owned by `/fluent-mcp-tools`.
Event model/filter semantics and causality patterns are owned by `/fluent-event-api`.

## Pre-Check: Load Source Analysis

Before testing, check if `/fluent-custom-code` analysis artifacts exist:

```
accounts/<PROFILE>/analysis/code/source-map.json
accounts/<PROFILE>/analysis/code/constraints.json
```

If found, use them to:
- `source-map.json` → `modules[].rules[].parameters` — know what attributes events need
- `source-map.json` → `modules[].rules[].entityTypes` — validate entity type coverage
- `constraints.json` → `risks[]` — focus tests on high-risk areas

If not found, rely on workflow JSON and runtime discovery only. Treat artifact-gate failures as "not found" (for example missing required files, missing hashes, or blocking `missingSources` in `constraints.json`).

## When to Use

- Verifying a workflow works end-to-end after changes
- Testing a specific path (HD delivery, CC pickup, cancellation, short pick)
- Regression testing after deploying a new module version
- Validating event processing and state transitions
- Confirming external system integration points (webhooks fire correctly)

## Pre-flight: GraphQL Validation Gate (MANDATORY)

See `knowledge/platform/graphql-preflight.md`.

Before executing ANY query or mutation constructed by the LLM — including entity creation mutations, state-check queries, and polling queries:

1. **Validate** via `graphql.validate({ query: "<query>" })` — check the `valid` field (NOT `ok`)
2. **Or build** via `graphql.buildQuery({ root: "<entity>", fields: [...] })` for schema-validated queries
3. If `valid: false`, fix before executing. One invalid field nullifies the entire response silently.

This is especially critical for mutations — a mutation with wrong input fields will fail at runtime and waste test cycles.

## Test Execution Framework

Every E2E test follows this pattern:

```
0. DISCOVER environment (via /fluent-test-data)
1. CREATE entity using discovered refs (via /fluent-test-data)
2. For each step:
   a. SEND event (via MCP event.send)
   b. WAIT for async processing (poll with timeout)
   c. VERIFY entity state (via MCP graphql.query)
   d. Record PASS or FAIL
3. REPORT results
```

### Key MCP Tools Used

| Operation | MCP Tool | Server |
|-----------|----------|--------|
| Discover environment | `graphql.query` | fluent-mcp-extn |
| Create entity | `graphql.query` (mutation) | fluent-mcp-extn |
| Discover available actions | `workflow.transitions` | fluent-mcp-extn |
| Send event | `event.send` | fluent-mcp-extn |
| Check event status | `event.list` | fluent-mcp-extn |
| Query entity state | `graphql.query` | fluent-mcp-extn |
| Introspect schema | `graphql.introspect` | fluent-mcp-extn |

## Progress

Emit this block at each phase transition to show progress:

```
▸ /fluent-e2e-test [1/6]
  ✓ Environment discovery    → Plan-driven test discovery
  ○ Create test entity       ○ Execute test steps
  ○ Assert & report          ○ Post-test analysis
```

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

## Phase 0: Environment Discovery (mandatory)

**Before creating any entity**, run the `/fluent-test-data` discovery sequence to obtain:

- Retailer ID and ref
- Active warehouse ref (for HD) and store ref (for CC)
- Product catalogue ref and at least one product ref with inventory
- Customer ID (create if none exist)
- Consignment prefix (from settings, or default `A_`)

**Never hardcode refs.** Different retailers have different catalogues, locations, and products. Always query the live environment.

## Phase 0.5: Plan-Driven Test Discovery

When a feature plan exists, use its Test Plan section (§16) as the primary source for test scenarios instead of manually constructing them.

### Detection
1. Check `accounts/<PROFILE>/features/*/status.json` for features with `plan: "APPROVED"` and `status` of `IN_PROGRESS`, `BUILT`, `DEPLOYED`, or `APPROVED`
2. If found, read the corresponding `plan.md`
3. Parse the `## Test Plan` or `## §16 Test Plan` section

### What to Extract from §16

| Plan Field | Maps to E2E |
|------------|-------------|
| Scenario name | Test suite label |
| Preconditions | Phase 0 entity setup requirements |
| Event sequence | Phase 1+ SEND steps (ordered) |
| Expected status at each step | VERIFY assertions |
| Expected webhook fires | Additional assertions (check `event.list` for webhook events) |
| Edge cases / negative paths | Separate test scenarios |

### Auto-Generation Protocol

For each scenario in §16:
1. **Parse preconditions** → determine entity type, required attributes, location/product refs
2. **Parse event sequence** → build ordered list of `event.send` calls with expected status transitions
3. **Parse assertions** → build `test.assert` calls for each status checkpoint
4. **Parse edge cases** → create separate negative test scenarios

### Example Mapping

Plan §16 entry:
```
| Scenario | Preconditions | Events | Expected |
|----------|--------------|--------|----------|
| HD Happy Path | ORDER at CREATED, warehouse W1 active | SendToFulfilment → Confirm → Complete | COMPLETE |
```

Maps to E2E steps:
```
1. CREATE ORDER with ref TEST-HD-<timestamp>
2. SEND SendToFulfilment → VERIFY status=AWAITING_FULFILMENT
3. SEND Confirm → VERIFY status=CONFIRMED
4. SEND Complete → VERIFY status=COMPLETE
```

### Fallback
If no plan exists or §16 is missing, fall back to the existing manual test construction flow (Phase 1+).

### Handoff
```
-> READY: Loaded N test scenarios from plan §16 for feature '<slug>'
```
Or:
```
-> SKIP: No plan §16 found — using manual test construction
```

### Phase 0.6: Post-Deployment User Action Verification

**When to run:** After deploying workflows with `userActions` and before running test scenarios.

**Purpose:** Verify that deployed user actions are actually visible via Transition API from the target app's perspective.

**Steps:**

1. **Transition API validation** — For each workflow status that has user actions:
   ```
   workflow.transitions({
     triggers: [{
       type: "<ENTITY_TYPE>",
       subtype: "<SUBTYPE>",
       status: "<STATUS>",
       retailerId: <ID>,
       flexType: "<WORKFLOW_NAME>",
       flexVersion: "<deployed_version>",
       module: "adminconsole"
     }]
   })
   ```
   **THREE MANDATORY parameters** — omitting ANY one silently returns empty results (no error):
   - **`module`** — REQUIRED. Use `"adminconsole"` for the OMS App (the OMS App's module alias, legacy alias). `"all"` returns NOTHING — always use a specific module name.
   - **`flexType`** — REQUIRED. Workflow identifier. For child entities (CREDIT_MEMO, FULFILMENT), BOTH the standalone child workflow name (e.g., `"CREDIT_MEMO::APPEASEMENT"`) AND the parent workflow name (e.g., `"BILLING_ACCOUNT::CUSTOMER"`) work — use the matching `flexVersion` for whichever you choose. The UI uses the entity's `workflowRef` (which for child entities = parent workflow).
   - **`flexVersion`** — REQUIRED. Always include the exact deployed version number. Without it, cached stale versions may be used, causing false "no user actions" results.

2. **Verify non-empty** — If `userActions[]` is empty:
   - Check `module` matches what the app sends (`"adminconsole"` for the OMS App)
   - Check `flexType` matches either the entity's `workflowRef` (parent workflow for child entities) or the standalone child workflow — both work with the Transition API when paired with the correct `flexVersion`
   - Check ruleset has `subtype` and `eventName`
   - Signal: `→ BLOCKED: User actions not visible after deployment`

3. **Browser verification** (when Chrome DevTools MCP available):
   - Navigate to entity detail page at expected status
   - Verify buttons matching `userActions[]` are visible
   - If absent: hard refresh, verify manifest setting exists for the module (`fc.mystique.manifest.<module>`)
   - Signal: `→ READY: User actions verified via API and browser`

## Dynamic Transition Discovery

Instead of hardcoding event sequences, use `workflow.transitions` to dynamically discover available actions at each state:

```
1. Create entity using discovered refs (via /fluent-test-data)
2. workflow.transitions → get available actions at current status
3. For each action:
   a. event.send with eventName and required attributes from response
   b. Poll entity status until transition completes
   c. workflow.transitions → get next available actions
4. Repeat until no more userActions

If `userActions` is empty, do **not** assume terminal immediately:
- It can also mean a system-managed/gated status.
- Verify entity status and recent events before concluding terminal.
- If status is non-terminal, continue via workflow/event-driven progression and trace checks.
```

**Benefits:**
- Test sequences adapt automatically when workflows change
- Discovers required attributes for each event (avoids missing-attribute errors)
- Validates that expected user actions are available after deployment

**Example — discover actions at current status:**
```
workflow.transitions({
  triggers: [{
    type: "ORDER",
    subtype: "HD",
    status: "<current_status>",
    retailerId: "<discovered.retailerId>",
    flexType: "ORDER::HD",
    flexVersion: "<deployed_version>"
  }]
})
```

**THREE MANDATORY parameters** — `module`, `flexType`, and `flexVersion` are ALL required. Omitting any one silently returns empty results (no error). `"all"` returns NOTHING — always use a specific module name (`adminconsole` for OMS App, `servicepoint` for Store App — these are `orchestrationAlias` values, not manifest setting suffixes). Always include `flexVersion` with the exact deployed version number.

The response `userActions[].eventName` maps directly to `event.send`'s `name` parameter.
The response `userActions[].attributes` tells you what to include in `event.send`'s `attributes`.

### Strict User Action Contract (Execution Guardrails)

Use this contract whenever tests rely on `workflow.transitions`:

1. Treat `workflow.transitions` as the executable action contract for the current state.
2. Send the event name exactly as returned in `userActions[].eventName` (never infer from labels).
3. Send only `userActions[].attributes` with exact `name` and expected shape; do not invent keys.
4. Keep trigger scope aligned: `type`, `subtype`, and `flexType` must match the entity and workflow branch.
5. **Ensure THREE mandatory parameters are present**: `module` (specific name, NOT `"all"`), `flexType`, and `flexVersion`. Omitting any one silently returns empty results.
6. If an expected action is missing, verify: (a) `module` matches what the target app sends (`"adminconsole"` for the OMS App), (b) `flexType` matches the entity's `workflowRef`, (c) `flexVersion` is the exact deployed version.
7. If `userActions` is still empty on a non-terminal status, verify workflow JSON has ruleset-level `userActions` with explicit `eventName` and ruleset has `subtype`.

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

## Poll-and-Assert Pattern

After sending an event, the entity status changes asynchronously. Use this pattern to wait:

### Poll entity status until expected state (or timeout)

```
1. Send event via event.send (mode: "async")
2. Wait 3 seconds (initial processing time)
3. Query entity status via graphql.query
4. If status matches expected → PASS
5. If status doesn't match → wait 5 more seconds, retry (up to 12 retries = 60s total)
6. If timeout → FAIL with "Expected <EXPECTED>, got <ACTUAL> after 60s"
```

**Composite workflow note (ORDER::MULTI and similar):**
- After `ConfirmValidation`, use a longer wait window (20-30s) before first assertion.
- Fulfilment creation and aggregate gates can complete asynchronously in several hops.

### Poll event status until processed

> For the complete event model, filter syntax, and execution semantics, see `/fluent-event-api`. This skill focuses on test choreography and assertion patterns.

```
1. After event.send, note the event details
2. event.list filtered by entityRef + name + recent time window
3. Check eventStatus: SUCCESS = processed, FAILED = error, PENDING = still processing
4. If PENDING → wait 5s and retry
5. If FAILED → report error details from event.get
```

> **Canonical reference:** See `/fluent-event-api` for complete event status values, filter syntax, and query patterns.

## Test Scenarios

### Scenario: ORDER HD (Home Delivery) — Full Lifecycle

**Pre-requisite:** Run `/fluent-test-data` discovery. Need: retailerId, warehouseRef, productRef, catalogueRef, customerId, consignmentPrefix.

**Entities created:** 1 ORDER with 1 HD fulfilment choice (all refs from discovery)

**Steps:**

| # | Action | Event | Expected Order Status | Expected Fulfilment Status |
|---|--------|-------|----------------------|---------------------------|
| 1 | Create order | *(via /fluent-test-data)* | CREATED → ON_VALIDATION | — |
| 2 | Confirm validation | `ConfirmValidation` on ORDER | ORDER_SPLIT → IN_PROGRESS | CREATED |
| 3 | Confirm allocation | `ConfirmAllocation` on FULFILMENT | IN_PROGRESS | RECEIVED |
| 4 | Create invoice | `CreateInvoice` on FULFILMENT | IN_PROGRESS | INVOICED |
| 5 | Confirm pick | `ConfirmPick` on FULFILMENT | IN_PROGRESS | PICKPACK → *(auto)* |
| 6 | Confirm shipment | `ConfirmShipment` on FULFILMENT | SHIPPED | SHIPPED |
| 7 | Confirm delivery | `ConfirmDelivery` on FULFILMENT | COMPLETED | DELIVERED |

**Step 1 — Create Order:**

Run `/fluent-test-data` to generate the `createOrder` mutation with discovered refs. The skill queries locations, products, catalogues, and customers — then builds the mutation payload dynamically. See `knowledge/platform/create-order-reference.md` for the full type tree, patterns (HD, CC, split shipment), and gotchas.

**Step 2 — ConfirmValidation (triggers full cascade):**
```
event.send({
  name: "ConfirmValidation",
  entityRef: "<order_ref>",
  entityType: "ORDER",
  retailerId: "<discovered.retailerId>"
})
```

After this event, the async cascade runs automatically:
- ProcessOrder → ORDER_SPLIT
- RouteFulfilmentChoice → ProcessHDFulfilmentChoice
- CreateFulfilmentFromSourcingLocation → creates FULFILMENT
- NotifyFCComplete → SourceOrder → IN_PROGRESS

**Wait 15 seconds**, then verify:
- Order status = `IN_PROGRESS`
- Fulfilment exists with status = `CREATED`
- Query fulfilment ref for subsequent events

If fulfilment is not found, run fallback lookup sequence before failing:
1. Query fulfilment from the order edge (`order.fulfilments`).
2. Query fulfilment by order ID (`fulfilments(orderId: [...])`) if supported.
3. Check event history for `FAILED` or `PENDING` events.
4. Query `ORCHESTRATION_AUDIT` (`category=exception`) for rule-level errors.

**Steps 3-7 — Fulfilment events:**

Each fulfilment event follows the same pattern:
```
event.send({
  name: "<EVENT_NAME>",
  entityRef: "<fulfilment_ref>",
  entityType: "FULFILMENT",
  retailerId: "<discovered.retailerId>",
  attributes: { ... }
})
```

Use `workflow.transitions` at each step to confirm what attributes are required. Common patterns:

| Event | Typical Attributes |
|-------|-------------------|
| `ConfirmAllocation` | *(check transitions response — often none)* |
| `CreateInvoice` | *(check transitions response — often none)* |
| `ConfirmPick` | `pickedAt` (ISO datetime), `pickedItems` (array of `{ ref, filledQuantity }` from discovered product refs) |
| `ConfirmShipment` | `trackingNumber` (generate: `E2E-TRACK-<TIMESTAMP>`), `carrierRef` (generate: `E2E-CARRIER`), `shippedAt` (ISO now) |
| `ConfirmDelivery` | `deliveredAt` (ISO now) |

### Scenario: ORDER CC (Click & Collect)

**Pre-requisite:** Same as HD, but also need a store location (type=STORE) from discovery.

Same as HD through step 5 (ConfirmPick), then diverges:

| # | Event | Expected Fulfilment Status |
|---|-------|---------------------------|
| 6 | *(auto after pick)* | READY_FOR_PICKUP |
| 7 | `ConfirmCollection` on FULFILMENT | COLLECTED |
| — | *(auto)* | ORDER → COMPLETED |

### Scenario: Cancel Order

| # | Action | Event | Expected Status |
|---|--------|-------|----------------|
| 1 | Create order | *(via /fluent-test-data)* | ON_VALIDATION |
| 2 | Cancel | `CancelOrder` on ORDER | CANCELLED |

### Scenario: Short Pick

| # | Action | Expected Fulfilment Status |
|---|--------|---------------------------|
| 1-4 | Normal flow through INVOICED | INVOICED |
| 5 | `ConfirmPick` with `pickedItems` where `filledQuantity < requestedQuantity` | PARTIAL |

### Scenario: Dynamic (Workflow-Driven)

For custom or unknown workflows, use fully dynamic discovery:

```
1. Run /fluent-test-data discovery
2. Create entity using discovered refs
3. Loop:
   a. workflow.transitions for current entity state
   b. If no userActions:
      - verify status category and recent events first
      - stop only when entity is confirmed terminal
   c. Pick first userAction (or specific one by label)
   d. event.send with eventName + required attributes from response
   e. Poll until entity transitions
   f. Go to (a)
4. Report all transitions walked
```

This approach works for ANY workflow without knowing the state machine in advance.

## Test Report Format

After running a scenario, output a structured report:

```
=== E2E Test Report ===
Scenario: ORDER HD Full Lifecycle
Order Ref: <generated_ref>
Retailer: <discovered.retailerRef> (ID: <discovered.retailerId>)
Start Time: <ISO timestamp>

Discovery:
  Warehouse: <discovered.warehouseRef>
  Product: <discovered.productRef> (catalogue: <discovered.catalogueRef>)
  Customer: <discovered.customerId>

Step 1: Create Order
  Action: createOrder mutation (refs from live discovery)
  Result: PASS — Order created, ID=<id>, status=CREATED
  Duration: <N>s

Step 2: ConfirmValidation → IN_PROGRESS
  Action: event.send ConfirmValidation
  Expected: Order=IN_PROGRESS, Fulfilment=CREATED
  Actual: Order=IN_PROGRESS, Fulfilment=CREATED (ref: <fulfilment_ref>)
  Result: PASS
  Duration: <N>s (async cascade)

...

=== Summary ===
Steps: N/N passed
Total Duration: <N>s
Result: ALL PASSED
```

## Post-Test Event Analysis

After a test scenario completes (pass or fail), extract detailed execution data from the event audit trail for comprehensive validation. This supplements the poll-and-assert pattern with full execution evidence.

> **Preferred: compact flowInspect first.** After test completion, call `event.flowInspect` with the order ref as `rootEntityRef` using default compact mode (~2-3k tokens). The compact summary includes status flow, anomaly findings, failed webhooks, and slowest rulesets — sufficient for most test reports. Only add targeted flags (`includeRuleDetails`, `includeCustomLogs`) if the compact summary reveals issues that need drill-down. **NEVER use `compact: false`** — it returns ~30k tokens and fills context. Use the manual patterns below only when you need extraction beyond what flowInspect provides.

### Snapshot Verification

Use entity snapshots from ORCHESTRATION_AUDIT events to verify entity state at each transition without additional GraphQL queries:

> **Event filter reference:** For complete filter syntax, see `/fluent-event-api`.

```
event.list({
  "eventType": "ORCHESTRATION_AUDIT",
  "context.rootEntityRef": "<ORDER_REF>",
  "count": 200
})
```

Filter by `category == "snapshot"` to get the full entity state at each orchestration step. Each snapshot contains the complete entity (status, items, attributes, relationships) at the moment before rules executed.

**Verification pattern:**
```
For each test step that passed:
  1. Find the snapshot event for that entity at the expected status
  2. Verify key fields:
     - Items count and quantities match expected
     - Attributes set by previous steps are present (e.g., trackingNumber after ConfirmShipment)
     - Customer/address data is correctly attached
     - Child entity refs (fulfilmentChoice, fulfilment) are populated
  3. If a step failed, compare the snapshot against expected to identify what was different
```

### Mutation Verification

Extract all mutations executed during the test to verify the workflow made the correct GraphQL calls:

Filter ORCHESTRATION_AUDIT events where `name` is null and `attributes` contains `request.queryString`. Each mutation event shows the exact GraphQL mutation and input variables.

This catches issues where:
- A rule set the wrong status (mutation input has unexpected status value)
- A rule updated the wrong entity (mutation targets a different entity ID)
- Expected attribute updates were not made (mutation input missing expected fields)

### Webhook Delivery Verification

After test completion, verify all expected webhooks were delivered:

Filter ORCHESTRATION_AUDIT events where `name == "Send Webhook"`. Check `Response code` for each:
- `200` = delivered successfully
- `404` = endpoint not found (check setting)
- `0` = connection timeout (check endpoint availability)

Include webhook delivery results in the test report as an additional validation layer.

### Enhanced Test Report (with event analysis)

After the standard test report, append an event analysis section:

```
=== Event Analysis ===

Mutations: 7 total (all successful)
Webhooks: 4 sent (3 delivered, 1 failed — webhook.fulfilment.shipped → 404)
Snapshots: 3 captured (ORDER@CREATED, FULFILMENT@CREATED, FULFILMENT@PICKPACK)
Scheduled Events: 1 (ValidationGraceExpired, 30s delay, pre-empted by ConfirmValidation)
NO_MATCH Events: 1 (ValidationGraceExpired → expected, timer pre-empted)
Custom Logs: 4 entries (3 INFO, 1 WARN)

Recommendation: Fix webhook setting "webhook.fulfilment.shipped" before go-live
```

## Session Tracking

When invoked, log the following to the session tracking protocol (consumed by `/fluent-session`):

**On entry:**
```json
{ "skill": "<this-skill-name>", "timestamp": "<ISO-8601>", "arguments": { "<key>": "<value>", "...": "..." } }
```

**On exit:**
```json
{ "skill": "<this-skill-name>", "outcome": "<completed|failed|skipped>", "changesProduced": ["<seq-numbers>"], "toolCallsProduced": ["<seq-numbers>"], "nextRecommended": "<from-handoff-section>" }
```

All MCP tool calls made during execution should include `"skill": "<this-skill-name>"` in their tracking record for attribution. The `arguments` object should capture the key parameters actually passed (profile, retailer, entity type, etc.) — not a fixed schema. The `nextRecommended` value comes from the Handoff section below.

### Update status.json gates

If a feature context exists (`accounts/<PROFILE>/features/<slug>/status.json`):
- On **all tests pass**: set `test: "PASSED"`, set `status: "VERIFIED"`, and update `updated` timestamp
- On **any test failure**: set `test: "FAILED"` (do NOT change `status` — leave as-is for investigation)

## Tips

- **Always run /fluent-test-data discovery first** — Never assume refs exist
- **Use unique refs per test run** — Include timestamp or counter to avoid collisions
- **Wait 15s after ConfirmValidation** — The async cascade creates FC → fulfilment → gates, all in sequence
- **For composite workflows, poll up to 60s** — CREATE/validation cascades can take longer than single-entity flows
- **Wait 5-10s between fulfilment events** — Async processing needs time
- **Always query fulfilment ref** after step 2 — The ref is generated by the workflow (pattern varies by implementation)
- **Check event.list if a step fails** — Filter by entityRef + eventStatus=FAILED to see error details
- **Query ORCHESTRATION_AUDIT events on failure** — When a step fails, query audit events for the failing entity to see exactly what happened: `event.list({ eventType: "ORCHESTRATION_AUDIT", "context.entityRef": "<REF>", from: "<recent>", count: 50 })`. Look for `category=exception` events for stack traces, `category=ACTION` for what rules executed, and `category=ruleSet` for timing.
- **If `workflow.transitions` returns empty `userActions` on non-terminal statuses** — verify THREE mandatory params first (`module` specific name not `"all"`, `flexType`, `flexVersion`), then check subtype/eventName/modules alignment. Continue workflow/event-driven progression and trace checks; do not stop early
- **On FAIL, hand off to /fluent-trace** — Pass entityRef, entityType, eventId (if known), expected status, and actual status; avoid duplicating trace decision-tree logic in this skill
- **If tests fail post-deployment, consider `/fluent-rollback`** — Revert to the previous known-good state while investigating root cause. This is especially useful when a deployment introduced a regression and you need to restore service quickly
- **Use event.send with mode: "async"** — Synchronous mode is not recommended for workflow events
- **Use `workflow.transitions`** to discover required attributes at each step instead of guessing
- **For browser-level UI verification, use `/fluent-ui-test`** — This skill tests API-level entity transitions; `/fluent-ui-test` tests the rendered Mystique UI in a real browser via Chrome DevTools MCP

## Post-Execution: Feedback Capture

After completing this skill (whether success or failure), write a feedback record:

1. **Classify outcome:** `SUCCESS` (completed cleanly), `PARTIAL_SUCCESS` (completed after fixing issues), `FAILURE` (could not complete), `BLOCKED` (prereq missing), `USER_CORRECTED` (user overrode approach)
2. **Build record:** Create a `feedback-record-v1` JSON object with:
   - `skill`: `"fluent-e2e-test"`
   - `feature`: feature slug if applicable, null otherwise
   - `phases`: trace of each phase with PASS/FAIL/SKIP
   - `learnings`: any gotchas discovered during execution
   - `userCorrections`: any corrections the user provided
3. **Redact secrets:** Strip tokens, passwords, API keys. Keep business identifiers.
4. **Append** one JSON line to `accounts/<PROFILE>/feedback/fluent-e2e-test.jsonl`
5. **Update** `accounts/<PROFILE>/feedback/index.json` counters (create with `mkdir -p` if missing)

**Skip capture if:** The execution was trivially simple (e.g., user asked a question, no actual write operation happened).

## Known Pitfalls
<!-- feedback-promoted: managed section, updated by feedback loop -->

_(No promoted learnings yet.)_

<!-- end feedback-promoted -->
