Analyze a Classic Workflow
Compare a Classic Workflow against a set of requirements and produce a
prioritized change list mapped to specific XAML edit points. This is the
skill behind requests like "I'm updating my Change Request process — here
are the new requirements; tell me what to change."
When to use
- "I'm updating my {process name}. Here are my new requirements: …. The
current workflow is at …. What needs to change?"
- "Does this workflow meet these requirements?"
- "What's missing in this workflow given …?"
- "Find issues / gaps in this workflow"
- "Audit this workflow for performance / security / maintainability"
(no specific requirements — use the patterns table from the trigger-types
reference as the implicit checklist)
Inputs
- Required: Path to a Classic Workflow XAML file (and optionally its
.xaml.data.xml sibling).
- Required (one of):
- A list of explicit requirements from the user (free text or a doc), OR
- An implicit "audit for best practices" instruction (no requirements
given).
Outputs
A prioritized, actionable change list with:
- Recap of the current workflow (≤ 10-line summary).
- Requirements coverage table — each requirement vs current state.
- Recommended changes in priority order, each with:
- What to change (in plain English)
- Where in the XAML (step name + element type)
- Effort estimate: trivial / small / medium / large
- Risk level: low / medium / high
- Whether it requires deactivation, activation, or solution re-import
- Open questions for the user where the requirements were ambiguous.
Procedure
Step 1 — Read the current workflow
Invoke the read-workflow procedure first.
You need the structured summary to reason about what changes apply where.
Do this even if the user is impatient — without the parse, recommendations
are guessing.
Step 2 — Normalize the requirements
If the user pasted free-form requirements, restate them as a numbered list
of testable assertions. For each requirement, extract:
- Trigger condition ("when …")
- Action ("the workflow should …")
- Constraint ("but only if …")
- Output ("and notify …")
If the user just said "audit this", skip this step and use the patterns
table from
reference/trigger-types.md §"Patterns to flag in summaries / reviews"
as the implicit requirement set.
Step 3 — Build the coverage table
For each requirement, check the parsed workflow:
| Requirement state |
What it means |
Recommended action |
| ✅ Already satisfied |
An existing step covers it correctly |
None |
| ⚠️ Partially satisfied |
A step exists but conditions / fields differ |
Modify existing step |
| ❌ Missing |
No step covers this requirement |
Add new step(s) |
| ⛔ Conflicting |
An existing step contradicts the requirement |
Remove or restructure |
| ❓ Ambiguous |
The requirement isn't specific enough to map |
Ask the user |
Step 3a — Run the universal client-side validation rules
In addition to the user's requirements, every Classic Workflow can be checked
for a fixed set of structural problems that don't need a live org connection.
Report any failures as ⛔ Conflicting or ⚠️ Partially satisfied rows so
they land in the change plan.
| # |
Rule |
Severity if violated |
| 1 |
Workflow has a non-empty display name |
error |
| 2 |
PrimaryEntity is set and is not none |
error |
| 3 |
If Mode = Real-Time, no mxswa:ActivityReference whose AQN starts with …ConditionSequence has Wait="[True]" (Wait Conditions are background-only) |
error |
| 4 |
If triggertypemask includes Update, triggeronupdateattributelist is non-empty (otherwise the workflow fires on every update) |
warning |
| 5 |
Every mxswa:SendEmail has at least one recipient (To, Cc, or Bcc resolves to a non-empty value) |
error |
| 6 |
Every Check Condition has at least one branch with at least one child step |
warning |
| 7 |
Every mxswa:CreateEntity for an ownable entity sets either an OwnerId field or relies on the workflow RunAs (otherwise records will be owned by the SYSTEM user, which often surprises users) |
warning |
| 8 |
Every mxswa:StartChildWorkflow references a workflow ID that is not the current workflow's ID (no self-recursion) |
error |
| 9 |
Every mxswa:ActivityReference element has a non-empty AssemblyQualifiedName (a missing AQN is corrupt XAML) |
error |
| 10 |
Every direct mxswa:* activity has a non-empty DisplayName (missing names will display as (no name) and confuse comparison/diff tooling) |
warning |
| 11 |
Every EvaluateCondition operator that is not Null or NotNull has a corresponding Parameters EvaluateExpression for its right operand |
error |
| 12 |
If Scope = Organization, the RunAs is Owner (not CallingUser) — otherwise the workflow may not have permission to read records outside the calling user's BU |
warning |
| 13 |
If the workflow is triggered by Update on a column AND issues an mxswa:UpdateEntity that writes the same column on the same record, there is a guard (Check Condition comparing old vs new value, or a "WorkflowProcessed" flag) — otherwise the engine's 16-runs-per-row infinite-loop kill switch will fire (web-research §4) |
error |
| 14 |
If Mode = Real-Time, no Parallel Wait Branch activity is present (real-time forbids parallel-wait, same as Wait Conditions) |
error |
| 15 |
If a Check Condition uses operator Under or NotUnder, the deployment notes flag a Hierarchical relationship dependency on the condition's entity — activation will fail in target orgs without a relationship marked Hierarchical (web-research §8) |
warning |
| 16 |
If multiple workflows in the solution all trigger on the same PrimaryEntity and Update of the same columns, flag a lock contention risk ("multiple workflows updating the same table") and recommend consolidating logic (web-research §5 row 2) |
warning |
| 17 |
If Mode = Background and Workflow Job Retention is not set to "Automatically delete completed workflow jobs", flag the storage-growth recommendation (web-research §5 row 6) |
info |
| 18 |
If logic is duplicated across multiple workflows (same sequence of activities with the same parameters), recommend extracting to a child workflow (web-research §5 row 4) |
info |
Anything server-side (entity actually exists, schema names valid, option
set values valid, child workflow ID exists, recipient queue ID exists) is
out of scope here — those checks need a live Dataverse connection. Note them
in the open-questions section if they look risky.
Step 4 — Plan the edits
For each non-✅ row, draft the edit:
- Type of change: add step, modify step, remove step, change trigger,
change scope/mode/runas, restructure conditions.
- Where: by step display name and ordinal position.
- What activities are involved: list the
mxswa:* or
ActivityReference elements that need to be added/modified/removed.
- Effort estimate:
- Trivial — change a literal value or one expression.
- Small — add/remove/reorder a single SDK activity step.
- Medium — add or restructure a Check Condition with branches; change
the trigger configuration.
- Large — change
Mode (Background ↔ Real-Time) or PrimaryEntity;
split into multiple workflows; introduce custom activities.
- Risk level:
- Low — change is local and reversible (e.g. update a subject line).
- Medium — change affects branching or expressions used elsewhere.
- High — change touches activation/security (
RunAs, Scope,
Mode, Trigger) or removes existing logic.
Step 5 — Group edits by deployment unit
Note which changes can ride together vs which need separate deployments:
- All changes to a single workflow ride together — one deactivate / edit /
activate cycle.
- Changes that introduce new custom activities require a plugin assembly
deploy first.
- Changes to the workflow's Mode (Background ↔ Real-Time) are best done
as a Copy-then-replace rather than an in-place edit, because activated
workflow runs can't be paused mid-execution and waited for.
Step 6 — Surface open questions
If the requirements left genuine ambiguity, list the questions explicitly
at the end. Don't fill in defaults silently. Examples:
- "Requirement 3 says 'notify the manager' — should that be the assignee's
manager, the record owner's manager, or a fixed user?"
- "Requirement 5 says 'after a delay' — how long? (Real-Time mode can't
wait; this would force Background mode.)"
- "Requirement 7 needs a custom calculation — should I assume an existing
custom workflow activity, or write the math inline as a VB expression?"
Output template
# Change Plan — {Workflow Display Name}
## Current state (summary)
{≤10-line recap from read-workflow}
## Requirements coverage
| # | Requirement | State | Action |
|---|-------------|-------|--------|
| 1 | {restated requirement} | ✅ Already satisfied | None |
| 2 | {restated requirement} | ❌ Missing | Add SendEmail step after Check Condition's True branch |
| 3 | {restated requirement} | ⚠️ Partially satisfied — uses wrong field | Update SetEntityProperty target |
| 4 | {restated requirement} | ❓ Ambiguous | See open questions |
## Recommended changes (priority order)
### 1. {Change title} — Effort: {S/M/L} • Risk: {L/M/H}
**What:** {plain-English description}
**Where:** Step "{step display name}" (a `mxswa:UpdateEntity` at position 4 of the root Sequence)
**Why:** {requirement number it satisfies / problem it fixes}
**XAML hint:** {one-sentence pointer like "Add an `mxswa:SendEmail` after the existing `UpdateEntity`"}
### 2. {…}
…
## Deployment notes
- All changes can deploy in **{N}** activate/deactivate cycle(s).
- {any plugin / custom activity dependencies}
- {any breaking changes that justify Copy-then-replace}
## Open questions
1. {question}
2. {question}
(Once you answer these, I can produce the actual edits with the
[write-workflow](../dataverse-classic-write/SKILL.md) skill.)
Don't
- Don't make the edits in this skill — that's the
write-workflow skill's
job. Stop at recommendations.
- Don't assume requirements. If something's ambiguous, list it as an open
question rather than picking a default.
- Don't propose changes that the format doesn't support (e.g. "add a Wait
Condition to a Real-Time workflow"). Flag the conflict instead.
- Don't conflate "best practices" with "user requirements". If the user
gave specific requirements, those win. Best-practice findings go in a
separate section labeled
## Additional findings (not in your requirements).
1---2name: dataverse-classic-analyze3description: Gap-analyze an existing Dataverse Classic Workflow against new requirements and flag risky patterns. Use when user says "I have new requirements, what needs to change", "does this workflow meet this spec", "gap analysis", "review this workflow", "what is wrong with this workflow", "why does this loop", "is this workflow going to run away", "audit this workflow", or supplies a requirements document alongside a `.xaml`. Produces a requirement-by-requirement verdict plus a change plan, and checks the documented failure modes: infinite-loop protection (the 16-in-a-short-window rule), hierarchical Under / Not Under operator behavior, scope and run-as mismatches, and MS Learn best-practice violations. Do NOT use for plain summarization (use dataverse-classic-read) or for applying the changes (use dataverse-classic-write).4license: MIT-05---67# Analyze a Classic Workflow89**Compare a Classic Workflow against a set of requirements and produce a10prioritized change list mapped to specific XAML edit points.** This is the11skill behind requests like "I'm updating my Change Request process — here12are the new requirements; tell me what to change."1314---1516## When to use1718- "I'm updating my {process name}. Here are my new requirements: …. The19 current workflow is at …. What needs to change?"20- "Does this workflow meet these requirements?"21- "What's missing in this workflow given …?"22- "Find issues / gaps in this workflow"23- "Audit this workflow for performance / security / maintainability"24 (no specific requirements — use the patterns table from the trigger-types25 reference as the implicit checklist)2627## Inputs2829- **Required:** Path to a Classic Workflow XAML file (and optionally its30 `.xaml.data.xml` sibling).31- **Required (one of):**32 - A list of explicit requirements from the user (free text or a doc), OR33 - An implicit "audit for best practices" instruction (no requirements34 given).3536## Outputs3738A prioritized, actionable change list with:391. **Recap** of the current workflow (≤ 10-line summary).402. **Requirements coverage table** — each requirement vs current state.413. **Recommended changes** in priority order, each with:42 - What to change (in plain English)43 - Where in the XAML (step name + element type)44 - Effort estimate: trivial / small / medium / large45 - Risk level: low / medium / high46 - Whether it requires deactivation, activation, or solution re-import474. **Open questions** for the user where the requirements were ambiguous.4849---5051## Procedure5253### Step 1 — Read the current workflow5455Invoke the [read-workflow](../dataverse-classic-read/SKILL.md) procedure first.56You need the structured summary to reason about what changes apply where.57Do this even if the user is impatient — without the parse, recommendations58are guessing.5960### Step 2 — Normalize the requirements6162If the user pasted free-form requirements, restate them as a numbered list63of testable assertions. For each requirement, extract:64- **Trigger condition** ("when …")65- **Action** ("the workflow should …")66- **Constraint** ("but only if …")67- **Output** ("and notify …")6869If the user just said "audit this", skip this step and use the patterns70table from71[reference/trigger-types.md §"Patterns to flag in summaries / reviews"](../dataverse-classic-workflow/reference/trigger-types.md#patterns-to-flag-in-summaries--reviews)72as the implicit requirement set.7374### Step 3 — Build the coverage table7576For each requirement, check the parsed workflow:7778| Requirement state | What it means | Recommended action |79|-------------------|---------------|-------------------|80| ✅ Already satisfied | An existing step covers it correctly | None |81| ⚠️ Partially satisfied | A step exists but conditions / fields differ | Modify existing step |82| ❌ Missing | No step covers this requirement | Add new step(s) |83| ⛔ Conflicting | An existing step contradicts the requirement | Remove or restructure |84| ❓ Ambiguous | The requirement isn't specific enough to map | Ask the user |8586### Step 3a — Run the universal client-side validation rules8788In addition to the user's requirements, every Classic Workflow can be checked89for a fixed set of structural problems that don't need a live org connection.90Report any failures as `⛔ Conflicting` or `⚠️ Partially satisfied` rows so91they land in the change plan.9293| # | Rule | Severity if violated |94|---|---|---|95| 1 | Workflow has a non-empty display name | error |96| 2 | `PrimaryEntity` is set and is not `none` | error |97| 3 | If `Mode = Real-Time`, no `mxswa:ActivityReference` whose AQN starts with `…ConditionSequence` has `Wait="[True]"` (Wait Conditions are background-only) | error |98| 4 | If `triggertypemask` includes Update, `triggeronupdateattributelist` is non-empty (otherwise the workflow fires on every update) | warning |99| 5 | Every `mxswa:SendEmail` has at least one recipient (`To`, `Cc`, or `Bcc` resolves to a non-empty value) | error |100| 6 | Every Check Condition has at least one branch with at least one child step | warning |101| 7 | Every `mxswa:CreateEntity` for an ownable entity sets either an `OwnerId` field or relies on the workflow `RunAs` (otherwise records will be owned by the SYSTEM user, which often surprises users) | warning |102| 8 | Every `mxswa:StartChildWorkflow` references a workflow ID that is not the current workflow's ID (no self-recursion) | error |103| 9 | Every `mxswa:ActivityReference` element has a non-empty `AssemblyQualifiedName` (a missing AQN is corrupt XAML) | error |104| 10 | Every direct `mxswa:*` activity has a non-empty `DisplayName` (missing names will display as `(no name)` and confuse comparison/diff tooling) | warning |105| 11 | Every `EvaluateCondition` operator that is not `Null` or `NotNull` has a corresponding `Parameters` `EvaluateExpression` for its right operand | error |106| 12 | If `Scope = Organization`, the `RunAs` is `Owner` (not `CallingUser`) — otherwise the workflow may not have permission to read records outside the calling user's BU | warning |107| 13 | If the workflow is triggered by Update on a column AND issues an `mxswa:UpdateEntity` that writes the same column on the same record, there is a guard (Check Condition comparing old vs new value, or a "WorkflowProcessed" flag) — otherwise the engine's 16-runs-per-row infinite-loop kill switch will fire ([web-research §4](../dataverse-classic-workflow/reference/web-research.md#4-infinite-loop-protection-the-16-in-a-short-window-rule)) | error |108| 14 | If `Mode = Real-Time`, no `Parallel Wait Branch` activity is present (real-time forbids parallel-wait, same as Wait Conditions) | error |109| 15 | If a Check Condition uses operator `Under` or `NotUnder`, the deployment notes flag a **Hierarchical relationship dependency** on the condition's entity — activation will fail in target orgs without a relationship marked Hierarchical ([web-research §8](../dataverse-classic-workflow/reference/web-research.md#8-hierarchical-operators-under--not-under)) | warning |110| 16 | If multiple workflows in the solution all trigger on the same `PrimaryEntity` and Update of the same columns, flag a **lock contention risk** ("multiple workflows updating the same table") and recommend consolidating logic ([web-research §5 row 2](../dataverse-classic-workflow/reference/web-research.md#5-authoritative-best-practice-list-from-ms-learn)) | warning |111| 17 | If `Mode = Background` and `Workflow Job Retention` is not set to "Automatically delete completed workflow jobs", flag the storage-growth recommendation ([web-research §5 row 6](../dataverse-classic-workflow/reference/web-research.md#5-authoritative-best-practice-list-from-ms-learn)) | info |112| 18 | If logic is duplicated across multiple workflows (same sequence of activities with the same parameters), recommend extracting to a child workflow ([web-research §5 row 4](../dataverse-classic-workflow/reference/web-research.md#5-authoritative-best-practice-list-from-ms-learn)) | info |113114Anything **server-side** (entity actually exists, schema names valid, option115set values valid, child workflow ID exists, recipient queue ID exists) is116out of scope here — those checks need a live Dataverse connection. Note them117in the open-questions section if they look risky.118119### Step 4 — Plan the edits120121For each non-✅ row, draft the edit:122- **Type of change:** add step, modify step, remove step, change trigger,123 change scope/mode/runas, restructure conditions.124- **Where:** by step display name and ordinal position.125- **What activities are involved:** list the `mxswa:*` or126 `ActivityReference` elements that need to be added/modified/removed.127- **Effort estimate:**128 - *Trivial* — change a literal value or one expression.129 - *Small* — add/remove/reorder a single SDK activity step.130 - *Medium* — add or restructure a Check Condition with branches; change131 the trigger configuration.132 - *Large* — change `Mode` (Background ↔ Real-Time) or `PrimaryEntity`;133 split into multiple workflows; introduce custom activities.134- **Risk level:**135 - *Low* — change is local and reversible (e.g. update a subject line).136 - *Medium* — change affects branching or expressions used elsewhere.137 - *High* — change touches activation/security (`RunAs`, `Scope`,138 `Mode`, `Trigger`) or removes existing logic.139140### Step 5 — Group edits by deployment unit141142Note which changes can ride together vs which need separate deployments:143- All changes to a single workflow ride together — one deactivate / edit /144 activate cycle.145- Changes that introduce new custom activities require a plugin assembly146 deploy first.147- Changes to the workflow's Mode (Background ↔ Real-Time) are best done148 as a Copy-then-replace rather than an in-place edit, because activated149 workflow runs can't be paused mid-execution and waited for.150151### Step 6 — Surface open questions152153If the requirements left genuine ambiguity, list the questions explicitly154at the end. Don't fill in defaults silently. Examples:155156- "Requirement 3 says 'notify the manager' — should that be the assignee's157 manager, the record owner's manager, or a fixed user?"158- "Requirement 5 says 'after a delay' — how long? (Real-Time mode can't159 wait; this would force Background mode.)"160- "Requirement 7 needs a custom calculation — should I assume an existing161 custom workflow activity, or write the math inline as a VB expression?"162163---164165## Output template166167````168# Change Plan — {Workflow Display Name}169170## Current state (summary)171172{≤10-line recap from read-workflow}173174## Requirements coverage175176| # | Requirement | State | Action |177|---|-------------|-------|--------|178| 1 | {restated requirement} | ✅ Already satisfied | None |179| 2 | {restated requirement} | ❌ Missing | Add SendEmail step after Check Condition's True branch |180| 3 | {restated requirement} | ⚠️ Partially satisfied — uses wrong field | Update SetEntityProperty target |181| 4 | {restated requirement} | ❓ Ambiguous | See open questions |182183## Recommended changes (priority order)184185### 1. {Change title} — Effort: {S/M/L} • Risk: {L/M/H}186**What:** {plain-English description}187**Where:** Step "{step display name}" (a `mxswa:UpdateEntity` at position 4 of the root Sequence)188**Why:** {requirement number it satisfies / problem it fixes}189**XAML hint:** {one-sentence pointer like "Add an `mxswa:SendEmail` after the existing `UpdateEntity`"}190191### 2. {…}192…193194## Deployment notes195196- All changes can deploy in **{N}** activate/deactivate cycle(s).197- {any plugin / custom activity dependencies}198- {any breaking changes that justify Copy-then-replace}199200## Open questions2012021. {question}2032. {question}204205(Once you answer these, I can produce the actual edits with the206[write-workflow](../dataverse-classic-write/SKILL.md) skill.)207````208209---210211## Don't212213- Don't make the edits in this skill — that's the `write-workflow` skill's214 job. Stop at recommendations.215- Don't assume requirements. If something's ambiguous, list it as an open216 question rather than picking a default.217- Don't propose changes that the format doesn't support (e.g. "add a Wait218 Condition to a Real-Time workflow"). Flag the conflict instead.219- Don't conflate "best practices" with "user requirements". If the user220 gave specific requirements, those win. Best-practice findings go in a221 separate section labeled `## Additional findings (not in your requirements)`.