Compare Two Classic Workflows
Diff two Classic Workflow XAML files and explain what changed in
human-readable form. Useful when comparing an old workflow to a new
template-based copy, or comparing two branches of the same workflow.
When to use
- "What changed between version A and B of this workflow?"
- "Compare
old/MyProcess.xaml to new/MyProcess.xaml"
- "I made a copy via the workflow-template route — how does my copy differ
from the original?"
- "What's different about the workflow in branch
feature/x vs main?"
Inputs
- Required: Two paths to Classic Workflow XAML files.
- Optional: The two
.xaml.data.xml siblings (for metadata-level diff).
- Optional: A label for each side (e.g. "old" vs "new", "production"
vs "draft", "before refactor" vs "after refactor"). Default labels
are "A" and "B".
Outputs
A diff report with:
- Metadata diff — name, primary entity, trigger, scope, mode, run-as.
- Structural diff — added / removed / reordered steps.
- Step-level diff — for each step that exists in both, what changed
inside it (field assignments, conditions, expressions).
- Cosmetic diff — display name changes, comment updates, UserData
changes (collapsed; user can expand if curious).
- Risk-flagged callouts — changes the user should pay extra attention
to (Mode change, Scope change, Trigger change, RunAs change, condition
logic change).
Procedure
Step 1 — Parse both sides
Run the read-workflow procedure on each file.
This gives you two structured representations to diff.
Step 2 — Match steps across the two sides
Steps don't have stable IDs across copies. Match them with this priority:
- By DisplayName — exact match wins.
- By position — if two unmatched steps occupy the same ordinal
position, treat them as the same step.
- By type + key fields — an
UpdateEntity step on the same entity
with overlapping field assignments is probably "the same step renamed".
When matching is ambiguous, surface it as a finding ("Step at position 4
in A could be either step 4 or step 5 in B; treating as renamed.").
Step 3 — Diff metadata
Compare the metadata sibling fields:
| Field |
A |
B |
Change |
| Name |
… |
… |
(none / renamed) |
| PrimaryEntity |
… |
… |
… |
| Mode |
… |
… |
⛔ Critical: changes execution semantics |
| Scope |
… |
… |
⚠️ Affects who can trigger |
| RunAs |
… |
… |
⚠️ Affects security |
| Trigger |
… |
… |
⚠️ Changes when it fires |
| Filtering attributes |
… |
… |
… |
Step 4 — Diff the step list
Produce three lists:
- Added in B — steps present in B but not A.
- Removed from A — steps present in A but not B.
- Reordered — steps present in both but in a different position.
For each entry, give the step type and friendly name.
Step 5 — Diff matched steps
For each pair of matched steps, dive into the activity:
- UpdateEntity / CreateEntity: which fields are now assigned vs were
assigned before? Which expressions changed?
- SendEmail: subject, body, recipients (from / to / cc).
- Check Condition: which branches' conditions changed? Did a branch
get added or removed? Did the contents of a branch's body change?
- Custom activity: which input parameters changed?
- Stop Workflow: status (Succeeded / Canceled) and message.
For expressions, render in friendly form (per
reference/vb-expressions.md) — show
the before and after side by side.
Step 6 — Filter cosmetic differences
The following are usually noise and should be collapsed unless the user
asks for them explicitly:
UserData blob changes (designer state).
- Whitespace and indentation changes.
mva:VisualBasicValue metadata blob changes (if the actual VB
expression text is unchanged).
- Reordering of attributes within a single element.
Surface a one-line summary: "Plus N cosmetic / metadata changes (collapsed)."
Step 7 — Flag high-risk diffs
Add a "Critical / Risk callouts" section for any of:
- Mode change (Background ↔ Real-Time).
- Scope change.
- RunAs change.
- Trigger bitmask change (different trigger types).
- Removed Stop Workflow steps.
- Added or removed Check Condition branches (changes the logic flow).
- Added child workflow calls (
StartChildWorkflow).
- Removed filtering attributes on an OnUpdate trigger.
Output template
# Workflow Diff — {Label A} ↔ {Label B}
## Metadata
| Field | {Label A} | {Label B} |
|-------|-----------|-----------|
| Name | … | … |
| Primary entity | … | … |
| Mode | Background | Real-Time ⛔ |
| Scope | Organization | Organization |
| Run as | Owner | Owner |
| Trigger | OnCreate, OnUpdate | OnCreate |
| Filtering attributes | name, statuscode | (removed) ⚠️ |
## Step changes
### Added in {Label B}
- Step 4: **Send approval email** (`mxswa:SendEmail`)
- Step 6: **Check Condition: Region is EU** (`ConditionSequence`)
### Removed from {Label A}
- Step 3 was: **Set legacy flag** (`mxswa:UpdateEntity`)
### Reordered
- "Update status" moved from position 5 → position 7.
## Step-level changes
### Step 2 — "Update account" (`mxswa:UpdateEntity`)
- Field `description`:
- {Label A}: `"Reviewed by " & {User: Full Name}`
- {Label B}: `"Reviewed on " & {Now} & " by " & {User: Full Name}`
- Field `prioritycode` removed from assignments.
### Step 5 — "Check Condition: Status changed"
- Branch "Yes":
- **Added:** SendEmail step.
- **Modified:** Update step now also sets `lastreviewdate`.
- Branch "Else": unchanged.
## Critical / Risk callouts
- ⛔ **Mode changed Background → Real-Time.** All `Persist` and Wait
activities must be removed (they were not detected in this workflow,
so this is safe — but verify external calls don't block the user save).
- ⚠️ **Filtering attributes removed.** The OnUpdate trigger will now
fire on every update to the entity — significant performance impact.
## Cosmetic / metadata
Plus 14 cosmetic changes (designer state, whitespace, expression metadata).
Run with `--include-cosmetic` to see them.
Don't
- Don't show raw XAML diffs unless the user asks for them. The point of
this skill is human-readable explanation.
- Don't claim a step is "the same" when matching is uncertain — surface
the ambiguity.
- Don't echo the user's real entity logical names or workflow names into
generated example output. Diff results that reference the user's actual
workflow are fine (you're diffing their files); examples in
documentation must use placeholders.
1---2name: dataverse-classic-compare3description: Structurally diff two Dataverse Classic Workflow XAML files and report what actually changed. Use when user says "what changed between these two workflows", "diff these workflows", "compare version A and B", "compare DEV and PROD copies of this workflow", "why does this behave differently in the other environment", "did anything change other than formatting", or supplies two `.xaml` files. Compares triggers, scope, steps, and conditions at the activity level rather than by text diff, so reordered attributes, regenerated GUIDs, and `UserData` designer blobs do not drown the real differences. Do NOT use for summarizing a single workflow (use dataverse-classic-read), applying changes (use dataverse-classic-write), or cloning one workflow into another (use dataverse-classic-copy).4license: MIT-05---67# Compare Two Classic Workflows89**Diff two Classic Workflow XAML files and explain what changed in10human-readable form.** Useful when comparing an old workflow to a new11template-based copy, or comparing two branches of the same workflow.1213---1415## When to use1617- "What changed between version A and B of this workflow?"18- "Compare `old/MyProcess.xaml` to `new/MyProcess.xaml`"19- "I made a copy via the workflow-template route — how does my copy differ20 from the original?"21- "What's different about the workflow in branch `feature/x` vs `main`?"2223## Inputs2425- **Required:** Two paths to Classic Workflow XAML files.26- **Optional:** The two `.xaml.data.xml` siblings (for metadata-level diff).27- **Optional:** A label for each side (e.g. "old" vs "new", "production"28 vs "draft", "before refactor" vs "after refactor"). Default labels29 are "A" and "B".3031## Outputs3233A diff report with:341. **Metadata diff** — name, primary entity, trigger, scope, mode, run-as.352. **Structural diff** — added / removed / reordered steps.363. **Step-level diff** — for each step that exists in both, what changed37 inside it (field assignments, conditions, expressions).384. **Cosmetic diff** — display name changes, comment updates, UserData39 changes (collapsed; user can expand if curious).405. **Risk-flagged callouts** — changes the user should pay extra attention41 to (Mode change, Scope change, Trigger change, RunAs change, condition42 logic change).4344---4546## Procedure4748### Step 1 — Parse both sides4950Run the [read-workflow](../dataverse-classic-read/SKILL.md) procedure on each file.51This gives you two structured representations to diff.5253### Step 2 — Match steps across the two sides5455Steps don't have stable IDs across copies. Match them with this priority:56571. **By DisplayName** — exact match wins.582. **By position** — if two unmatched steps occupy the same ordinal59 position, treat them as the same step.603. **By type + key fields** — an `UpdateEntity` step on the same entity61 with overlapping field assignments is probably "the same step renamed".6263When matching is ambiguous, surface it as a finding ("Step at position 464in A could be either step 4 or step 5 in B; treating as renamed.").6566### Step 3 — Diff metadata6768Compare the metadata sibling fields:6970| Field | A | B | Change |71|-------|---|---|--------|72| Name | … | … | (none / renamed) |73| PrimaryEntity | … | … | … |74| Mode | … | … | ⛔ Critical: changes execution semantics |75| Scope | … | … | ⚠️ Affects who can trigger |76| RunAs | … | … | ⚠️ Affects security |77| Trigger | … | … | ⚠️ Changes when it fires |78| Filtering attributes | … | … | … |7980### Step 4 — Diff the step list8182Produce three lists:8384- **Added in B** — steps present in B but not A.85- **Removed from A** — steps present in A but not B.86- **Reordered** — steps present in both but in a different position.8788For each entry, give the step type and friendly name.8990### Step 5 — Diff matched steps9192For each pair of matched steps, dive into the activity:93- **UpdateEntity / CreateEntity:** which fields are now assigned vs were94 assigned before? Which expressions changed?95- **SendEmail:** subject, body, recipients (from / to / cc).96- **Check Condition:** which branches' conditions changed? Did a branch97 get added or removed? Did the contents of a branch's body change?98- **Custom activity:** which input parameters changed?99- **Stop Workflow:** status (Succeeded / Canceled) and message.100101For expressions, render in friendly form (per102[reference/vb-expressions.md](../dataverse-classic-workflow/reference/vb-expressions.md)) — show103the before and after side by side.104105### Step 6 — Filter cosmetic differences106107The following are usually noise and should be collapsed unless the user108asks for them explicitly:109- `UserData` blob changes (designer state).110- Whitespace and indentation changes.111- `mva:VisualBasicValue` metadata blob changes (if the actual VB112 expression text is unchanged).113- Reordering of attributes within a single element.114115Surface a one-line summary: "Plus N cosmetic / metadata changes (collapsed)."116117### Step 7 — Flag high-risk diffs118119Add a "Critical / Risk callouts" section for any of:120- Mode change (Background ↔ Real-Time).121- Scope change.122- RunAs change.123- Trigger bitmask change (different trigger types).124- Removed Stop Workflow steps.125- Added or removed Check Condition branches (changes the logic flow).126- Added child workflow calls (`StartChildWorkflow`).127- Removed filtering attributes on an OnUpdate trigger.128129---130131## Output template132133````134# Workflow Diff — {Label A} ↔ {Label B}135136## Metadata137138| Field | {Label A} | {Label B} |139|-------|-----------|-----------|140| Name | … | … |141| Primary entity | … | … |142| Mode | Background | Real-Time ⛔ |143| Scope | Organization | Organization |144| Run as | Owner | Owner |145| Trigger | OnCreate, OnUpdate | OnCreate |146| Filtering attributes | name, statuscode | (removed) ⚠️ |147148## Step changes149150### Added in {Label B}151- Step 4: **Send approval email** (`mxswa:SendEmail`)152- Step 6: **Check Condition: Region is EU** (`ConditionSequence`)153154### Removed from {Label A}155- Step 3 was: **Set legacy flag** (`mxswa:UpdateEntity`)156157### Reordered158- "Update status" moved from position 5 → position 7.159160## Step-level changes161162### Step 2 — "Update account" (`mxswa:UpdateEntity`)163- Field `description`:164 - {Label A}: `"Reviewed by " & {User: Full Name}`165 - {Label B}: `"Reviewed on " & {Now} & " by " & {User: Full Name}`166- Field `prioritycode` removed from assignments.167168### Step 5 — "Check Condition: Status changed"169- Branch "Yes":170 - **Added:** SendEmail step.171 - **Modified:** Update step now also sets `lastreviewdate`.172- Branch "Else": unchanged.173174## Critical / Risk callouts175176- ⛔ **Mode changed Background → Real-Time.** All `Persist` and Wait177 activities must be removed (they were not detected in this workflow,178 so this is safe — but verify external calls don't block the user save).179- ⚠️ **Filtering attributes removed.** The OnUpdate trigger will now180 fire on every update to the entity — significant performance impact.181182## Cosmetic / metadata183184Plus 14 cosmetic changes (designer state, whitespace, expression metadata).185Run with `--include-cosmetic` to see them.186````187188---189190## Don't191192- Don't show raw XAML diffs unless the user asks for them. The point of193 this skill is human-readable explanation.194- Don't claim a step is "the same" when matching is uncertain — surface195 the ambiguity.196- Don't echo the user's real entity logical names or workflow names into197 generated example output. Diff results that reference the user's actual198 workflow are fine (you're diffing their files); examples in199 documentation must use placeholders.