Microsoft Ships a Per-Property Migration Changelog Inside Your App. Nobody Reads It.
There is a machine-readable record of every property Microsoft added, removed, and renamed on the modern controls. It is sitting in your .msapp right now.
If you have used the modern controls for more than a year, you have hit this: an app that worked stops working, or a property you set silently stops applying, or Alignment is suddenly Align and your theme component breaks. You search the docs. The docs describe the control as it is today. There is no changelog.
There is a changelog. It is inside your app file.
Unpack any recent .msapp and open References/Templates.json. Alongside the classic control templates you will find a PcfTemplates array, and inside each entry a field called PcfConversions:
{
"Name": "PowerApps_CoreControls_TextCanvas",
"Version": "0.0.51",
"PcfConversions": [
{
"From": "0.0.13",
"To": "0.0.14",
"Action": [
{ "Name": "Alignment", "Type": "rename", "NewName": "Align" },
{ "Name": "As", "Type": "remove" },
{ "Name": "Truncate", "Type": "remove" },
{ "Name": "AutoHeight", "Type": "add" },
{ "Name": "VerticalAlign", "Type": "add" }
]
}
]
}
That is a migration table. From version, To version, and the exact property-level add / remove / rename operations the platform applies when it upgrades your control across that boundary.
In the app we examined, this table covers 10 modern controls, 77 version transitions, and 298 individual property changes. It is the closest thing that exists to an official history of the modern control set — and it is more precise than a changelog would be, because it is executable.
The renames, in full
These are the ones that break formulas and component contracts.
| Control | Version | Change |
|---|---|---|
TextCanvas | 0.0.13 → 0.0.14 | Alignment → Align |
TextCanvas | 0.0.17 → 0.0.18 | Italic → FontItalic, Strikethrough → FontStrikethrough, Underline → FontUnderline |
CheckboxCanvas | 0.0.6 → 0.0.7 | Value → Checked |
TabList | 1.0.13 → 1.0.14 | AccessibilityLabel → AccessibleLabel |
And the effective renames, done as a remove plus an add — which the platform does not link for you:
| Control | Version | Old | New |
|---|---|---|---|
DatePickerCanvas | 0.0.2 → 0.0.3 | Value | SelectedDate |
DatePickerCanvas | 0.0.16 → 0.0.17 | StartYear, EndYear | StartDate, EndDate |
DropdownCanvas | 0.0.18 → 0.0.19 | BaseColor | BasePaletteColor |
Toggle | 1.0.13 → 1.0.14 | BaseColor | BasePaletteColor |
TextInputCanvas | 0.0.38 → 0.0.39 | DelayOutput | TriggerOutput |
TabList | 2.1.1 → 2.1.2 | RenderSize | Size |
TabList | 1.0.10 → 1.0.11 | IsVertical | Alignment |
Value → SelectedDate on the date picker is a remove and an add. There is no rename action linking them. If you were binding to Value, the migration deleted your binding.
The event properties that quietly disappeared
OnSelect was removed from five modern controls:
| Control | Version | Removed |
|---|---|---|
TextCanvas | 0.0.14 → 0.0.15 | OnSelect, OnChange |
ComboboxCanvas | 0.0.9 → 0.0.10 | OnSelect |
DropdownCanvas | 0.0.12 → 0.0.13 | OnSelect |
DatePickerCanvas | 0.0.2 → 0.0.3 | OnSelect |
LinkCanvas | 0.0.4 → 0.0.5 | OnSelect |
OnChange was removed from ButtonCanvas (0.0.13→14), Toggle (1.0.8→9), LinkCanvas (0.0.14→15) and CheckboxCanvas (0.0.12→13) — though the checkbox got a genuine upgrade in exchange, gaining OnSelect, OnCheck and OnUncheck in the same hop.
If you ever wondered why the modern text control has no OnSelect while the classic label does: it had one, for five versions, and then it did not.
The best part: the borders that shipped, got yanked, and came back
Read these three rows together.
TextCanvas 0.0.25 → 0.0.26 add BorderStyle, BorderThickness, BorderColor (+ 4 radii, 4 paddings, Fill)
TextCanvas 0.0.36 → 0.0.37 remove BorderStyle, BorderThickness, BorderColor
TextCanvas 0.0.37 → 0.0.38 add BorderStyle, BorderThickness, BorderColor
Added at 26. Removed at 37. Re-added at 38 — one version later.
Now the same pattern across the family:
| Control | Removed at | Re-added at |
|---|---|---|
TextCanvas | 0.0.36 → 0.0.37 | 0.0.37 → 0.0.38 |
TextInputCanvas | 0.0.36 → 0.0.37 | 0.0.37 → 0.0.38 |
ComboboxCanvas | 0.0.37 → 0.0.38 | 0.0.38 → 0.0.39 |
LinkCanvas | 0.0.37 → 0.0.38 | 0.0.38 → 0.0.39 |
DropdownCanvas | 0.0.39 → 0.0.40 | 0.0.40 → 0.0.41 |
ButtonCanvas | 0.0.40 → 0.0.41 | 0.0.41 → 0.0.42 |
DatePickerCanvas | 0.0.30 → 0.0.31 | 0.0.31 → 0.0.32 |
Seven of the ten modern controls removed their border properties and restored them exactly one version later.
The removals also took HoverBorderColor, PressedBorderColor, DisabledBorderColor and FocusedBorderColor with them on five of those controls — and those four did not come back in the restore.
You are looking at a coordinated rollback and re-land, recorded in the format the platform uses to migrate your app. This is what a bad release looks like from the inside. If your modern controls lost their hover borders somewhere along the way and never got them back, this table is why.
Size on TextCanvas has the same shape at smaller scale: removed at 0.0.9 → 0.0.10, re-added at 0.0.10 → 0.0.11.
The theming build-out, reconstructed
The conversion table also tells you the order in which the modern controls became themeable — which explains why styling them has felt inconsistent for years.
BasePaletteColorarrives first, control by control:ButtonCanvas0.0.18,TabList2.2.1,ComboboxCanvas0.0.15,TextInputCanvas0.0.16,DatePickerCanvas0.0.7,CheckboxCanvas0.0.14,LinkCanvas0.0.14. One knob, one palette colour.FontSizenext, as a property separate fromSize, again staggered across seven controls.- The full font block —
Font,FontColor,FontWeight,FontItalic,FontUnderline,FontStrikethrough— lands as a single 6-property add:TextCanvas0.0.18,ButtonCanvas0.0.26,ComboboxCanvas0.0.21,TextInputCanvas0.0.22,DatePickerCanvas0.0.13,CheckboxCanvas0.0.20,Toggle1.0.20,TabList2.2.9. - The appearance block —
Appearance,Fill, borders, radii, four paddings, 14 properties at once — lands last:TextInputCanvas0.0.27,ComboboxCanvas0.0.28,DropdownCanvas0.0.30,DatePickerCanvas0.0.21,LinkCanvas0.0.28. - Then the rollback above.
Same properties, same groupings, seven different version numbers. There was a plan; it was rolled out per-control rather than atomically. Every “why does this control not have that property yet” question you have ever asked is a row in this table.
The size knobs came late and separately: CheckboxSize at CheckboxCanvas 0.0.23, ToggleSize at Toggle 1.0.33. Required arrived at ComboboxCanvas 0.0.44. ValidationState swept four controls in the 0.0.16–0.0.21 range.
The complete version overview, per control
Everything above is a selection. Here is the whole table — every recorded hop for all ten modern controls, generated directly from the file rather than transcribed.
Read + as added, − as removed, → as renamed. “Shipping” is the version this app was authored against; hops below it are the history the migration engine replays to bring an older control up to current.
TextCanvas — shipping 0.0.51, 8 recorded hops, 32 property changes
| Hop | Added | Removed | Renamed |
|---|---|---|---|
0.0.9 → 0.0.10 | — | Size | — |
0.0.10 → 0.0.11 | Size | — | — |
0.0.13 → 0.0.14 | AutoHeight, VerticalAlign | As, Truncate | Alignment → Align |
0.0.14 → 0.0.15 | — | OnSelect, OnChange | — |
0.0.17 → 0.0.18 | Font, FontColor | — | Italic → FontItalic, Strikethrough → FontStrikethrough, Underline → FontUnderline |
0.0.25 → 0.0.26 | Fill, PaddingTop, PaddingBottom, PaddingLeft, PaddingRight, BorderThickness, BorderColor, BorderRadiusTopLeft, BorderRadiusTopRight, BorderRadiusBottomRight, BorderRadiusBottomLeft, BorderStyle | — | — |
0.0.36 → 0.0.37 | — | BorderStyle, BorderThickness, BorderColor | — |
0.0.37 → 0.0.38 | BorderStyle, BorderThickness, BorderColor | — | — |
TextInputCanvas — shipping 0.0.54, 10 recorded hops, 39 property changes
| Hop | Added | Removed | Renamed |
|---|---|---|---|
0.0.13 → 0.0.14 | MaxLength, Placeholder, Type | — | — |
0.0.15 → 0.0.16 | BasePaletteColor | — | — |
0.0.16 → 0.0.17 | ValidationState | — | — |
0.0.18 → 0.0.19 | FontSize | — | — |
0.0.21 → 0.0.22 | Font, FontColor, FontWeight, FontItalic, FontUnderline, FontStrikethrough | — | — |
0.0.22 → 0.0.23 | Align | — | — |
0.0.26 → 0.0.27 | Appearance, BorderColor, BorderRadius, BorderStyle, BorderThickness, DisabledBorderColor, Fill, FocusedBorderColor, HoverBorderColor, PaddingBottom, PaddingLeft, PaddingRight, PaddingTop, PressedBorderColor | — | — |
0.0.36 → 0.0.37 | — | BorderStyle, BorderThickness, HoverBorderColor, PressedBorderColor, DisabledBorderColor, FocusedBorderColor, BorderColor | — |
0.0.37 → 0.0.38 | BorderStyle, BorderThickness, BorderColor | — | — |
0.0.38 → 0.0.39 | TriggerOutput | DelayOutput | — |
ButtonCanvas — shipping 0.0.45, 7 recorded hops, 40 property changes
| Hop | Added | Removed | Renamed |
|---|---|---|---|
0.0.13 → 0.0.14 | — | OnChange | — |
0.0.17 → 0.0.18 | BasePaletteColor | — | — |
0.0.20 → 0.0.21 | FontSize | — | — |
0.0.25 → 0.0.26 | Font, FontColor, FontWeight, FontItalic, FontUnderline, FontStrikethrough | — | — |
0.0.29 → 0.0.30 | BorderStyle, BorderThickness, BorderColor, BorderRadiusTopLeft, BorderRadiusTopRight, BorderRadiusBottomRight, BorderRadiusBottomLeft, PaddingTop, PaddingRight, PaddingBottom, PaddingLeft, Align, VerticalAlign, HoverBorderColor, PressedBorderColor, DisabledBorderColor, FocusedBorderColor, Icon, Layout, IconRotation, IconStyle | — | — |
0.0.40 → 0.0.41 | — | BorderStyle, BorderThickness, HoverBorderColor, PressedBorderColor, DisabledBorderColor, FocusedBorderColor, BorderColor | — |
0.0.41 → 0.0.42 | BorderStyle, BorderThickness, BorderColor | — | — |
ComboboxCanvas — shipping 0.0.51, 11 recorded hops, 39 property changes
| Hop | Added | Removed | Renamed |
|---|---|---|---|
0.0.4 → 0.0.5 | IsSearchable, InputTextPlaceholder | — | — |
0.0.6 → 0.0.7 | SearchText | — | — |
0.0.9 → 0.0.10 | — | OnSelect | — |
0.0.14 → 0.0.15 | BasePaletteColor, FontSize | — | — |
0.0.16 → 0.0.17 | ValidationState | — | — |
0.0.20 → 0.0.21 | Font, FontColor, FontWeight, FontItalic, FontUnderline, FontStrikethrough | — | — |
0.0.27 → 0.0.28 | Appearance, BorderColor, BorderRadius, BorderStyle, BorderThickness, DisabledBorderColor, Fill, FocusedBorderColor, HoverBorderColor, PaddingBottom, PaddingLeft, PaddingRight, PaddingTop, PressedBorderColor | — | — |
0.0.37 → 0.0.38 | — | BorderStyle, BorderThickness, HoverBorderColor, PressedBorderColor, DisabledBorderColor, FocusedBorderColor, BorderColor | — |
0.0.38 → 0.0.39 | BorderStyle, BorderThickness, BorderColor | — | — |
0.0.43 → 0.0.44 | Required | — | — |
0.0.46 → 0.0.47 | TriggerOutput | — | — |
DropdownCanvas — shipping 0.0.45, 7 recorded hops, 30 property changes
| Hop | Added | Removed | Renamed |
|---|---|---|---|
0.0.12 → 0.0.13 | — | OnSelect | — |
0.0.17 → 0.0.18 | BaseColor, FontSize | — | — |
0.0.18 → 0.0.19 | BasePaletteColor | BaseColor | — |
0.0.20 → 0.0.21 | ValidationState | — | — |
0.0.29 → 0.0.30 | Appearance, BorderColor, BorderRadius, BorderStyle, BorderThickness, DisabledBorderColor, Fill, FocusedBorderColor, HoverBorderColor, PaddingBottom, PaddingLeft, PaddingRight, PaddingTop, PressedBorderColor | — | — |
0.0.39 → 0.0.40 | — | BorderStyle, BorderThickness, HoverBorderColor, PressedBorderColor, DisabledBorderColor, FocusedBorderColor, BorderColor | — |
0.0.40 → 0.0.41 | BorderStyle, BorderThickness, BorderColor | — | — |
DatePickerCanvas — shipping 0.0.46, 9 recorded hops, 46 property changes
| Hop | Added | Removed | Renamed |
|---|---|---|---|
0.0.2 → 0.0.3 | SelectedDate, IsEditable, Format, StartYear, EndYear, StartOfWeek, Placeholder | Value, OnSelect | — |
0.0.6 → 0.0.7 | BasePaletteColor | — | — |
0.0.7 → 0.0.8 | ValidationState | — | — |
0.0.9 → 0.0.10 | FontSize | — | — |
0.0.12 → 0.0.13 | Font, FontColor, FontWeight, FontItalic, FontUnderline, FontStrikethrough | — | — |
0.0.16 → 0.0.17 | EndDate, StartDate | EndYear, StartYear | — |
0.0.20 → 0.0.21 | Appearance, BorderColor, BorderRadius, BorderStyle, BorderThickness, DisabledBorderColor, Fill, FocusedBorderColor, HoverBorderColor, PaddingBottom, PaddingLeft, PaddingRight, PaddingTop, PressedBorderColor | — | — |
0.0.30 → 0.0.31 | — | BorderStyle, BorderThickness, HoverBorderColor, PressedBorderColor, DisabledBorderColor, FocusedBorderColor, BorderColor | — |
0.0.31 → 0.0.32 | BorderStyle, BorderThickness, BorderColor | — | — |
That first row is the most destructive single hop in the dataset. Seven properties added, Value and OnSelect both removed, in one step — and Value → SelectedDate is recorded as a remove plus an add, not a rename, so nothing links the old binding to the new one.
CheckboxCanvas — shipping 0.0.30, 6 recorded hops, 14 property changes
| Hop | Added | Removed | Renamed |
|---|---|---|---|
0.0.6 → 0.0.7 | — | — | Value → Checked |
0.0.12 → 0.0.13 | OnSelect, OnCheck, OnUncheck | OnChange | — |
0.0.13 → 0.0.14 | BasePaletteColor | — | — |
0.0.15 → 0.0.16 | FontSize | — | — |
0.0.19 → 0.0.20 | Font, FontColor, FontWeight, FontItalic, FontUnderline, FontStrikethrough | — | — |
0.0.22 → 0.0.23 | CheckboxSize | — | — |
LinkCanvas — shipping 0.0.45, 8 recorded hops, 33 property changes
| Hop | Added | Removed | Renamed |
|---|---|---|---|
0.0.4 → 0.0.5 | — | As, OnSelect | — |
0.0.13 → 0.0.14 | BasePaletteColor | — | — |
0.0.14 → 0.0.15 | Align, AutoHeight, VerticalAlign, Wrap | OnChange | — |
0.0.16 → 0.0.17 | FontSize | — | — |
0.0.21 → 0.0.22 | Font, FontWeight, FontItalic, FontUnderline, FontStrikethrough | — | — |
0.0.27 → 0.0.28 | Appearance, Fill, BorderStyle, BorderThickness, BorderColor, BorderRadiusTopLeft, BorderRadiusTopRight, BorderRadiusBottomRight, BorderRadiusBottomLeft, PaddingTop, PaddingRight, PaddingBottom, PaddingLeft | — | — |
0.0.37 → 0.0.38 | — | BorderStyle, BorderThickness, BorderColor | — |
0.0.38 → 0.0.39 | BorderStyle, BorderThickness, BorderColor | — | — |
Toggle — shipping 1.1.5, 5 recorded hops, 12 property changes
| Hop | Added | Removed | Renamed |
|---|---|---|---|
1.0.8 → 1.0.9 | — | OnChange | — |
1.0.10 → 1.0.11 | BaseColor, FontSize | — | — |
1.0.13 → 1.0.14 | BasePaletteColor | BaseColor | — |
1.0.19 → 1.0.20 | Font, FontColor, FontWeight, FontItalic, FontUnderline, FontStrikethrough | — | — |
1.0.32 → 1.0.33 | ToggleSize | — | — |
TabList — shipping 2.2.31, 6 recorded hops, 13 property changes
| Hop | Added | Removed | Renamed |
|---|---|---|---|
1.0.10 → 1.0.11 | Alignment | IsVertical | — |
1.0.13 → 1.0.14 | — | — | AccessibilityLabel → AccessibleLabel |
2.1.1 → 2.1.2 | Size | RenderSize | — |
2.2.0 → 2.2.1 | BasePaletteColor | — | — |
2.2.2 → 2.2.3 | FontSize | — | — |
2.2.8 → 2.2.9 | Font, FontColor, FontWeight, FontItalic, FontUnderline, FontStrikethrough | — | — |
Reading the tables sideways
Three patterns only become visible once all ten are side by side.
The hops are sparse, and the gaps are the story. TextInputCanvas ships at 0.0.54 but its last recorded hop is 0.0.38 → 0.0.39. Sixteen versions with no entry at all. A hop exists only when the property surface changes, so those sixteen releases were bug fixes and rendering work. This is a changelog of contract changes, not of releases.
Nearly every control gained the same six font properties, at eight different times. Font, FontColor, FontWeight, FontItalic, FontUnderline, FontStrikethrough land as one block on seven controls — DatePickerCanvas 0.0.13, CheckboxCanvas 0.0.20, ComboboxCanvas 0.0.21, TextInputCanvas 0.0.22, ButtonCanvas 0.0.26, Toggle 1.0.20, TabList 2.2.9 — and on LinkCanvas 0.0.22 as five of the six, without FontColor.
TextCanvas is the exception, and an instructive one: at 0.0.18 it adds only Font and FontColor, then renames Italic, Strikethrough and Underline into FontItalic, FontStrikethrough, FontUnderline. It reaches the same six-property surface as the others by a different route, because it already had those properties under their old names. Gen 3 then renames all of them straight back.
The 14-property appearance block is equally staggered, landing at DatePickerCanvas 0.0.21, TextInputCanvas 0.0.27, ComboboxCanvas 0.0.28, DropdownCanvas 0.0.30 — then being partly torn out again roughly ten versions later on each.
Totals across all ten: 77 hops, 298 property changes — 229 adds, 63 removals, 6 renames.
Those six renames are the entire set the platform records for the modern controls:
| Control | Version | Rename |
|---|---|---|
TextCanvas | 0.0.13 → 0.0.14 | Alignment → Align |
TextCanvas | 0.0.17 → 0.0.18 | Italic → FontItalic |
TextCanvas | 0.0.17 → 0.0.18 | Strikethrough → FontStrikethrough |
TextCanvas | 0.0.17 → 0.0.18 | Underline → FontUnderline |
TabList | 1.0.13 → 1.0.14 | AccessibilityLabel → AccessibleLabel |
CheckboxCanvas | 0.0.6 → 0.0.7 | Value → Checked |
Six renames against 63 removals is the ratio worth noticing. When Microsoft changes a property on these controls it is roughly ten times more likely to delete it than to rename it — and a rename is the only one of the two the migration engine can follow automatically.
Postscript: the boundary the table does not cover — and Microsoft’s own guide
Everything above describes movement within the PowerApps_CoreControls_* generation. In a later export (August 2026) we found a third generation: modernText, modernTextInput, modernCombobox, modernDatePicker, back in the classic shared-template format at ~300 bytes per instance instead of 71 KB.
PcfConversions says nothing about that boundary. There is no hop from PowerApps_CoreControls_TextCanvas to modernText. So we derived the mapping by diffing property surfaces — and Microsoft’s Recent updates to modern controls in canvas apps guide lets us check the work.
A note on sourcing, because it matters for what follows. Everything derived from template diffs below is reproducible from the commands in the Methodology section — run them yourself and you will get the same answer. Everything attributed to Microsoft’s guide is quoted from that documentation and has not been independently verified against a running environment. Where the two agree, that is a genuine cross-check. Where the guide is the only source, it is labelled as such.
The derived renames match the documentation exactly:
| Derived from templates | Microsoft’s guide | Match |
|---|---|---|
FontColor → Color | FontColor → Color | ✓ |
FontSize → Size | FontSize → Size | ✓ |
FontItalic → Italic | FontItalic → Italic | ✓ |
FontStrikethrough → Strikethrough | same | ✓ |
FontUnderline → Underline | same | ✓ |
Weight → FontWeight (Text only) | Weight → FontWeight, “Text only” | ✓ |
BorderRadius → four corner properties | RadiusTopLeft/TopRight/BottomLeft/BottomRight | ✓ |
TabIndex absent from gen 3 | ”TabIndex removed” (Icon) | ✓ |
OnSelect present on modernText | ”new OnSelect event” (Text) | ✓ |
Every one of those was recoverable from the files before the guide existed. The entire Font* prefix is dropped — the same six-property block that gen 2 spent two years adding to eight controls, one at a time, is renamed away wholesale.
Two things the guide adds that no amount of template diffing would have revealed, and they are the dangerous ones:
1. String values became enums. Properties that took "Bold" or "Start" now require FontWeight.Bold, Align.Left, ValidationState.Error, Appearance.FilledDarker, BorderStyle.Solid, IconStyle.Outline. The property name is unchanged, so a name-level diff sees nothing — but a formula passing the old string breaks. Worse: FontWeight.Medium no longer exists and silently maps to FontWeight.Normal on update. Your semibold text quietly becomes regular.
2. OnChange fires at different times. Same property, same name, different semantics:
| Control | Was | Now |
|---|---|---|
| Text Input | every keystroke | focus out only |
| Number Input | every keystroke | focus out + step clicks |
| Combo Box | delayed / focus out | every selection |
| Radio | inconsistent | every selection, reliably |
Microsoft flags the Text Input change as critical, and it is: any app doing live search or running validation on each keystroke stops working the moment the control updates — with no error, no warning, and no property rename to detect. The recommended fix is to reference the output property (TextInput1.Text) directly instead of relying on OnChange.
Neither category appears in PcfConversions, because the table records only add/remove/rename of property names. A value-domain change and a timing change are both invisible to it. That is the honest ceiling on what the embedded changelog can tell you.
The guide also confirms the scope is much larger than our sample: 16 controls have updated versions (Text, Number Input, Date Picker, Text Input, Tab List, Combo Box, Radio, Link, Info Button, Button, Dropdown, Icon, Slider, Toggle, Checkbox, Form). Our app only used four of them, and an .msapp only embeds what it uses.
Also worth noting for anyone reading the tables above: Value → Default shows up again in gen 3, on Slider and (as DefaultSelectedItems → Default) on Dropdown. On modernTextInput the old read/write Value is split into Default (settable) and Text (direction="out") — one property becoming two, with a direction change. No rename action can express that, which is exactly why it needs a guide and not a table.
Why this is worth your attention
It is a real API contract. PcfConversions is not documentation, it is the migration engine’s input. It is authoritative in a way the docs are not.
It is machine-readable. Roughly 120 lines of code turns it into a linter: parse your app’s control versions, walk forward through the conversion table, and flag every formula referencing a property that a future hop removes or renames. That is a pre-upgrade break report for canvas apps, and it does not exist today.
It is a version pin you did not know you had. Your app records the control version it was authored against. The gap between that and current is measured in these hops.
It is the honest history of the modern control set. 298 property changes over 77 version hops across 10 controls — every one a potential breakage that shipped without a release note.
Methodology
Sample: one production .msapp exported 2026-02-16. A 2023-era app we compared against has no PcfTemplates key at all — the modern control machinery did not exist in that format yet.
unzip -q app.msapp -d app/
python3 - <<'EOF'
import json
d = json.load(open('app/References/Templates.json'))
for t in d.get('PcfTemplates', []):
print(f"## {t['Name']} @ {t['Version']}")
for c in t['PcfConversions'] or []:
acts = '; '.join(
f"{a['Type']} {a['Name']}" + (f" -> {a['NewName']}" if a.get('NewName') else '')
for a in c['Action'])
print(f" {c['From']} -> {c['To']}: {acts}")
EOF
The table only lists controls your app actually uses, so coverage varies per app. To see all ten you need an app that uses all ten — or you union the tables from several apps, which is what we did.