diff --git a/.gitignore b/.gitignore
index 397b2f2bd5..85dcf9149a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,213 +1,213 @@
 # Common
 \#*
 .\#*
 GPATH
 GRTAGS
 GTAGS
 TAGS
 Makefile
 Makefile.in
 .deps
 .dirstamp
 .libs
 *.pc
 *.pyc
 *.bz2
 *.tar.gz
 *.rpm
 *.la
 *.lo
 *.o
 *~
 *.gcda
 *.gcno
 
 
 # Autobuild
 aclocal.m4
 autoconf
 autoheader
 autom4te.cache/
 automake
 build.counter
 compile
 config.guess
 config.log
 config.status
 config.sub
 configure
 depcomp
 install-sh
 include/stamp-*
 libtool
 libtool.m4
 ltdl.m4
 libltdl
 ltmain.sh
 missing
 py-compile
 /m4/argz.m4
 /m4/ltargz.m4
 /m4/ltoptions.m4
 /m4/ltsugar.m4
 /m4/ltversion.m4
 /m4/lt~obsolete.m4
 test-driver
 ylwrap
 
 # Configure targets
 Doxyfile
 /cts/CTS.py
 /cts/CTSlab.py
 /cts/CTSvars.py
 /cts/LSBDummy
 /cts/OCFIPraTest.py
 /cts/benchmark/clubench
 /cts/cluster_test
 /cts/cts
 /cts/cts-cli
 /cts/cts-coverage
 /cts/cts-exec
 /cts/cts-fencing
 /cts/cts-log-watcher
 /cts/cts-regression
 /cts/cts-scheduler
 /cts/cts-support
 /cts/fence_dummy
 /cts/lxc_autogen.sh
 /cts/pacemaker-cts-dummyd
 /cts/pacemaker-cts-dummyd@.service
 /daemons/execd/pacemaker_remote
 /daemons/execd/pacemaker_remote.service
 /daemons/fenced/fence_legacy
 /daemons/pacemakerd/pacemaker
 /daemons/pacemakerd/pacemaker.combined.upstart
 /daemons/pacemakerd/pacemaker.service
 /daemons/pacemakerd/pacemaker.upstart
 /extra/logrotate/pacemaker
 /extra/resources/ClusterMon
 /extra/resources/HealthSMART
 /extra/resources/SysInfo
 /extra/resources/ifspeed
 /extra/resources/o2cb
 include/config.h
 include/config.h.in
 include/crm_config.h
 publican.cfg
 /tools/cibsecret
 /tools/crm_error
 /tools/crm_failcount
 /tools/crm_master
 /tools/crm_mon.service
 /tools/crm_mon.upstart
 /tools/crm_report
 /tools/crm_standby
 /tools/report.collector
 /tools/report.common
 
 # Build targets
 *.7
 *.7.xml
 *.7.html
 *.8
 *.8.xml
 *.8.html
 doc/*/en-US/images/*.png
 doc/*/tmp/**
 doc/*/publish
 /daemons/attrd/pacemaker-attrd
 /daemons/based/pacemaker-based
 /daemons/based/cibmon
 /daemons/controld/pacemaker-controld
 /daemons/execd/cts-exec-helper
 /daemons/execd/pacemaker-execd
 /daemons/execd/pacemaker-remoted
 /daemons/fenced/cts-fence-helper
 /daemons/fenced/pacemaker-fenced
 /daemons/fenced/pacemaker-fenced.xml
 /daemons/pacemakerd/pacemakerd
 /daemons/schedulerd/pacemaker-schedulerd
 /daemons/schedulerd/pacemaker-schedulerd.xml
 /daemons/schedulerd/ptest
 doc/api/*
 doc/Clusters_from_Scratch.txt
 doc/Pacemaker_Explained.txt
 doc/acls.html
 doc/crm_fencing.html
 doc/publican-catalog*
 scratch
 /tools/attrd_updater
 /tools/cibadmin
 /tools/crmadmin
 /tools/crm_attribute
 /tools/crm_diff
 /tools/crm_mon
 /tools/crm_node
 /tools/crm_resource
 /tools/crm_shadow
 /tools/crm_simulate
 /tools/crm_ticket
 /tools/crm_verify
 /tools/iso8601
 /tools/stonith_admin
 xml/crm.dtd
 xml/pacemaker*.rng
 xml/versions.rng
 doc/shared/en-US/*.xml
 doc/Clusters_from_Scratch.build
 doc/Clusters_from_Scratch/en-US/Ap-*.xml
 doc/Clusters_from_Scratch/en-US/Ch-*.xml
 doc/Pacemaker_Administration.build
 doc/Pacemaker_Administration/en-US/Ch-*.xml
 doc/Pacemaker_Development.build
 doc/Pacemaker_Development/en-US/Ch-*.xml
 doc/Pacemaker_Explained.build
 doc/Pacemaker_Explained/en-US/Ch-*.xml
 doc/Pacemaker_Explained/en-US/Ap-*.xml
 doc/Pacemaker_Remote.build
 doc/Pacemaker_Remote/en-US/Ch-*.xml
 lib/gnu/libgnu.a
 lib/gnu/stdalign.h
 *.coverity
 
 # Test detritus
 /cts/.regression.failed.diff
 /cts/scheduler/*.ref
 /cts/scheduler/*.up
 /cts/scheduler/*.up.err
 /cts/scheduler/bug-rh-1097457.log
 /cts/scheduler/bug-rh-1097457.trs
 /cts/scheduler/shadow.*
 /cts/test-suite.log
-/xml/test-2/*.up
-/xml/test-2/*.up.err
+/xml/test-*/*.up
+/xml/test-*/*.up.err
 /xml/assets/diffview.js
 
 # Formerly built files (helps when jumping back and forth in checkout)
 /attrd
 /cib
 /coverage.sh
 /crmd
 /cts/HBDummy
 /fencing
 /lrmd
 /mcp
 /pengine
 
 #Other 
 mock
 HTML
 pacemaker*.spec
 coverity-*
 
 compat_reports
 .ABI-build
 abi_dumps
 logs
 
 *.patch
 *.diff
 *.sed
 *.orig
 *.rej
 *.swp
diff --git a/.travis.yml b/.travis.yml
index 74614503c2..8c4546bfb6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,89 +1,121 @@
 # Control file for the Travis autobuilder
 # https://docs.travis-ci.com/user/customizing-the-build/
 
 language: c
-compiler:
- - gcc
- - clang
-# - cov-build
+
+matrix:
+  include:
+    - compiler: gcc
+      env:      MAINT_EXTRA=0
+    - compiler: clang
+      env:      MAINT_EXTRA=0
+    #- compiler: cov-build
+    #  env:      MAINT_EXTRA=0
+    - compiler: gcc
+      env:      MAINT_EXTRA=1
 
 env:
   global:
 
     # -- BEGIN Coverity Scan ENV
     # Used by https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh
     # The build command with all of the arguments that you would apply to a manual `cov-build`
     - COVERITY_SCAN_BUILD_COMMAND="make"
 
     # Email address for notifications related to this build
     - OWNER_EMAIL="andrew@beekhof.net"
 
     # Regular expression selects on which branches to run analysis
     # Be aware of quotas. Do not run on every branch/commit
     - COVERITY_SCAN_BRANCH_PATTERN="1.1"
 
     # COVERITY_SCAN_TOKEN via "travis encrypt" using the repo's public key
     - secure: "qnrF7L8RejLUY7URdNe7XP4Hu4R55C0tvAuMRg4EjVtelOpw+nIgA7BLiX19q/70VjFuKcGnMhW28TdYl0uwMMdWKKxmwTim04Sy3UfOE2BPeuQOBphr+8s9gd0U1MO8j2dZ84A40t5Mkk946wWZwT0okpjOr/PfBOZkU3o87FM="
 
     # -- END Coverity Scan ENV
 
 # sudo add-apt-repository ppa:hotot-team
 before_install:
  - sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ trusty main"
  - sudo apt-get update -qq
 
 # To switch to Travis-CI's containerized (non-sudo) architecture,
 # all our dependencies need to be on Travis's whitelist:
 #   https://github.com/travis-ci/apt-package-whitelist
 #
 # The only ones that aren't already are:
 # - cluster-glue-dev: see open issue:
 #   https://github.com/travis-ci/apt-package-whitelist/issues/2936
 # - resource-agents: see open issue:
 #   https://github.com/travis-ci/apt-package-whitelist/issues/4261
 # - libdbus-1-dev: see multiple open issues:
 #   https://github.com/travis-ci/apt-package-whitelist/issues?utf8=%E2%9C%93&q=is%3Aissue+libdbus+-1-dev
 #   (a workaround is to install libdbus-glib-1-dev, which depends on it and is whitelisted)
 install:
- - sudo apt-get install -qq automake autoconf chrpath libtool perl python python-dev
- - sudo apt-get install -qq libbz2-dev libdbus-1-dev libglib2.0-dev libgnutls-dev libltdl-dev
- - sudo apt-get install -qq libncurses5-dev libpam0g-dev libxml2-dev libxslt1-dev uuid-dev
- - sudo apt-get install -qq libqb-dev libcfg-dev libcmap-dev libcorosync-common-dev libcpg-dev
- - sudo apt-get install -qq libquorum-dev libsam-dev libtotem-pg-dev libvotequorum-dev
- - sudo apt-get install -qq cluster-glue-dev resource-agents
+ - test $MAINT_EXTRA -ne 0
+   || sudo apt-get install -qq
+      automake autoconf libtool
+      python python-dev
+      libbz2-dev libdbus-1-dev libglib2.0-dev libgnutls-dev libltdl-dev
+      libncurses5-dev libpam0g-dev libxml2-dev libxslt1-dev uuid-dev
+      libqb-dev libcfg-dev libcmap-dev libcorosync-common-dev libcpg-dev
+      libquorum-dev libsam-dev libtotem-pg-dev libvotequorum-dev
+      cluster-glue-dev resource-agents
+ - test $MAINT_EXTRA -eq 0
+   || sudo apt-get install -qq
+      make libxml2-utils xsltproc
 
 before_script:
 # Save and restore CC so that ./configure can pass
- - export CC_SAVED=$CC
- - export CC=`echo ${CC} | sed s/cov-build/gcc/`
- - ./autogen.sh
- - ./configure
- - export CC=$CC_SAVED
+ - test $MAINT_EXTRA -ne 0 || {
+     export CC_SAVED=$CC;
+     export CC=$(echo ${CC} | sed s/cov-build/gcc/);
+     ./autogen.sh;
+     ./configure;
+     export CC=$CC_SAVED;
+   }
+ - test $MAINT_EXTRA -eq 0 || (
+     cd xml;
+     { cat Makefile.am; printf 'hack_rng\x3a %s' '${RNG_generated}'; }
+     | make -f- top_srcdir=$(pwd)/.. top_builddir=$(pwd)/.. hack_rng
+   )
 
 script: 
-- if test ${CC} != cov-build; then sudo make install-exec-local || true; fi
-- if test ${CC} != cov-build; then make && ./cts/cts-regression -V cli scheduler exec; fi
-- if test ${CC} = cov-build; then export CC=gcc; bash ./travisci_build_coverity_scan.sh; fi
+# XXX Is the following item needed?
+- test $MAINT_EXTRA -ne 0 || test ${CC} = cov-build
+  || sudo make install-exec-local || true
+- test $MAINT_EXTRA -ne 0 || test ${CC} = cov-build
+  || { make && ./cts/cts-regression -V cli scheduler exec; }
+- test $MAINT_EXTRA -ne 0 || test ${CC} != cov-build
+  || export CC=gcc; bash ./travisci_build_coverity_scan.sh
+- test $MAINT_EXTRA -eq 0 || ( cd xml;
+    ./regression.sh && ./regression.sh -B && ./regression.sh -S && {
+      schemas=; for schema in *.rng; do
+        case ${schema} in *cibtr*) ;; *) schemas="${schemas} ${schema}";; esac;
+      done;
+      xmllint --noout --relaxng 'http://relaxng.org/relaxng.rng' ${schemas};
+    }
+  )
 
 #after_script:
 #after_success:
 
 after_failure:
  - lsb_release -a
  - sudo cat /etc/apt/sources.list
  - whoami
  - env | sort 
  - cat include/config.h
 
 notifications:
   irc: "irc.freenode.org#pcmk"
 #  email:
 #    recipients:
 #      - developers@clusterlabs.org
 
 # whitelist
 branches:
   only:
     - master
     - "1.1"
     - "2.0"
diff --git a/cts/cli/regression.upgrade.exp b/cts/cli/regression.upgrade.exp
new file mode 100644
index 0000000000..d2599f8ee2
--- /dev/null
+++ b/cts/cli/regression.upgrade.exp
@@ -0,0 +1,129 @@
+Created new pacemaker configuration
+Setting up shadow instance
+A new shadow instance was created.  To begin using it paste the following into your shell:
+  CIB_shadow=cts-cli ; export CIB_shadow
+=#=#=#= Begin test: Set stonith-enabled=false =#=#=#=
+=#=#=#= Current cib after: Set stonith-enabled=false =#=#=#=
+<cib epoch="1" num_updates="0" admin_epoch="0">
+  <configuration>
+    <crm_config>
+      <cluster_property_set id="cib-bootstrap-options">
+        <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
+      </cluster_property_set>
+    </crm_config>
+    <nodes/>
+    <resources/>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
+=#=#=#= End test: Set stonith-enabled=false - OK (0) =#=#=#=
+* Passed: crm_attribute  - Set stonith-enabled=false
+=#=#=#= Begin test: Configure the initial resource =#=#=#=
+=#=#=#= Current cib after: Configure the initial resource =#=#=#=
+<cib epoch="2" num_updates="0" admin_epoch="0">
+  <configuration>
+    <crm_config>
+      <cluster_property_set id="cib-bootstrap-options">
+        <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
+      </cluster_property_set>
+    </crm_config>
+    <nodes/>
+    <resources>
+      <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
+        <operations>
+          <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
+          <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s">
+            <instance_attributes id="mySmartFuse-inputpower-instanceparams">
+              <nvpair id="mySmartFuse-inputpower-requires" name="requires" value="inputpower"/>
+            </instance_attributes>
+          </op>
+          <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s">
+            <instance_attributes id="mySmartFuse-outputpower-instanceparams">
+              <nvpair id="mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+            </instance_attributes>
+          </op>
+        </operations>
+        <instance_attributes id="mySmartFuse-params">
+          <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+        <!-- a bit hairy but valid -->
+        <instance_attributes id-ref="mySmartFuse-outputpower-instanceparams"/>
+      </primitive>
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
+=#=#=#= End test: Configure the initial resource - OK (0) =#=#=#=
+* Passed: cibadmin       - Configure the initial resource
+=#=#=#= Begin test: Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping) =#=#=#=
+INFO: Resources-operation instance_attributes: mySmartFuse-monitor-inputpower (rsc=mySmartFuse, meta=mySmartFuse-inputpower-instanceparams): dropping requires
+INFO: Resources-operation instance_attributes: ... only start/promote operation taken into account
+INFO: Resources-operation instance_attributes: mySmartFuse-monitor-outputpower (rsc=mySmartFuse, meta=mySmartFuse-outputpower-instanceparams): dropping requires
+INFO: Resources-operation instance_attributes: ... only start/promote operation taken into account
+DEBUG: instance_attributes: original element pointed to with @id-ref (mySmartFuse-outputpower-instanceparams) disappeared during upgrade
+=#=#=#= Current cib after: Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping) =#=#=#=
+<cib epoch="2" num_updates="0" admin_epoch="1">
+  <configuration>
+    <crm_config>
+      <cluster_property_set id="cib-bootstrap-options">
+        <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
+      </cluster_property_set>
+    </crm_config>
+    <nodes/>
+    <resources>
+      <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
+        <operations>
+          <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
+          <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s"/>
+          <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s"/>
+        </operations>
+        <instance_attributes id="mySmartFuse-params">
+          <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+        <!-- a bit hairy but valid -->
+        <instance_attributes id="_cibtr-2_mySmartFuse-outputpower-instanceparams">
+          <nvpair id="__cibtr-2_mySmartFuse-outputpower-instanceparams__mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+        </instance_attributes>
+      </primitive>
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
+=#=#=#= End test: Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping) - OK (0) =#=#=#=
+* Passed: cibadmin       - Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping)
+=#=#=#= Begin test: Query a resource instance attribute (shall survive) =#=#=#=
+outputpower
+=#=#=#= Current cib after: Query a resource instance attribute (shall survive) =#=#=#=
+<cib epoch="2" num_updates="0" admin_epoch="1">
+  <configuration>
+    <crm_config>
+      <cluster_property_set id="cib-bootstrap-options">
+        <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
+      </cluster_property_set>
+    </crm_config>
+    <nodes/>
+    <resources>
+      <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
+        <operations>
+          <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
+          <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s"/>
+          <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s"/>
+        </operations>
+        <instance_attributes id="mySmartFuse-params">
+          <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+        <!-- a bit hairy but valid -->
+        <instance_attributes id="_cibtr-2_mySmartFuse-outputpower-instanceparams">
+          <nvpair id="__cibtr-2_mySmartFuse-outputpower-instanceparams__mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+        </instance_attributes>
+      </primitive>
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
+=#=#=#= End test: Query a resource instance attribute (shall survive) - OK (0) =#=#=#=
+* Passed: crm_resource   - Query a resource instance attribute (shall survive)
diff --git a/cts/cli/regression.validity.exp b/cts/cli/regression.validity.exp
index d195b13aad..e7d8d386eb 100644
--- a/cts/cli/regression.validity.exp
+++ b/cts/cli/regression.validity.exp
@@ -1,434 +1,448 @@
 Created new pacemaker configuration
 Setting up shadow instance
 A new shadow instance was created.  To begin using it paste the following into your shell:
   CIB_shadow=cts-cli ; export CIB_shadow
 =#=#=#= Begin test: Try to make resulting CIB invalid (enum violation) =#=#=#=
    1 <cib epoch="4" num_updates="0" admin_epoch="0">
    2   <configuration>
    3     <crm_config/>
    4     <nodes/>
    5     <resources>
    6       <primitive id="dummy1" class="ocf" provider="pacemaker" type="Dummy"/>
    7       <primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>
    8     </resources>
    9     <constraints>
   10       <rsc_order id="ord_1-2" first="dummy1" first-action="break" then="dummy2"/>
   11     </constraints>
   12   </configuration>
   13   <status/>
   14 </cib>
   15 
 Call failed: Update does not conform to the configured schema
 =#=#=#= Current cib after: Try to make resulting CIB invalid (enum violation) =#=#=#=
 <cib epoch="3" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config/>
     <nodes/>
     <resources>
       <primitive id="dummy1" class="ocf" provider="pacemaker" type="Dummy"/>
       <primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints>
       <rsc_order id="ord_1-2" first="dummy1" first-action="start" then="dummy2"/>
     </constraints>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: Try to make resulting CIB invalid (enum violation) - Invalid configuration (78) =#=#=#=
 * Passed: cibadmin       - Try to make resulting CIB invalid (enum violation)
 =#=#=#= Begin test: Run crm_simulate with invalid CIB (enum violation) =#=#=#=
 update_validation 	debug: Testing 'pacemaker-1.2' validation (1 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-1.2 validation failed
 update_validation 	debug: Testing 'pacemaker-1.3' validation (2 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-1.3 validation failed
 update_validation 	debug: Testing 'pacemaker-2.0' validation (3 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.0 validation failed
 update_validation 	debug: Testing 'pacemaker-2.1' validation (4 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.1 validation failed
 update_validation 	debug: Testing 'pacemaker-2.2' validation (5 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.2 validation failed
 update_validation 	debug: Testing 'pacemaker-2.3' validation (6 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.3 validation failed
 update_validation 	debug: Testing 'pacemaker-2.4' validation (7 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.4 validation failed
 update_validation 	debug: Testing 'pacemaker-2.5' validation (8 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.5 validation failed
 update_validation 	debug: Testing 'pacemaker-2.6' validation (9 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.6 validation failed
 update_validation 	debug: Testing 'pacemaker-2.7' validation (10 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.7 validation failed
 update_validation 	debug: Testing 'pacemaker-2.8' validation (11 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.8 validation failed
 update_validation 	debug: Testing 'pacemaker-2.9' validation (12 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.9 validation failed
 update_validation 	debug: Testing 'pacemaker-2.10' validation (13 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.10 validation failed
 update_validation 	debug: Testing 'pacemaker-3.0' validation (14 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-3.0 validation failed
-Your current configuration pacemaker-1.2 could not validate with any schema in range [pacemaker-1.2, pacemaker-3.0], cannot upgrade to pacemaker-3.0.
+update_validation 	debug: Testing 'pacemaker-3.1' validation (15 of X)
+element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
+element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
+update_validation 	trace: pacemaker-3.1 validation failed
+Your current configuration pacemaker-1.2 could not validate with any schema in range [pacemaker-1.2, pacemaker-3.1], cannot upgrade to pacemaker-3.0.
 =#=#=#= End test: Run crm_simulate with invalid CIB (enum violation) - Invalid configuration (78) =#=#=#=
 * Passed: crm_simulate   - Run crm_simulate with invalid CIB (enum violation)
 =#=#=#= Begin test: Try to make resulting CIB invalid (unrecognized validate-with) =#=#=#=
    1 <cib epoch="3" num_updates="1" admin_epoch="0">
    2   <configuration>
    3     <crm_config/>
    4     <nodes/>
    5     <resources>
    6       <primitive id="dummy1" class="ocf" provider="pacemaker" type="Dummy"/>
    7       <primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>
    8     </resources>
    9     <constraints>
   10       <rsc_order id="ord_1-2" first="dummy1" first-action="start" then="dummy2"/>
   11     </constraints>
   12   </configuration>
   13   <status/>
   14 </cib>
   15 
 Call failed: Update does not conform to the configured schema
 =#=#=#= Current cib after: Try to make resulting CIB invalid (unrecognized validate-with) =#=#=#=
 <cib epoch="3" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config/>
     <nodes/>
     <resources>
       <primitive id="dummy1" class="ocf" provider="pacemaker" type="Dummy"/>
       <primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints>
       <rsc_order id="ord_1-2" first="dummy1" first-action="start" then="dummy2"/>
     </constraints>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: Try to make resulting CIB invalid (unrecognized validate-with) - Invalid configuration (78) =#=#=#=
 * Passed: cibadmin       - Try to make resulting CIB invalid (unrecognized validate-with)
 =#=#=#= Begin test: Run crm_simulate with invalid CIB (unrecognized validate-with) =#=#=#=
 update_validation 	debug: Unknown validation schema
 update_validation 	debug: Testing 'pacemaker-1.0' validation (0 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-1.0 validation failed
 update_validation 	debug: Testing 'pacemaker-1.2' validation (1 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-1.2 validation failed
 update_validation 	debug: Testing 'pacemaker-1.3' validation (2 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-1.3 validation failed
 update_validation 	debug: Testing 'pacemaker-2.0' validation (3 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.0 validation failed
 update_validation 	debug: Testing 'pacemaker-2.1' validation (4 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.1 validation failed
 update_validation 	debug: Testing 'pacemaker-2.2' validation (5 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.2 validation failed
 update_validation 	debug: Testing 'pacemaker-2.3' validation (6 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.3 validation failed
 update_validation 	debug: Testing 'pacemaker-2.4' validation (7 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.4 validation failed
 update_validation 	debug: Testing 'pacemaker-2.5' validation (8 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.5 validation failed
 update_validation 	debug: Testing 'pacemaker-2.6' validation (9 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.6 validation failed
 update_validation 	debug: Testing 'pacemaker-2.7' validation (10 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.7 validation failed
 update_validation 	debug: Testing 'pacemaker-2.8' validation (11 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.8 validation failed
 update_validation 	debug: Testing 'pacemaker-2.9' validation (12 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.9 validation failed
 update_validation 	debug: Testing 'pacemaker-2.10' validation (13 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.10 validation failed
 update_validation 	debug: Testing 'pacemaker-3.0' validation (14 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-3.0 validation failed
-Your current configuration pacemaker-9999.0 could not validate with any schema in range [unknown, pacemaker-3.0], cannot upgrade to pacemaker-3.0.
+update_validation 	debug: Testing 'pacemaker-3.1' validation (15 of X)
+element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
+update_validation 	trace: pacemaker-3.1 validation failed
+Your current configuration pacemaker-9999.0 could not validate with any schema in range [unknown, pacemaker-3.1], cannot upgrade to pacemaker-3.0.
 =#=#=#= End test: Run crm_simulate with invalid CIB (unrecognized validate-with) - Invalid configuration (78) =#=#=#=
 * Passed: crm_simulate   - Run crm_simulate with invalid CIB (unrecognized validate-with)
 =#=#=#= Begin test: Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1) =#=#=#=
    1 <cib epoch="3" num_updates="0" admin_epoch="0">
    2   <configuration>
    3     <crm_config/>
    4     <nodes/>
    5     <resources>
    6       <primitive id="dummy1" class="ocf" provider="pacemaker" type="Dummy"/>
    7       <primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>
    8     </resources>
    9     <constraints>
   10       <rsc_order id="ord_1-2" first="dummy1" first-action="start" then="dummy2"/>
   11     </constraints>
   12     <tags/>
   13   </configuration>
   14   <status/>
   15 </cib>
   16 
 Call failed: Update does not conform to the configured schema
 =#=#=#= Current cib after: Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1) =#=#=#=
 <cib epoch="3" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config/>
     <nodes/>
     <resources>
       <primitive id="dummy1" class="ocf" provider="pacemaker" type="Dummy"/>
       <primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints>
       <rsc_order id="ord_1-2" first="dummy1" first-action="start" then="dummy2"/>
     </constraints>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1) - Invalid configuration (78) =#=#=#=
 * Passed: cibadmin       - Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1)
 =#=#=#= Begin test: Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1) =#=#=#=
 update_validation 	debug: Testing 'pacemaker-1.2' validation (1 of X)
 element tags: Relax-NG validity error : Element configuration has extra content: tags
 update_validation 	trace: pacemaker-1.2 validation failed
 update_validation 	debug: Testing 'pacemaker-1.3' validation (2 of X)
-update_validation 	debug: Upgrading pacemaker-1.3-style configuration to pacemaker-2.0 with upgrade-1.3.xsl
-update_validation 	info: Transformation upgrade-1.3.xsl successful
+update_validation 	debug: pacemaker-1.3-style configuration is also valid for pacemaker-2.0
 update_validation 	debug: Testing 'pacemaker-2.0' validation (3 of X)
+update_validation 	debug: Configuration valid for schema: pacemaker-2.0
 update_validation 	debug: pacemaker-2.0-style configuration is also valid for pacemaker-2.1
 update_validation 	debug: Testing 'pacemaker-2.1' validation (4 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.1
 update_validation 	debug: pacemaker-2.1-style configuration is also valid for pacemaker-2.2
 update_validation 	debug: Testing 'pacemaker-2.2' validation (5 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.2
 update_validation 	debug: pacemaker-2.2-style configuration is also valid for pacemaker-2.3
 update_validation 	debug: Testing 'pacemaker-2.3' validation (6 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.3
 update_validation 	debug: pacemaker-2.3-style configuration is also valid for pacemaker-2.4
 update_validation 	debug: Testing 'pacemaker-2.4' validation (7 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.4
 update_validation 	debug: pacemaker-2.4-style configuration is also valid for pacemaker-2.5
 update_validation 	debug: Testing 'pacemaker-2.5' validation (8 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.5
 update_validation 	debug: pacemaker-2.5-style configuration is also valid for pacemaker-2.6
 update_validation 	debug: Testing 'pacemaker-2.6' validation (9 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.6
 update_validation 	debug: pacemaker-2.6-style configuration is also valid for pacemaker-2.7
 update_validation 	debug: Testing 'pacemaker-2.7' validation (10 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.7
 update_validation 	debug: pacemaker-2.7-style configuration is also valid for pacemaker-2.8
 update_validation 	debug: Testing 'pacemaker-2.8' validation (11 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.8
 update_validation 	debug: pacemaker-2.8-style configuration is also valid for pacemaker-2.9
 update_validation 	debug: Testing 'pacemaker-2.9' validation (12 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.9
 update_validation 	debug: pacemaker-2.9-style configuration is also valid for pacemaker-2.10
 update_validation 	debug: Testing 'pacemaker-2.10' validation (13 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.10
-update_validation 	debug: Upgrading pacemaker-2.10-style configuration to pacemaker-3.0 with upgrade-2.10.xsl
-update_validation 	info: Transformation upgrade-2.10.xsl successful
+update_validation 	debug: pacemaker-2.10-style configuration is also valid for pacemaker-3.0
 update_validation 	debug: Testing 'pacemaker-3.0' validation (14 of X)
-update_validation 	trace: Stopping at pacemaker-3.0
-update_validation 	info: Transformed the configuration from pacemaker-1.2 to pacemaker-3.0
+update_validation 	debug: Configuration valid for schema: pacemaker-3.0
+update_validation 	debug: pacemaker-3.0-style configuration is also valid for pacemaker-3.1
+update_validation 	debug: Testing 'pacemaker-3.1' validation (15 of X)
+update_validation 	debug: Configuration valid for schema: pacemaker-3.1
+update_validation 	trace: Stopping at pacemaker-3.1
+update_validation 	info: Transformed the configuration from pacemaker-1.2 to pacemaker-3.1
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 
 Current cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 Transition Summary:
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 
 Executing cluster transition:
 
 Revised cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 =#=#=#= End test: Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1) - OK (0) =#=#=#=
 * Passed: crm_simulate   - Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1)
 =#=#=#= Begin test: Make resulting CIB valid, although without validate-with attribute =#=#=#=
 =#=#=#= Current cib after: Make resulting CIB valid, although without validate-with attribute =#=#=#=
 <cib epoch="3" num_updates="1" admin_epoch="0" validate-with="none">
   <configuration>
     <crm_config/>
     <nodes/>
     <resources>
       <primitive id="dummy1" class="ocf" provider="pacemaker" type="Dummy"/>
       <primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints>
       <rsc_order id="ord_1-2" first="dummy1" first-action="start" then="dummy2"/>
     </constraints>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: Make resulting CIB valid, although without validate-with attribute - OK (0) =#=#=#=
 * Passed: cibadmin       - Make resulting CIB valid, although without validate-with attribute
 =#=#=#= Begin test: Run crm_simulate with valid CIB, but without validate-with attribute =#=#=#=
 Configuration validation is currently disabled. It is highly encouraged and prevents many common cluster issues.
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 
 Current cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 Transition Summary:
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 
 Executing cluster transition:
 
 Revised cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 =#=#=#= End test: Run crm_simulate with valid CIB, but without validate-with attribute - OK (0) =#=#=#=
 * Passed: crm_simulate   - Run crm_simulate with valid CIB, but without validate-with attribute
 =#=#=#= Begin test: Make resulting CIB invalid, and without validate-with attribute =#=#=#=
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
+element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
+element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 =#=#=#= Current cib after: Make resulting CIB invalid, and without validate-with attribute =#=#=#=
 <cib epoch="31" num_updates="0" admin_epoch="0" validate-with="none">
   <configuration>
     <crm_config/>
     <nodes/>
     <resources>
       <primitive id="dummy1" class="ocf" provider="pacemaker" type="Dummy"/>
       <primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints>
       <rsc_order id="ord_1-2" first="dummy1" first-action="break" then="dummy2"/>
     </constraints>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: Make resulting CIB invalid, and without validate-with attribute - OK (0) =#=#=#=
 * Passed: cibadmin       - Make resulting CIB invalid, and without validate-with attribute
 =#=#=#= Begin test: Run crm_simulate with invalid CIB, also without validate-with attribute =#=#=#=
 Configuration validation is currently disabled. It is highly encouraged and prevents many common cluster issues.
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
+validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
+validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 unpack_simple_rsc_order 	error: Cannot invert rsc_order constraint ord_1-2. Please specify the inverse manually.
 
 Current cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 Transition Summary:
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 
 Executing cluster transition:
 
 Revised cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 =#=#=#= End test: Run crm_simulate with invalid CIB, also without validate-with attribute - OK (0) =#=#=#=
 * Passed: crm_simulate   - Run crm_simulate with invalid CIB, also without validate-with attribute
diff --git a/cts/cts-cli.in b/cts/cts-cli.in
index 7abe4bbf2c..a917e87259 100755
--- a/cts/cts-cli.in
+++ b/cts/cts-cli.in
@@ -1,914 +1,967 @@
 #!@BASH_PATH@
 #
 # Copyright 2008-2018 Andrew Beekhof <andrew@beekhof.net>
 #
 # This source code is licensed under the GNU General Public License version 2
 # or later (GPLv2+) WITHOUT ANY WARRANTY.
 #
 
 #
 # Note on portable usage of sed: GNU/POSIX/*BSD sed have a limited subset of
 # compatible functionality. Do not use the -i option, alternation (\|),
 # \0, or character sequences such as \n or \s.
 #
 
 USAGE_TEXT="Usage: cts-cli [<options>]
 Options:
  --help          Display this text, then exit
  -V, --verbose   Display any differences from expected output
- -t 'TEST [...]' Run only specified tests (default: 'dates tools acls validity')
+ -t 'TEST [...]' Run only specified tests (default: 'dates tools acls validity upgrade')
  -p DIR          Look for executables in DIR (may be specified multiple times)
  -v, --valgrind  Run all commands under valgrind
  -s              Save actual output as expected output"
 
 # If readlink supports -e (i.e. GNU), use it
 readlink -e / >/dev/null 2>/dev/null
 if [ $? -eq 0 ]; then
     test_home="$(dirname $(readlink -e $0))"
 else
     test_home="$(dirname $0)"
 fi
 
 : ${shadow=cts-cli}
 shadow_dir=$(mktemp -d ${TMPDIR:-/tmp}/cts-cli.shadow.XXXXXXXXXX)
 num_errors=0
 num_passed=0
 GREP_OPTIONS=
 verbose=0
-tests="dates tools acls validity"
+tests="dates tools acls validity upgrade"
 do_save=0
 VALGRIND_CMD=
 VALGRIND_OPTS="
     -q
     --gen-suppressions=all
     --show-reachable=no
     --leak-check=full
     --trace-children=no
     --time-stamp=yes
     --num-callers=20
     --suppressions=$test_home/valgrind-pcmk.suppressions
 "
 
 # These constants must track crm_exit_t values
 CRM_EX_OK=0
 CRM_EX_ERROR=1
 CRM_EX_INSUFFICIENT_PRIV=4
 CRM_EX_USAGE=64
 CRM_EX_CONFIG=78
 CRM_EX_OLD=103
 CRM_EX_NOSUCH=105
 CRM_EX_UNSAFE=107
 CRM_EX_EXISTS=108
 CRM_EX_MULTIPLE=109
 
 function test_assert() {
     target=$1; shift
     cib=$1; shift
     app=`echo "$cmd" | sed 's/\ .*//'`
     printf "* Running: $app - $desc\n" 1>&2
 
     printf "=#=#=#= Begin test: $desc =#=#=#=\n"
     eval $VALGRIND_CMD $cmd 2>&1
     rc=$?
 
     if [ x$cib != x0 ]; then
         printf "=#=#=#= Current cib after: $desc =#=#=#=\n"
         CIB_user=root cibadmin -Q
     fi
 
     printf "=#=#=#= End test: $desc - $(crm_error --exit $rc) ($rc) =#=#=#=\n"
 
     if [ $rc -ne $target ]; then
         num_errors=$(( $num_errors + 1 ))
         printf "* Failed (rc=%.3d): %-14s - %s\n" $rc $app "$desc"
         printf "* Failed (rc=%.3d): %-14s - %s\n" $rc $app "$desc (`which $app`)" 1>&2
         return
         exit $CRM_EX_ERROR
     else
         printf "* Passed: %-14s - %s\n" $app "$desc"
         num_passed=$(( $num_passed + 1 ))
     fi
 }
 
 function test_tools() {
     local TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
     local TMPORIG=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.existing.xml.XXXXXXXXXX)
     export CIB_shadow_dir="${shadow_dir}"
 
     $VALGRIND_CMD crm_shadow --batch --force --create-empty $shadow  2>&1
     export CIB_shadow=$shadow
 
     desc="Validate CIB"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_OK
 
     desc="Configure something before erasing"
     cmd="crm_attribute -n cluster-delay -v 60s"
     test_assert $CRM_EX_OK
 
     desc="Require --force for CIB erasure"
     cmd="cibadmin -E"
     test_assert $CRM_EX_UNSAFE
 
     desc="Allow CIB erasure with --force"
     cmd="cibadmin -E --force"
     test_assert $CRM_EX_OK
 
     desc="Query CIB"
     cmd="cibadmin -Q > $TMPORIG"
     test_assert $CRM_EX_OK
 
     desc="Set cluster option"
     cmd="crm_attribute -n cluster-delay -v 60s"
     test_assert $CRM_EX_OK
 
     desc="Query new cluster option"
     cmd="cibadmin -Q -o crm_config | grep cib-bootstrap-options-cluster-delay"
     test_assert $CRM_EX_OK
 
     desc="Query cluster options"
     cmd="cibadmin -Q -o crm_config > $TMPXML"
     test_assert $CRM_EX_OK
 
     desc="Set no-quorum policy"
     cmd="crm_attribute -n no-quorum-policy -v ignore"
     test_assert $CRM_EX_OK
 
     desc="Delete nvpair"
     cmd="cibadmin -D -o crm_config --xml-text '<nvpair id=\"cib-bootstrap-options-cluster-delay\"/>'"
     test_assert $CRM_EX_OK
 
     desc="Create operation should fail"
     cmd="cibadmin -C -o crm_config --xml-file $TMPXML"
     test_assert $CRM_EX_EXISTS
 
     desc="Modify cluster options section"
     cmd="cibadmin -M -o crm_config --xml-file $TMPXML"
     test_assert $CRM_EX_OK
 
     desc="Query updated cluster option"
     cmd="cibadmin -Q -o crm_config | grep cib-bootstrap-options-cluster-delay"
     test_assert $CRM_EX_OK
 
     desc="Set duplicate cluster option"
     cmd="crm_attribute -n cluster-delay -v 40s -s duplicate"
     test_assert $CRM_EX_OK
 
     desc="Setting multiply defined cluster option should fail"
     cmd="crm_attribute -n cluster-delay -v 30s"
     test_assert $CRM_EX_MULTIPLE
 
     desc="Set cluster option with -s"
     cmd="crm_attribute -n cluster-delay -v 30s -s duplicate"
     test_assert $CRM_EX_OK
 
     desc="Delete cluster option with -i"
     cmd="crm_attribute -n cluster-delay -D -i cib-bootstrap-options-cluster-delay"
     test_assert $CRM_EX_OK
 
     desc="Create node1 and bring it online"
     cmd="crm_simulate --live-check --in-place --node-up=node1"
     test_assert $CRM_EX_OK
 
     desc="Create node attribute"
     cmd="crm_attribute -n ram -v 1024M -N node1 -t nodes"
     test_assert $CRM_EX_OK
 
     desc="Query new node attribute"
     cmd="cibadmin -Q -o nodes | grep node1-ram"
     test_assert $CRM_EX_OK
 
     desc="Set a transient (fail-count) node attribute"
     cmd="crm_attribute -n fail-count-foo -v 3 -N node1 -t status"
     test_assert $CRM_EX_OK
 
     desc="Query a fail count"
     cmd="crm_failcount --query -r foo -N node1"
     test_assert $CRM_EX_OK
 
     desc="Delete a transient (fail-count) node attribute"
     cmd="crm_attribute -n fail-count-foo -D -N node1 -t status"
     test_assert $CRM_EX_OK
 
     desc="Digest calculation"
     cmd="cibadmin -Q | cibadmin -5 -p 2>&1 > /dev/null"
     test_assert $CRM_EX_OK
 
     # This update will fail because it has version numbers
     desc="Replace operation should fail"
     cmd="cibadmin -R --xml-file $TMPORIG"
     test_assert $CRM_EX_OLD
 
     desc="Default standby value"
     cmd="crm_standby -N node1 -G"
     test_assert $CRM_EX_OK
  
     desc="Set standby status"
     cmd="crm_standby -N node1 -v true"
     test_assert $CRM_EX_OK
  
     desc="Query standby value"
     cmd="crm_standby -N node1 -G"
     test_assert $CRM_EX_OK
  
     desc="Delete standby value"
     cmd="crm_standby -N node1 -D"
     test_assert $CRM_EX_OK
 
     desc="Create a resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"dummy\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/>'"
     test_assert $CRM_EX_OK
 
     desc="Create a resource meta attribute"
     cmd="crm_resource -r dummy --meta -p is-managed -v false"
     test_assert $CRM_EX_OK
 
     desc="Query a resource meta attribute"
     cmd="crm_resource -r dummy --meta -g is-managed"
     test_assert $CRM_EX_OK
 
     desc="Remove a resource meta attribute"
     cmd="crm_resource -r dummy --meta -d is-managed"
     test_assert $CRM_EX_OK
 
     desc="Create a resource attribute"
     cmd="crm_resource -r dummy -p delay -v 10s"
     test_assert $CRM_EX_OK
 
     desc="List the configured resources"
     cmd="crm_resource -L"
     test_assert $CRM_EX_OK
 
     desc="Require a destination when migrating a resource that is stopped"
     cmd="crm_resource -r dummy -M"
     test_assert $CRM_EX_USAGE
 
     desc="Don't support migration to non-existent locations"
     cmd="crm_resource -r dummy -M -N i.dont.exist"
     test_assert $CRM_EX_NOSUCH
 
     desc="Create a fencing resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"Fence\" class=\"stonith\" type=\"fence_true\"/>'"
     test_assert $CRM_EX_OK
 
     desc="Bring resources online"
     cmd="crm_simulate --live-check --in-place -S"
     test_assert $CRM_EX_OK
 
     desc="Try to move a resource to its existing location"
     cmd="crm_resource -r dummy --move --host node1"
     test_assert $CRM_EX_EXISTS
 
     desc="Move a resource from its existing location"
     cmd="crm_resource -r dummy --move"
     test_assert $CRM_EX_OK
 
     desc="Clear out constraints generated by --move"
     cmd="crm_resource -r dummy --clear"
     test_assert $CRM_EX_OK
 
     desc="Default ticket granted state"
     cmd="crm_ticket -t ticketA -G granted -d false"
     test_assert $CRM_EX_OK
 
     desc="Set ticket granted state"
     cmd="crm_ticket -t ticketA -r --force"
     test_assert $CRM_EX_OK
 
     desc="Query ticket granted state"
     cmd="crm_ticket -t ticketA -G granted"
     test_assert $CRM_EX_OK
 
     desc="Delete ticket granted state"
     cmd="crm_ticket -t ticketA -D granted --force"
     test_assert $CRM_EX_OK
 
     desc="Make a ticket standby"
     cmd="crm_ticket -t ticketA -s"
     test_assert $CRM_EX_OK
 
     desc="Query ticket standby state"
     cmd="crm_ticket -t ticketA -G standby"
     test_assert $CRM_EX_OK
 
     desc="Activate a ticket"
     cmd="crm_ticket -t ticketA -a"
     test_assert $CRM_EX_OK
 
     desc="Delete ticket standby state"
     cmd="crm_ticket -t ticketA -D standby"
     test_assert $CRM_EX_OK
 
     desc="Ban a resource on unknown node"
     cmd="crm_resource -r dummy -B -N host1"
     test_assert $CRM_EX_NOSUCH
 
     desc="Create two more nodes and bring them online"
     cmd="crm_simulate --live-check --in-place --node-up=node2 --node-up=node3"
     test_assert $CRM_EX_OK
 
     desc="Ban dummy from node1"
     cmd="crm_resource -r dummy -B -N node1"
     test_assert $CRM_EX_OK
 
     desc="Ban dummy from node2"
     cmd="crm_resource -r dummy -B -N node2"
     test_assert $CRM_EX_OK
 
     desc="Relocate resources due to ban"
     cmd="crm_simulate --live-check --in-place -S"
     test_assert $CRM_EX_OK
 
     desc="Move dummy to node1"
     cmd="crm_resource -r dummy -M -N node1"
     test_assert $CRM_EX_OK
 
     desc="Clear implicit constraints for dummy on node2"
     cmd="crm_resource -r dummy -U -N node2"
     test_assert $CRM_EX_OK
 
     desc="Drop the status section"
     cmd="cibadmin -R -o status --xml-text '<status/>'"
     test_assert $CRM_EX_OK 0
     
     desc="Create a clone"
     cmd="cibadmin -C -o resources --xml-text '<clone id=\"test-clone\"><primitive id=\"test-primitive\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/></clone>'"
     test_assert $CRM_EX_OK 0
 
     desc="Create a resource meta attribute"
     cmd="crm_resource -r test-primitive --meta -p is-managed -v false"
     test_assert $CRM_EX_OK
 
     desc="Create a resource meta attribute in the primitive"
     cmd="crm_resource -r test-primitive --meta -p is-managed -v false --force"
     test_assert $CRM_EX_OK
 
     desc="Update resource meta attribute with duplicates"
     cmd="crm_resource -r test-clone --meta -p is-managed -v true"
     test_assert $CRM_EX_OK
 
     desc="Update resource meta attribute with duplicates (force clone)"
     cmd="crm_resource -r test-clone --meta -p is-managed -v true --force"
     test_assert $CRM_EX_OK
 
     desc="Update child resource meta attribute with duplicates"
     cmd="crm_resource -r test-primitive --meta -p is-managed -v false"
     test_assert $CRM_EX_OK
 
     desc="Delete resource meta attribute with duplicates"
     cmd="crm_resource -r test-clone --meta -d is-managed"
     test_assert $CRM_EX_OK
 
     desc="Delete resource meta attribute in parent"
     cmd="crm_resource -r test-primitive --meta -d is-managed"
     test_assert $CRM_EX_OK
 
     desc="Create a resource meta attribute in the primitive"
     cmd="crm_resource -r test-primitive --meta -p is-managed -v false --force"
     test_assert $CRM_EX_OK
 
     desc="Update existing resource meta attribute"
     cmd="crm_resource -r test-clone --meta -p is-managed -v true"
     test_assert $CRM_EX_OK
     
     desc="Create a resource meta attribute in the parent"
     cmd="crm_resource -r test-clone --meta -p is-managed -v true --force"
     test_assert $CRM_EX_OK
 
     desc="Copy resources"
     cmd="cibadmin -Q -o resources > $TMPXML"
     test_assert $CRM_EX_OK 0
 
     desc="Delete resource paremt meta attribute (force)"
     cmd="crm_resource -r test-clone --meta -d is-managed --force"
     test_assert $CRM_EX_OK
 
     desc="Restore duplicates"
     cmd="cibadmin -R -o resources --xml-file $TMPXML"
     test_assert $CRM_EX_OK
 
     desc="Delete resource child meta attribute"
     cmd="crm_resource -r test-primitive --meta -d is-managed"
     test_assert $CRM_EX_OK
 
     unset CIB_shadow_dir
     rm -f "$TMPXML" "$TMPORIG"
 }
 
 function test_dates() {
     desc="2014-01-01 00:30:00 - 1 Hour"
     cmd="iso8601 -d '2014-01-01 00:30:00Z' -D P-1H -E '2013-12-31 23:30:00Z'"
     test_assert $CRM_EX_OK 0
 
     for y in 06 07 08 09 10 11 12 13 14 15 16 17 18; do
         desc="20$y-W01-7"
         cmd="iso8601 -d '20$y-W01-7 00Z'"
         test_assert $CRM_EX_OK 0
 
         desc="20$y-W01-7 - round-trip"
         cmd="iso8601 -d '20$y-W01-7 00Z' -W -E '20$y-W01-7 00:00:00Z'"
         test_assert $CRM_EX_OK 0
 
         desc="20$y-W01-1"
         cmd="iso8601 -d '20$y-W01-1 00Z'"
         test_assert $CRM_EX_OK 0
 
         desc="20$y-W01-1 - round-trip"
         cmd="iso8601 -d '20$y-W01-1 00Z' -W -E '20$y-W01-1 00:00:00Z'"
         test_assert $CRM_EX_OK 0
     done
 
     desc="2009-W53-07"
     cmd="iso8601 -d '2009-W53-7 00:00:00Z' -W -E '2009-W53-7 00:00:00Z'"
     test_assert $CRM_EX_OK 0
 
     desc="2009-01-31 + 1 Month"
     cmd="iso8601 -d '2009-01-31 00:00:00Z' -D P1M -E '2009-02-28 00:00:00Z'"
     test_assert $CRM_EX_OK 0
 
     desc="2009-01-31 + 2 Months"
     cmd="iso8601 -d '2009-01-31 00:00:00Z' -D P2M -E '2009-03-31 00:00:00Z'"
     test_assert $CRM_EX_OK 0
 
     desc="2009-01-31 + 3 Months"
     cmd="iso8601 -d '2009-01-31 00:00:00Z' -D P3M -E '2009-04-30 00:00:00Z'"
     test_assert $CRM_EX_OK 0
 
     desc="2009-03-31 - 1 Month"
     cmd="iso8601 -d '2009-03-31 00:00:00Z' -D P-1M -E '2009-02-28 00:00:00Z'"
     test_assert $CRM_EX_OK 0
 }
 
 function test_acl_loop() {
     local TMPXML="$1"
 
     # Make sure we're rejecting things for the right reasons
     export PCMK_trace_functions=__xml_acl_check,__xml_acl_post_process
     export PCMK_stderr=1
 
     CIB_user=root cibadmin --replace --xml-text '<resources/>'
 
     export CIB_user=unknownguy
     desc="$CIB_user: Query configuration"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Set enable-acl"
     cmd="crm_attribute -n enable-acl -v false"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Set stonith-enabled"
     cmd="crm_attribute -n stonith-enabled -v false"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Create a resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"dummy\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/>'"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     export CIB_user=l33t-haxor
     desc="$CIB_user: Query configuration"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Set enable-acl"
     cmd="crm_attribute -n enable-acl -v false"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Set stonith-enabled"
     cmd="crm_attribute -n stonith-enabled -v false"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Create a resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"dummy\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/>'"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     export CIB_user=niceguy
     desc="$CIB_user: Query configuration"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_OK 0
 
     desc="$CIB_user: Set enable-acl"
     cmd="crm_attribute -n enable-acl -v false"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Set stonith-enabled"
     cmd="crm_attribute -n stonith-enabled -v false"
     test_assert $CRM_EX_OK
 
     desc="$CIB_user: Create a resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"dummy\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/>'"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     export CIB_user=root
     desc="$CIB_user: Query configuration"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_OK 0
 
     desc="$CIB_user: Set stonith-enabled"
     cmd="crm_attribute -n stonith-enabled -v true"
     test_assert $CRM_EX_OK
 
     desc="$CIB_user: Create a resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"dummy\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/>'"
     test_assert $CRM_EX_OK
 
     export CIB_user=l33t-haxor
 
     desc="$CIB_user: Create a resource meta attribute"
     cmd="crm_resource -r dummy --meta -p target-role -v Stopped"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Query a resource meta attribute"
     cmd="crm_resource -r dummy --meta -g target-role"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Remove a resource meta attribute"
     cmd="crm_resource -r dummy --meta -d target-role"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     export CIB_user=niceguy
 
     desc="$CIB_user: Create a resource meta attribute"
     cmd="crm_resource -r dummy --meta -p target-role -v Stopped"
     test_assert $CRM_EX_OK
 
     desc="$CIB_user: Query a resource meta attribute"
     cmd="crm_resource -r dummy --meta -g target-role"
     test_assert $CRM_EX_OK
 
     desc="$CIB_user: Remove a resource meta attribute"
     cmd="crm_resource -r dummy --meta -d target-role"
     test_assert $CRM_EX_OK
 
     desc="$CIB_user: Create a resource meta attribute"
     cmd="crm_resource -r dummy --meta -p target-role -v Started"
     test_assert $CRM_EX_OK
 
     export CIB_user=badidea
     desc="$CIB_user: Query configuration - implied deny"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_OK 0
 
     export CIB_user=betteridea
     desc="$CIB_user: Query configuration - explicit deny"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_OK 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --delete --xml-text '<acls/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     export CIB_user=niceguy
     desc="$CIB_user: Replace - remove acls"
     cmd="cibadmin --replace --xml-file $TMPXML"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -C -o resources --xml-text '<primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - create resource"
     cmd="cibadmin --replace --xml-file $TMPXML"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" crm_attribute -n enable-acl -v false
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - modify attribute (deny)"
     cmd="cibadmin --replace --xml-file $TMPXML"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --replace --xml-text '<nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - delete attribute (deny)"
     cmd="cibadmin --replace --xml-file $TMPXML"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text '<primitive id="dummy" description="nothing interesting"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - create attribute (deny)"
     cmd="cibadmin --replace --xml-file $TMPXML"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     CIB_user=bob
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text '<primitive id="dummy" description="nothing interesting"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - create attribute (allow)"
     cmd="cibadmin --replace -o resources --xml-file $TMPXML"
     test_assert $CRM_EX_OK 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text '<primitive id="dummy" description="something interesting"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - modify attribute (allow)"
     cmd="cibadmin --replace -o resources --xml-file $TMPXML"
     test_assert $CRM_EX_OK 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --replace -o resources --xml-text '<primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - delete attribute (allow)"
     cmd="cibadmin --replace -o resources --xml-file $TMPXML"
     test_assert $CRM_EX_OK 0
 }
 
 function test_acls() {
     local SHADOWPATH
     local TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.acls.xml.XXXXXXXXXX)
     export CIB_shadow_dir="${shadow_dir}"
 
     $VALGRIND_CMD crm_shadow --batch --force --create-empty $shadow --validate-with pacemaker-1.3 2>&1
     export CIB_shadow=$shadow
 
     cat <<EOF > "$TMPXML"
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
     </acls>
 EOF
 
     desc="Configure some ACLs"
     cmd="cibadmin -M -o acls --xml-file $TMPXML"
     test_assert $CRM_EX_OK
 
     desc="Enable ACLs"
     cmd="crm_attribute -n enable-acl -v true"
     test_assert $CRM_EX_OK
 
     desc="Set cluster option"
     cmd="crm_attribute -n no-quorum-policy -v ignore"
     test_assert $CRM_EX_OK
 
     desc="New ACL"
     cmd="cibadmin --create -o acls --xml-text '<acl_user id=\"badidea\"><read id=\"badidea-resources\" xpath=\"//meta_attributes\"/></acl_user>'"
     test_assert $CRM_EX_OK
 
     desc="Another ACL"
     cmd="cibadmin --create -o acls --xml-text '<acl_user id=\"betteridea\"><read id=\"betteridea-resources\" xpath=\"//meta_attributes\"/></acl_user>'"
     test_assert $CRM_EX_OK
 
     desc="Updated ACL"
     cmd="cibadmin --replace -o acls --xml-text '<acl_user id=\"betteridea\"><deny id=\"betteridea-nothing\" xpath=\"/cib\"/><read id=\"betteridea-resources\" xpath=\"//meta_attributes\"/></acl_user>'"
     test_assert $CRM_EX_OK
 
     test_acl_loop "$TMPXML"
 
     printf "\n\n    !#!#!#!#! Upgrading to latest CIB schema and re-testing !#!#!#!#!\n"
     printf "\nUpgrading to latest CIB schema and re-testing\n" 1>&2
 
     export CIB_user=root
     desc="$CIB_user: Upgrade to latest CIB schema"
     cmd="cibadmin --upgrade --force -V"
     test_assert $CRM_EX_OK
 
     SHADOWPATH="$(crm_shadow --file)"
     # sed -i isn't portable :-(
     cp -p "$SHADOWPATH" "${SHADOWPATH}.$$" # to keep permissions
     sed -e 's/epoch=.2/epoch=\"6/g' -e 's/admin_epoch=.1/admin_epoch=\"0/g' \
         "$SHADOWPATH" > "${SHADOWPATH}.$$"
     mv -- "${SHADOWPATH}.$$" "$SHADOWPATH"
 
     test_acl_loop "$TMPXML"
 
     unset CIB_shadow_dir
     rm -f "$TMPXML"
 }
 
 function test_validity() {
     local TMPGOOD=$(mktemp ${TMPDIR:-/tmp}/cts-cli.validity.good.xml.XXXXXXXXXX)
     local TMPBAD=$(mktemp ${TMPDIR:-/tmp}/cts-cli.validity.bad.xml.XXXXXXXXXX)
     export CIB_shadow_dir="${shadow_dir}"
 
     $VALGRIND_CMD crm_shadow --batch --force --create-empty $shadow --validate-with pacemaker-1.2 2>&1
     export CIB_shadow=$shadow
-    export PCMK_trace_functions=update_validation,cli_config_update
+    export PCMK_trace_functions=apply_upgrade,update_validation,cli_config_update
     export PCMK_stderr=1
 
     cibadmin -C -o resources --xml-text '<primitive id="dummy1" class="ocf" provider="pacemaker" type="Dummy"/>'
     cibadmin -C -o resources --xml-text '<primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>'
     cibadmin -C -o constraints --xml-text '<rsc_order id="ord_1-2" first="dummy1" first-action="start" then="dummy2"/>'
     cibadmin -Q > "$TMPGOOD"
 
 
     desc="Try to make resulting CIB invalid (enum violation)"
     cmd="cibadmin -M -o constraints --xml-text '<rsc_order id=\"ord_1-2\" first=\"dummy1\" first-action=\"break\" then=\"dummy2\"/>'"
     test_assert $CRM_EX_CONFIG
 
     sed 's|"start"|"break"|' "$TMPGOOD" > "$TMPBAD"
     desc="Run crm_simulate with invalid CIB (enum violation)"
     cmd="crm_simulate -x $TMPBAD -S"
     test_assert $CRM_EX_CONFIG 0
 
 
     desc="Try to make resulting CIB invalid (unrecognized validate-with)"
     cmd="cibadmin -M --xml-text '<cib validate-with=\"pacemaker-9999.0\"/>'"
     test_assert $CRM_EX_CONFIG
 
     sed 's|"pacemaker-1.2"|"pacemaker-9999.0"|' "$TMPGOOD" > "$TMPBAD"
     desc="Run crm_simulate with invalid CIB (unrecognized validate-with)"
     cmd="crm_simulate -x $TMPBAD -S"
     test_assert $CRM_EX_CONFIG 0
 
 
     desc="Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1)"
     cmd="cibadmin -C -o configuration --xml-text '<tags/>'"
     test_assert $CRM_EX_CONFIG
 
     sed 's|</configuration>|<tags/></configuration>|' "$TMPGOOD" > "$TMPBAD"
     desc="Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1)"
     cmd="crm_simulate -x $TMPBAD -S"
     test_assert $CRM_EX_OK 0
 
 
     sed 's|[ 	][ 	]*validate-with="[^"]*"||' "$TMPGOOD" > "$TMPBAD"
     desc="Make resulting CIB valid, although without validate-with attribute"
     cmd="cibadmin -R --xml-file $TMPBAD"
     test_assert $CRM_EX_OK
 
     desc="Run crm_simulate with valid CIB, but without validate-with attribute"
     cmd="crm_simulate -x $TMPBAD -S"
     test_assert $CRM_EX_OK 0
 
 
     # this will just disable validation and accept the config, outputting
     # validation errors
     sed -e 's|[ 	][ 	]*validate-with="[^"]*"||' \
         -e 's|\([ 	][ 	]*epoch="[^"]*\)"|\10"|' -e 's|"start"|"break"|' \
         "$TMPGOOD" > "$TMPBAD"
     desc="Make resulting CIB invalid, and without validate-with attribute"
     cmd="cibadmin -R --xml-file $TMPBAD"
     test_assert $CRM_EX_OK
 
     desc="Run crm_simulate with invalid CIB, also without validate-with attribute"
     cmd="crm_simulate -x $TMPBAD -S"
     test_assert $CRM_EX_OK 0
 
     unset CIB_shadow_dir
     rm -f "$TMPGOOD" "$TMPBAD"
 }
 
+test_upgrade() {
+    local TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
+    export CIB_shadow_dir="${shadow_dir}"
+
+    $VALGRIND_CMD crm_shadow --batch --force --create-empty $shadow --validate-with pacemaker-2.10 2>&1
+    export CIB_shadow=$shadow
+
+    desc="Set stonith-enabled=false"
+    cmd="crm_attribute -n stonith-enabled -v false"
+    test_assert $CRM_EX_OK
+
+    cat <<EOF > "$TMPXML"
+    <resources>
+      <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
+        <operations>
+          <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
+          <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s">
+            <instance_attributes id="mySmartFuse-inputpower-instanceparams">
+              <nvpair id="mySmartFuse-inputpower-requires" name="requires" value="inputpower"/>
+            </instance_attributes>
+          </op>
+          <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s">
+            <instance_attributes id="mySmartFuse-outputpower-instanceparams">
+              <nvpair id="mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+            </instance_attributes>
+          </op>
+        </operations>
+        <instance_attributes id="mySmartFuse-params">
+          <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+	<!-- a bit hairy but valid -->
+        <instance_attributes id-ref="mySmartFuse-outputpower-instanceparams"/>
+      </primitive>
+    </resources>
+EOF
+
+    desc="Configure the initial resource"
+    cmd="cibadmin -M -o resources --xml-file $TMPXML"
+    test_assert $CRM_EX_OK
+
+    desc="Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping)"
+    cmd="cibadmin --upgrade --force -V -V"
+    test_assert $CRM_EX_OK
+
+    desc="Query a resource instance attribute (shall survive)"
+    cmd="crm_resource -r mySmartFuse -g requires"
+    test_assert $CRM_EX_OK
+
+    unset CIB_shadow_dir
+    rm -f "$TMPXML"
+}
+
 # Process command-line arguments
 while [ $# -gt 0 ]; do
     case "$1" in
         -t)
             tests="$2"
             shift 2
             ;;
         -V|--verbose)
             verbose=1
             shift
             ;;
         -v|--valgrind)
             export G_SLICE=always-malloc
             VALGRIND_CMD="valgrind $VALGRIND_OPTS"
             shift
             ;;
         -s)
             do_save=1
             shift
             ;;
         -p)
             export PATH="$2:$PATH"
             shift
             ;;
         --help)
             echo "$USAGE_TEXT"
             exit $CRM_EX_OK
             ;;
         *)
             echo "error: unknown option $1"
             echo
             echo "$USAGE_TEXT"
             exit $CRM_EX_USAGE
             ;;
     esac
 done
 
 for t in $tests; do
     case "$t" in
         dates) ;;
         tools) ;;
         acls) ;;
         validity) ;;
+        upgrade) ;;
         *)
             echo "error: unknown test $t"
             echo
             echo "$USAGE_TEXT"
             exit $CRM_EX_USAGE
             ;;
     esac
 done
 
 # Check whether we're running from source directory
 SRCDIR=$(dirname $test_home)
 if [ -x "$SRCDIR/tools/crm_simulate" ]; then
     export PATH="$SRCDIR/tools:$PATH"
     echo "Using local binaries from: $SRCDIR/tools"
 
     if [ -x "$SRCDIR/xml" ]; then
         export PCMK_schema_directory="$SRCDIR/xml"
         echo "Using local schemas from: $PCMK_schema_directory"
     fi
 fi
 
 for t in $tests; do
     echo "Testing $t"
     TMPFILE=$(mktemp ${TMPDIR:-/tmp}/cts-cli.$t.XXXXXXXXXX)
     eval TMPFILE_$t="$TMPFILE"
     test_$t > "$TMPFILE"
 
     sed -e 's/cib-last-written.*>/>/'\
         -e 's/ last-run=\"[0-9]*\"//'\
         -e 's/crm_feature_set="[^"]*" //'\
         -e 's/validate-with="[^"]*" //'\
         -e 's/Created new pacemaker-.* configuration/Created new pacemaker configuration/'\
         -e 's/.*\(__xml_.*\)@.*\.c:[0-9][0-9]*)/\1/g' \
         -e 's/.*\(unpack_.*\)@.*\.c:[0-9][0-9]*)/\1/g' \
         -e 's/.*\(update_validation\)@.*\.c:[0-9][0-9]*)/\1/g' \
         -e 's/ last-rc-change=\"[0-9]*\"//'\
         -e 's|^/tmp/cts-cli\.validity\.bad.xml\.[^:]*:|validity.bad.xml:|'\
         -e 's/^Entity: line [0-9][0-9]*: //'\
         -e 's/\(validation ([0-9][0-9]* of \)[0-9][0-9]*\().*\)/\1X\2/' \
         "$TMPFILE" > "${TMPFILE}.$$"
     mv -- "${TMPFILE}.$$" "$TMPFILE"
 
     if [ $do_save -eq 1 ]; then
         cp "$TMPFILE" $test_home/cli/regression.$t.exp
     fi
 done
 
 rm -rf "${shadow_dir}"
     
 failed=0
 
 if [ $verbose -eq 1 ]; then
     echo -e "\n\nResults"
 fi
 for t in $tests; do
     eval TMPFILE="\$TMPFILE_$t"
     if [ $verbose -eq 1 ]; then
         diff -wu $test_home/cli/regression.$t.exp "$TMPFILE"
     else
         diff -w $test_home/cli/regression.$t.exp "$TMPFILE" >/dev/null 2>&1
     fi
     if [ $? -ne 0 ]; then
         failed=1
     fi
 done
 
 echo -e "\n\nSummary"
 for t in $tests; do
     eval TMPFILE="\$TMPFILE_$t"
     grep -e "^*" "$TMPFILE"
 done
 
 if [ $num_errors -ne 0 ]; then
     echo "$num_errors tests failed; see output in:"
     for t in $tests; do
         eval TMPFILE="\$TMPFILE_$t"
         echo "    $TMPFILE"
     done
     exit $CRM_EX_ERROR
 
 elif [ $failed -eq 1 ]; then
     echo "$num_passed tests passed but output was unexpected; see output in:"
     for t in $tests; do
         eval TMPFILE="\$TMPFILE_$t"
         echo "    $TMPFILE"
     done
     exit $CRM_EX_DIGEST
 
 else
     echo $num_passed tests passed
     for t in $tests; do
         eval TMPFILE="\$TMPFILE_$t"
         rm -f "$TMPFILE"
     done
     crm_shadow --force --delete $shadow >/dev/null 2>&1
     exit $CRM_EX_OK
 fi
diff --git a/include/crm/common/xml.h b/include/crm/common/xml.h
index 2697cece8c..fe2e1d51e5 100644
--- a/include/crm/common/xml.h
+++ b/include/crm/common/xml.h
@@ -1,395 +1,395 @@
 /*
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #ifndef CRM_COMMON_XML__H
 #  define CRM_COMMON_XML__H
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
  * \file
  * \brief Wrappers for and extensions to libxml2
  * \ingroup core
  */
 
 #  include <stdio.h>
 #  include <sys/types.h>
 #  include <unistd.h>
 
 #  include <stdlib.h>
 #  include <errno.h>
 #  include <fcntl.h>
 
 #  include <crm/crm.h>
 
 #  include <libxml/tree.h>
 #  include <libxml/xpath.h>
 
 /* Define compression parameters for IPC messages
  *
  * Compression costs a LOT, so we don't want to do it unless we're hitting
  * message limits. Currently, we use 128KB as the threshold, because higher
  * values don't play well with the heartbeat stack. With an earlier limit of
  * 10KB, compressing 184 of 1071 messages accounted for 23% of the total CPU
  * used by the cib.
  */
 #  define CRM_BZ2_BLOCKS		4
 #  define CRM_BZ2_WORK		20
 #  define CRM_BZ2_THRESHOLD	128 * 1024
 
 #  define XML_PARANOIA_CHECKS 0
 
 gboolean add_message_xml(xmlNode * msg, const char *field, xmlNode * xml);
 xmlNode *get_message_xml(xmlNode * msg, const char *field);
 GHashTable *xml2list(xmlNode * parent);
 
 xmlNode *crm_create_nvpair_xml(xmlNode *parent, const char *id,
                                const char *name, const char *value);
 
 void hash2nvpair(gpointer key, gpointer value, gpointer user_data);
 void hash2field(gpointer key, gpointer value, gpointer user_data);
 void hash2metafield(gpointer key, gpointer value, gpointer user_data);
 void hash2smartfield(gpointer key, gpointer value, gpointer user_data);
 
 xmlDoc *getDocPtr(xmlNode * node);
 
 /*
  * Replacement function for xmlCopyPropList which at the very least,
  * doesn't work the way *I* would expect it to.
  *
  * Copy all the attributes/properties from src into target.
  *
  * Not recursive, does not return anything.
  *
  */
 void copy_in_properties(xmlNode * target, xmlNode * src);
 void expand_plus_plus(xmlNode * target, const char *name, const char *value);
 void fix_plus_plus_recursive(xmlNode * target);
 
 /*
  * Create a node named "name" as a child of "parent"
  * If parent is NULL, creates an unconnected node.
  *
  * Returns the created node
  *
  */
 xmlNode *create_xml_node(xmlNode * parent, const char *name);
 
 /*
  * Make a copy of name and value and use the copied memory to create
  * an attribute for node.
  *
  * If node, name or value are NULL, nothing is done.
  *
  * If name or value are an empty string, nothing is done.
  *
  * Returns FALSE on failure and TRUE on success.
  *
  */
 const char *crm_xml_add(xmlNode * node, const char *name, const char *value);
 
 const char *crm_xml_replace(xmlNode * node, const char *name, const char *value);
 
 const char *crm_xml_add_int(xmlNode * node, const char *name, int value);
 const char *crm_xml_add_ms(xmlNode *node, const char *name, guint ms);
 
 
 /*!
  * \brief Add a boolean attribute to an XML object
  *
  * Add an attribute with the value XML_BOOLEAN_TRUE or XML_BOOLEAN_FALSE
  * as appropriate to an XML object.
  *
  * \param[in,out] node   XML object to add attribute to
  * \param[in]     name   Name of attribute to add
  * \param[in]     value  Boolean whose value will be tested
  *
  * \return Pointer to newly created XML attribute's content, or NULL on error
  */
 static inline const char *
 crm_xml_add_boolean(xmlNode *node, const char *name, gboolean value)
 {
     return crm_xml_add(node, name, (value? "true" : "false"));
 }
 
 /*
  *
  */
 void purge_diff_markers(xmlNode * a_node);
 
 /*
  * Returns a deep copy of src_node
  *
  */
 xmlNode *copy_xml(xmlNode * src_node);
 
 /*
  * Add a copy of xml_node to new_parent
  */
 xmlNode *add_node_copy(xmlNode * new_parent, xmlNode * xml_node);
 
 int add_node_nocopy(xmlNode * parent, const char *name, xmlNode * child);
 
 /*
  * XML I/O Functions
  *
  * Whitespace between tags is discarded.
  */
 xmlNode *filename2xml(const char *filename);
 
 xmlNode *stdin2xml(void);
 
 xmlNode *string2xml(const char *input);
 
 int write_xml_fd(xmlNode * xml_node, const char *filename, int fd, gboolean compress);
 int write_xml_file(xmlNode * xml_node, const char *filename, gboolean compress);
 
 char *dump_xml_formatted(xmlNode * msg);
 /* Also dump the text node with xml_log_option_text enabled */ 
 char *dump_xml_formatted_with_text(xmlNode * msg);
 
 char *dump_xml_unformatted(xmlNode * msg);
 
 /*
  * Diff related Functions
  */
 xmlNode *diff_xml_object(xmlNode * left, xmlNode * right, gboolean suppress);
 
 xmlNode *subtract_xml_object(xmlNode * parent, xmlNode * left, xmlNode * right,
                              gboolean full, gboolean * changed, const char *marker);
 
 gboolean can_prune_leaf(xmlNode * xml_node);
 
 gboolean apply_xml_diff(xmlNode *old_xml, xmlNode *diff, xmlNode **new_xml);
 
 /*
  * Searching & Modifying
  */
 xmlNode *find_xml_node(xmlNode * cib, const char *node_path, gboolean must_find);
 
 xmlNode *find_entity(xmlNode * parent, const char *node_name, const char *id);
 
 void xml_remove_prop(xmlNode * obj, const char *name);
 
 gboolean replace_xml_child(xmlNode * parent, xmlNode * child, xmlNode * update,
                            gboolean delete_only);
 
 gboolean update_xml_child(xmlNode * child, xmlNode * to_update);
 
 int find_xml_children(xmlNode ** children, xmlNode * root,
                       const char *tag, const char *field, const char *value,
                       gboolean search_matches);
 
 int crm_element_value_int(const xmlNode *data, const char *name, int *dest);
 int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest);
 char *crm_element_value_copy(const xmlNode *data, const char *name);
 xmlNode *get_xpath_object(const char *xpath, xmlNode * xml_obj, int error_level);
 xmlNode *get_xpath_object_relative(const char *xpath, xmlNode * xml_obj, int error_level);
 
 static inline const char *
 crm_element_name(const xmlNode *xml)
 {
     return xml? (const char *)(xml->name) : NULL;
 }
 
 const char *crm_element_value(const xmlNode *data, const char *name);
 
 /*!
  * \brief Copy an element from one XML object to another
  *
  * \param[in]     obj1     Source XML
  * \param[in,out] obj2     Destination XML
  * \param[in]     element  Name of element to copy
  *
  * \return Pointer to copied value (from source)
  */
 static inline const char *
 crm_copy_xml_element(xmlNode *obj1, xmlNode *obj2, const char *element)
 {
     const char *value = crm_element_value(obj1, element);
 
     crm_xml_add(obj2, element, value);
     return value;
 }
 
 gboolean xml_has_children(const xmlNode * root);
 
 char *calculate_on_disk_digest(xmlNode * local_cib);
 char *calculate_operation_digest(xmlNode * local_cib, const char *version);
 char *calculate_xml_versioned_digest(xmlNode * input, gboolean sort, gboolean do_filter,
                                      const char *version);
 
 /* schema-related functions (from schemas.c) */
 gboolean validate_xml(xmlNode * xml_blob, const char *validation, gboolean to_logs);
 gboolean validate_xml_verbose(xmlNode * xml_blob);
 
 /*!
  * \brief Update CIB XML to most recent schema version
  *
  * "Update" means either actively employ XSLT-based transformation(s)
  * (if intermediate product to transform valid per its declared schema version,
  * transformation available, proceeded successfully with a result valid per
  * expectated newer schema version), or just try to bump the marked validating
  * schema until all gradually rising schema versions attested or the first
  * such attempt subsequently fails to validate.   Which of the two styles will
  * be used depends on \p transform parameter (positive/negative, respectively).
  *
  * \param[in,out] xml_blob   XML tree representing CIB, may be swapped with
  *                           an "updated" one
  * \param[out]    best       The highest configuration version (per its index
  *                           in the global schemas table) it was possible to
  *                           reach during the update steps while ensuring
  *                           the validity of the result; if no validation
  *                           success was observed against possibly multiple
  *                           schemas, the value is less or equal the result
- *                           of <tt>get_schema_version</tt> applied on the
- *                           input \p xml_blob value (unless that function
- *                           maps it to -1, then 0 would be used instead)
+ *                           of \c get_schema_version applied on the input
+ *                           \p xml_blob value (unless that function maps it
+ *                           to -1, then 0 would be used instead)
  * \param[in]     max        When \p transform is positive, this allows to
  *                           set upper boundary schema (per its index in the
- *                           global schemas table) beyond which its forbidden
+ *                           global schemas table) beyond which it's forbidden
  *                           to update by the means of XSLT transformation
  * \param[in]     transform  Whether to employ XSLT-based transformation so
- *                           as allow overcoming possible incompatibilities
+ *                           as to allow overcoming possible incompatibilities
  *                           between major schema versions (see above)
  * \param[in]     to_logs    If true, output notable progress info to
  *                           internal log streams; if false, to stderr
  *
- * \return <tt>pcmk_ok</tt> if no non-recoverable error encountered (up to
+ * \return \c pcmk_ok if no non-recoverable error encountered (up to
  *         caller to evaluate if the update satisfies the requirements
  *         per returned \p best value), negative value carrying the reason
  *         otherwise
  */
 int update_validation(xmlNode **xml_blob, int *best, int max,
                       gboolean transform, gboolean to_logs);
 
 int get_schema_version(const char *name);
 const char *get_schema_name(int version);
 const char *xml_latest_schema(void);
 gboolean cli_config_update(xmlNode ** xml, int *best_version, gboolean to_logs);
 
 void crm_xml_init(void);
 void crm_xml_cleanup(void);
 
 static inline xmlNode *
 __xml_first_child(const xmlNode *parent)
 {
     xmlNode *child = parent? parent->children : NULL;
 
     while (child && (child->type == XML_TEXT_NODE)) {
         child = child->next;
     }
     return child;
 }
 
 static inline xmlNode *
 __xml_next(const xmlNode *child)
 {
     xmlNode *next = child? child->next : NULL;
 
     while (next && (next->type == XML_TEXT_NODE)) {
         next = next->next;
     }
     return next;
 }
 
 static inline xmlNode *
 __xml_first_child_element(const xmlNode *parent)
 {
     xmlNode *child = parent? parent->children : NULL;
 
     while (child && (child->type != XML_ELEMENT_NODE)) {
         child = child->next;
     }
     return child;
 }
 
 static inline xmlNode *
 __xml_next_element(const xmlNode *child)
 {
     xmlNode *next = child? child->next : NULL;
 
     while (next && (next->type != XML_ELEMENT_NODE)) {
         next = next->next;
     }
     return next;
 }
 
 void free_xml(xmlNode * child);
 
 xmlNode *first_named_child(const xmlNode *parent, const char *name);
 xmlNode *crm_next_same_xml(const xmlNode *sibling);
 
 xmlNode *sorted_xml(xmlNode * input, xmlNode * parent, gboolean recursive);
 xmlXPathObjectPtr xpath_search(xmlNode * xml_top, const char *path);
 void crm_foreach_xpath_result(xmlNode *xml, const char *xpath,
                               void (*helper)(xmlNode*, void*), void *user_data);
 xmlNode *expand_idref(xmlNode * input, xmlNode * top);
 
 void freeXpathObject(xmlXPathObjectPtr xpathObj);
 xmlNode *getXpathResult(xmlXPathObjectPtr xpathObj, int index);
 void dedupXpathResults(xmlXPathObjectPtr xpathObj);
 
 static inline int numXpathResults(xmlXPathObjectPtr xpathObj)
 {
     if(xpathObj == NULL || xpathObj->nodesetval == NULL) {
         return 0;
     }
     return xpathObj->nodesetval->nodeNr;
 }
 
 bool xml_acl_enabled(xmlNode *xml);
 void xml_acl_disable(xmlNode *xml);
 bool xml_acl_denied(xmlNode *xml); /* Part or all of a change was rejected */
 bool xml_acl_filtered_copy(const char *user, xmlNode* acl_source, xmlNode *xml, xmlNode ** result);
 
 bool xml_tracking_changes(xmlNode * xml);
 bool xml_document_dirty(xmlNode *xml);
 void xml_track_changes(xmlNode * xml, const char *user, xmlNode *acl_source, bool enforce_acls);
 void xml_calculate_changes(xmlNode *old_xml, xmlNode *new_xml);
 void xml_calculate_significant_changes(xmlNode *old_xml, xmlNode *new_xml);
 void xml_accept_changes(xmlNode * xml);
 void xml_log_changes(uint8_t level, const char *function, xmlNode *xml);
 void xml_log_patchset(uint8_t level, const char *function, xmlNode *xml);
 bool xml_patch_versions(xmlNode *patchset, int add[3], int del[3]);
 
 xmlNode *xml_create_patchset(
     int format, xmlNode *source, xmlNode *target, bool *config, bool manage_version);
 int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version);
 
 void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest);
 
 void save_xml_to_file(xmlNode * xml, const char *desc, const char *filename);
 char *xml_get_path(xmlNode *xml);
 
 char * crm_xml_escape(const char *text);
 void crm_xml_sanitize_id(char *id);
 void crm_xml_set_id(xmlNode *xml, const char *format, ...)
     __attribute__ ((__format__ (__printf__, 2, 3)));
 
 /*!
  * \brief xmlNode destructor which can be used in glib collections
  */
 void crm_destroy_xml(gpointer data);
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
index fc895daa2a..26f7aa5316 100644
--- a/lib/common/schemas.c
+++ b/lib/common/schemas.c
@@ -1,963 +1,1257 @@
 /*
  * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <stdio.h>
 #include <string.h>
 #include <dirent.h>
 #include <errno.h>
 #include <sys/stat.h>
 #include <stdarg.h>
 
 #include <libxml/relaxng.h>
 
 #if HAVE_LIBXSLT
 #  include <libxslt/xslt.h>
 #  include <libxslt/transform.h>
 #  include <libxslt/xsltutils.h>
 #endif
 
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/xml_internal.h>  /* CRM_XML_LOG_BASE */
 
 typedef struct {
     unsigned char v[2];
 } schema_version_t;
 
 #define SCHEMA_ZERO { .v = { 0, 0 } }
 
 #define schema_scanf(s, prefix, version, suffix) \
     sscanf((s), prefix "%hhu.%hhu" suffix, &((version).v[0]), &((version).v[1]))
 
 #define schema_strdup_printf(prefix, version, suffix) \
     crm_strdup_printf(prefix "%u.%u" suffix, (version).v[0], (version).v[1])
 
 typedef struct {
     xmlRelaxNGPtr rng;
     xmlRelaxNGValidCtxtPtr valid;
     xmlRelaxNGParserCtxtPtr parser;
 } relaxng_ctx_cache_t;
 
 enum schema_validator_e {
     schema_validator_none,
     schema_validator_rng
 };
 
 struct schema_s {
     char *name;
     char *location;
     char *transform;
     void *cache;
     enum schema_validator_e validator;
     int after_transform;
     schema_version_t version;
+    char *transform_enter;
+    bool transform_onleave;
 };
 
 static struct schema_s *known_schemas = NULL;
 static int xml_schema_max = 0;
+static bool silent_logging = FALSE;
 
 static void
 xml_log(int priority, const char *fmt, ...)
 G_GNUC_PRINTF(2, 3);
 
 static void
 xml_log(int priority, const char *fmt, ...)
 {
     va_list ap;
 
     va_start(ap, fmt);
-    /* XXX should not this enable dechunking as well? */
-    CRM_XML_LOG_BASE(priority, FALSE, 0, NULL, fmt, ap);
+    if (silent_logging == FALSE) {
+        /* XXX should not this enable dechunking as well? */
+        CRM_XML_LOG_BASE(priority, FALSE, 0, NULL, fmt, ap);
+    }
     va_end(ap);
 }
 
 static int
 xml_latest_schema_index(void)
 {
     return xml_schema_max - 3; // index from 0, ignore "pacemaker-next"/"none"
 }
 
 static int
 xml_minimum_schema_index(void)
 {
     static int best = 0;
     if (best == 0) {
         int lpc = 0;
 
         best = xml_latest_schema_index();
         for (lpc = best; lpc > 0; lpc--) {
             if (known_schemas[lpc].version.v[0]
                 < known_schemas[best].version.v[0]) {
                 return best;
             } else {
                 best = lpc;
             }
         }
         best = xml_latest_schema_index();
     }
     return best;
 }
 
 const char *
 xml_latest_schema(void)
 {
     return get_schema_name(xml_latest_schema_index());
 }
 
 static const char *
 get_schema_root(void)
 {
     static const char *base = NULL;
 
     if (base == NULL) {
         base = getenv("PCMK_schema_directory");
     }
     if (base == NULL || strlen(base) == 0) {
         base = CRM_SCHEMA_DIRECTORY;
     }
     return base;
 }
 
 static char *
 get_schema_path(const char *name, const char *file)
 {
     const char *base = get_schema_root();
 
     if (file) {
         return crm_strdup_printf("%s/%s", base, file);
     }
     return crm_strdup_printf("%s/%s.rng", base, name);
 }
 
 static inline bool
 version_from_filename(const char *filename, schema_version_t *version)
 {
     int rc = schema_scanf(filename, "pacemaker-", *version, ".rng");
 
     return (rc == 2);
 }
 
 static int
 schema_filter(const struct dirent *a)
 {
     int rc = 0;
     schema_version_t version = SCHEMA_ZERO;
 
     if (strstr(a->d_name, "pacemaker-") != a->d_name) {
         /* crm_trace("%s - wrong prefix", a->d_name); */
 
     } else if (!crm_ends_with_ext(a->d_name, ".rng")) {
         /* crm_trace("%s - wrong suffix", a->d_name); */
 
     } else if (!version_from_filename(a->d_name, &version)) {
         /* crm_trace("%s - wrong format", a->d_name); */
 
     } else {
         /* crm_debug("%s - candidate", a->d_name); */
         rc = 1;
     }
 
     return rc;
 }
 
 static int
 schema_sort(const struct dirent **a, const struct dirent **b)
 {
     schema_version_t a_version = SCHEMA_ZERO;
     schema_version_t b_version = SCHEMA_ZERO;
 
     if (!version_from_filename(a[0]->d_name, &a_version)
         || !version_from_filename(b[0]->d_name, &b_version)) {
         // Shouldn't be possible, but makes static analysis happy
         return 0;
     }
 
     for (int i = 0; i < 2; ++i) {
         if (a_version.v[i] < b_version.v[i]) {
             return -1;
         } else if (a_version.v[i] > b_version.v[i]) {
             return 1;
         }
     }
     return 0;
 }
 
+/*!
+ * \internal
+ * \brief Add given schema + auxiliary data to internal bookkeeping.
+ *
+ * \note When providing \p version, should not be called directly but
+ *       through \c add_schema_by_version.
+ */
 static void
 add_schema(enum schema_validator_e validator, const schema_version_t *version,
            const char *name, const char *location, const char *transform,
+           const char *transform_enter, bool transform_onleave,
            int after_transform)
 {
     int last = xml_schema_max;
     bool have_version = FALSE;
 
     xml_schema_max++;
     known_schemas = realloc_safe(known_schemas,
                                  xml_schema_max * sizeof(struct schema_s));
     CRM_ASSERT(known_schemas != NULL);
     memset(known_schemas+last, 0, sizeof(struct schema_s));
     known_schemas[last].validator = validator;
     known_schemas[last].after_transform = after_transform;
 
     for (int i = 0; i < 2; ++i) {
         known_schemas[last].version.v[i] = version->v[i];
         if (version->v[i]) {
             have_version = TRUE;
         }
     }
     if (have_version) {
         known_schemas[last].name = schema_strdup_printf("pacemaker-", *version, "");
         known_schemas[last].location = crm_strdup_printf("%s.rng",
                                                          known_schemas[last].name);
     } else {
         CRM_ASSERT(name);
         CRM_ASSERT(location);
         schema_scanf(name, "%*[^-]-", known_schemas[last].version, "");
         known_schemas[last].name = strdup(name);
         known_schemas[last].location = strdup(location);
     }
 
     if (transform) {
         known_schemas[last].transform = strdup(transform);
     }
+    if (transform_enter) {
+        known_schemas[last].transform_enter = strdup(transform_enter);
+    }
+    known_schemas[last].transform_onleave = transform_onleave;
     if (after_transform == 0) {
         after_transform = xml_schema_max;  /* upgrade is a one-way */
     }
     known_schemas[last].after_transform = after_transform;
 
     if (known_schemas[last].after_transform < 0) {
         crm_debug("Added supported schema %d: %s (%s)",
                   last, known_schemas[last].name, known_schemas[last].location);
 
     } else if (known_schemas[last].transform) {
         crm_debug("Added supported schema %d: %s (%s upgrades to %d with %s)",
                   last, known_schemas[last].name, known_schemas[last].location,
                   known_schemas[last].after_transform,
                   known_schemas[last].transform);
 
     } else {
         crm_debug("Added supported schema %d: %s (%s upgrades to %d)",
                   last, known_schemas[last].name, known_schemas[last].location,
                   known_schemas[last].after_transform);
     }
 }
 
+/*!
+ * \internal
+ * \brief Add version-specified schema + auxiliary data to internal bookkeeping.
+ * \return \c -ENOENT when no upgrade schema associated, \c pcmk_ok otherwise.
+ *
+ * \note There's no reliance on the particular order of schemas entering here.
+ *
+ * \par A bit of theory
+ * We track 3 XSLT stylesheets that differ per usage:
+ * - "upgrade":
+ *   . sparsely spread over the sequence of all available schemas,
+ *     as they are only relevant when major version of the schema
+ *     is getting bumped -- in that case, it MUST be set
+ *   . name convention:  upgrade-X.Y.xsl
+ * - "upgrade-enter":
+ *   . may only accompany "upgrade" occurrence, but doesn't need to
+ *     be present anytime such one is, i.e., it MAY not be set when
+ *     "upgrade" is
+ *   . name convention:  upgrade-X.Y-enter.xsl,
+ *     when not present: upgrade-enter.xsl
+ * - "upgrade-leave":
+ *   . like "upgrade-enter", but SHOULD be present whenever
+ *     "upgrade-enter" is
+ *   . name convention:  (see "upgrade-enter")
+ */
+static int
+add_schema_by_version(const schema_version_t *version, int next,
+                      bool transform_expected)
+{
+    bool transform_onleave = FALSE;
+    int rc = pcmk_ok;
+    struct stat s;
+    char *xslt = NULL,
+         *transform_upgrade = NULL,
+         *transform_enter = NULL;
+
+    /* prologue for further transform_expected handling */
+    if (transform_expected) {
+        /* check if there's suitable "upgrade" stylesheet */
+        transform_upgrade = schema_strdup_printf("upgrade-", *version, ".xsl");
+        xslt = get_schema_path(NULL, transform_upgrade);
+    }
+
+    if (!transform_expected) {
+        /* jump directly to the end */
+
+    } else if (stat(xslt, &s) == 0) {
+        /* perhaps there's also a targeted "upgrade-enter" stylesheet */
+        transform_enter = schema_strdup_printf("upgrade-", *version, "-enter.xsl");
+        free(xslt);
+        xslt = get_schema_path(NULL, transform_enter);
+        if (stat(xslt, &s) != 0) {
+            /* or initially, at least a generic one */
+            crm_debug("Upgrade-enter transform %s not found", xslt);
+            free(xslt);
+            xslt = get_schema_path(NULL, "upgrade-enter.xsl");
+            if (stat(xslt, &s) != 0) {
+                crm_debug("Upgrade-enter transform %s not found, either", xslt);
+                free(xslt);
+                xslt = NULL;
+            }
+        }
+        /* xslt contains full path to "upgrade-enter" stylesheet */
+        if (xslt != NULL) {
+            /* then there should be "upgrade-leave" counterpart */
+            memcpy(strrchr(xslt, '-') + 1, "leave", 5);  /* enter -> leave */
+            transform_onleave = (stat(xslt, &s) == 0);
+            free(xslt);
+        } else {
+            free(transform_enter);
+            transform_enter = NULL;
+        }
+
+    } else {
+        crm_err("Upgrade transform %s not found", xslt);
+        free(xslt);
+        free(transform_upgrade);
+        transform_upgrade = NULL;
+        next = -1;
+        rc = -ENOENT;
+    }
+
+    add_schema(schema_validator_rng, version, NULL, NULL,
+               transform_upgrade, transform_enter, transform_onleave, next);
+
+    free(transform_upgrade);
+    free(transform_enter);
+
+    return rc;
+}
+
 /*!
  * \internal
  * \brief Load pacemaker schemas into cache
  */
 void
 crm_schema_init(void)
 {
     int lpc, max;
     const char *base = get_schema_root();
     struct dirent **namelist = NULL;
     const schema_version_t zero = SCHEMA_ZERO;
 
     max = scandir(base, &namelist, schema_filter, schema_sort);
     if (max < 0) {
         crm_notice("scandir(%s) failed: %s (%d)", base, strerror(errno), errno);
 
     } else {
         for (lpc = 0; lpc < max; lpc++) {
+            bool transform_expected = FALSE;
             int next = 0;
             schema_version_t version = SCHEMA_ZERO;
-            char *transform = NULL;
 
             if (!version_from_filename(namelist[lpc]->d_name, &version)) {
                 // Shouldn't be possible, but makes static analysis happy
                 crm_err("Skipping schema '%s': could not parse version",
                         namelist[lpc]->d_name);
                 continue;
             }
             if ((lpc + 1) < max) {
                 schema_version_t next_version = SCHEMA_ZERO;
 
                 if (version_from_filename(namelist[lpc+1]->d_name, &next_version)
-                    && (version.v[0] < next_version.v[0])) {
-
-                    struct stat s;
-                    char *xslt = NULL;
-
-                    transform = schema_strdup_printf("upgrade-", version, ".xsl");
-                    xslt = get_schema_path(NULL, transform);
-                    if (stat(xslt, &s) != 0) {
-                        crm_err("Transform %s not found", xslt);
-                        free(xslt);
-                        add_schema(schema_validator_rng, &version, NULL, NULL,
-                                   NULL, -1);
-                        break;
-                    } else {
-                        free(xslt);
-                    }
+                        && (version.v[0] < next_version.v[0])) {
+                    transform_expected = TRUE;
                 }
 
             } else {
                 next = -1;
             }
-            add_schema(schema_validator_rng, &version, NULL, NULL, transform,
-                       next);
-            free(transform);
+            if (add_schema_by_version(&version, next, transform_expected)
+                    == -ENOENT) {
+                break;
+            }
         }
 
         for (lpc = 0; lpc < max; lpc++) {
             free(namelist[lpc]);
         }
         free(namelist);
     }
 
     add_schema(schema_validator_rng, &zero, "pacemaker-next",
-               "pacemaker-next.rng", NULL, -1);
+               "pacemaker-next.rng", NULL, NULL, FALSE, -1);
 
     add_schema(schema_validator_none, &zero, "none",
-               "N/A", NULL, -1);
+               "N/A", NULL, NULL, FALSE, -1);
 }
 
 #if 0
 static void
 relaxng_invalid_stderr(void *userData, xmlErrorPtr error)
 {
     /*
        Structure xmlError
        struct _xmlError {
        int      domain  : What part of the library raised this er
        int      code    : The error code, e.g. an xmlParserError
        char *   message : human-readable informative error messag
        xmlErrorLevel    level   : how consequent is the error
        char *   file    : the filename
        int      line    : the line number if available
        char *   str1    : extra string information
        char *   str2    : extra string information
        char *   str3    : extra string information
        int      int1    : extra number information
        int      int2    : column number of the error or 0 if N/A
        void *   ctxt    : the parser context if available
        void *   node    : the node in the tree
        }
      */
     crm_err("Structured error: line=%d, level=%d %s", error->line, error->level, error->message);
 }
 #endif
 
 static gboolean
 validate_with_relaxng(xmlDocPtr doc, gboolean to_logs, const char *relaxng_file,
                       relaxng_ctx_cache_t **cached_ctx)
 {
     int rc = 0;
     gboolean valid = TRUE;
     relaxng_ctx_cache_t *ctx = NULL;
 
     CRM_CHECK(doc != NULL, return FALSE);
     CRM_CHECK(relaxng_file != NULL, return FALSE);
 
     if (cached_ctx && *cached_ctx) {
         ctx = *cached_ctx;
 
     } else {
         crm_info("Creating RNG parser context");
         ctx = calloc(1, sizeof(relaxng_ctx_cache_t));
 
         xmlLoadExtDtdDefaultValue = 1;
         ctx->parser = xmlRelaxNGNewParserCtxt(relaxng_file);
         CRM_CHECK(ctx->parser != NULL, goto cleanup);
 
         if (to_logs) {
             xmlRelaxNGSetParserErrors(ctx->parser,
                                       (xmlRelaxNGValidityErrorFunc) xml_log,
                                       (xmlRelaxNGValidityWarningFunc) xml_log,
                                       GUINT_TO_POINTER(LOG_ERR));
         } else {
             xmlRelaxNGSetParserErrors(ctx->parser,
                                       (xmlRelaxNGValidityErrorFunc) fprintf,
                                       (xmlRelaxNGValidityWarningFunc) fprintf,
                                       stderr);
         }
 
         ctx->rng = xmlRelaxNGParse(ctx->parser);
         CRM_CHECK(ctx->rng != NULL,
                   crm_err("Could not find/parse %s", relaxng_file);
                   goto cleanup);
 
         ctx->valid = xmlRelaxNGNewValidCtxt(ctx->rng);
         CRM_CHECK(ctx->valid != NULL, goto cleanup);
 
         if (to_logs) {
             xmlRelaxNGSetValidErrors(ctx->valid,
                                      (xmlRelaxNGValidityErrorFunc) xml_log,
                                      (xmlRelaxNGValidityWarningFunc) xml_log,
                                      GUINT_TO_POINTER(LOG_ERR));
         } else {
             xmlRelaxNGSetValidErrors(ctx->valid,
                                      (xmlRelaxNGValidityErrorFunc) fprintf,
                                      (xmlRelaxNGValidityWarningFunc) fprintf,
                                      stderr);
         }
     }
 
     /* xmlRelaxNGSetValidStructuredErrors( */
     /*  valid, relaxng_invalid_stderr, valid); */
 
     xmlLineNumbersDefault(1);
     rc = xmlRelaxNGValidateDoc(ctx->valid, doc);
     if (rc > 0) {
         valid = FALSE;
 
     } else if (rc < 0) {
         crm_err("Internal libxml error during validation");
     }
 
   cleanup:
 
     if (cached_ctx) {
         *cached_ctx = ctx;
 
     } else {
         if (ctx->parser != NULL) {
             xmlRelaxNGFreeParserCtxt(ctx->parser);
         }
         if (ctx->valid != NULL) {
             xmlRelaxNGFreeValidCtxt(ctx->valid);
         }
         if (ctx->rng != NULL) {
             xmlRelaxNGFree(ctx->rng);
         }
         free(ctx);
     }
 
     return valid;
 }
 
 /*!
  * \internal
  * \brief Clean up global memory associated with XML schemas
  */
 void
 crm_schema_cleanup(void)
 {
     int lpc;
     relaxng_ctx_cache_t *ctx = NULL;
 
     for (lpc = 0; lpc < xml_schema_max; lpc++) {
 
         switch (known_schemas[lpc].validator) {
             case schema_validator_none: // not cached
                 break;
             case schema_validator_rng: // cached
                 ctx = (relaxng_ctx_cache_t *) known_schemas[lpc].cache;
                 if (ctx == NULL) {
                     break;
                 }
                 if (ctx->parser != NULL) {
                     xmlRelaxNGFreeParserCtxt(ctx->parser);
                 }
                 if (ctx->valid != NULL) {
                     xmlRelaxNGFreeValidCtxt(ctx->valid);
                 }
                 if (ctx->rng != NULL) {
                     xmlRelaxNGFree(ctx->rng);
                 }
                 free(ctx);
                 known_schemas[lpc].cache = NULL;
                 break;
         }
         free(known_schemas[lpc].name);
         free(known_schemas[lpc].location);
         free(known_schemas[lpc].transform);
+        free(known_schemas[lpc].transform_enter);
     }
     free(known_schemas);
     known_schemas = NULL;
 
     xsltCleanupGlobals();  /* XXX proper, explicit reshaking regarding
                                   init/fini routines is pending (pair
                                   of facade functions to express the
                                   intentions in a clean way) */
 }
 
 static gboolean
 validate_with(xmlNode *xml, int method, gboolean to_logs)
 {
     xmlDocPtr doc = NULL;
     gboolean valid = FALSE;
     char *file = NULL;
 
     if (method < 0) {
         return FALSE;
     }
 
     if (known_schemas[method].validator == schema_validator_none) {
         return TRUE;
     }
 
     CRM_CHECK(xml != NULL, return FALSE);
     doc = getDocPtr(xml);
     file = get_schema_path(known_schemas[method].name,
                            known_schemas[method].location);
 
     crm_trace("Validating with: %s (type=%d)",
               crm_str(file), known_schemas[method].validator);
     switch (known_schemas[method].validator) {
         case schema_validator_rng:
             valid =
                 validate_with_relaxng(doc, to_logs, file,
                                       (relaxng_ctx_cache_t **) & (known_schemas[method].cache));
             break;
         default:
             crm_err("Unknown validator type: %d",
                     known_schemas[method].validator);
             break;
     }
 
     free(file);
     return valid;
 }
 
+static bool
+validate_with_silent(xmlNode *xml, int method)
+{
+    bool rc, sl_backup = silent_logging;
+    silent_logging = TRUE;
+    rc = validate_with(xml, method, TRUE);
+    silent_logging = sl_backup;
+    return rc;
+}
+
 static void
 dump_file(const char *filename)
 {
 
     FILE *fp = NULL;
     int ch, line = 0;
 
     CRM_CHECK(filename != NULL, return);
 
     fp = fopen(filename, "r");
     if (fp == NULL) {
         crm_perror(LOG_ERR, "Could not open %s for reading", filename);
         return;
     }
 
     fprintf(stderr, "%4d ", ++line);
     do {
         ch = getc(fp);
         if (ch == EOF) {
             putc('\n', stderr);
             break;
         } else if (ch == '\n') {
             fprintf(stderr, "\n%4d ", ++line);
         } else {
             putc(ch, stderr);
         }
     } while (1);
 
     fclose(fp);
 }
 
 gboolean
 validate_xml_verbose(xmlNode *xml_blob)
 {
     int fd = 0;
     xmlDoc *doc = NULL;
     xmlNode *xml = NULL;
     gboolean rc = FALSE;
     char *filename = NULL;
 
     filename = crm_strdup_printf("%s/cib-invalid.XXXXXX", crm_get_tmpdir());
 
     umask(S_IWGRP | S_IWOTH | S_IROTH);
     fd = mkstemp(filename);
     write_xml_fd(xml_blob, filename, fd, FALSE);
 
     dump_file(filename);
 
     doc = xmlParseFile(filename);
     xml = xmlDocGetRootElement(doc);
     rc = validate_xml(xml, NULL, FALSE);
     free_xml(xml);
 
     unlink(filename);
     free(filename);
 
     return rc;
 }
 
 gboolean
 validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
 {
     int version = 0;
 
     if (validation == NULL) {
         validation = crm_element_value(xml_blob, XML_ATTR_VALIDATION);
     }
 
     if (validation == NULL) {
         int lpc = 0;
         bool valid = FALSE;
 
         for (lpc = 0; lpc < xml_schema_max; lpc++) {
             if (validate_with(xml_blob, lpc, FALSE)) {
                 valid = TRUE;
                 crm_xml_add(xml_blob, XML_ATTR_VALIDATION,
                             known_schemas[lpc].name);
                 crm_info("XML validated against %s", known_schemas[lpc].name);
                 if(known_schemas[lpc].after_transform == 0) {
                     break;
                 }
             }
         }
 
         return valid;
     }
 
     version = get_schema_version(validation);
     if (strcmp(validation, "none") == 0) {
         return TRUE;
     } else if (version < xml_schema_max) {
         return validate_with(xml_blob, version, to_logs);
     }
 
     crm_err("Unknown validator: %s", validation);
     return FALSE;
 }
 
 #if HAVE_LIBXSLT
 
 static void
 cib_upgrade_err(void *ctx, const char *fmt, ...)
 G_GNUC_PRINTF(2, 3);
 
+/* With this arrangement, an attempt to identify the message severity
+   as explicitly signalled directly from XSLT is performed in rather
+   a smart way (no reliance on formatting string + arguments being
+   always specified as ["%s", purposeful_string], as it can also be
+   ["%s: %s", some_prefix, purposeful_string] etc. so every argument
+   pertaining %s specifier is investigated), and if such a mark found,
+   the respective level is determined and, when the messages are to go
+   to the native logs, the mark itself gets dropped
+   (by the means of string shift).
+
+   NOTE: whether the native logging is the right sink is decided per
+         the ctx parameter -- NULL denotes this case, otherwise it
+         carries a pointer to the numeric expression of the desired
+         target logging level (messages with higher level will be
+         suppressed)
+
+   NOTE: on some architectures, this string shift may not have any
+         effect, but that's an acceptable tradeoff
+
+   The logging level for not explicitly designated messages
+   (suspicious, likely internal errors or some runaways) is
+   LOG_WARNING.
+ */
 static void
 cib_upgrade_err(void *ctx, const char *fmt, ...)
 {
-    va_list ap;
+    va_list ap, aq;
+    char *arg_cur;
+
+    bool found = FALSE;
+    const char *fmt_iter = fmt;
+    uint8_t msg_log_level = LOG_WARNING;  /* default for runaway messages */
+    const unsigned * log_level = (const unsigned *) ctx;
+    enum {
+        escan_seennothing,
+        escan_seenpercent,
+    } scan_state = escan_seennothing;
 
     va_start(ap, fmt);
-    CRM_XML_LOG_BASE(LOG_WARNING, TRUE, 0, "CIB upgrade: ", fmt, ap);
+    va_copy(aq, ap);
+
+    while (!found && *fmt_iter != '\0') {
+        /* while casing schema borrowed from libqb:qb_vsnprintf_serialize */
+        switch (*fmt_iter++) {
+        case '%':
+            if (scan_state == escan_seennothing) {
+                scan_state = escan_seenpercent;
+            } else if (scan_state == escan_seenpercent) {
+                scan_state = escan_seennothing;
+            }
+            break;
+        case 's':
+            if (scan_state == escan_seenpercent) {
+                scan_state = escan_seennothing;
+                arg_cur = va_arg(aq, char *);
+                if (arg_cur != NULL) {
+                    switch (arg_cur[0]) {
+                    case 'W':
+                        if (!strncmp(arg_cur, "WARNING: ",
+                                     sizeof("WARNING: ") - 1)) {
+                            msg_log_level = LOG_WARNING;
+                        }
+                        if (ctx == NULL) {
+                            memmove(arg_cur, arg_cur + sizeof("WARNING: ") - 1,
+                                    strlen(arg_cur + sizeof("WARNING: ") - 1) + 1);
+                        }
+                        found = TRUE;
+                        break;
+                    case 'I':
+                        if (!strncmp(arg_cur, "INFO: ",
+                                     sizeof("INFO: ") - 1)) {
+                            msg_log_level = LOG_INFO;
+                        }
+                        if (ctx == NULL) {
+                            memmove(arg_cur, arg_cur + sizeof("INFO: ") - 1,
+                                    strlen(arg_cur + sizeof("INFO: ") - 1) + 1);
+                        }
+                        found = TRUE;
+                        break;
+                    case 'D':
+                        if (!strncmp(arg_cur, "DEBUG: ",
+                                     sizeof("DEBUG: ") - 1)) {
+                            msg_log_level = LOG_DEBUG;
+                        }
+                        if (ctx == NULL) {
+                            memmove(arg_cur, arg_cur + sizeof("DEBUG: ") - 1,
+                                    strlen(arg_cur + sizeof("DEBUG: ") - 1) + 1);
+                        }
+                        found = TRUE;
+                        break;
+                    }
+                }
+            }
+            break;
+        case '#': case '-': case ' ': case '+': case '\'': case 'I': case '.':
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+        case '*':
+            break;
+        case 'l':
+        case 'z':
+        case 't':
+        case 'j':
+        case 'd': case 'i':
+        case 'o':
+        case 'u':
+        case 'x': case 'X':
+        case 'e': case 'E':
+        case 'f': case 'F':
+        case 'g': case 'G':
+        case 'a': case 'A':
+        case 'c':
+        case 'p':
+            if (scan_state == escan_seenpercent) {
+                (void) va_arg(aq, void *);  /* skip forward */
+                scan_state = escan_seennothing;
+            }
+            break;
+        default:
+            scan_state = escan_seennothing;
+            break;
+        }
+    }
+
+    if (log_level != NULL) {
+        /* intention of the following offset is:
+           cibadmin -V -> start showing INFO labelled messages */
+        if (*log_level + 4 >= msg_log_level) {
+            vfprintf(stderr, fmt, ap);
+        }
+    } else {
+        CRM_XML_LOG_BASE(msg_log_level, TRUE, 0, "CIB upgrade: ", fmt, ap);
+    }
+
+    va_end(aq);
     va_end(ap);
 }
 
 
 /* Denotes temporary emergency fix for "xmldiff'ing not text-node-ready";
    proper fix is most likely to teach __xml_diff_object and friends to
    deal with XML_TEXT_NODE (and more?), i.e., those nodes currently
    missing "_private" field (implicitly as NULL) which clashes with
    unchecked accesses (e.g. in __xml_offset) -- the outcome may be that
    those unexpected XML nodes will simply be ignored for the purpose of
    diff'ing, or it may be made more robust, or per the user's preference
    (which then may be exposed as crm_diff switch).
 
    Said XML_TEXT_NODE may appear unexpectedly due to how upgrade-2.10.xsl
    is arranged.
 
    The emergency fix is simple: reparse XSLT output with blank-ignoring
    parser. */
 #ifndef PCMK_SCHEMAS_EMERGENCY_XSLT
 #define PCMK_SCHEMAS_EMERGENCY_XSLT 1
 #endif
 
 static xmlNode *
 apply_transformation(xmlNode *xml, const char *transform, gboolean to_logs)
 {
     char *xform = NULL;
     xmlNode *out = NULL;
     xmlDocPtr res = NULL;
     xmlDocPtr doc = NULL;
     xsltStylesheet *xslt = NULL;
 #if PCMK_SCHEMAS_EMERGENCY_XSLT != 0
     xmlChar *emergency_result;
     int emergency_txt_len;
     int emergency_res;
 #endif
 
     CRM_CHECK(xml != NULL, return FALSE);
     doc = getDocPtr(xml);
     xform = get_schema_path(NULL, transform);
 
     xmlLoadExtDtdDefaultValue = 1;
     xmlSubstituteEntitiesDefault(1);
 
     /* for capturing, e.g., what's emitted via <xsl:message> */
     if (to_logs) {
         xsltSetGenericErrorFunc(NULL, cib_upgrade_err);
     } else {
-        xsltSetGenericErrorFunc((void *) stderr, (xmlGenericErrorFunc) fprintf);
+        xsltSetGenericErrorFunc(&crm_log_level, cib_upgrade_err);
     }
 
     xslt = xsltParseStylesheetFile((const xmlChar *)xform);
     CRM_CHECK(xslt != NULL, goto cleanup);
 
     res = xsltApplyStylesheet(xslt, doc, NULL);
     CRM_CHECK(res != NULL, goto cleanup);
 
     xsltSetGenericErrorFunc(NULL, NULL);  /* restore default one */
 
 
 #if PCMK_SCHEMAS_EMERGENCY_XSLT != 0
     emergency_res = xsltSaveResultToString(&emergency_result,
                                            &emergency_txt_len, res, xslt);
     xmlFreeDoc(res);
     CRM_CHECK(emergency_res == 0, goto cleanup);
     out = string2xml((const char *) emergency_result);
     free(emergency_result);
 #else
     out = xmlDocGetRootElement(res);
 #endif
 
   cleanup:
     if (xslt) {
         xsltFreeStylesheet(xslt);
     }
 
     free(xform);
 
     return out;
 }
-#endif
+
+/*!
+ * \internal
+ * \brief Possibly full enter->upgrade->leave trip per internal bookkeeping.
+ *
+ * \note Only emits warnings about enter/leave phases in case of issues.
+ */
+static xmlNode *
+apply_upgrade(xmlNode *xml, const struct schema_s *schema, gboolean to_logs)
+{
+    bool transform_onleave = schema->transform_onleave;
+    char *transform_leave;
+    xmlNode *upgrade = NULL,
+            *final = NULL;
+
+    if (schema->transform_enter) {
+        crm_debug("Upgrading %s-style configuration, pre-upgrade phase with %s",
+                  schema->name, schema->transform_enter);
+        upgrade = apply_transformation(xml, schema->transform_enter, to_logs);
+        if (upgrade == NULL) {
+            crm_warn("Upgrade-enter transformation %s failed",
+                     schema->transform_enter);
+            transform_onleave = FALSE;
+        }
+    }
+    if (upgrade == NULL) {
+        upgrade = xml;
+    }
+
+    crm_debug("Upgrading %s-style configuration, main phase with %s",
+              schema->name, schema->transform);
+    final = apply_transformation(upgrade, schema->transform, to_logs);
+
+    if (final != NULL && transform_onleave) {
+        free_xml(upgrade);
+        upgrade = final;
+        transform_leave = strdup(schema->transform_enter);
+        /* enter -> leave */
+        memcpy(strrchr(transform_leave, '-') + 1, "leave", 5);
+        crm_debug("Upgrading %s-style configuration, post-upgrade phase with %s",
+                  schema->name, transform_leave);
+        final = apply_transformation(upgrade, transform_leave, to_logs);
+        if (final == NULL) {
+            crm_warn("Upgrade-leave transformation %s failed", transform_leave);
+            final = upgrade;
+        } else {
+            free_xml(upgrade);
+        }
+        free(transform_leave);
+    }
+
+    return final;
+}
+
+#endif  /* HAVE_LIBXSLT */
 
 const char *
 get_schema_name(int version)
 {
     if (version < 0 || version >= xml_schema_max) {
         return "unknown";
     }
     return known_schemas[version].name;
 }
 
 int
 get_schema_version(const char *name)
 {
     int lpc = 0;
 
     if (name == NULL) {
         name = "none";
     }
     for (; lpc < xml_schema_max; lpc++) {
         if (safe_str_eq(name, known_schemas[lpc].name)) {
             return lpc;
         }
     }
     return -1;
 }
 
 /* set which validation to use */
 int
 update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
                   gboolean to_logs)
 {
     xmlNode *xml = NULL;
     char *value = NULL;
     int max_stable_schemas = xml_latest_schema_index();
     int lpc = 0, match = -1, rc = pcmk_ok;
     int next = -1;  /* -1 denotes "inactive" value */
 
     CRM_CHECK(best != NULL, return -EINVAL);
     *best = 0;
 
     CRM_CHECK(xml_blob != NULL, return -EINVAL);
     CRM_CHECK(*xml_blob != NULL, return -EINVAL);
 
     xml = *xml_blob;
     value = crm_element_value_copy(xml, XML_ATTR_VALIDATION);
 
     if (value != NULL) {
         match = get_schema_version(value);
 
         lpc = match;
         if (lpc >= 0 && transform == FALSE) {
             *best = lpc++;
 
         } else if (lpc < 0) {
             crm_debug("Unknown validation schema");
             lpc = 0;
         }
     }
 
     if (match >= max_stable_schemas) {
         /* nothing to do */
         free(value);
         *best = match;
         return pcmk_ok;
     }
 
     while (lpc <= max_stable_schemas) {
         crm_debug("Testing '%s' validation (%d of %d)",
                   known_schemas[lpc].name ? known_schemas[lpc].name : "<unset>",
                   lpc, max_stable_schemas);
 
         if (validate_with(xml, lpc, to_logs) == FALSE) {
             if (next != -1) {
                 crm_info("Configuration not valid for schema: %s",
                          known_schemas[lpc].name);
                 next = -1;
             } else {
                 crm_trace("%s validation failed",
                           known_schemas[lpc].name ? known_schemas[lpc].name : "<unset>");
             }
             if (*best) {
                 /* we've satisfied the validation, no need to check further */
                 break;
             }
             rc = -pcmk_err_schema_validation;
 
         } else {
             if (next != -1) {
                 crm_debug("Configuration valid for schema: %s",
                           known_schemas[next].name);
                 next = -1;
             }
             rc = pcmk_ok;
         }
 
         if (rc == pcmk_ok) {
             *best = lpc;
         }
 
         if (rc == pcmk_ok && transform) {
             xmlNode *upgrade = NULL;
             next = known_schemas[lpc].after_transform;
 
             if (next <= lpc) {
                 /* There is no next version, or next would regress */
                 crm_trace("Stopping at %s", known_schemas[lpc].name);
                 break;
 
             } else if (max > 0 && (lpc == max || next > max)) {
                 crm_trace("Upgrade limit reached at %s (lpc=%d, next=%d, max=%d)",
                           known_schemas[lpc].name, lpc, next, max);
                 break;
 
-            } else if (known_schemas[lpc].transform == NULL) {
+            } else if (known_schemas[lpc].transform == NULL
+                       /* possibly avoid transforming when readily valid
+                          (in general more restricted when crossing the major
+                          version boundary, as X.0 "transitional" version is
+                          expected to be more strict than it's successors that
+                          may re-allow constructs from previous major line) */
+                       || validate_with_silent(xml, next)) {
                 crm_debug("%s-style configuration is also valid for %s",
                            known_schemas[lpc].name, known_schemas[next].name);
 
                 lpc = next;
 
             } else {
                 crm_debug("Upgrading %s-style configuration to %s with %s",
                            known_schemas[lpc].name, known_schemas[next].name,
-                           known_schemas[lpc].transform ? known_schemas[lpc].transform : "no-op");
+                           known_schemas[lpc].transform);
 
 #if HAVE_LIBXSLT
-                upgrade = apply_transformation(xml, known_schemas[lpc].transform, to_logs);
+                upgrade = apply_upgrade(xml, &known_schemas[lpc], to_logs);
 #endif
                 if (upgrade == NULL) {
                     crm_err("Transformation %s failed",
                             known_schemas[lpc].transform);
                     rc = -pcmk_err_transform_failed;
 
                 } else if (validate_with(upgrade, next, to_logs)) {
                     crm_info("Transformation %s successful",
                              known_schemas[lpc].transform);
                     lpc = next;
                     *best = next;
                     free_xml(xml);
                     xml = upgrade;
                     rc = pcmk_ok;
 
                 } else {
                     crm_err("Transformation %s did not produce a valid configuration",
                             known_schemas[lpc].transform);
                     crm_log_xml_info(upgrade, "transform:bad");
                     free_xml(upgrade);
                     rc = -pcmk_err_schema_validation;
                 }
                 next = -1;
             }
         }
 
         if (transform == FALSE || rc != pcmk_ok) {
             /* we need some progress! */
             lpc++;
         }
     }
 
     if (*best > match && *best) {
         crm_info("%s the configuration from %s to %s",
                    transform?"Transformed":"Upgraded",
                    value ? value : "<none>", known_schemas[*best].name);
         crm_xml_add(xml, XML_ATTR_VALIDATION, known_schemas[*best].name);
     }
 
     *xml_blob = xml;
     free(value);
     return rc;
 }
 
 gboolean
 cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
 {
     gboolean rc = TRUE;
     const char *value = crm_element_value(*xml, XML_ATTR_VALIDATION);
     char *const orig_value = strdup(value == NULL ? "(none)" : value);
 
     int version = get_schema_version(value);
     int orig_version = version;
     int min_version = xml_minimum_schema_index();
 
     if (version < min_version) {
         xmlNode *converted = NULL;
 
         converted = copy_xml(*xml);
         update_validation(&converted, &version, 0, TRUE, to_logs);
 
         value = crm_element_value(converted, XML_ATTR_VALIDATION);
         if (version < min_version) {
             if (version < orig_version || orig_version == -1) {
                 if (to_logs) {
                     crm_config_err("Your current configuration %s could not"
                                    " validate with any schema in range [%s, %s],"
                                    " cannot upgrade to %s.",
                                    orig_value,
                                    get_schema_name(orig_version),
                                    xml_latest_schema(),
                                    get_schema_name(min_version));
                 } else {
                     fprintf(stderr, "Your current configuration %s could not"
                                     " validate with any schema in range [%s, %s],"
                                     " cannot upgrade to %s.\n",
                                     orig_value,
                                     get_schema_name(orig_version),
                                     xml_latest_schema(),
                                     get_schema_name(min_version));
                 }
             } else if (to_logs) {
                 crm_config_err("Your current configuration could only be upgraded to %s... "
                                "the minimum requirement is %s.", crm_str(value),
                                get_schema_name(min_version));
             } else {
                 fprintf(stderr, "Your current configuration could only be upgraded to %s... "
                         "the minimum requirement is %s.\n",
                         crm_str(value), get_schema_name(min_version));
             }
 
             free_xml(converted);
             converted = NULL;
             rc = FALSE;
 
         } else {
             free_xml(*xml);
             *xml = converted;
 
             if (version < xml_latest_schema_index()) {
                 crm_config_warn("Your configuration was internally updated to %s... "
                                 "which is acceptable but not the most recent",
                                 get_schema_name(version));
 
             } else if (to_logs) {
                 crm_info("Your configuration was internally updated to the latest version (%s)",
                          get_schema_name(version));
             }
         }
 
     } else if (version >= get_schema_version("none")) {
         if (to_logs) {
             crm_config_warn("Configuration validation is currently disabled."
                             " It is highly encouraged and prevents many common cluster issues.");
 
         } else {
             fprintf(stderr, "Configuration validation is currently disabled."
                     " It is highly encouraged and prevents many common cluster issues.\n");
         }
     }
 
     if (best_version) {
         *best_version = version;
     }
 
     free(orig_value);
     return rc;
 }
diff --git a/xml/Makefile.am b/xml/Makefile.am
index 0c3183a552..6fcb77c01d 100644
--- a/xml/Makefile.am
+++ b/xml/Makefile.am
@@ -1,172 +1,176 @@
 #
 # Copyright (C) 2004 Andrew Beekhof
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; either version 2
 # of the License, or (at your option) any later version.
 # 
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 # 
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #
 MAINTAINERCLEANFILES    = Makefile.in
 
 RNGdir			= $(CRM_SCHEMA_DIRECTORY)
 
 xsltdir			= $(RNGdir)
-xslt_DATA		= $(top_srcdir)/xml/upgrade-*.xsl
+dist_xslt_DATA		= $(top_srcdir)/xml/upgrade-1.3.xsl \
+			  $(top_srcdir)/xml/upgrade-2.10.xsl \
+			  $(top_srcdir)/xml/upgrade-*enter.xsl \
+			  $(top_srcdir)/xml/upgrade-*leave.xsl
 
 noinst_DATA		= context-of.xsl
 
 # See Readme.md for details on updating schema files
 
 # Sorted list of available numeric RNG versions,
 # extracted from filenames like NAME-MAJOR[.MINOR][.MINOR-MINOR].rng
 RNG_numeric_versions    = $(shell ls -1 $(top_srcdir)/xml/*.rng \
 			  | sed -n -e 's/^.*-\([0-9][0-9.]*\).rng$$/\1/p' \
 			  | sort -u -t. -k 1,1n -k 2,2n -k 3,3n)
 
 # The highest numeric version
 RNG_max			?= $(lastword $(RNG_numeric_versions))
 
 # A sorted list of all RNG versions (numeric and "next")
 RNG_versions		= next $(RNG_numeric_versions)
 RNG_version_pairs	= $(join \
 			    ${RNG_numeric_versions},$(addprefix \
 			      -,$(wordlist \
 			        2,$(words ${RNG_numeric_versions}),${RNG_numeric_versions} \
 			      ) next \
 			    ) \
 			  )
 RNG_version_pairs_cnt	= $(words ${RNG_version_pairs})
 RNG_version_pairs_last  = $(wordlist \
 			    $(words \
 			      $(wordlist \
 			        2,${RNG_version_pairs_cnt},${RNG_version_pairs} \
 			      ) \
 			    ),${RNG_version_pairs_cnt},${RNG_version_pairs} \
 			  )
 
 RNG_generated		= pacemaker.rng $(foreach base,$(RNG_versions),pacemaker-$(base).rng) versions.rng
 
-RNG_cfg_base	 	= options nodes resources constraints fencing acls tags alerts
-RNG_base	 	= cib $(RNG_cfg_base) status score rule nvset
-RNG_files	 	= $(foreach base,$(RNG_base),$(wildcard $(base)*.rng))
+RNG_cfg_base		= options nodes resources constraints fencing acls tags alerts
+RNG_base		= cib $(RNG_cfg_base) status score rule nvset
+RNG_files		= $(foreach base,$(RNG_base),$(wildcard $(base).rng $(base)-*.rng))
 
 # List of non-Pacemaker RNGs
 RNG_extra		= crm_mon.rng
 
-RNG_DATA		= $(RNG_files) $(RNG_generated) $(RNG_extra)
+dist_RNG_DATA		= $(RNG_files) $(RNG_extra)
+nodist_RNG_DATA		= $(RNG_generated)
 
 EXTRA_DIST		= best-match.sh
 
 versions:
 	echo "Max: $(RNG_max)"
 	echo "Available: $(RNG_versions)"
 
 versions.rng: Makefile.am
 	echo "  RNG      $@"
 	echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
 	echo '<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">' >> $@
 	echo '  <start>' >> $@
 	echo '   <interleave>' >> $@
 	echo '    <optional>' >> $@
 	echo '      <attribute name="validate-with">' >> $@
 	echo '        <choice>' >> $@
 	echo '          <value>none</value>' >> $@
 	echo '          <value>pacemaker-0.6</value>' >> $@
 	echo '          <value>transitional-0.6</value>' >> $@
 	echo '          <value>pacemaker-0.7</value>' >> $@
 	echo '          <value>pacemaker-1.1</value>' >> $@
 	for rng in $(RNG_versions); do echo "          <value>pacemaker-$$rng</value>" >> $@; done
 	echo '        </choice>' >> $@
 	echo '      </attribute>' >> $@
 	echo '    </optional>' >> $@
 	echo '    <attribute name="admin_epoch"><data type="nonNegativeInteger"/></attribute>' >> $@
 	echo '    <attribute name="epoch"><data type="nonNegativeInteger"/></attribute>' >> $@
 	echo '    <attribute name="num_updates"><data type="nonNegativeInteger"/></attribute>' >> $@
 	echo '   </interleave>' >> $@
 	echo '  </start>' >> $@
 	echo '</grammar>' >> $@
 
 pacemaker.rng: pacemaker-$(RNG_max).rng
 	echo "  RNG      $@"
 	cp $(top_builddir)/xml/$< $@
 
 pacemaker-%.rng: $(RNG_files) best-match.sh Makefile.am
 	echo "  RNG      $@"
 	echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
 	echo '<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">' >> $@
 	echo '  <start>' >> $@
 	echo '    <element name="cib">' >> $@
 	$(top_srcdir)/xml/best-match.sh cib $(*) $(@) "      "
 	echo '      <element name="configuration">' >> $@
 	echo '        <interleave>' >> $@
 	for rng in $(RNG_cfg_base); do $(top_srcdir)/xml/best-match.sh $$rng $(*) $(@) "          " || :; done
 	echo '        </interleave>' >> $@
 	echo '      </element>' >> $@
 	echo '      <optional>' >> $@
 	echo '        <element name="status">' >> $@
 	$(top_srcdir)/xml/best-match.sh status $(*) $(@) "          "
 	echo '        </element>' >> $@
 	echo '      </optional>' >> $@
 	echo '    </element>' >> $@
 	echo '  </start>' >> $@
 	echo '</grammar>' >> $@
 
 # diff fails with ec=2 if no predecessor is found;
 # this uses '=' GNU extension to sed, if that's not available,
 # one can use: hline=`echo "$${p}" | grep -Fn "$${hunk}" | cut -d: -f1`;
 # XXX: use line information from hunk to avoid "not detected" for ambiguity
 version_diff = \
 	@for p in $(1); do \
 	  set `echo "$${p}" | tr '-' ' '`; \
 	  echo "\#\#\# *-$$2.rng vs. predecessor"; \
 	  for v in *-$$2.rng; do \
 	    echo "\#\#\#\# $${v} vs. predecessor"; b=`echo "$${v}" | cut -d- -f1`; \
 	    old=`./best-match.sh $${b} $$1`; \
 	    p=`diff -u "$${old}" "$${v}" 2>/dev/null`; \
 	    case $$? in \
 	    1) echo "$${p}" | sed -n -e '/^@@ /!d;=;p' \
 	       -e ':l;n;/^\([- ]\|+.*<[^ />]\+\([^/>]\+="ID\|>$$\)\)/bl;s/^[+ ]\(.*\)/\1/p' \
 	       | while read hline; do \
 	           read h && read i || break; \
 	           iline=`grep -Fn "$${i}" "$${v}" | cut -d: -f1`; \
 	           ctxt="(not detected)"; \
 	           if test `echo "$${iline}" | wc -l` -eq 1; then \
 	             ctxt=`{ sed -n -e "1,$$(($${iline}-1))p" "$${v}"; \
 	                     echo "<inject id=\"GOAL\"/>$${i}"; \
 	                     sed -n -e "$$(($${iline}+1)),$$ p" "$${v}"; \
 	                   } | $(XSLTPROC) --param skip 1 context-of.xsl -`; \
 	           fi; \
 	           echo "$${p}" | sed -n -e "$$(($${hline}-2)),$${hline}!d" \
 	             -e '/^\(+++\|---\)/p'; \
 	           echo "$${h} context: $${ctxt}"; \
 	           echo "$${p}" | sed -n -e "1,$${hline}d" \
 	             -e '/^\(---\|@@ \)/be;p;d;:e;n;be'; \
 	           done; \
 	       ;; \
 	    2) echo "\#\#\#\#\# $${v} has no predecessor";; \
 	    esac; \
 	  done; \
 	done
 
 diff: best-match.sh
 	@echo "#  Comparing changes in + since $(RNG_max)"
 	$(call version_diff,${RNG_version_pairs_last})
 
 fulldiff: best-match.sh
 	@echo "#  Comparing all changes across all the subsequent increments"
 	$(call version_diff,${RNG_version_pairs})
 
 sync:
 	git rm -f $(wildcard *-next.rng)
 	make pacemaker-next.rng
 
 CLEANFILES = $(RNG_generated)
diff --git a/xml/Readme.md b/xml/Readme.md
index 73aa64f584..b8b04ca75b 100644
--- a/xml/Readme.md
+++ b/xml/Readme.md
@@ -1,122 +1,141 @@
 # Schema Reference
 
 Pacemaker's XML schema has a version of its own, independent of the version of
 Pacemaker itself.
 
 ## Versioned Schema Evolution
 
 A versioned schema offers transparent backward and forward compatibility.
 
 - It reflects the timeline of schema-backed features (introduction,
   changes to the syntax, possibly deprecation) through the versioned
   stable schema increments, while keeping schema versions used by default
   by older Pacemaker versions untouched.
 
 - Pacemaker internally uses the latest stable schema version, and relies on
   supplemental transformations to promote cluster configurations based on
   older, incompatible schema versions into the desired form.
 
 - It allows experimental features with a possibly unstable configuration
   interface to be developed using the special `next` version of the schema.
 
 ## Mapping Pacemaker Versions to Schema Versions
 
 | Pacemaker | Latest Schema | Changed
 | --------- | ------------- | ----------------------------------------------
 | `2.0.0`   | `3.0`         | `constraints`, `resources`
 | `1.1.18`  | `2.10`        | `resources`, `alerts`
 | `1.1.17`  | `2.9`         | `resources`, `rule`
 | `1.1.16`  | `2.6`         | `constraints`
 | `1.1.15`  | `2.5`         | `alerts`
 | `1.1.14`  | `2.4`         | `fencing`
 | `1.1.13`  | `2.3`         | `constraints`
 | `1.1.12`  | `2.0`         | `nodes`, `nvset`, `resources`, `tags`, `acls`
 | `1.1.8`+  | `1.2`         |
 
 ## Schema generation
 
 Each logical portion of the schema goes into its own RNG file, named like
 `${base}-${X}.${Y}.rng`. `${base}` identifies the portion of the schema
 (e.g. constraints, resources); ${X}.${Y} is the latest schema version that
 contained changes in this portion of the schema.
 
 The complete, overall schema, `pacemaker-${X}.${Y}.rng`, is automatically
 generated from the other files via the Makefile.
 
 # Updating schema files #
 
 ## Experimental features ##
 
 Experimental features go into `${base}-next.rng` where `${base}` is the
 affected portion of the schema. If such a file does not already exist,
 create it by copying the most recent `${base}-${X}.${Y}.rng`.
 
 Pacemaker will not use the experimental schema by default; the cluster
 administrator must explicitly set the `validate-with` property appropriately to
 use it.
 
 ## Stable features ##
 
 The current stable version is determined at runtime when
 crm_schema_init() scans the CRM_SCHEMA_DIRECTORY.
 
 It will have the form `pacemaker-${X}.${Y}` and the highest
 `${X}.${Y}` wins.
 
 ### Simple Additions
 
 When the new syntax is a simple addition to the previous one, create a
 new entry, incrementing `${Y}`.
 
 ### Feature Removal or otherwise Incompatible Changes
 
 When the new syntax is not a simple addition to the previous one,
 create a new entry, incrementing `${X}` and setting `${Y} = 0`.
 
 An XSLT file is also required that converts an old syntax to the new
 one and must be named `upgrade-${Xold}.${Yold}.xsl`.
 
 See `xml/upgrade-1.3.xsl` for an example.
 
 Since `xml/upgrade-2.10.xsl`, rather self-descriptive approach is taken,
 separating metadata of the replacements and other modifications to
 perform from the actual executive parts, which is leveraged, e.g., with
 the on-the-fly overview as obtained with `./regression.sh -X test2to3`.
 Also this was the first time particular key names of `nvpair`s,
 i.e. below the granularity of the schemas so far, received attention,
 and consequently, no longer expected names became systemically banned
 in the after-upgrade schemas, using `<except>` construct in the
 data type specification pertaining the affected XML path.
 
+The implied complexity also resulted in establishing a new compound,
+stepwise transformation, alleviating the procedural burden from the
+core upgrade recipe.  In particular, `id-ref` based syntactic
+simplification granted in the CIB format introduces nonnegligible
+internal "noise" because of the extra indirection encumbered with
+generally non-bijective character of such a scheme (context-dependent
+interpretation).  To reduce this strain, a symmetric arrangement is
+introduced as a pair of _enter_/_leave_ (pre-upgrade/post-upgrade)
+transformations where the latter is meant to eventually reversibly
+restore what the former intentionally simplified (normalized) for
+upgrade transformation's peruse.  It's optional (even the post-upgrade
+counterpart is optional alone) and depends on whether the suitable
+files are found along the upgrade transformation itself: e.g., for
+`upgrade-2.10.xsl`, such files are `upgrade-2.10-enter.xsl` and
+`upgrade-2.10-leave.xsl`.  Note that unfolding + refolding `id-ref`
+shortcuts is just a practically imposed individual case of how to
+reversibly make the configuration space tractable in the upgrade
+itself, allowing for more sophistication down the road.
+
 ### General Procedure
 
 1. Copy the most recent version of `${base}-*.rng` to `${base}-${X}.${Y}.rng` 
 1. Commit the copy, e.g. `"Low: xml: clone ${base} schema in preparation for
    changes"`. This way, the actual change will be obvious in the commit history.
 1. Modify `${base}-${X}.${Y}.rng` as required.
 1. If required, add an XSLT file, and update `xslt_SCRIPTS` in `xml/Makefile.am`.
 1. Commit
 1. `make -C xml clean; make -C xml all` to rebuild the schemas in the local
    source directory.
 1. The CIB validity regression tests will break after the schema is updated.
    Run `tools/regression.sh` to get the new output,
    `diff tools/regression.validity.{out,exp}` to ensure the changes look correct,
    `cp tools/regression.validity.{out,exp}` to update the expected output,
    then commit the change.
 1. Similarly, with the new major version `${X}`, it's advisable to refresh
    scheduler tests at some point, see the instructions in `cts/README.md`.
 
 ## Using a New Schema
 
 New features will not be available until the cluster administrator:
 
 1. Updates all the nodes
 1. Runs the equivalent of `cibadmin --upgrade --force`
 
 ## Random Notes
 
 From the source directory, run `make -C xml diff` to see the changes
 in the current schema (compared to the previous ones) and also the
 pending changes in `pacemaker-next`.
 Alternatively, if the intention is to grok the overall historical schema
 evolution, use `make -C xml fulldiff`.
diff --git a/xml/assets/upgrade-2.10-htmldiff.xsl b/xml/assets/upgrade-2.10-htmldiff.xsl
index 22922904c6..175bdb20c4 100644
--- a/xml/assets/upgrade-2.10-htmldiff.xsl
+++ b/xml/assets/upgrade-2.10-htmldiff.xsl
@@ -1,351 +1,358 @@
 <!--
  Copyright 2018 Red Hat, Inc.
  Author: Jan Pokorny <jpokorny@redhat.com>
  Part of pacemaker project
  SPDX-License-Identifier: GPL-2.0-or-later
  -->
 <xsl:stylesheet version="1.0"
                 xmlns="http://www.w3.org/1999/xhtml"
                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xmlns:cibtr="http://clusterlabs.org/ns/pacemaker/cibtr-2"
                 xmlns:exsl="http://exslt.org/common">
 <!-- NOTE: this is an exception from rule forbidding EXSLT's usage -->
 
-<xsl:include href="../upgrade-2.10.xsl"/>
+<xsl:include href="../upgrade-2.10-roundtrip.xsl"/>
 
 <!--
  we are embedding files from 3rd party project so as to reproduce the content
  of XML into HTML-formatted presentation form; alternatively:
  * from mozilla/firefox:
    - view-source.xsl by Keith Visco (example transformation for transformiix)
      https://dxr.mozilla.org/mozilla/source/extensions/transformiix/source/examples
    - XMLPrettyPrint.xsl by Jonas Sicking
      https://dxr.mozilla.org/mozilla-central/source/dom/xml/resources
      https://hg.mozilla.org/mozilla-central/file/9b2a99adc05e/content/xml/document/resources/XMLPrettyPrint.xsl
      or possibly its readily sanitized version from rdf-viewer project
      https://github.com/marianafranco/rdf-viewer
  * custom stylesheet to be written
  -->
 <xsl:param name="highlight-namespace" select="''"/>
 <!--
 <xsl:include href="https://raw.githubusercontent.com/Boldewyn/view-source/master/library.xsl"/>
 <xsl:include href="https://raw.githubusercontent.com/Boldewyn/view-source/master/original.xsl"/>
  -->
 <xsl:include href="view-source-library.xsl"/>
 <xsl:include href="view-source-original.xsl"/>
 
 <xsl:output method="xml" encoding="UTF-8"
             omit-xml-declaration="yes"
             doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
             doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>
 
 <!-- B: identity mode -->
 <xsl:template match="@*|node()" mode="identity">
   <xsl:copy>
     <xsl:apply-templates select="@*|node()" mode="identity"/>
   </xsl:copy>
 </xsl:template>
 
 <!-- used in test files to allow in-browser on-the-fly checking -->
 <xsl:template match="processing-instruction()[
                        name() = 'xml-stylesheet'
                        and
                        count(..|/) = 1
                      ]"
               mode="identity"/>
 <!-- E: identity mode -->
 
 <xsl:template match="/">
   <xsl:variable name="before-upgrade">
-    <xsl:apply-templates mode="identity"/>
+    <xsl:apply-templates select="." mode="identity"/>
   </xsl:variable>
-
   <xsl:variable name="after-upgrade">
-    <xsl:apply-templates mode="cibtr:main"/>
+    <xsl:apply-templates select="." mode="cibtr:roundtrip"/>
   </xsl:variable>
 
   <html>
     <head>
       <title>
         <xsl:text>upgrade-2.10 on-the-fly in-browser transformation</xsl:text>
       </title>
       <style>
         ol.count,.possibly-revealed { display: none; }
         li.delete { color: red; }
         li.delete em { background-color: #FFE4E1; }
         li.insert { color: green; }
         li.insert em { background-color: #FAFAD2; }
         .count,.data { font-family: monospace;
                        background-color: #F8F8FF;
                        border: 1px solid #DCDCDC; }
+        .err_warning { color: red; background-color: #FFE4E1; }
+        .err_info { color: green; background-color: #FAFAD2; }
+        .err_debug { }
       </style>
       <script type="text/javascript">
         var global = { prettydiff: {} },  /* for diffview.js */
             diffview_source = new String("../assets/diffview.js");
 
         /* add location-based file detail to the title */
         var split_url = document.URL.split('/'),
             basename = new String(split_url[split_url.length - 1]),
             /* see whether there's 'test-\d+' in URL as a discriminator */
             is_test = split_url.some(function(item, index, array) {
               if (index &lt; array.length - 1 &amp;&amp; item.match(/test-\d+/))
                 return true;
               return false;
             });
 
         window.addEventListener("DOMContentLoaded", function(event) {
           /* update title + headline */
           var basename_title = new String(basename + " upgrade");
           document.getElementById("headline").innerText = basename_title;
           document.title = basename_title + " [" + document.title + "]";
 
           /* add location-based file detail to the acknowledgement's text */
           document.getElementById("acknowledgement")
             .innerHTML = document.getElementById("acknowledgement").innerHTML
                          .replace("@basename@", basename);
 
           /* make expand/collapse buttons udner debugging section work */
           document.querySelectorAll("#original, #transformed").forEach(
             function(item) {
               item.querySelector(".expand").addEventListener("click",
                                                              function(event) {
                 item.querySelectorAll(".possibly-revealed").forEach(
                   function(item) {
                     item.classList.replace("possibly-revealed", "revealed");
                   }
                 );
                 this.classList.add("possibly-revealed");
                 event.preventDefault();
               });
               item.querySelector(".collapse").addEventListener("click",
                                                                function(event) {
                 item.querySelectorAll(".revealed").forEach(
                   function(item) {
                     item.classList.replace("revealed", "possibly-revealed");
                   }
                 );
                 item.querySelector(".expand").classList.remove("possibly-revealed");
                 event.preventDefault();
               });
             }
           );
 
           if (is_test) {
             var xhr1 = new XMLHttpRequest(),
                 xhr2 = new XMLHttpRequest(),
                 basename_split = basename.split('.');
 
             /* fetch expected out-of-band messages */
             xhr1.onload = function() {
-              document.getElementById("expected-messages").innerText = this.responseText;
+              var formatted = this.responseText.replace(/^(WARNING|INFO|DEBUG)(: .*)$/gm,
+                                                        function(match, label, rest) {
+                return '&lt;span class="err_' + label.toLowerCase() + '"&gt;&lt;em&gt;'
+                        + label + '&lt;/em&gt;' + rest + '&lt;/span&gt;&lt;br/&gt;';
+              });
+              document.getElementById("expected-messages").innerHTML = formatted;
               document.querySelectorAll(["#expected-messages",
                                          "#expected-messages-ext",
                                          "#navigation"]).forEach(
                 function(item) {
                   item.classList.remove("possibly-revealed");
                 }
               );
             };
             xhr1.open("GET", basename_split.splice(0, basename_split.length - 1)
                                            .join('.') + ".ref.err");
             xhr1.responseType = "text";
             xhr1.send();
 
             /* fetch previous/next pointers */
             xhr2.onload = function() {
               var prev_link, next_link,
                   found = false;
               Array.prototype.every.call(
                 this.responseXML.getElementsByTagName("a"),
                 function(item) {
                   if (item.href.endsWith(basename_split[basename_split.length - 1])) {
                     if (item.href.endsWith(basename))
                       found = true;
                     else if (!found)
                       prev_link = item;
                     else if (next_link !== undefined)
                       return false;
                     else
                       next_link = item;
                   }
                   return true;
                 }
               );
               if (prev_link !== undefined)
                 document.getElementById("navigation-prev").href = prev_link.href;
               if (next_link !== undefined)
               document.getElementById("navigation-next").href = next_link.href;
             };
             xhr2.open("GET", ".");
             xhr2.responseType = "document";
             xhr2.send();
           }
         });
 
         window.addEventListener("load", function(event) {
           /* trigger diff'ing */
           document
             .getElementById("output")
             .innerHTML = global.prettydiff.diffview({
               source: document.getElementById("original-placeholder").innerText,
               sourcelabel: "Differences: original",
               diff: document.getElementById("transformed-placeholder").innerText,
               difflabel: "transformed (some whitespace stripped)",
               diffview: "inline",
               lang: "text"
             })[0];
 
           /* add proper location of diffview.js */
           var diffview_link = document.getElementById("diffview-link");
           if (diffview_link.host != document.location.host) {
             diffview_link.href = diffview_source;
             diffview_link.parentElement.querySelector(".possibly-revealed")
               .classList.remove("possibly-revealed");
             diffview_link.parentElement.querySelector(".revealed")
               .classList.replace("revealed", "possibly-revealed");
           }
         });
 
         /* bind left/right arrows */
         window.addEventListener("keydown", function(event) {
           switch (event.keyCode) {
           case 37:
             document.location = document.getElementById("navigation-prev").href;
             break;
           case 39:
             document.location = document.getElementById("navigation-next").href;
             break;
           }
         });
       </script>
       <script type="text/javascript" src="../assets/diffview.js"/>
       <!-- fallback to externally fetched js, without any guarantees,
            safety ones or otherwise -->
       <script type="text/javascript">
         if (typeof global.prettydiff.diffview == "undefined") {
           diffview_source = new String("https://raw.githubusercontent.com/prettydiff/prettydiff/2.2.8/lib/diffview.js");
           document.write(unescape('%3Cscript type="text/javascript" src=' + diffview_source + '/%3E'));
         }
       </script>
     </head>
     <body>
       <h1 id="headline">test</h1>
       <p>
         <strong>Using <a href="../upgrade-2.10.xsl">upgrade-2.10</a> on-the-fly in-browser transformation</strong>
         <span id="navigation" class="possibly-revealed">
           [
           <a id="navigation-prev" href="#">previous</a>
           and
           <a id="navigation-next" href="#">next</a>, or use arrows
           ]
         </span>
       </p>
       <p id="output">
         Differences highlight view to be loaded here.
       </p>
       <h3>Diagnostics</h3>
       <p>
         Open <a href="https://webmasters.stackexchange.com/a/77337">JS console</a>
         (e.g. <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>J</kbd>, focusing JS + log combo)
         <span id="expected-messages-ext" class="possibly-revealed">
           to check the actual messages from the in-browser transformation match the baseline:
         </span>
       </p>
-      <pre id="expected-messages" class="data possibly-revealed">
+      <p id="expected-messages" class="data possibly-revealed">
         Expected diagnostic messages to be loaded here.
-      </pre>
+      </p>
       <h3>Debugging</h3>
       <p>
         These are raw data (beware, already chewed with the
         <a href="../assets/view-source-original.xsl">view-source</a>
         transformation, hence not very suitable for copying) entering
         the differential generating processs:
       </p>
       <p id="original">
         <span>
           <a class="expand" href="">original+</a>
           <a class="collapse possibly-revealed" href="">original-</a>
         </span>
         <br/>
         <pre id="original-placeholder" class="data possibly-revealed">
           <xsl:apply-templates select="exsl:node-set($before-upgrade)/node()" mode="original"/>
         </pre>
       </p>
       <p id="transformed">
         <span>
           <a class="expand" href="">transformed+</a>
           <a class="collapse possibly-revealed" href="">transformed-</a>
         </span>
         <br/>
         <pre id="transformed-placeholder" class="data possibly-revealed">
           <xsl:apply-templates select="exsl:node-set($after-upgrade)/node()" mode="original"/>
         </pre>
       </p>
       <hr/>
       <p id="acknowledgement">
         This generated page is based on the externally provided pacemaker XML
         configuration file (CIB), <span class="data">@basename@</span>, which is
         the primary object of interest here.
         But the rendered page wouldn't be possible without the actual
         transformations and other auxiliary files that come with these notices:
         <br/>
         <ul>
           <li id="ack-diffview">
             <a href="../assets/diffview.js" id="diffview-link">diffview.js</a>
             <p class="data revealed">
               This file was obtained from <a href="https://github.com/prettydiff/prettydiff">prettydiff/prettydiff</a> project:<br/>
               <a href="https://raw.githubusercontent.com/prettydiff/prettydiff/2.2.8/lib/diffview.js">diffview.js</a><br/>
               <br/>
               Licensing governed with:<br/>
               <a href="https://github.com/prettydiff/prettydiff/blob/2.2.8/license.txt">license.txt</a><br/>
               <br/>
               > Rights holder Austin Cheney and Pretty Diff<br/>
               > <br/>
               > Pretty Diff project, as of version 2.1.17 and all following versions<br/>
               > unless otherwise changed, is licensed with a Creative Commons 1.0<br/>
               > Universal license (CC0).
             </p>
             <p class="data possibly-revealed">
               This file is being served directly from <a href="https://raw.githubusercontent.com/prettydiff/prettydiff/2.2.8/lib/diffview.js">
               GitHub hosted location</a>, hence refer to <a href="https://raw.githubusercontent.com/prettydiff/prettydiff/2.2.8">
               respective repo tree</a>
             </p>
           </li>
           <li id="ack-view-source">
             <a href="../assets/view-source-library.xsl">library.xsl</a>
             and
             <a href="../assets/view-source-original.xsl">original.xsl</a>
             <p class="data">
               This file was obtained from <a href="https://github.com/Boldewyn/view-source">Boldewyn/view-source</a> project:<br/>
               <a href="https://raw.githubusercontent.com/Boldewyn/view-source/f425605366b9f5a52e6a71632785d6e4543c705e/library.xsl">library.xsl</a><br/>
               <a href="https://raw.githubusercontent.com/Boldewyn/view-source/f425605366b9f5a52e6a71632785d6e4543c705e/original.xsl">original.xsl</a><br/>
               <br/>
               Licensing governed with:<br/>
               <a href="https://github.com/Boldewyn/view-source/blob/f425605366b9f5a52e6a71632785d6e4543c705e/README">README</a><br/>
               <br/>
               > The stylesheet is published under an MIT-style license and the GPL v2.<br/>
               > Choose at your liking.
             </p>
           </li>
           <li id="ack-upgrade">
             <a href="../assets/upgrade-2.10-htmldiff.xsl">upgrade-2.10-htmldiff.xsl</a>
             (master template for this report) and
             <a href="../upgrade-2.10.xsl">upgrade-2.10.xsl</a>
             (actual upgrade engine)
             <p class="data">
               Copyright 2018 <a href="https://redhat.com">Red Hat, Inc.</a><br/>
               Author: <a href="https://wiki.clusterlabs.org/wiki/User:Jpokorny">Jan Pokorny</a>
               &lt;<a href="mailto:jpokorny@redhat.com">jpokorny@redhat.com</a>&gt;<br/>
               <a href="https://github.com/ClusterLabs/pacemaker/tree/master/xml">Part</a> of
               <a href="https://wiki.clusterlabs.org/wiki/Pacemaker">pacemaker</a> project<br/>
               <a href="https://spdx.org/sites/cpstandard/files/pages/files/using_spdx_license_list_short_identifiers.pdf#page=5">SPDX-License-Identifier</a>:
               <a href="https://spdx.org/licenses/GPL-2.0-or-later.html">GPL-2.0-or-later</a>
             </p>
           </li>
         </ul>
       </p>
     </body>
   </html>
 </xsl:template>
 
 </xsl:stylesheet>
diff --git a/xml/cibtr-2.rng b/xml/cibtr-2.rng
index 0c7651b935..36e832817c 100644
--- a/xml/cibtr-2.rng
+++ b/xml/cibtr-2.rng
@@ -1,198 +1,211 @@
 <!--
  Copyright 2018 Red Hat, Inc.
  Author: Jan Pokorny <jpokorny@redhat.com>
  Part of pacemaker project
  SPDX-License-Identifier: GPL-2.0-or-later
  -->
 <grammar xmlns="http://relaxng.org/ns/structure/1.0"
          xmlns:cibtr="http://clusterlabs.org/ns/pacemaker/cibtr-2"
          datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <start>
     <ref name="cibtr-2"/>
   </start>
 
   <define name="cibtr-2">
     <element name="cibtr:map">
       <zeroOrMore>
         <ref name="cibtr-2.table"/>
       </zeroOrMore>
     </element>
   </define>
 
   <define name="cibtr-2.table">
     <element name="cibtr:table">
       <attribute name="for">
         <data type="ID"/>
       </attribute>
       <attribute name="msg-prefix">
         <data type="string"/>
       </attribute>
       <choice>
         <zeroOrMore>
           <ref name="cibtr-2.replace.nonwhereaware"/>
         </zeroOrMore>
         <group>
           <attribute name="where-cases">
             <!-- pipe-delimited enumeration-->
             <data type="string">
               <param name="minLength">1</param>
             </data>
           </attribute>
           <!-- cannot arrange this as an interleave of
                cibtr-2.replace.whereaware+ and
                cibtr-2.replace.nonwhereaware* because of
                http://relaxng.org/spec-20011203.html#attribute-restrictions -->
           <zeroOrMore>
             <ref name="cibtr-2.replace.whereaware"/>
           </zeroOrMore>
         </group>
       </choice>
     </element>
   </define>
 
   <!-- leaf attributes -->
 
   <define name="cibtr-2.replace.attr-in-case-of">
     <attribute name="in-case-of">
       <!-- pipe-delimited enumeration-->
       <data type="string"/>
     </attribute>
   </define>
 
   <define name="cibtr-2.replace.attr-in-case-of-droppable-prefix">
     <attribute name="in-case-of-droppable-prefix">
       <!-- just a single argument taken verbatim -->
       <data type="string">
         <param name="minLength">1</param>
       </data>
     </attribute>
   </define>
 
   <define name="cibtr-2.replace.attr-msg-extra">
     <attribute name="msg-extra">
       <data type="string">
         <param name="minLength">1</param>
       </data>
     </attribute>
   </define>
 
+  <define name="cibtr-2.replace.attr-msg-severity">
+    <attribute name="msg-severity">
+      <choice>
+        <value>WARNING</value>
+        <value>INFO</value>
+        <value>DEBUG</value>
+      </choice>
+    </attribute>
+  </define>
+
   <define name="cibtr-2.replace.attr-redefined-as">
     <attribute name="redefined-as">
       <data type="string">
         <param name="minLength">1</param>
       </data>
     </attribute>
   </define>
 
   <define name="cibtr-2.replace.attr-what">
     <attribute name="what">
       <data type="NCName"/>
     </attribute>
   </define>
 
   <define name="cibtr-2.replace.attr-where">
     <attribute name="where">
       <data type="NCName"/>
     </attribute>
   </define>
 
   <define name="cibtr-2.replace.attr-with-possibly">
     <attribute name="with">
       <choice>
         <data type="NCName"/>
         <empty/>
       </choice>
     </attribute>
   </define>
 
   <define name="cibtr-2.replace.attr-with-surely">
     <attribute name="with">
       <choice>
         <data type="NCName"/>
       </choice>
     </attribute>
   </define>
 
   <define name="cibtr-2.replace.attrs-common">
     <ref name="cibtr-2.replace.attr-what"/>
     <optional>
       <ref name="cibtr-2.replace.attr-msg-extra"/>
     </optional>
+    <optional>
+      <ref name="cibtr-2.replace.attr-msg-severity"/>
+    </optional>
   </define>
 
   <define name="cibtr-2.replace.attrs-redefined-as-in-case-of">
    <ref name="cibtr-2.replace.attr-redefined-as"/>
     <!-- can be combined with in-case-of, but cannot be combined
          with in-case-of-droppable-prefix -->
     <optional>
       <ref name="cibtr-2.replace.attr-in-case-of"/>
     </optional>
   </define>
 
   <!-- leaf production using the above attribute definitions -->
 
   <define name="cibtr-2.replace.nonwhereaware">
     <element name="cibtr:replace">
       <ref name="cibtr-2.replace.attrs-common"/>
       <choice>
         <group>
           <ref name="cibtr-2.replace.attr-with-possibly"/>
           <optional>
             <choice>
               <ref name="cibtr-2.replace.attrs-redefined-as-in-case-of"/>
               <ref name="cibtr-2.replace.attr-in-case-of"/>
             </choice>
           </optional>
         </group>
         <group>
           <ref name="cibtr-2.replace.attr-with-surely"/>
           <optional>
             <choice>
               <ref name="cibtr-2.replace.attrs-redefined-as-in-case-of"/>
               <ref name="cibtr-2.replace.attr-in-case-of"/>
               <ref name="cibtr-2.replace.attr-in-case-of-droppable-prefix"/>
             </choice>
           </optional>
         </group>
       </choice>
     </element>
   </define>
 
   <define name="cibtr-2.replace.whereaware">
     <element name="cibtr:replace">
       <ref name="cibtr-2.replace.attrs-common"/>
       <!-- cf. comment at cibtr-2.table -->
       <choice>
         <group>
           <ref name="cibtr-2.replace.attr-with-surely"/>
           <ref name="cibtr-2.replace.attr-where"/>
           <optional>
             <choice>
               <ref name="cibtr-2.replace.attrs-redefined-as-in-case-of"/>
               <ref name="cibtr-2.replace.attr-in-case-of"/>
               <ref name="cibtr-2.replace.attr-in-case-of-droppable-prefix"/>
             </choice>
           </optional>
         </group>
         <group>
           <ref name="cibtr-2.replace.attr-with-surely"/>
           <optional>
             <ref name="cibtr-2.replace.attr-where"/>
           </optional>
           <choice>
             <ref name="cibtr-2.replace.attrs-redefined-as-in-case-of"/>
             <ref name="cibtr-2.replace.attr-in-case-of"/>
             <ref name="cibtr-2.replace.attr-in-case-of-droppable-prefix"/>
           </choice>
         </group>
         <group>
           <ref name="cibtr-2.replace.attr-with-possibly"/>
           <optional>
             <ref name="cibtr-2.replace.attr-in-case-of"/>
           </optional>
         </group>
       </choice>
     </element>
   </define>
 
 </grammar>
diff --git a/xml/regression.sh b/xml/regression.sh
index c3bce333c2..b078a1cd1a 100755
--- a/xml/regression.sh
+++ b/xml/regression.sh
@@ -1,640 +1,727 @@
 #!/bin/sh
 # Copyright 2018 Red Hat, Inc.
 # Author: Jan Pokorny <jpokorny@redhat.com>
 # Part of pacemaker project
 # SPDX-License-Identifier: GPL-2.0-or-later
 
 set -eu
 test -d assets && test -d test-2 \
   || { echo 'Run me from source-tree-like location'; exit 1; }
 # $1=reference (can be '-' for stdin), $2=investigated
 # alt.: wdiff, colordiff, ...
 DIFF=${DIFF:-diff}
 DIFFOPTS=${DIFFOPTS--u}
 DIFFPAGER=${DIFFPAGER:-less -LRX}
 # $1=schema, $2=validated
 # alt.: jing -i
 RNGVALIDATOR=${RNGVALIDATOR:-xmllint --noout --relaxng}
 # $1=stylesheet, $2=source
 # alt.: Xalan, saxon, sabcmd/Sablotron (note: only validates reliably with -B)
 _xalan_wrapper() {
 	{ ${_XSLTPROCESSOR} "$2" "$1" 2>&1 >&3 \
 	  | sed -e '/^Source tree node.*$/d' \
 	        -e 's|^XSLT message: \(.*\) (Occurred.*)|\1|'; } 3>&- 3>&1 >&2
 }
 # Sablotron doesn't translate '-' file specification to stdin
 # and limits the length of the output message
 _sabcmd_wrapper() {
 	_sabw_sheet=${1:?}
 	_sabw_source=${2:?}
 	test "${_sabw_sheet}" != - || _sabw_sheet=/dev/stdin
 	test "${_sabw_source}" != - || _sabw_source=/dev/stdin
 	{ ${_XSLTPROCESSOR} "${_sabw_sheet}" "${_sabw_source}" 2>&1 >&3 \
 	  | sed -e '/^Warning \[code:89\]/d' \
 	        -e 's|^  xsl:message (\(.*\))$|\1|'; } 3>&- 3>&1 >&2
 }
 # filtered out message: https://bugzilla.redhat.com/show_bug.cgi?id=1577367
 _saxon_wrapper() {
 	{ ${_XSLTPROCESSOR} "-xsl:$1" "-s:$2" -versionmsg:off 2>&1 >&3 \
 	  | sed -e '/^Cannot find CatalogManager.properties$/d'; } 3>&- 3>&1 >&2
 }
 XSLTPROCESSOR=${XSLTPROCESSOR:-xsltproc --nonet}
 _XSLTPROCESSOR=${XSLTPROCESSOR}
 case "${XSLTPROCESSOR}" in
 [Xx]alan*|*/[Xx]alan*) XSLTPROCESSOR=_xalan_wrapper;;
 sabcmd*|*/sabcmd*)     XSLTPROCESSOR=_sabcmd_wrapper;;
 saxon*|*/saxon*)       XSLTPROCESSOR=_saxon_wrapper;;
 esac
 HTTPPORT=${HTTPPORT:-8000}  # Python's default
 WEBBROWSER=${WEBBROWSER:-firefox}
 
 tests=  # test* names (should go first) here will become preselected default
 
 #
 # commons
 #
 
 emit_result() {
 	_er_howmany=${1:?}  # how many errors (0/anything else incl. strings)
 	_er_subject=${2:?}
 	_er_prefix=${3-}
 
 	test -z "${_er_prefix}" || _er_prefix="${_er_prefix}: "
 
 	if test "${_er_howmany}" = 0; then
 		printf "%s%s finished OK\n" "${_er_prefix}" "${_er_subject}"
 	else
 		printf "%s%s encountered ${_er_howmany} errors\n" \
 		       "${_er_prefix}" "${_er_subject}"
 	fi
 }
 
 emit_error() {
 	_ee_msg=${1:?}
 	printf "%s\n" "${_ee_msg}" >&2
 }
 
 # returns 1 + floor of base 2 logaritm for _lo0r_i in 1...255,
 # or 0 for _lo0r_i = 0
 log2_or_0_return() {
 	_lo0r_i=${1:?}
 	return $(((!(_lo0r_i >> 1) && _lo0r_i) * 1 \
                 + (!(_lo0r_i >> 2) && _lo0r_i & (1 << 1)) * 2 \
                 + (!(_lo0r_i >> 3) && _lo0r_i & (1 << 2)) * 3 \
                 + (!(_lo0r_i >> 4) && _lo0r_i & (1 << 3)) * 4 \
                 + (!(_lo0r_i >> 5) && _lo0r_i & (1 << 4)) * 5 \
                 + (!(_lo0r_i >> 6) && _lo0r_i & (1 << 5)) * 6 \
                 + (!(_lo0r_i >> 7) && _lo0r_i & (1 << 6)) * 7 \
                 + !!(_lo0r_i >> 7) * 7 ))
 }
 
 # rough addition of two base 2 logarithms
 log2_or_0_add() {
 	_lo0a_op1=${1:?}
 	_lo0a_op2=${2:?}
 
 	if test ${_lo0a_op1} -gt ${_lo0a_op2}; then
 		return ${_lo0a_op1}
 	elif test ${_lo0a_op2} -gt ${_lo0a_op1}; then
 		return ${_lo0a_op2}
 	elif test ${_lo0a_op1} -gt 0; then
 		return $((_lo0a_op1 + 1))
 	else
 		return ${_lo0a_op1}
 	fi
 }
 
 #
 # test phases
 #
 
 # stdin: input file per line
 test_browser() {
 	_tb_cleanref=0
 	_tb_serverpid=
 
 	if ! read _tb_first; then
 		return 1
 	fi
 	cat >/dev/null 2>/dev/null  # read out the rest
 
 	test -f assets/diffview.js \
 	  || curl -Lo assets/diffview.js \
 	     'https://raw.githubusercontent.com/prettydiff/prettydiff/2.2.8/lib/diffview.js'
 
 	{ which python3 >/dev/null 2>/dev/null \
 	  && { python3 -m http.server "${HTTPPORT}" -b 127.0.0.1 \
 	       || emit_error "Python3 HTTP server fail"; return; } \
 	  || which python2 >/dev/null 2>/dev/null \
 	       && { printf '%s %s\n' \
 	            'Python 2 backed HTTP server cannot listen at particular' \
 	            'address, discretion regarding firewall rules recommended!'
 	            python2 -m SimpleHTTPServer "${HTTPPORT}" \
 	            || emit_error 'Python2 HTTP server fail'; return; } \
 	       || emit_error 'Cannot run Python based HTTP server' ; } &
 	_tb_serverpid=$!
 	${WEBBROWSER} "http://localhost:${HTTPPORT}/${_tb_first}" &
 	printf "When finished, just press Ctrl+C or kill %d, please\n" \
 	       "${_tb_serverpid}"
 	wait
 }
 
 # -r ... whether to remove referential files as well
 # stdin: input file per line
 test_cleaner() {
 	_tc_cleanref=0
 
 	while test $# -gt 0; do
 		case "$1" in
 		-r) _tc_cleanref=1;;
 		esac
 		shift
 	done
 
 	while read _tc_origin; do
 		_tc_origin=${_tc_origin%.*}
 		rm -f "${_tc_origin}.up" "${_tc_origin}.up.err"
 		rm -f "$(dirname "${_tc_origin}")/.$(basename "${_tc_origin}").up"
 		test ${_tc_cleanref} -eq 0 \
 		  || rm -f "${_tc_origin}.ref" "${_tc_origin}.ref.err"
 	done
 }
 
+# -a= ... action modifier to derive template name from (if any; enter/leave)
+# -o= ... which conventional version to deem as the transform origin
 test_selfcheck() {
 	_tsc_ret=0
+	_tsc_action=
 	_tsc_template=
 	_tsc_validator=
 
 	while test $# -gt 0; do
 		case "$1" in
+		-a=*) _tsc_action="${1#-a=}";;
 		-o=*) _tsc_template="${1#-o=}";;
 		esac
 		shift
 	done
 	_tsc_validator="${_tsc_template:?}"
 	_tsc_validator="cibtr-${_tsc_validator%%.*}.rng"
-	_tsc_template="upgrade-${_tsc_template}.xsl"
+	_tsc_action=${_tsc_action:+-${_tsc_action}}
+	_tsc_template="upgrade-${_tsc_template}${_tsc_action}.xsl"
 
 	# check schema (sub-grammar) for custom transformation mapping alone
-	if ! ${RNGVALIDATOR} 'http://relaxng.org/relaxng.rng' "${_tsc_validator}"; then
+        if test -z "${_tsc_action}" \
+	  && ! ${RNGVALIDATOR} 'http://relaxng.org/relaxng.rng' "${_tsc_validator}"; then
 		_tsc_ret=$((_tsc_ret + 1))
 	fi
+
 	# check the overall XSLT per the main grammar + said sub-grammar
-	if ! ${RNGVALIDATOR} "xslt_${_tsc_validator}" "${_tsc_template}"; then
+        if ! ${RNGVALIDATOR} \
+          "$(test -f "${_tsc_validator}" \
+             && echo "xslt_${_tsc_validator}" \
+             || echo 'http://www.thaiopensource.com/relaxng/xslt.rng')" \
+          "${_tsc_template}"; then
 		_tsc_ret=$((_tsc_ret + 1))
 	fi
 
 	log2_or_0_return ${_tsc_ret}
 }
 
 test_explanation() {
 	_tsc_template=
 
 	while test $# -gt 0; do
 		case "$1" in
 		-o=*) _tsc_template="upgrade-${1#-o=}.xsl";;
 		esac
 		shift
 	done
 
 	${XSLTPROCESSOR} upgrade-detail.xsl "${_tsc_template}"
 }
 
 # stdout: filename of the transformed file
 test_runner_upgrade() {
 	_tru_template=${1:?}
 	_tru_source=${2:?}  # filename
 	_tru_mode=${3:?}  # extra modes wrt. "referential" outcome, see below
 
 	_tru_ref="${_tru_source%.*}.ref"
         { test "$((_tru_mode & (1 << 0)))" -ne 0 \
 	  || test -f "${_tru_ref}.err"; } \
 	  && _tru_ref_err="${_tru_ref}.err" || _tru_ref_err=/dev/null
 	_tru_target="${_tru_source%.*}.up"
 	_tru_target_err="${_tru_target}.err"
 
 	if test $((_tru_mode & (1 << 2))) -eq 0; then
 		${XSLTPROCESSOR} "${_tru_template}" "${_tru_source}" \
 		  > "${_tru_target}" 2> "${_tru_target_err}" \
 		  || { _tru_ref=$?; echo "${_tru_target_err}"
 		       return ${_tru_ref}; }
 	else
 		# when -B (deblanked outcomes handling) requested, we:
 		# - drop blanks from the source XML
 		#   (effectively emulating pacemaker handling)
 		# - re-drop blanks from the XSLT outcome,
 		#   which is compared with referential outcome
 		#   processed with even greedier custom deblanking
 		#   (extraneous inter-element whitespace like blank
 		#   lines will not get removed otherwise, see lower)
 		xmllint --noblanks "${_tru_source}" \
 		  | ${XSLTPROCESSOR} "${_tru_template}" - \
 		  > "${_tru_target}" 2> "${_tru_target_err}" \
 		  || { _tru_ref=$?; echo "${_tru_target_err}"
 		       return ${_tru_ref}; }
 		# reusing variable no longer needed
 		_tru_template="$(dirname "${_tru_target}")"
 		_tru_template="${_tru_template}/.$(basename "${_tru_target}")"
 		mv "${_tru_target}" "${_tru_template}"
 		${XSLTPROCESSOR} - "${_tru_template}" > "${_tru_target}" <<-EOF
 	<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 	<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes"/>
 	<xsl:template match="@*|*|comment()|processing-instruction()">
 	  <xsl:copy>
 	    <xsl:apply-templates select="@*|node()"/>
 	  </xsl:copy>
 	</xsl:template>
 	<xsl:template match="text()">
 	  <xsl:value-of select="normalize-space(.)"/>
 	</xsl:template>
 	</xsl:stylesheet>
 EOF
 	fi
 
 	# only respond with the flags except for "-B", i.e., when both:
 	# - _tru_mode non-zero
 	# - "-B" in _tru_mode is zero (hence non-zero when flipped with XOR)
 	if test "$((_tru_mode * ((_tru_mode ^ (1 << 2)) & (1 << 2))))" -ne 0; then
 		if test $((_tru_mode & (1 << 0))) -ne 0; then
 			cp -a "${_tru_target}" "${_tru_ref}"
 			cp -a "${_tru_target_err}" "${_tru_ref_err}"
 		fi
 		if test $((_tru_mode & (1 << 1))) -ne 0; then
-			"${DIFF}" ${DIFFOPTS} "${_tru_source}" "${_tru_ref}" \
-			  | ${DIFFPAGER} >&2
+			{ "${DIFF}" ${DIFFOPTS} "${_tru_source}" "${_tru_ref}" \
+			  && printf '\n(files match)\n'; } | ${DIFFPAGER} >&2
 			if test $? -ne 0; then
 				printf "\npager failure\n" >&2
 				return 1
 			fi
 			printf '\nIs comparison OK? ' >&2
 			if read _tru_answer </dev/tty; then
 				case "${_tru_answer}" in
 				y|yes) ;;
 				*) echo "Answer not 'y' nor 'yes'" >&2; return 1;;
 				esac
 			else
 				return 1
 			fi
 		fi
 	elif test -f "${_tru_ref}" && test -e "${_tru_ref_err}"; then
 		{ test "$((_tru_mode & (1 << 2)))" -eq 0 && cat "${_tru_ref}" \
 		    || ${XSLTPROCESSOR} - "${_tru_ref}" <<-EOF
 	<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 	<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes"/>
 	<xsl:template match="@*|*|comment()|processing-instruction()">
 	  <xsl:copy>
 	    <xsl:apply-templates select="@*|node()"/>
 	  </xsl:copy>
 	</xsl:template>
 	<xsl:template match="text()">
 	  <xsl:value-of select="normalize-space(.)"/>
 	</xsl:template>
 	</xsl:stylesheet>
 EOF
 		} \
 		  | "${DIFF}" ${DIFFOPTS} - "${_tru_target}" >&2 \
 		  && "${DIFF}" ${DIFFOPTS} "${_tru_ref_err}" \
 		       "${_tru_target_err}" >&2
 		if test $? -ne 0; then
 			emit_error "Outputs differ from referential ones"
 			echo "/dev/null"
 			return 1
 		fi
 	else
 		emit_error "Referential file(s) missing: ${_tru_ref}"
 		echo "/dev/null"
 		return 1
 	fi
 
 	echo "${_tru_target}"
 }
 
 test_runner_validate() {
 	_trv_schema=${1:?}
 	_trv_target=${2:?}  # filename
 
 	if ! ${RNGVALIDATOR} "${_trv_schema}" "${_trv_target}" \
 	    2>/dev/null; then
 		${RNGVALIDATOR} "${_trv_schema}" "${_trv_target}"
 	fi
 }
 
+# -a= ... action modifier completing template name (e.g. 2.10-(enter|leave))
 # -o= ... which conventional version to deem as the transform origin
 # -t= ... which conventional version to deem as the transform target
 # -B
 # -D
 # -G ... see usage
 # stdin: input file per line
 test_runner() {
 	_tr_mode=0
 	_tr_ret=0
+	_tr_action=
 	_tr_schema_o=
 	_tr_schema_t=
 	_tr_target=
 	_tr_template=
 
 	while test $# -gt 0; do
 		case "$1" in
-		-o=*) _tr_template="upgrade-${1#-o=}.xsl"
+		-a=*) _tr_action="${1#-a=}";;
+		-o=*) _tr_template="${1#-o=}"
 		      _tr_schema_o="pacemaker-${1#-o=}.rng";;
 		-t=*) _tr_schema_t="pacemaker-${1#-t=}.rng";;
 		-G) _tr_mode=$((_tr_mode | (1 << 0)));;
 		-D) _tr_mode=$((_tr_mode | (1 << 1)));;
 		-B) _tr_mode=$((_tr_mode | (1 << 2)));;
 		esac
 		shift
 	done
+	_tr_template="upgrade-${_tr_action:-${_tr_template:?}}.xsl"
 
 	if ! test -f "${_tr_schema_o:?}" || ! test -f "${_tr_schema_t:?}"; then
 		emit_error "Origin and/or target schema missing, rerun make"
 		return 1
 	fi
 
 	while read _tr_origin; do
 		printf '%-60s' "${_tr_origin}... "
 
 		# pre-validate
 		if ! test_runner_validate "${_tr_schema_o}" "${_tr_origin}"; then
 			_tr_ret=$((_tr_ret + 1)); echo "E:pre-validate"; continue
 		fi
 
 		# upgrade
 		if ! _tr_target=$(test_runner_upgrade "${_tr_template}" \
 		                 "${_tr_origin}" "${_tr_mode}"); then
 			_tr_ret=$((_tr_ret + 1));
 			test -n "${_tr_target}" || break
 			echo "E:upgrade"
 			test -s "${_tr_target}" \
 			  && { echo ---; cat "${_tr_target}" || :; echo ---; }
 			continue
 		fi
 
 		# post-validate
 		if ! test_runner_validate "${_tr_schema_t}" "${_tr_target}"; then
 			_tr_ret=$((_tr_ret + 1)); echo "E:post-validate"; continue
 		fi
 
 		echo "OK"
 	done
 
 	log2_or_0_return ${_tr_ret}
 }
 
 #
 # particular test variations
+# -C
+# -S
+# -X
+# -W ... see usage
 # stdin: granular test specification(s) if any
 #
 
 test2to3() {
 	_t23_pattern=
 
 	while read _t23_spec; do
 		_t23_spec=${_t23_spec%.xml}
 		_t23_spec=${_t23_spec%\*}
 		_t23_pattern="${_t23_pattern} -name ${_t23_spec}*.xml -o"
 	done
 	test -z "${_t23_pattern}" || _t23_pattern="( ${_t23_pattern%-o} )"
 
 	find test-2 -name test-2 -o -type d -prune \
 	  -o -name '*.xml' ${_t23_pattern} -print | env LC_ALL=C sort \
 	  | { case " $* " in
 	      *\ -C\ *) test_cleaner;;
 	      *\ -S\ *) test_selfcheck -o=2.10;;
 	      *\ -X\ *) test_explanation -o=2.10;;
 	      *\ -W\ *) test_browser;;
 	      *) test_runner -o=2.10 -t=3.0 "$@" || return $?;;
 	      esac; }
 }
 tests="${tests} test2to3"
 
+test2to3enter() {
+	_t23e_pattern=
+
+	while read _t23e_spec; do
+		_t23e_spec=${_t23e_spec%.xml}
+		_t23e_spec=${_t23e_spec%\*}
+		_t23e_pattern="${_t23e_pattern} -name ${_t23e_spec}*.xml -o"
+	done
+	test -z "${_t23e_pattern}" || _t23e_pattern="( ${_t23e_pattern%-o} )"
+
+	find test-2-enter -name test-2-enter -o -type d -prune \
+	  -o -name '*.xml' ${_t23e_pattern} -print | env LC_ALL=C sort \
+	  | { case " $* " in
+	      *\ -C\ *) test_cleaner;;
+	      *\ -S\ *) test_selfcheck -a=enter -o=2.10;;
+	      *\ -W\ *) emit_result "not implemented" "option -W";;
+	      *\ -X\ *) emit_result "not implemented" "option -X";;
+	      *) test_runner -a=2.10-enter -o=2.10 -t=2.10 "$@" || return $?;;
+	      esac; }
+}
+tests="${tests} test2to3enter"
+
+test2to3leave() {
+	_t23l_pattern=
+
+	while read _t23l_spec; do
+		_t23l_spec=${_t23l_spec%.xml}
+		_t23l_spec=${_t23l_spec%\*}
+		_t23l_pattern="${_t23l_pattern} -name ${_t23l_spec}*.xml -o"
+	done
+	test -z "${_t23l_pattern}" || _t23l_pattern="( ${_t23l_pattern%-o} )"
+
+	find test-2-leave -name test-2-leave -o -type d -prune \
+	  -o -name '*.xml' ${_t23l_pattern} -print | env LC_ALL=C sort \
+	  | { case " $* " in
+	      *\ -C\ *) test_cleaner;;
+	      *\ -S\ *) test_selfcheck -a=leave -o=2.10;;
+	      *\ -W\ *) emit_result "not implemented" "option -W";;
+	      *\ -X\ *) emit_result "not implemented" "option -X";;
+	      *) test_runner -a=2.10-leave -o=3.0 -t=3.0 "$@" || return $?;;
+	      esac; }
+}
+tests="${tests} test2to3leave"
+
+test2to3roundtrip() {
+	_t23rt_pattern=
+
+	while read _t23tr_spec; do
+		_t23rt_spec=${_t23rt_spec%.xml}
+		_t23rt_spec=${_t23rt_spec%\*}
+		_t23rt_pattern="${_t23rt_pattern} -name ${_t23rt_spec}*.xml -o"
+	done
+	test -z "${_t23rt_pattern}" || _t23rt_pattern="( ${_t23rt_pattern%-o} )"
+
+	find test-2-roundtrip -name test-2-roundtrip -o -type d -prune \
+	  -o -name '*.xml' ${_t23rt_pattern} -print | env LC_ALL=C sort \
+	  | { case " $* " in
+	      *\ -C\ *) test_cleaner;;
+	      *\ -S\ *) test_selfcheck -a=roundtrip -o=2.10;;
+	      *\ -W\ *) test_browser;;
+	      *\ -X\ *) emit_result "not implemented" "option -X";;
+	      *) test_runner -a=2.10-roundtrip -o=2.10 -t=3.0 "$@" || return $?;;
+	      esac; }
+}
+tests="${tests} test2to3roundtrip"
+
 # -B
 # -D
 # -G ... see usage
 cts_scheduler() {
 	_tcp_mode=0
 	_tcp_ret=0
 	_tcp_validatewith=
 	_tcp_schema_o=
 	_tcp_schema_t=
 	_tcp_template=
 
 	find ../cts/scheduler -name scheduler -o -type d -prune \
 	  -o -name '*.xml' -print | env LC_ALL=C sort \
 	  | { case " $* " in
 	      *\ -C\ *) test_cleaner -r;;
 	      *\ -S\ *) emit_result "not implemented" "option -S";;
+	      *\ -W\ *) emit_result "not implemented" "option -W";;
 	      *\ -X\ *) emit_result "not implemented" "option -X";;
 	      *)
 		while test $# -gt 0; do
 			case "$1" in
 			-G) _tcp_mode=$((_tcp_mode | (1 << 0)));;
 			-D) _tcp_mode=$((_tcp_mode | (1 << 1)));;
 			-B) _tcp_mode=$((_tcp_mode | (1 << 2)));;
 			esac
 			shift
 		done
 		while read _tcp_origin; do
 			_tcp_validatewith=$(${XSLTPROCESSOR} - "${_tcp_origin}" <<-EOF
 	<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 	<xsl:output method="text" encoding="UTF-8"/>
 	<xsl:template match="/">
 	  <xsl:choose>
 	    <xsl:when test="starts-with(cib/@validate-with, 'pacemaker-')">
 	      <xsl:variable name="Version" select="substring-after(cib/@validate-with, 'pacemaker-')"/>
 	      <xsl:choose>
 	        <xsl:when test="contains(\$Version, '.')">
 	          <xsl:value-of select="substring-before(\$Version, '.')"/>
 	        </xsl:when>
 	        <xsl:otherwise>
 	          <xsl:value-of select="cib/@validate-with"/>
 	        </xsl:otherwise>
 	      </xsl:choose>
 	    </xsl:when>
 	    <xsl:otherwise>
 	     <xsl:value-of select="cib/@validate-with"/>
 	    </xsl:otherwise>
 	  </xsl:choose>
 	</xsl:template>
 	</xsl:stylesheet>
 EOF
 )
 			_tcp_schema_t=${_tcp_validatewith}
 			case "${_tcp_validatewith}" in
 			1) _tcp_schema_o=1.3;;
 			2) _tcp_schema_o=2.10;;
 			# only for gradual refinement as upgrade-2.10.xsl under
 			# active development, move to 3.x when schema v4 emerges
 			3) _tcp_schema_o=2.10
 			   _tcp_schema_t=2;;
 			*) emit_error \
 			   "need to skip ${_tcp_origin} (schema: ${_tcp_validatewith})"
 			   continue;;
 			esac
 			_tcp_template="upgrade-${_tcp_schema_o}.xsl"
 			_tcp_schema_t="pacemaker-$((_tcp_schema_t + 1)).0.rng"
 			test "${_tcp_schema_o%%.*}" = "${_tcp_validatewith}" \
 			  && _tcp_schema_o="pacemaker-${_tcp_schema_o}.rng" \
 			  || _tcp_schema_o="${_tcp_schema_t}"
 
 			# pre-validate
 			if test "${_tcp_schema_o}" != "${_tcp_schema_t}" \
 			  && ! test_runner_validate "${_tcp_schema_o}" "${_tcp_origin}"; then
 				_tcp_ret=$((_tcp_ret + 1)); echo "E:pre-validate"; continue
 			fi
 
 			# upgrade
 			test "$((_tcp_mode & (1 << 0)))" -ne 0 \
 			  || ln -fs "$(pwd)/${_tcp_origin}" "${_tcp_origin%.*}.ref"
 			if ! _tcp_target=$(test_runner_upgrade "${_tcp_template}" \
 			                   "${_tcp_origin}" "${_tcp_mode}"); then
 				_tcp_ret=$((_tcp_ret + 1));
 				test -n "${_tcp_target}" || break
 				echo "E:upgrade"
 				test -s "${_tcp_target}" \
 				  && { echo ---; cat "${_tcp_target}" || :; echo ---; }
 				continue
 			fi
 			test "$((_tcp_mode & (1 << 0)))" -ne 0 \
 			  || rm -f "${_tcp_origin%.*}.ref"
 
 			# post-validate
 			if ! test_runner_validate "${_tcp_schema_t}" "${_tcp_target}"; then
 				_tcp_ret=$((_tcp_ret + 1)); echo "E:post-validate"; continue
 			fi
 
 			test "$((_tcp_mode & (1 << 0)))" -eq 0 \
 			  || mv "${_tcp_target}" "${_tcp_origin}"
 		done; log2_or_0_return ${_tcp_ret};;
 	      esac; }
 }
 tests="${tests} cts_scheduler"
 
 #
 # "framework"
 #
 
 # option-likes ... options to be passed down
 # argument-likes ... drives a test selection
 test_suite() {
 	_ts_pass=
 	_ts_select=
 	_ts_select_full=
 	_ts_test_specs=
 	_ts_global_ret=0
 	_ts_ret=0
 
 	while test $# -gt 0; do
 		case "$1" in
 		-) printf '%s\n' 'waiting for tests specified at stdin...';
 		   while read _ts_spec; do _ts_select="${_ts_spec}@$1"; done;;
 		-*) _ts_pass="${_ts_pass} $1";;
 		*) _ts_select_full="${_ts_select_full}@$1"
 		   _ts_select="${_ts_select}@${1%%/*}";;
 		esac
 		shift
 	done
 	_ts_select="${_ts_select}@"
 	_ts_select_full="${_ts_select_full}@"
 
 	for _ts_test in ${tests}; do
 
 		while true; do
 			case "${_ts_select}" in
 			*@${_ts_test}@*)
 			_ts_select="${_ts_select%@${_ts_test}@*}"\
 "@${_ts_select#*@${_ts_test}@}"
 			break
 			;;
 			@) case "${_ts_test}" in test*) break;; esac
 			;;
 			esac
 			continue 2  # move on to matching with next local test
 		done
 
 		_ts_test_specs=
 		while true; do
 			case "${_ts_select_full}" in
 			*@${_ts_test}/*)
 				_ts_test_full="${_ts_test}/${_ts_select_full#*@${_ts_test}/}"
 				_ts_test_full="${_ts_test_full%%@*}"
 				_ts_select_full="${_ts_select_full%@${_ts_test_full}@*}"\
 "@${_ts_select_full#*@${_ts_test_full}@}"
 				_ts_test_specs="${_ts_test_specs} ${_ts_test_full#*/}"
 			;;
 			*)
 			break
 			;;
 			esac
 		done
 
 		for _ts_test_spec in ${_ts_test_specs}; do
 			printf '%s\n' "${_ts_test_spec}"
 		done | "${_ts_test}" ${_ts_pass} || _ts_ret=$?
 
 		test ${_ts_ret} = 0 \
 		  && emit_result ${_ts_ret} "${_ts_test}" \
 		  || emit_result "at least 2^$((_ts_ret - 1))" "${_ts_test}"
 		log2_or_0_add ${_ts_global_ret} ${_ts_ret}
 		_ts_global_ret=$?
 	done
 	if test "${_ts_select}" != @; then
 		emit_error "Non-existing test(s):$(echo "${_ts_select}" \
 		                                   | tr '@' ' ')"
 		log2_or_0_add ${_ts_global_ret} 1 || _ts_global_ret=$?
 	fi
 
 	return ${_ts_global_ret}
 }
 
 # NOTE: big letters are dedicated for per-test-set behaviour,
 #       small ones for generic/global behaviour
 usage() {
 	printf \
-	  '%s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n' \
-	  "usage: $0 [-{B,C,D,G,S,X}]* [-|{${tests## }}*]" \
+	  '%s\n%s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n' \
+	  "usage: $0 [-{B,C,D,G,S,X}]* \\" \
+          "       [-|{${tests## }}*]" \
 	  "- when no suites (arguments) provided, \"test*\" ones get used" \
 	  "- with '-' suite specification the actual ones grabbed on stdin" \
 	  "- use '-B' to run validate-only check suppressing blanks first" \
 	  "- use '-C' to only cleanup ephemeral byproducts" \
 	  "- use '-D' to review originals vs. \"referential\" outcomes" \
 	  "- use '-G' to generate \"referential\" outcomes" \
 	  "- use '-S' for template self-check (requires net access)" \
 	  "- use '-W' to run browser-based, on-the-fly diff'ing test drive" \
 	  "- use '-X' to show explanatory details about the upgrade" \
 	  "- test specification can be granular, e.g. 'test2to3/022'"
 	printf \
 	  '\n%s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n' \
 	  'environment variables affecting the run + default/current values:' \
 	  "- DIFF (${DIFF}): tool to compute and show differences of 2 files" \
 	  "- DIFFOPTS (${DIFFOPTS}): options to the above tool" \
 	  "- DIFFPAGER (${DIFFPAGER}): possibly accompanying the above tool" \
 	  "- RNGVALIDATOR (${RNGVALIDATOR}): RelaxNG validator" \
 	  "- XSLTPROCESSOR (${_XSLTPROCESSOR}): XSLT 1.0 capable processor" \
 	  "- HTTPPORT (${HTTPPORT}): port used by test drive HTTP server run" \
 	  "- WEBBROWSER (${WEBBROWSER}): used for in-browser test drive"
 }
 
 main() {
 	_main_pass=
 	_main_bailout=0
 	_main_ret=0
 
 	while test $# -gt 0; do
 		case "$1" in
 		-h) usage; exit;;
 		-C|-G|-S|-X) _main_bailout=1;;
 		esac
 		_main_pass="${_main_pass} $1"
 		shift
 	done
 
 	test_suite ${_main_pass} || _main_ret=$?
-	test ${_main_bailout} -eq 1 && return ${_main_ret} \
+	test ${_main_bailout} -ne 0 \
 	  || test_suite -C ${_main_pass} >/dev/null || true
 	test ${_main_ret} = 0 && emit_result ${_main_ret} "Overall suite" \
 	  || emit_result "at least 2^$((_main_ret - 1))" "Overall suite"
 
 	return ${_main_ret}
 }
 
 main "$@"
diff --git a/xml/resources-3.0.rng b/xml/resources-3.0.rng
index 3000b78208..f5b915833b 100644
--- a/xml/resources-3.0.rng
+++ b/xml/resources-3.0.rng
@@ -1,465 +1,465 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0"
          datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <start>
-      <ref name="element-resources"/>
+    <ref name="element-resources"/>
   </start>
 
   <define name="element-resources">
     <element name="resources">
       <zeroOrMore>
         <choice>
           <ref name="element-primitive"/>
           <ref name="element-template"/>
           <ref name="element-group"/>
           <ref name="element-clone"/>
           <ref name="element-master"/>
           <ref name="element-bundle"/>
         </choice>
       </zeroOrMore>
     </element>
   </define>
 
   <!--
    see upgrade-2.10.xsl
    - cibtr:table for="resource-meta-attributes"
    -->
   <define name="primitive-template.meta_attributes.nvpair.name-unsupported">
     <attribute name="name">
       <data type="string">
         <except>
           <choice>
             <value>isolation</value>
             <value>isolation-host</value>
             <value>isolation-instance</value>
             <value>isolation-wrapper</value>
           </choice>
         </except>
       </data>
     </attribute>
   </define>
 
   <!--
    see upgrade-2.10.xsl
    - cibtr:table for="resource-instance-attributes"
    -->
   <define name="primitive-template.instance_attributes.nvpair.name-unsupported">
     <attribute name="name">
       <data type="string">
         <except>
           <choice>
             <value>pcmk_arg_map</value>
             <value>pcmk_list_cmd</value>
             <value>pcmk_monitor_cmd</value>
             <value>pcmk_off_cmd</value>
             <value>pcmk_on_cmd</value>
             <value>pcmk_reboot_cmd</value>
             <value>pcmk_status_cmd</value>
           </choice>
         </except>
       </data>
     </attribute>
   </define>
 
   <define name="element-resource-extra.primitive-template">
     <zeroOrMore>
       <choice>
         <element name="meta_attributes">
           <grammar>
             <include href="nvset-3.0.rng">
               <define name="element-nvset.name">
                 <parentRef name="primitive-template.meta_attributes.nvpair.name-unsupported"/>
               </define>
             </include>
           </grammar>
         </element>
         <element name="instance_attributes">
           <grammar>
             <include href="nvset-3.0.rng">
               <define name="element-nvset.name">
                 <parentRef name="primitive-template.instance_attributes.nvpair.name-unsupported"/>
               </define>
             </include>
           </grammar>
         </element>
       </choice>
     </zeroOrMore>
   </define>
 
   <define name="element-primitive">
     <element name="primitive">
       <interleave>
         <attribute name="id"><data type="ID"/></attribute>
         <choice>
           <group>
             <ref name="element-resource-class"/>
             <attribute name="type"><text/></attribute>
           </group>
           <attribute name="template"><data type="IDREF"/></attribute>
         </choice>
         <optional>
           <attribute name="description"><text/></attribute>
         </optional>
         <ref name="element-resource-extra.primitive-template"/>
         <ref name="element-operations"/>
         <zeroOrMore>
           <element name="utilization">
             <externalRef href="nvset-3.0.rng"/>
           </element>
         </zeroOrMore>
       </interleave>
     </element>
   </define>
 
   <define name="element-template">
     <element name="template">
       <interleave>
         <attribute name="id"><data type="ID"/></attribute>
         <ref name="element-resource-class"/>
         <attribute name="type"><text/></attribute>
         <optional>
           <attribute name="description"><text/></attribute>
         </optional>
         <ref name="element-resource-extra.primitive-template"/>
         <ref name="element-operations"/>
         <zeroOrMore>
           <element name="utilization">
             <externalRef href="nvset-3.0.rng"/>
           </element>
         </zeroOrMore>
       </interleave>
     </element>
   </define>
 
   <define name="element-bundle">
     <element name="bundle">
       <interleave>
         <attribute name="id"><data type="ID"/></attribute>
         <optional>
           <attribute name="description"><text/></attribute>
         </optional>
         <ref name="element-resource-extra"/>
         <choice>
           <element name="docker">
             <attribute name="image"><text/></attribute>
             <optional>
               <attribute name="replicas"><data type="integer"/></attribute>
             </optional>
             <optional>
               <attribute name="replicas-per-host"><data type="integer"/></attribute>
             </optional>
             <optional>
               <choice>
                 <attribute name="masters"><data type="integer"/></attribute>
                 <attribute name="promoted-max"><data type="integer"/></attribute>
               </choice>
             </optional>
             <optional>
               <attribute name="run-command"> <text/></attribute>
             </optional>
             <optional>
               <attribute name="network"><text/></attribute>
             </optional>
             <optional>
               <attribute name="options"><text/></attribute>
             </optional>
           </element>
           <element name="rkt">
             <attribute name="image"><text/></attribute>
             <optional>
               <attribute name="replicas"><data type="integer"/></attribute>
             </optional>
             <optional>
               <attribute name="replicas-per-host"><data type="integer"/></attribute>
             </optional>
             <optional>
               <choice>
                 <attribute name="masters"><data type="integer"/></attribute>
                 <attribute name="promoted-max"><data type="integer"/></attribute>
               </choice>
             </optional>
             <optional>
               <attribute name="run-command"> <text/></attribute>
             </optional>
             <optional>
               <attribute name="network"><text/></attribute>
             </optional>
             <optional>
               <attribute name="options"><text/></attribute>
             </optional>
           </element>
         </choice>
         <optional>
           <element name="network">
             <optional>
               <attribute name="ip-range-start"><text/></attribute>
             </optional>
             <optional>
               <attribute name="control-port"><data type="integer"/></attribute>
             </optional>
             <optional>
               <attribute name="host-interface"><text/></attribute>
             </optional>
             <optional>
               <attribute name="host-netmask"><data type="integer"/></attribute>
             </optional>
             <optional>
               <attribute name="add-host"><data type="boolean"/></attribute>
             </optional>
             <zeroOrMore>
               <element name="port-mapping">
                 <attribute name="id"><data type="ID"/></attribute>
                 <choice>
                   <group>
                     <attribute name="port"><data type="integer"/></attribute>
                     <optional>
                       <attribute name="internal-port"><data type="integer"/></attribute>
                     </optional>
                   </group>
                   <attribute name="range">
                     <data type="string">
                       <param name="pattern">([0-9\-]+)</param>
                     </data>
                   </attribute>
                 </choice>
               </element>
             </zeroOrMore>
           </element>
         </optional>
         <optional>
           <element name="storage">
             <zeroOrMore>
               <element name="storage-mapping">
                 <attribute name="id"><data type="ID"/></attribute>
                 <choice>
                   <attribute name="source-dir"><text/></attribute>
                   <attribute name="source-dir-root"><text/></attribute>
                 </choice>
                 <attribute name="target-dir"><text/></attribute>
                 <optional>
                   <attribute name="options"><text/></attribute>
                 </optional>
               </element>
             </zeroOrMore>
           </element>
         </optional>
         <optional>
           <ref name="element-primitive"/>
         </optional>
       </interleave>
     </element>
   </define>
 
   <define name="element-group">
     <element name="group">
       <attribute name="id"><data type="ID"/></attribute>
       <optional>
         <attribute name="description"><text/></attribute>
       </optional>
       <interleave>
         <ref name="element-resource-extra"/>
         <oneOrMore>
           <ref name="element-primitive"/>
         </oneOrMore>
       </interleave>
     </element>
   </define>
 
   <define name="element-clone">
     <element name="clone">
       <attribute name="id"><data type="ID"/></attribute>
       <optional>
         <attribute name="description"><text/></attribute>
       </optional>
       <interleave>
         <ref name="element-resource-extra"/>
         <choice>
           <ref name="element-primitive"/>
           <ref name="element-group"/>
         </choice>
       </interleave>
     </element>
   </define>
 
   <define name="element-master">
     <element name="master">
       <attribute name="id"><data type="ID"/></attribute>
       <optional>
         <attribute name="description"><text/></attribute>
       </optional>
       <interleave>
         <ref name="element-resource-extra"/>
         <choice>
           <ref name="element-primitive"/>
           <ref name="element-group"/>
         </choice>
       </interleave>
     </element>
   </define>
 
   <define name="element-resource-extra">
     <zeroOrMore>
       <choice>
         <element name="meta_attributes">
           <externalRef href="nvset-3.0.rng"/>
         </element>
         <element name="instance_attributes">
           <externalRef href="nvset-3.0.rng"/>
         </element>
       </choice>
     </zeroOrMore>
   </define>
 
   <!--
    see upgrade-2.10.xsl
    - cibtr:table for="resources-operation"
    -->
   <define name="op.meta_attributes.nvpair.name-unsupported">
     <attribute name="name">
       <data type="string">
         <except>
           <choice>
             <value>requires</value>
           </choice>
         </except>
       </data>
     </attribute>
   </define>
 
   <!--
    see above and upgrade-2.10.xsl
    - cibtr:table for="resources-operation-instance-attributes"
    NOTE: this is rather a grey area, but setting special parameters
          just for the particular operation is currently not customary,
          and unsupported by higher level tools, e.g. pcs:
          https://bugzilla.redhat.com/show_bug.cgi?id=1469801
          so take the liberty to exclude them for now
    -->
   <define name="op.instance_attributes.nvpair.name-unsupported">
     <attribute name="name">
       <data type="string">
         <except>
           <choice>
             <value>interval-origin</value>
             <value>start-delay</value>
 
             <value>enabled</value>
             <value>on-fail</value>
             <value>record-pending</value>
             <value>role</value>
             <value>timeout</value>
 
             <value>requires</value>
           </choice>
         </except>
       </data>
     </attribute>
   </define>
 
   <define name="element-resource-extra.op">
     <zeroOrMore>
       <choice>
         <element name="meta_attributes">
           <grammar>
             <include href="nvset-3.0.rng">
               <define name="element-nvset.name">
                 <parentRef name="op.meta_attributes.nvpair.name-unsupported"/>
               </define>
             </include>
           </grammar>
         </element>
         <element name="instance_attributes">
           <grammar>
             <include href="nvset-3.0.rng">
               <define name="element-nvset.name">
                 <parentRef name="op.instance_attributes.nvpair.name-unsupported"/>
               </define>
             </include>
           </grammar>
         </element>
       </choice>
     </zeroOrMore>
   </define>
 
   <define name="element-operations">
     <optional>
       <element name="operations">
         <optional>
           <attribute name="id"><data type="ID"/></attribute>
         </optional>
         <optional>
           <attribute name="id-ref"><data type="IDREF"/></attribute>
         </optional>
         <zeroOrMore>
           <element name="op">
             <attribute name="id"><data type="ID"/></attribute>
             <attribute name="name"><text/></attribute>
             <attribute name="interval"><text/></attribute>
             <optional>
               <attribute name="description"><text/></attribute>
             </optional>
             <optional>
               <choice>
                 <attribute name="start-delay"><text/></attribute>
                 <attribute name="interval-origin"><text/></attribute>
               </choice>
             </optional>
             <optional>
               <attribute name="timeout"><text/></attribute>
             </optional>
             <optional>
               <attribute name="enabled"><data type="boolean"/></attribute>
             </optional>
             <optional>
               <attribute name="record-pending"><data type="boolean"/></attribute>
             </optional>
             <optional>
               <attribute name="role">
                 <choice>
                   <value>Stopped</value>
                   <value>Started</value>
                   <value>Slave</value>
                   <value>Master</value>
                 </choice>
               </attribute>
             </optional>
             <optional>
               <attribute name="on-fail">
                 <choice>
                   <value>ignore</value>
                   <value>block</value>
                   <value>stop</value>
                   <value>restart</value>
                   <value>standby</value>
                   <value>fence</value>
                   <value>restart-container</value>
                 </choice>
               </attribute>
             </optional>
             <ref name="element-resource-extra.op"/>
           </element>
         </zeroOrMore>
       </element>
     </optional>
   </define>
 
   <define name="element-resource-class">
     <choice>
       <group>
         <attribute name="class"><value>ocf</value></attribute>
         <attribute name="provider"><text/></attribute>
       </group>
       <attribute name="class">
         <choice>
           <value>lsb</value>
           <value>heartbeat</value>
           <value>stonith</value>
           <value>upstart</value>
           <value>service</value>
           <value>systemd</value>
           <value>nagios</value>
         </choice>
       </attribute>
     </choice>
   </define>
 </grammar>
diff --git a/xml/resources-3.0.rng b/xml/resources-3.1.rng
similarity index 85%
copy from xml/resources-3.0.rng
copy to xml/resources-3.1.rng
index 3000b78208..5558ee1fa9 100644
--- a/xml/resources-3.0.rng
+++ b/xml/resources-3.1.rng
@@ -1,465 +1,401 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <grammar xmlns="http://relaxng.org/ns/structure/1.0"
          datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
   <start>
-      <ref name="element-resources"/>
+    <ref name="element-resources"/>
   </start>
 
   <define name="element-resources">
     <element name="resources">
       <zeroOrMore>
         <choice>
           <ref name="element-primitive"/>
           <ref name="element-template"/>
           <ref name="element-group"/>
           <ref name="element-clone"/>
           <ref name="element-master"/>
           <ref name="element-bundle"/>
         </choice>
       </zeroOrMore>
     </element>
   </define>
 
   <!--
    see upgrade-2.10.xsl
    - cibtr:table for="resource-meta-attributes"
    -->
   <define name="primitive-template.meta_attributes.nvpair.name-unsupported">
     <attribute name="name">
       <data type="string">
         <except>
           <choice>
             <value>isolation</value>
             <value>isolation-host</value>
             <value>isolation-instance</value>
             <value>isolation-wrapper</value>
           </choice>
         </except>
       </data>
     </attribute>
   </define>
 
-  <!--
-   see upgrade-2.10.xsl
-   - cibtr:table for="resource-instance-attributes"
-   -->
-  <define name="primitive-template.instance_attributes.nvpair.name-unsupported">
-    <attribute name="name">
-      <data type="string">
-        <except>
-          <choice>
-            <value>pcmk_arg_map</value>
-            <value>pcmk_list_cmd</value>
-            <value>pcmk_monitor_cmd</value>
-            <value>pcmk_off_cmd</value>
-            <value>pcmk_on_cmd</value>
-            <value>pcmk_reboot_cmd</value>
-            <value>pcmk_status_cmd</value>
-          </choice>
-        </except>
-      </data>
-    </attribute>
-  </define>
-
   <define name="element-resource-extra.primitive-template">
     <zeroOrMore>
       <choice>
         <element name="meta_attributes">
           <grammar>
             <include href="nvset-3.0.rng">
               <define name="element-nvset.name">
                 <parentRef name="primitive-template.meta_attributes.nvpair.name-unsupported"/>
               </define>
             </include>
           </grammar>
         </element>
         <element name="instance_attributes">
-          <grammar>
-            <include href="nvset-3.0.rng">
-              <define name="element-nvset.name">
-                <parentRef name="primitive-template.instance_attributes.nvpair.name-unsupported"/>
-              </define>
-            </include>
-          </grammar>
+          <externalRef href="nvset-3.0.rng"/>
         </element>
       </choice>
     </zeroOrMore>
   </define>
 
   <define name="element-primitive">
     <element name="primitive">
       <interleave>
         <attribute name="id"><data type="ID"/></attribute>
         <choice>
           <group>
             <ref name="element-resource-class"/>
             <attribute name="type"><text/></attribute>
           </group>
           <attribute name="template"><data type="IDREF"/></attribute>
         </choice>
         <optional>
           <attribute name="description"><text/></attribute>
         </optional>
         <ref name="element-resource-extra.primitive-template"/>
         <ref name="element-operations"/>
         <zeroOrMore>
           <element name="utilization">
             <externalRef href="nvset-3.0.rng"/>
           </element>
         </zeroOrMore>
       </interleave>
     </element>
   </define>
 
   <define name="element-template">
     <element name="template">
       <interleave>
         <attribute name="id"><data type="ID"/></attribute>
         <ref name="element-resource-class"/>
         <attribute name="type"><text/></attribute>
         <optional>
           <attribute name="description"><text/></attribute>
         </optional>
         <ref name="element-resource-extra.primitive-template"/>
         <ref name="element-operations"/>
         <zeroOrMore>
           <element name="utilization">
             <externalRef href="nvset-3.0.rng"/>
           </element>
         </zeroOrMore>
       </interleave>
     </element>
   </define>
 
   <define name="element-bundle">
     <element name="bundle">
       <interleave>
         <attribute name="id"><data type="ID"/></attribute>
         <optional>
           <attribute name="description"><text/></attribute>
         </optional>
         <ref name="element-resource-extra"/>
         <choice>
           <element name="docker">
             <attribute name="image"><text/></attribute>
             <optional>
               <attribute name="replicas"><data type="integer"/></attribute>
             </optional>
             <optional>
               <attribute name="replicas-per-host"><data type="integer"/></attribute>
             </optional>
             <optional>
               <choice>
                 <attribute name="masters"><data type="integer"/></attribute>
                 <attribute name="promoted-max"><data type="integer"/></attribute>
               </choice>
             </optional>
             <optional>
               <attribute name="run-command"> <text/></attribute>
             </optional>
             <optional>
               <attribute name="network"><text/></attribute>
             </optional>
             <optional>
               <attribute name="options"><text/></attribute>
             </optional>
           </element>
           <element name="rkt">
             <attribute name="image"><text/></attribute>
             <optional>
               <attribute name="replicas"><data type="integer"/></attribute>
             </optional>
             <optional>
               <attribute name="replicas-per-host"><data type="integer"/></attribute>
             </optional>
             <optional>
               <choice>
                 <attribute name="masters"><data type="integer"/></attribute>
                 <attribute name="promoted-max"><data type="integer"/></attribute>
               </choice>
             </optional>
             <optional>
               <attribute name="run-command"> <text/></attribute>
             </optional>
             <optional>
               <attribute name="network"><text/></attribute>
             </optional>
             <optional>
               <attribute name="options"><text/></attribute>
             </optional>
           </element>
         </choice>
         <optional>
           <element name="network">
             <optional>
               <attribute name="ip-range-start"><text/></attribute>
             </optional>
             <optional>
               <attribute name="control-port"><data type="integer"/></attribute>
             </optional>
             <optional>
               <attribute name="host-interface"><text/></attribute>
             </optional>
             <optional>
               <attribute name="host-netmask"><data type="integer"/></attribute>
             </optional>
             <optional>
               <attribute name="add-host"><data type="boolean"/></attribute>
             </optional>
             <zeroOrMore>
               <element name="port-mapping">
                 <attribute name="id"><data type="ID"/></attribute>
                 <choice>
                   <group>
                     <attribute name="port"><data type="integer"/></attribute>
                     <optional>
                       <attribute name="internal-port"><data type="integer"/></attribute>
                     </optional>
                   </group>
                   <attribute name="range">
                     <data type="string">
                       <param name="pattern">([0-9\-]+)</param>
                     </data>
                   </attribute>
                 </choice>
               </element>
             </zeroOrMore>
           </element>
         </optional>
         <optional>
           <element name="storage">
             <zeroOrMore>
               <element name="storage-mapping">
                 <attribute name="id"><data type="ID"/></attribute>
                 <choice>
                   <attribute name="source-dir"><text/></attribute>
                   <attribute name="source-dir-root"><text/></attribute>
                 </choice>
                 <attribute name="target-dir"><text/></attribute>
                 <optional>
                   <attribute name="options"><text/></attribute>
                 </optional>
               </element>
             </zeroOrMore>
           </element>
         </optional>
         <optional>
           <ref name="element-primitive"/>
         </optional>
       </interleave>
     </element>
   </define>
 
   <define name="element-group">
     <element name="group">
       <attribute name="id"><data type="ID"/></attribute>
       <optional>
         <attribute name="description"><text/></attribute>
       </optional>
       <interleave>
         <ref name="element-resource-extra"/>
         <oneOrMore>
           <ref name="element-primitive"/>
         </oneOrMore>
       </interleave>
     </element>
   </define>
 
   <define name="element-clone">
     <element name="clone">
       <attribute name="id"><data type="ID"/></attribute>
       <optional>
         <attribute name="description"><text/></attribute>
       </optional>
       <interleave>
         <ref name="element-resource-extra"/>
         <choice>
           <ref name="element-primitive"/>
           <ref name="element-group"/>
         </choice>
       </interleave>
     </element>
   </define>
 
   <define name="element-master">
     <element name="master">
       <attribute name="id"><data type="ID"/></attribute>
       <optional>
         <attribute name="description"><text/></attribute>
       </optional>
       <interleave>
         <ref name="element-resource-extra"/>
         <choice>
           <ref name="element-primitive"/>
           <ref name="element-group"/>
         </choice>
       </interleave>
     </element>
   </define>
 
   <define name="element-resource-extra">
     <zeroOrMore>
       <choice>
         <element name="meta_attributes">
           <externalRef href="nvset-3.0.rng"/>
         </element>
         <element name="instance_attributes">
           <externalRef href="nvset-3.0.rng"/>
         </element>
       </choice>
     </zeroOrMore>
   </define>
 
   <!--
    see upgrade-2.10.xsl
    - cibtr:table for="resources-operation"
    -->
   <define name="op.meta_attributes.nvpair.name-unsupported">
     <attribute name="name">
       <data type="string">
         <except>
           <choice>
             <value>requires</value>
           </choice>
         </except>
       </data>
     </attribute>
   </define>
 
-  <!--
-   see above and upgrade-2.10.xsl
-   - cibtr:table for="resources-operation-instance-attributes"
-   NOTE: this is rather a grey area, but setting special parameters
-         just for the particular operation is currently not customary,
-         and unsupported by higher level tools, e.g. pcs:
-         https://bugzilla.redhat.com/show_bug.cgi?id=1469801
-         so take the liberty to exclude them for now
-   -->
-  <define name="op.instance_attributes.nvpair.name-unsupported">
-    <attribute name="name">
-      <data type="string">
-        <except>
-          <choice>
-            <value>interval-origin</value>
-            <value>start-delay</value>
-
-            <value>enabled</value>
-            <value>on-fail</value>
-            <value>record-pending</value>
-            <value>role</value>
-            <value>timeout</value>
-
-            <value>requires</value>
-          </choice>
-        </except>
-      </data>
-    </attribute>
-  </define>
-
   <define name="element-resource-extra.op">
     <zeroOrMore>
       <choice>
         <element name="meta_attributes">
           <grammar>
             <include href="nvset-3.0.rng">
               <define name="element-nvset.name">
                 <parentRef name="op.meta_attributes.nvpair.name-unsupported"/>
               </define>
             </include>
           </grammar>
         </element>
         <element name="instance_attributes">
-          <grammar>
-            <include href="nvset-3.0.rng">
-              <define name="element-nvset.name">
-                <parentRef name="op.instance_attributes.nvpair.name-unsupported"/>
-              </define>
-            </include>
-          </grammar>
+          <externalRef href="nvset-3.0.rng"/>
         </element>
       </choice>
     </zeroOrMore>
   </define>
 
   <define name="element-operations">
     <optional>
       <element name="operations">
         <optional>
           <attribute name="id"><data type="ID"/></attribute>
         </optional>
         <optional>
           <attribute name="id-ref"><data type="IDREF"/></attribute>
         </optional>
         <zeroOrMore>
           <element name="op">
             <attribute name="id"><data type="ID"/></attribute>
             <attribute name="name"><text/></attribute>
             <attribute name="interval"><text/></attribute>
             <optional>
               <attribute name="description"><text/></attribute>
             </optional>
             <optional>
               <choice>
                 <attribute name="start-delay"><text/></attribute>
                 <attribute name="interval-origin"><text/></attribute>
               </choice>
             </optional>
             <optional>
               <attribute name="timeout"><text/></attribute>
             </optional>
             <optional>
               <attribute name="enabled"><data type="boolean"/></attribute>
             </optional>
             <optional>
               <attribute name="record-pending"><data type="boolean"/></attribute>
             </optional>
             <optional>
               <attribute name="role">
                 <choice>
                   <value>Stopped</value>
                   <value>Started</value>
                   <value>Slave</value>
                   <value>Master</value>
                 </choice>
               </attribute>
             </optional>
             <optional>
               <attribute name="on-fail">
                 <choice>
                   <value>ignore</value>
                   <value>block</value>
                   <value>stop</value>
                   <value>restart</value>
                   <value>standby</value>
                   <value>fence</value>
                   <value>restart-container</value>
                 </choice>
               </attribute>
             </optional>
             <ref name="element-resource-extra.op"/>
           </element>
         </zeroOrMore>
       </element>
     </optional>
   </define>
 
   <define name="element-resource-class">
     <choice>
       <group>
         <attribute name="class"><value>ocf</value></attribute>
         <attribute name="provider"><text/></attribute>
       </group>
       <attribute name="class">
         <choice>
           <value>lsb</value>
           <value>heartbeat</value>
           <value>stonith</value>
           <value>upstart</value>
           <value>service</value>
           <value>systemd</value>
           <value>nagios</value>
         </choice>
       </attribute>
     </choice>
   </define>
 </grammar>
diff --git a/xml/test-2-enter/010-clu-props.ref b/xml/test-2-enter/010-clu-props.ref
new file mode 100644
index 0000000000..86369fb3ab
--- /dev/null
+++ b/xml/test-2-enter/010-clu-props.ref
@@ -0,0 +1,17 @@
+<cib validate-with="pacemaker-2.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config>
+      <cluster_property_set id="cluster-opts">
+        <nvpair id="cluster-opts-stonith_enabled" name="stonith_enabled" value="off"/>
+      </cluster_property_set>
+      <!-- this doesn't make any sense, i.e., a design flaw -->
+      <cluster_property_set id="_cibtr-2_cluster-opts">
+        <nvpair id="__cibtr-2_cluster-opts__cluster-opts-stonith_enabled" name="stonith_enabled" value="off"/>
+      </cluster_property_set>
+    </crm_config>
+    <nodes/>
+    <resources/>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-enter/010-clu-props.ref.err b/xml/test-2-enter/010-clu-props.ref.err
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/xml/test-2-enter/010-clu-props.xml b/xml/test-2-enter/010-clu-props.xml
new file mode 100644
index 0000000000..e44f4dbc12
--- /dev/null
+++ b/xml/test-2-enter/010-clu-props.xml
@@ -0,0 +1,15 @@
+<cib validate-with="pacemaker-2.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config>
+      <cluster_property_set id="cluster-opts">
+        <nvpair id="cluster-opts-stonith_enabled" name="stonith_enabled" value="off"/>
+      </cluster_property_set>
+      <!-- this doesn't make any sense, i.e., a design flaw -->
+      <cluster_property_set id-ref="cluster-opts"/>
+    </crm_config>
+    <nodes/>
+    <resources/>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-enter/020-instance_atributes-rsc.ref b/xml/test-2-enter/020-instance_atributes-rsc.ref
new file mode 100644
index 0000000000..e746319593
--- /dev/null
+++ b/xml/test-2-enter/020-instance_atributes-rsc.ref
@@ -0,0 +1,41 @@
+<cib validate-with="pacemaker-2.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config/>
+    <nodes>
+
+      <node id="virt-063" uname="virt-063"/>
+      <node id="virt-064" uname="virt-064"/>
+      <node id="virt-069" uname="virt-069"/>
+
+    </nodes>
+    <resources>
+
+      <primitive id="myAddr1" class="ocf" provider="heartbeat" type="IPaddr2">
+        <operations>
+          <op id="myAddr1-monitor" name="monitor" interval="30s"/>
+        </operations>
+        <instance_attributes id="myAddr1-params">
+          <nvpair id="myAddr1-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+        <instance_attributes id="myAddr-common-params">
+          <nvpair id="myAddr-common-cidr_netmask" name="cidr_netmask" value="23"/>
+        </instance_attributes>
+      </primitive>
+
+      <primitive id="myAddr2" class="ocf" provider="heartbeat" type="IPaddr2">
+        <operations>
+          <op id="myAddr2-monitor" name="monitor" interval="30s"/>
+        </operations>
+        <instance_attributes id="myAddr2-params">
+          <nvpair id="myAddr2-ip" name="ip" value="192.0.2.42"/>
+        </instance_attributes>
+        <instance_attributes id="_cibtr-2_myAddr-common-params">
+          <nvpair id="__cibtr-2_myAddr-common-params__myAddr-common-cidr_netmask" name="cidr_netmask" value="23"/>
+        </instance_attributes>
+      </primitive>
+
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-enter/020-instance_atributes-rsc.ref.err b/xml/test-2-enter/020-instance_atributes-rsc.ref.err
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/xml/test-2-enter/020-instance_atributes-rsc.xml b/xml/test-2-enter/020-instance_atributes-rsc.xml
new file mode 100644
index 0000000000..0a651d0e95
--- /dev/null
+++ b/xml/test-2-enter/020-instance_atributes-rsc.xml
@@ -0,0 +1,39 @@
+<cib validate-with="pacemaker-2.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config/>
+    <nodes>
+
+      <node id="virt-063" uname="virt-063"/>
+      <node id="virt-064" uname="virt-064"/>
+      <node id="virt-069" uname="virt-069"/>
+
+    </nodes>
+    <resources>
+
+      <primitive id="myAddr1" class="ocf" provider="heartbeat" type="IPaddr2">
+        <operations>
+          <op id="myAddr1-monitor" name="monitor" interval="30s"/>
+        </operations>
+        <instance_attributes id="myAddr1-params">
+          <nvpair id="myAddr1-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+        <instance_attributes id="myAddr-common-params">
+          <nvpair id="myAddr-common-cidr_netmask" name="cidr_netmask" value="23"/>
+        </instance_attributes>
+      </primitive>
+
+      <primitive id="myAddr2" class="ocf" provider="heartbeat" type="IPaddr2">
+        <operations>
+          <op id="myAddr2-monitor" name="monitor" interval="30s"/>
+        </operations>
+        <instance_attributes id="myAddr2-params">
+          <nvpair id="myAddr2-ip" name="ip" value="192.0.2.42"/>
+        </instance_attributes>
+        <instance_attributes id-ref="myAddr-common-params"/>
+      </primitive>
+
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-enter/021-instance_atributes-rsc-nonbijective.ref b/xml/test-2-enter/021-instance_atributes-rsc-nonbijective.ref
new file mode 100644
index 0000000000..3a94fb075d
--- /dev/null
+++ b/xml/test-2-enter/021-instance_atributes-rsc-nonbijective.ref
@@ -0,0 +1,40 @@
+<cib validate-with="pacemaker-2.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config/>
+    <nodes>
+
+      <node id="virt-063" uname="virt-063"/>
+      <node id="virt-064" uname="virt-064"/>
+      <node id="virt-069" uname="virt-069"/>
+
+    </nodes>
+    <resources>
+
+      <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
+        <operations>
+          <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
+          <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s">
+            <instance_attributes id="mySmartFuse-inputpower-instanceparams">
+              <nvpair id="mySmartFuse-inputpower-requires" name="requires" value="inputpower"/>
+            </instance_attributes>
+          </op>
+          <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s">
+            <instance_attributes id="mySmartFuse-outputpower-instanceparams">
+              <nvpair id="mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+            </instance_attributes>
+          </op>
+        </operations>
+        <instance_attributes id="mySmartFuse-params">
+          <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+	<!-- a bit hairy but valid -->
+        <instance_attributes id="_cibtr-2_mySmartFuse-outputpower-instanceparams">
+              <nvpair id="__cibtr-2_mySmartFuse-outputpower-instanceparams__mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+            </instance_attributes>
+      </primitive>
+
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-enter/021-instance_atributes-rsc-nonbijective.ref.err b/xml/test-2-enter/021-instance_atributes-rsc-nonbijective.ref.err
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/xml/test-2-enter/021-instance_atributes-rsc-nonbijective.xml b/xml/test-2-enter/021-instance_atributes-rsc-nonbijective.xml
new file mode 100644
index 0000000000..7a12ebe403
--- /dev/null
+++ b/xml/test-2-enter/021-instance_atributes-rsc-nonbijective.xml
@@ -0,0 +1,38 @@
+<cib validate-with="pacemaker-2.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config/>
+    <nodes>
+
+      <node id="virt-063" uname="virt-063"/>
+      <node id="virt-064" uname="virt-064"/>
+      <node id="virt-069" uname="virt-069"/>
+
+    </nodes>
+    <resources>
+
+      <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
+        <operations>
+          <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
+          <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s">
+            <instance_attributes id="mySmartFuse-inputpower-instanceparams">
+              <nvpair id="mySmartFuse-inputpower-requires" name="requires" value="inputpower"/>
+            </instance_attributes>
+          </op>
+          <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s">
+            <instance_attributes id="mySmartFuse-outputpower-instanceparams">
+              <nvpair id="mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+            </instance_attributes>
+          </op>
+        </operations>
+        <instance_attributes id="mySmartFuse-params">
+          <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+	<!-- a bit hairy but valid -->
+        <instance_attributes id-ref="mySmartFuse-outputpower-instanceparams"/>
+      </primitive>
+
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-leave/010-clu-props-can.ref b/xml/test-2-leave/010-clu-props-can.ref
new file mode 100644
index 0000000000..afa924d4db
--- /dev/null
+++ b/xml/test-2-leave/010-clu-props-can.ref
@@ -0,0 +1,14 @@
+<cib validate-with="pacemaker-3.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config>
+      <cluster_property_set id="cluster-opts">
+        <nvpair id="cluster-opts-stonith_enabled" name="stonith-enabled" value="off"/>
+      </cluster_property_set>
+      <cluster_property_set id-ref="cluster-opts"/>
+    </crm_config>
+    <nodes/>
+    <resources/>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-leave/010-clu-props-can.ref.err b/xml/test-2-leave/010-clu-props-can.ref.err
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/xml/test-2-leave/010-clu-props-can.xml b/xml/test-2-leave/010-clu-props-can.xml
new file mode 100644
index 0000000000..cd82fa8eff
--- /dev/null
+++ b/xml/test-2-leave/010-clu-props-can.xml
@@ -0,0 +1,16 @@
+<cib validate-with="pacemaker-3.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config>
+      <cluster_property_set id="cluster-opts">
+        <nvpair id="cluster-opts-stonith_enabled" name="stonith-enabled" value="off"/>
+      </cluster_property_set>
+      <cluster_property_set id="_cibtr-2_cluster-opts">
+        <nvpair id="__cibtr-2_cluster-opts__cluster-opts-stonith_enabled" name="stonith-enabled" value="off"/>
+      </cluster_property_set>
+    </crm_config>
+    <nodes/>
+    <resources/>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-leave/011-clu-props-cannot.ref b/xml/test-2-leave/011-clu-props-cannot.ref
new file mode 100644
index 0000000000..c129f57df5
--- /dev/null
+++ b/xml/test-2-leave/011-clu-props-cannot.ref
@@ -0,0 +1,16 @@
+<cib validate-with="pacemaker-3.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config>
+      <cluster_property_set id="cluster-opts">
+        <nvpair id="cluster-opts-stonith_enabled" name="stonith-enabled" value="off"/>
+      </cluster_property_set>
+      <cluster_property_set id="_cibtr-2_cluster-opts">
+        <nvpair id="__cibtr-2_cluster-opts__cluster-opts-stonith_enabled" name="stonith-enabled" value="on"/>
+      </cluster_property_set>
+    </crm_config>
+    <nodes/>
+    <resources/>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-leave/011-clu-props-cannot.ref.err b/xml/test-2-leave/011-clu-props-cannot.ref.err
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/xml/test-2-leave/011-clu-props-cannot.xml b/xml/test-2-leave/011-clu-props-cannot.xml
new file mode 100644
index 0000000000..c129f57df5
--- /dev/null
+++ b/xml/test-2-leave/011-clu-props-cannot.xml
@@ -0,0 +1,16 @@
+<cib validate-with="pacemaker-3.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config>
+      <cluster_property_set id="cluster-opts">
+        <nvpair id="cluster-opts-stonith_enabled" name="stonith-enabled" value="off"/>
+      </cluster_property_set>
+      <cluster_property_set id="_cibtr-2_cluster-opts">
+        <nvpair id="__cibtr-2_cluster-opts__cluster-opts-stonith_enabled" name="stonith-enabled" value="on"/>
+      </cluster_property_set>
+    </crm_config>
+    <nodes/>
+    <resources/>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-leave/021-instance_atributes-rsc-nonbijective.ref b/xml/test-2-leave/021-instance_atributes-rsc-nonbijective.ref
new file mode 100644
index 0000000000..93ac06f674
--- /dev/null
+++ b/xml/test-2-leave/021-instance_atributes-rsc-nonbijective.ref
@@ -0,0 +1,32 @@
+<cib validate-with="pacemaker-3.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config/>
+    <nodes>
+
+      <node id="virt-063" uname="virt-063"/>
+      <node id="virt-064" uname="virt-064"/>
+      <node id="virt-069" uname="virt-069"/>
+
+    </nodes>
+    <resources>
+
+      <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
+        <operations>
+          <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
+          <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s"/>
+          <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s"/>
+        </operations>
+        <instance_attributes id="mySmartFuse-params">
+          <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+	<!-- a bit hairy but valid -->
+        <instance_attributes id="_cibtr-2_mySmartFuse-outputpower-instanceparams">
+          <nvpair id="__cibtr-2_mySmartFuse-outputpower-instanceparams__mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+        </instance_attributes>
+      </primitive>
+
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-leave/021-instance_atributes-rsc-nonbijective.ref.err b/xml/test-2-leave/021-instance_atributes-rsc-nonbijective.ref.err
new file mode 100644
index 0000000000..70adf2787b
--- /dev/null
+++ b/xml/test-2-leave/021-instance_atributes-rsc-nonbijective.ref.err
@@ -0,0 +1 @@
+DEBUG: instance_attributes: original element pointed to with @id-ref (mySmartFuse-outputpower-instanceparams) disappeared during upgrade
diff --git a/xml/test-2-leave/021-instance_atributes-rsc-nonbijective.xml b/xml/test-2-leave/021-instance_atributes-rsc-nonbijective.xml
new file mode 100644
index 0000000000..93ac06f674
--- /dev/null
+++ b/xml/test-2-leave/021-instance_atributes-rsc-nonbijective.xml
@@ -0,0 +1,32 @@
+<cib validate-with="pacemaker-3.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config/>
+    <nodes>
+
+      <node id="virt-063" uname="virt-063"/>
+      <node id="virt-064" uname="virt-064"/>
+      <node id="virt-069" uname="virt-069"/>
+
+    </nodes>
+    <resources>
+
+      <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
+        <operations>
+          <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
+          <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s"/>
+          <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s"/>
+        </operations>
+        <instance_attributes id="mySmartFuse-params">
+          <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+	<!-- a bit hairy but valid -->
+        <instance_attributes id="_cibtr-2_mySmartFuse-outputpower-instanceparams">
+          <nvpair id="__cibtr-2_mySmartFuse-outputpower-instanceparams__mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+        </instance_attributes>
+      </primitive>
+
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-roundtrip/021-instance_atributes-rsc-nonbijective.ref b/xml/test-2-roundtrip/021-instance_atributes-rsc-nonbijective.ref
new file mode 100644
index 0000000000..ee5819d59b
--- /dev/null
+++ b/xml/test-2-roundtrip/021-instance_atributes-rsc-nonbijective.ref
@@ -0,0 +1,32 @@
+<cib validate-with="pacemaker-3.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config/>
+    <nodes>
+
+      <node id="virt-063" uname="virt-063"/>
+      <node id="virt-064" uname="virt-064"/>
+      <node id="virt-069" uname="virt-069"/>
+
+    </nodes>
+    <resources>
+
+      <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
+        <operations>
+          <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
+          <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s"/>
+          <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s"/>
+        </operations>
+        <instance_attributes id="mySmartFuse-params">
+          <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+        <!-- a bit hairy but valid -->
+        <instance_attributes id="_cibtr-2_mySmartFuse-outputpower-instanceparams">
+              <nvpair id="__cibtr-2_mySmartFuse-outputpower-instanceparams__mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+            </instance_attributes>
+      </primitive>
+
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2-roundtrip/021-instance_atributes-rsc-nonbijective.ref.err b/xml/test-2-roundtrip/021-instance_atributes-rsc-nonbijective.ref.err
new file mode 100644
index 0000000000..68de733116
--- /dev/null
+++ b/xml/test-2-roundtrip/021-instance_atributes-rsc-nonbijective.ref.err
@@ -0,0 +1,5 @@
+INFO: Resources-operation instance_attributes: mySmartFuse-monitor-inputpower (rsc=mySmartFuse, meta=mySmartFuse-inputpower-instanceparams): dropping requires
+INFO: Resources-operation instance_attributes: ... only start/promote operation taken into account
+INFO: Resources-operation instance_attributes: mySmartFuse-monitor-outputpower (rsc=mySmartFuse, meta=mySmartFuse-outputpower-instanceparams): dropping requires
+INFO: Resources-operation instance_attributes: ... only start/promote operation taken into account
+DEBUG: instance_attributes: original element pointed to with @id-ref (mySmartFuse-outputpower-instanceparams) disappeared during upgrade
diff --git a/xml/test-2-roundtrip/021-instance_atributes-rsc-nonbijective.xml b/xml/test-2-roundtrip/021-instance_atributes-rsc-nonbijective.xml
new file mode 100644
index 0000000000..a5d25a5c34
--- /dev/null
+++ b/xml/test-2-roundtrip/021-instance_atributes-rsc-nonbijective.xml
@@ -0,0 +1,39 @@
+<?xml-stylesheet href="../assets/upgrade-2.10-htmldiff.xsl" type="text/xsl"?>
+<cib validate-with="pacemaker-2.0" admin_epoch="0" epoch="0" num_updates="0">
+  <configuration>
+    <crm_config/>
+    <nodes>
+
+      <node id="virt-063" uname="virt-063"/>
+      <node id="virt-064" uname="virt-064"/>
+      <node id="virt-069" uname="virt-069"/>
+
+    </nodes>
+    <resources>
+
+      <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
+        <operations>
+          <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
+          <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s">
+            <instance_attributes id="mySmartFuse-inputpower-instanceparams">
+              <nvpair id="mySmartFuse-inputpower-requires" name="requires" value="inputpower"/>
+            </instance_attributes>
+          </op>
+          <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s">
+            <instance_attributes id="mySmartFuse-outputpower-instanceparams">
+              <nvpair id="mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
+            </instance_attributes>
+          </op>
+        </operations>
+        <instance_attributes id="mySmartFuse-params">
+          <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
+        </instance_attributes>
+        <!-- a bit hairy but valid -->
+        <instance_attributes id-ref="mySmartFuse-outputpower-instanceparams"/>
+      </primitive>
+
+    </resources>
+    <constraints/>
+  </configuration>
+  <status/>
+</cib>
diff --git a/xml/test-2/010-rsc_colocation-dropped-for-noop-sa.ref.err b/xml/test-2/010-rsc_colocation-dropped-for-noop-sa.ref.err
index 95985d568f..50791bf19c 100644
--- a/xml/test-2/010-rsc_colocation-dropped-for-noop-sa.ref.err
+++ b/xml/test-2/010-rsc_colocation-dropped-for-noop-sa.ref.err
@@ -1,2 +1,2 @@
-Constraints-colocation: colocation-addr-httpd: dropping score-attribute
-Constraints-colocation: ... was actually never in effect
+INFO: Constraints-colocation: colocation-addr-httpd: dropping score-attribute
+INFO: Constraints-colocation: ... was actually never in effect
diff --git a/xml/test-2/020-rsc-requires-inline.ref.err b/xml/test-2/020-rsc-requires-inline.ref.err
index a13b4f27bd..9c6569747d 100644
--- a/xml/test-2/020-rsc-requires-inline.ref.err
+++ b/xml/test-2/020-rsc-requires-inline.ref.err
@@ -1 +1 @@
-Resources-operation: myAddr-start (rsc=myAddr): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: myAddr-start (rsc=myAddr): moving requires under meta_attributes as requires unless already defined there for matching start|promote
diff --git a/xml/test-2/021-rsc-requires-nvpair.ref.err b/xml/test-2/021-rsc-requires-nvpair.ref.err
index 9a04c4732e..6650f159f3 100644
--- a/xml/test-2/021-rsc-requires-nvpair.ref.err
+++ b/xml/test-2/021-rsc-requires-nvpair.ref.err
@@ -1 +1 @@
-Resources-operation: myAddr-start (rsc=myAddr, meta=myAddr-start-metaparams): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: myAddr-start (rsc=myAddr, meta=myAddr-start-metaparams): moving requires under meta_attributes as requires unless already defined there for matching start|promote
diff --git a/xml/test-2/022-rsc-requires-counterexamples.ref.err b/xml/test-2/022-rsc-requires-counterexamples.ref.err
index 5f89215b1b..6f6a9954fb 100644
--- a/xml/test-2/022-rsc-requires-counterexamples.ref.err
+++ b/xml/test-2/022-rsc-requires-counterexamples.ref.err
@@ -1,2 +1,2 @@
-Resources-operation: myAddr-stop (rsc=myAddr): dropping requires
-Resources-operation: ... only start/promote operation taken into account
+INFO: Resources-operation: myAddr-stop (rsc=myAddr): dropping requires
+INFO: Resources-operation: ... only start/promote operation taken into account
diff --git a/xml/test-2/023-rsc-requires-no-override.ref.err b/xml/test-2/023-rsc-requires-no-override.ref.err
index 100fab93c6..ad680b6302 100644
--- a/xml/test-2/023-rsc-requires-no-override.ref.err
+++ b/xml/test-2/023-rsc-requires-no-override.ref.err
@@ -1,4 +1,4 @@
-Resources-operation: myAddr-start (rsc=myAddr): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: stateful-promote (rsc=stateful, meta=stateful-promote-meta): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: stateful-demote (rsc=stateful, meta=stateful-demote-meta): dropping requires
-Resources-operation: ... only start/promote operation taken into account
+DEBUG: Resources-operation: myAddr-start (rsc=myAddr): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: stateful-promote (rsc=stateful, meta=stateful-promote-meta): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+INFO: Resources-operation: stateful-demote (rsc=stateful, meta=stateful-demote-meta): dropping requires
+INFO: Resources-operation: ... only start/promote operation taken into account
diff --git a/xml/test-2/024-rsc-requires-no-selfclash.ref.err b/xml/test-2/024-rsc-requires-no-selfclash.ref.err
index 49d9683336..b275532b33 100644
--- a/xml/test-2/024-rsc-requires-no-selfclash.ref.err
+++ b/xml/test-2/024-rsc-requires-no-selfclash.ref.err
@@ -1,14 +1,14 @@
-Resources-operation: myAddr1-start (rsc=myAddr1, meta=myAddr1-start-meta): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: myAddr1-start (rsc=myAddr1): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: myAddr2-start (rsc=myAddr2, meta=myAddr2-start-meta): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: myAddr2-start (rsc=myAddr2): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: stateful1-demote (rsc=stateful1, meta=stateful1-demote-meta): dropping requires
-Resources-operation: ... only start/promote operation taken into account
-Resources-operation: stateful1-promote (rsc=stateful1): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: stateful1-start (rsc=stateful1): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: stateful2-promote (rsc=stateful2, meta=stateful2-promote-meta1): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: stateful2-promote (rsc=stateful2, meta=stateful2-promote-meta1): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: stateful2-promote (rsc=stateful2, meta=stateful2-promote-meta2): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: stateful2-start (rsc=stateful2, meta=stateful2-promote-meta3): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: stateful2-demote (rsc=stateful2, meta=stateful2-promote-meta): dropping requires
-Resources-operation: ... only start/promote operation taken into account
+DEBUG: Resources-operation: myAddr1-start (rsc=myAddr1, meta=myAddr1-start-meta): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: myAddr1-start (rsc=myAddr1): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: myAddr2-start (rsc=myAddr2, meta=myAddr2-start-meta): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: myAddr2-start (rsc=myAddr2): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+INFO: Resources-operation: stateful1-demote (rsc=stateful1, meta=stateful1-demote-meta): dropping requires
+INFO: Resources-operation: ... only start/promote operation taken into account
+DEBUG: Resources-operation: stateful1-promote (rsc=stateful1): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: stateful1-start (rsc=stateful1): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: stateful2-promote (rsc=stateful2, meta=stateful2-promote-meta1): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: stateful2-promote (rsc=stateful2, meta=stateful2-promote-meta1): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: stateful2-promote (rsc=stateful2, meta=stateful2-promote-meta2): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: stateful2-start (rsc=stateful2, meta=stateful2-promote-meta3): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+INFO: Resources-operation: stateful2-demote (rsc=stateful2, meta=stateful2-promote-meta): dropping requires
+INFO: Resources-operation: ... only start/promote operation taken into account
diff --git a/xml/test-2/030-clu-props-plain-rename.ref.err b/xml/test-2/030-clu-props-plain-rename.ref.err
index 32306f9f53..878c504320 100644
--- a/xml/test-2/030-clu-props-plain-rename.ref.err
+++ b/xml/test-2/030-clu-props-plain-rename.ref.err
@@ -1,13 +1,13 @@
-Cluster properties: cluster-opts-cluster_recheck_interval: renaming cluster_recheck_interval as cluster-recheck-interval
-Cluster properties: cluster-opts-dc_deadtime: renaming dc_deadtime as dc-deadtime
-Cluster properties: cluster-opts-election_timeout: renaming election_timeout as election-timeout
-Cluster properties: cluster-opts-no_quorum_policy: renaming no_quorum_policy as no-quorum-policy
-Cluster properties: cluster-opts-remove_after_stop: renaming remove_after_stop as remove-after-stop
-Cluster properties: cluster-opts-shutdown_escalation: renaming shutdown_escalation as shutdown-escalation
-Cluster properties: cluster-opts-startup_fencing: renaming startup_fencing as startup-fencing
-Cluster properties: cluster-opts-stonith_action: renaming stonith_action as stonith-action
-Cluster properties: cluster-opts-stonith_enabled: renaming stonith_enabled as stonith-enabled
-Cluster properties: cluster-opts-stop_orphan_actions: renaming stop_orphan_actions as stop-orphan-actions
-Cluster properties: cluster-opts-stop_orphan_resources: renaming stop_orphan_resources as stop-orphan-resources
-Cluster properties: cluster-opts-symmetric_cluster: renaming symmetric_cluster as symmetric-cluster
-Cluster properties: cluster-opts-transition_idle_timeout: renaming transition_idle_timeout as cluster-delay
+DEBUG: Cluster properties: cluster-opts-cluster_recheck_interval: renaming cluster_recheck_interval as cluster-recheck-interval
+DEBUG: Cluster properties: cluster-opts-dc_deadtime: renaming dc_deadtime as dc-deadtime
+DEBUG: Cluster properties: cluster-opts-election_timeout: renaming election_timeout as election-timeout
+DEBUG: Cluster properties: cluster-opts-no_quorum_policy: renaming no_quorum_policy as no-quorum-policy
+DEBUG: Cluster properties: cluster-opts-remove_after_stop: renaming remove_after_stop as remove-after-stop
+DEBUG: Cluster properties: cluster-opts-shutdown_escalation: renaming shutdown_escalation as shutdown-escalation
+DEBUG: Cluster properties: cluster-opts-startup_fencing: renaming startup_fencing as startup-fencing
+DEBUG: Cluster properties: cluster-opts-stonith_action: renaming stonith_action as stonith-action
+DEBUG: Cluster properties: cluster-opts-stonith_enabled: renaming stonith_enabled as stonith-enabled
+DEBUG: Cluster properties: cluster-opts-stop_orphan_actions: renaming stop_orphan_actions as stop-orphan-actions
+DEBUG: Cluster properties: cluster-opts-stop_orphan_resources: renaming stop_orphan_resources as stop-orphan-resources
+DEBUG: Cluster properties: cluster-opts-symmetric_cluster: renaming symmetric_cluster as symmetric-cluster
+DEBUG: Cluster properties: cluster-opts-transition_idle_timeout: renaming transition_idle_timeout as cluster-delay
diff --git a/xml/test-2/031-clu-props-drop.ref.err b/xml/test-2/031-clu-props-drop.ref.err
index ca172ef2db..b26de82fc4 100644
--- a/xml/test-2/031-clu-props-drop.ref.err
+++ b/xml/test-2/031-clu-props-drop.ref.err
@@ -1,10 +1,10 @@
-Cluster properties: cluster-opts-cluster-infrastructure: dropping cluster-infrastructure for matching heartbeat|openais|classic openais|classic openais (with plugin)|cman
-Cluster properties: ... corosync (2+) infrastructure can be used instead, though the value is not of significance
-Cluster properties: cluster-opts-default-migration-threshold: dropping default-migration-threshold
-Cluster properties: ... migration-threshold in rsc_defaults can be configured instead
-Cluster properties: cluster-opts-default_migration_threshold: dropping default_migration_threshold
-Cluster properties: ... migration-threshold in rsc_defaults can be configured instead
-Cluster properties: cluster-opts-expected-quorum-votes: dropping expected-quorum-votes
-Cluster properties: ... corosync (2+) infrastructure tracks quorum on its own
-Cluster properties: cluster-opts-notification-agent: dropping notification-agent
-Cluster properties: ... standalone alerts can be configured instead
+INFO: Cluster properties: cluster-opts-cluster-infrastructure: dropping cluster-infrastructure for matching heartbeat|openais|classic openais|classic openais (with plugin)|cman
+INFO: Cluster properties: ... corosync (2+) infrastructure can be used instead, though the value is not of significance
+INFO: Cluster properties: cluster-opts-default-migration-threshold: dropping default-migration-threshold
+INFO: Cluster properties: ... migration-threshold in rsc_defaults can be configured instead
+INFO: Cluster properties: cluster-opts-default_migration_threshold: dropping default_migration_threshold
+INFO: Cluster properties: ... migration-threshold in rsc_defaults can be configured instead
+INFO: Cluster properties: cluster-opts-expected-quorum-votes: dropping expected-quorum-votes
+INFO: Cluster properties: ... corosync (2+) infrastructure tracks quorum on its own
+INFO: Cluster properties: cluster-opts-notification-agent: dropping notification-agent
+INFO: Cluster properties: ... standalone alerts can be configured instead
diff --git a/xml/test-2/032-clu-props-move.ref.err b/xml/test-2/032-clu-props-move.ref.err
index 417b355df6..ed5d3d3e28 100644
--- a/xml/test-2/032-clu-props-move.ref.err
+++ b/xml/test-2/032-clu-props-move.ref.err
@@ -1,3 +1,3 @@
-Cluster properties: cluster-opts-default-action-timeout: moving default-action-timeout under op_defaults as timeout unless already defined there
-Cluster properties: cluster-opts-default-resource-stickiness: moving default-resource-stickiness under rsc_defaults as resource-stickiness unless already defined there
-Cluster properties: cluster-opts-is-managed-default: moving is-managed-default under rsc_defaults as is-managed unless already defined there
+DEBUG: Cluster properties: cluster-opts-default-action-timeout: moving default-action-timeout under op_defaults as timeout unless already defined there
+DEBUG: Cluster properties: cluster-opts-default-resource-stickiness: moving default-resource-stickiness under rsc_defaults as resource-stickiness unless already defined there
+DEBUG: Cluster properties: cluster-opts-is-managed-default: moving is-managed-default under rsc_defaults as is-managed unless already defined there
diff --git a/xml/test-2/033-clu-props-move-merge.ref.err b/xml/test-2/033-clu-props-move-merge.ref.err
index 417b355df6..ed5d3d3e28 100644
--- a/xml/test-2/033-clu-props-move-merge.ref.err
+++ b/xml/test-2/033-clu-props-move-merge.ref.err
@@ -1,3 +1,3 @@
-Cluster properties: cluster-opts-default-action-timeout: moving default-action-timeout under op_defaults as timeout unless already defined there
-Cluster properties: cluster-opts-default-resource-stickiness: moving default-resource-stickiness under rsc_defaults as resource-stickiness unless already defined there
-Cluster properties: cluster-opts-is-managed-default: moving is-managed-default under rsc_defaults as is-managed unless already defined there
+DEBUG: Cluster properties: cluster-opts-default-action-timeout: moving default-action-timeout under op_defaults as timeout unless already defined there
+DEBUG: Cluster properties: cluster-opts-default-resource-stickiness: moving default-resource-stickiness under rsc_defaults as resource-stickiness unless already defined there
+DEBUG: Cluster properties: cluster-opts-is-managed-default: moving is-managed-default under rsc_defaults as is-managed unless already defined there
diff --git a/xml/test-2/034-clu-props-move-redef.ref.err b/xml/test-2/034-clu-props-move-redef.ref.err
index 85db6428f3..f8c148f382 100644
--- a/xml/test-2/034-clu-props-move-redef.ref.err
+++ b/xml/test-2/034-clu-props-move-redef.ref.err
@@ -1,3 +1,3 @@
-Cluster properties: cluster-opts-default-resource-failure-stickiness: moving default-resource-failure-stickiness under rsc_defaults as migration-threshold unless already defined there, redefined as 1, for matching -INFINITY
-Cluster properties: cluster-opts-default_resource_failure_stickiness: dropping default_resource_failure_stickiness
-Cluster properties: ... migration-threshold in rsc_defaults can be configured instead
+DEBUG: Cluster properties: cluster-opts-default-resource-failure-stickiness: moving default-resource-failure-stickiness under rsc_defaults as migration-threshold unless already defined there, redefined as 1, for matching -INFINITY
+INFO: Cluster properties: cluster-opts-default_resource_failure_stickiness: dropping default_resource_failure_stickiness
+INFO: Cluster properties: ... migration-threshold in rsc_defaults can be configured instead
diff --git a/xml/test-2/040-nodes-rename-type.ref.err b/xml/test-2/040-nodes-rename-type.ref.err
index e5a6b64a36..ce68fa4e9e 100644
--- a/xml/test-2/040-nodes-rename-type.ref.err
+++ b/xml/test-2/040-nodes-rename-type.ref.err
@@ -1,2 +1,2 @@
-Cluster node: virt-063 (id=virt-063): keeping type as type, redefined as member, for matching normal
-Cluster node: virt-064 (id=virt-064): keeping type as type, redefined as member, for matching normal
+DEBUG: Cluster node: virt-063 (id=virt-063): keeping type as type, redefined as member, for matching normal
+DEBUG: Cluster node: virt-064 (id=virt-064): keeping type as type, redefined as member, for matching normal
diff --git a/xml/test-2/050-rsc-attrs-instance-plain-rename.ref.err b/xml/test-2/050-rsc-attrs-instance-plain-rename.ref.err
index 2d3b3b8c50..a3129e54c9 100644
--- a/xml/test-2/050-rsc-attrs-instance-plain-rename.ref.err
+++ b/xml/test-2/050-rsc-attrs-instance-plain-rename.ref.err
@@ -1 +1 @@
-Resource instance_attributes: fence-vbox-pcmk_monitor_cmd: renaming pcmk_monitor_cmd as pcmk_monitor_action
+DEBUG: Resource instance_attributes: fence-vbox-pcmk_monitor_cmd: renaming pcmk_monitor_cmd as pcmk_monitor_action
diff --git a/xml/test-2/051-rsc-attrs-instance-pcmk_arg_map.ref.err b/xml/test-2/051-rsc-attrs-instance-pcmk_arg_map.ref.err
index b7dfd08fea..a0149c1661 100644
--- a/xml/test-2/051-rsc-attrs-instance-pcmk_arg_map.ref.err
+++ b/xml/test-2/051-rsc-attrs-instance-pcmk_arg_map.ref.err
@@ -1,3 +1,3 @@
-Resource instance_attributes: fence-vbox1-pcmk_arg_map: renaming pcmk_arg_map as pcmk_host_argument for matching port: prefix that will, meanwhile, get dropped
-Resource instance_attributes: fence-vbox2-pcmk_arg_map: dropping pcmk_arg_map
-Resource instance_attributes: fence-vbox3-pcmk_arg_map: dropping pcmk_arg_map
+DEBUG: Resource instance_attributes: fence-vbox1-pcmk_arg_map: renaming pcmk_arg_map as pcmk_host_argument for matching port: prefix that will, meanwhile, get dropped
+DEBUG: Resource instance_attributes: fence-vbox2-pcmk_arg_map: dropping pcmk_arg_map
+DEBUG: Resource instance_attributes: fence-vbox3-pcmk_arg_map: dropping pcmk_arg_map
diff --git a/xml/test-2/060-rsc-attrs-meta-isolation.ref.err b/xml/test-2/060-rsc-attrs-meta-isolation.ref.err
index 32533f92fd..fb40cc4a5f 100644
--- a/xml/test-2/060-rsc-attrs-meta-isolation.ref.err
+++ b/xml/test-2/060-rsc-attrs-meta-isolation.ref.err
@@ -1,4 +1,4 @@
-Resource meta_attributes: fake (meta=fake-meta_attributes): renaming isolation-wrapper as target-role, redefined as Stopped
-Resource meta_attributes: ... i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources
-Resource meta_attributes: fake (meta=fake-meta_attributes): renaming isolation-wrapper as target-role, redefined as Stopped
-Resource meta_attributes: ... i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources
+WARNING: Resource meta_attributes: fake (meta=fake-meta_attributes): renaming isolation-wrapper as target-role, redefined as Stopped
+WARNING: Resource meta_attributes: ... i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources
+WARNING: Resource meta_attributes: fake (meta=fake-meta_attributes): renaming isolation-wrapper as target-role, redefined as Stopped
+WARNING: Resource meta_attributes: ... i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources
diff --git a/xml/test-2/061-rsc-attrs-meta-exchange.ref.err b/xml/test-2/061-rsc-attrs-meta-exchange.ref.err
index 03c7a6fcbd..2938b77b13 100644
--- a/xml/test-2/061-rsc-attrs-meta-exchange.ref.err
+++ b/xml/test-2/061-rsc-attrs-meta-exchange.ref.err
@@ -1,3 +1,3 @@
-Resource meta_attributes: res1 (meta=res1-meta_attributes): renaming resource-failure-stickiness as migration-threshold, redefined as 1, for matching -INFINITY
-Resource meta_attributes: res2 (meta=res2-meta_attributes): dropping resource-failure-stickiness
-Resource meta_attributes: ... migration-threshold can be configured instead
+DEBUG: Resource meta_attributes: res1 (meta=res1-meta_attributes): renaming resource-failure-stickiness as migration-threshold, redefined as 1, for matching -INFINITY
+INFO: Resource meta_attributes: res2 (meta=res2-meta_attributes): dropping resource-failure-stickiness
+INFO: Resource meta_attributes: ... migration-threshold can be configured instead
diff --git a/xml/test-2/070-rsc-op-attrs-inst-requires-start.ref.err b/xml/test-2/070-rsc-op-attrs-inst-requires-start.ref.err
index 1aa7937627..6f707bbfda 100644
--- a/xml/test-2/070-rsc-op-attrs-inst-requires-start.ref.err
+++ b/xml/test-2/070-rsc-op-attrs-inst-requires-start.ref.err
@@ -1 +1 @@
-Resources-operation instance_attributes: myAddr-start (rsc=myAddr, meta=myAddr-start-instanceparams): moving requires under per-resource-meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation instance_attributes: myAddr-start (rsc=myAddr, meta=myAddr-start-instanceparams): moving requires under per-resource-meta_attributes as requires unless already defined there for matching start|promote
diff --git a/xml/test-2/071-rsc-op-attrs-inst-requires-nonstart.ref.err b/xml/test-2/071-rsc-op-attrs-inst-requires-nonstart.ref.err
index 0865c594da..6b6f8f7b19 100644
--- a/xml/test-2/071-rsc-op-attrs-inst-requires-nonstart.ref.err
+++ b/xml/test-2/071-rsc-op-attrs-inst-requires-nonstart.ref.err
@@ -1,2 +1,2 @@
-Resources-operation instance_attributes: myAddr-stop (rsc=myAddr, meta=myAddr-stop-instanceparams): dropping requires
-Resources-operation instance_attributes: ... only start/promote operation taken into account
+INFO: Resources-operation instance_attributes: myAddr-stop (rsc=myAddr, meta=myAddr-stop-instanceparams): dropping requires
+INFO: Resources-operation instance_attributes: ... only start/promote operation taken into account
diff --git a/xml/test-2/072-rsc-op-attrs-inst-requires-no-override.ref.err b/xml/test-2/072-rsc-op-attrs-inst-requires-no-override.ref.err
index bacdc09be7..cc5dd7d22a 100644
--- a/xml/test-2/072-rsc-op-attrs-inst-requires-no-override.ref.err
+++ b/xml/test-2/072-rsc-op-attrs-inst-requires-no-override.ref.err
@@ -1,4 +1,4 @@
-Resources-operation instance_attributes: myAddr-start (rsc=myAddr, meta=myAddr-start-instance): moving requires under per-resource-meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: myAddr-start (rsc=myAddr): moving requires under meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation instance_attributes: stateful-promote (rsc=stateful, meta=stateful-promote-instance): moving requires under per-resource-meta_attributes as requires unless already defined there for matching start|promote
-Resources-operation: stateful-promote (rsc=stateful, meta=stateful-promote-meta): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation instance_attributes: myAddr-start (rsc=myAddr, meta=myAddr-start-instance): moving requires under per-resource-meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: myAddr-start (rsc=myAddr): moving requires under meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation instance_attributes: stateful-promote (rsc=stateful, meta=stateful-promote-instance): moving requires under per-resource-meta_attributes as requires unless already defined there for matching start|promote
+DEBUG: Resources-operation: stateful-promote (rsc=stateful, meta=stateful-promote-meta): moving requires under meta_attributes as requires unless already defined there for matching start|promote
diff --git a/xml/test-2/073-rsc-op-attrs-inst-meta-meaning.ref.err b/xml/test-2/073-rsc-op-attrs-inst-meta-meaning.ref.err
index 0410a57811..18beb3aefa 100644
--- a/xml/test-2/073-rsc-op-attrs-inst-meta-meaning.ref.err
+++ b/xml/test-2/073-rsc-op-attrs-inst-meta-meaning.ref.err
@@ -1,4 +1,4 @@
-Resources-operation instance_attributes: myAddr-start (rsc=myAddr, meta=myAddr-start-instance): moving on-fail under meta_attributes as on-fail unless already defined there
-Resources-operation instance_attributes: myAddr-start (rsc=myAddr, meta=myAddr-start-instance): moving record-pending under meta_attributes as record-pending unless already defined there
-Resources-operation instance_attributes: myHttpd-monitor (rsc=myHttpd, meta=myHttpd-monitor-instance): moving timeout under meta_attributes as timeout unless already defined there
-Resources-operation instance_attributes: myHttpd-monitor (rsc=myHttpd, meta=myHttpd-monitor-instance2): moving timeout under meta_attributes as timeout unless already defined there
+DEBUG: Resources-operation instance_attributes: myAddr-start (rsc=myAddr, meta=myAddr-start-instance): moving on-fail under meta_attributes as on-fail unless already defined there
+DEBUG: Resources-operation instance_attributes: myAddr-start (rsc=myAddr, meta=myAddr-start-instance): moving record-pending under meta_attributes as record-pending unless already defined there
+DEBUG: Resources-operation instance_attributes: myHttpd-monitor (rsc=myHttpd, meta=myHttpd-monitor-instance): moving timeout under meta_attributes as timeout unless already defined there
+DEBUG: Resources-operation instance_attributes: myHttpd-monitor (rsc=myHttpd, meta=myHttpd-monitor-instance2): moving timeout under meta_attributes as timeout unless already defined there
diff --git a/xml/upgrade-2.10-enter.xsl b/xml/upgrade-2.10-enter.xsl
new file mode 100644
index 0000000000..e7eb1ba323
--- /dev/null
+++ b/xml/upgrade-2.10-enter.xsl
@@ -0,0 +1,176 @@
+<!--
+ Copyright 2018 Red Hat, Inc.
+ Author: Jan Pokorny <jpokorny@redhat.com>
+ Part of pacemaker project
+ SPDX-License-Identifier: GPL-2.0-or-later
+ -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:cibtr="http://clusterlabs.org/ns/pacemaker/cibtr-2"
+                exclude-result-prefixes="cibtr"
+                cibtr:filename="upgrade-2.10-enter.xsl">
+<xsl:output method="xml" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
+
+
+<!--
+
+ GENERIC UTILITIES
+
+ -->
+
+<!--
+ Recursive implementation of "basename"
+
+ Merely parameter driven, no implicit context taken into account:
+ - Uri: input in it's current phase of processing
+-->
+<xsl:template name="cibtr:WrapSpecificBasename">
+  <xsl:param name="Uri"/>
+  <xsl:choose>
+    <xsl:when test="not(contains($Uri, '/'))">
+      <xsl:value-of select="$Uri"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:call-template name="cibtr:WrapSpecificBasename">
+        <xsl:with-param name="Uri"
+                        select="substring-after($Uri, '/')"/>
+      </xsl:call-template>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<!--
+ Id-mangling-enriched identity template.
+ -->
+<xsl:template name="cibtr:HelperIdentityEnter">
+  <xsl:param name="TargetIdPrefix" select="''"/>
+  <xsl:copy>
+    <xsl:apply-templates select="@*|node()"
+                         mode="cibtr:enter">
+      <xsl:with-param name="TargetIdPrefix" select="$TargetIdPrefix"/>
+    </xsl:apply-templates>
+  </xsl:copy>
+</xsl:template>
+
+
+<!--
+
+ ACTUAL TRANSFORMATION
+
+ Extra modes: cibtr:enter
+
+ -->
+
+<xsl:variable name="cibtr:WrapSpecificPrefix">
+  <!-- no sleek way to fetch this, top-level xmlns:cibtr disappears early -->
+  <xsl:call-template name="cibtr:WrapSpecificBasename">
+    <xsl:with-param name="Uri"
+      select="namespace-uri(document('')/xsl:stylesheet/@cibtr:filename)"/>
+  </xsl:call-template>
+</xsl:variable>
+
+<xsl:variable name="cibtr:WrapSpecificPrefixInitialRoot"
+              select="concat('_', $cibtr:WrapSpecificPrefix, '_')"/>
+
+<!--
+ cibtr:enter mode
+ -->
+
+<!--
+ This is to cover elements with the internal structure characterized
+ with the following RelaxNG Compact encoded grammar:
+
+ > attribute id-ref { xsd:IDREF }
+ > | (attribute id { xsd:ID },
+ >    (rule?
+ >     & nvpair*
+ >     & attribute score {
+ >         xsd:integer
+ >         | xsd:token "INFINITY"
+ >         | xsd:token "+INFINITY"
+ >         | xsd:token "-INFINITY"
+ >       }?))
+
+ The context node corresponds to "@id-ref" branch, and Original to the other,
+ and the task here is to recursively copy anything from Original to target
+ (with new, unique IDs, of course), and to flip @id-ref to full-fledged,
+ now valid @id, which will be likewise unique, and importantly, reversibly
+ mappable back to original in "leave" XSLT counterpart.
+ -->
+<xsl:template match="*[
+                       @id-ref
+                       and
+                       contains(
+                         concat('|cluster_property_set',
+                                '|instance_attributes|',
+                                '|meta_attributes|'),
+                         concat('|', name(), '|')
+                       )
+                     ]"
+              mode="cibtr:enter">
+  <xsl:variable name="Original"
+                select="//*[
+                          name() = name(current())
+                          and
+                          @id = current()/@id-ref
+                        ]"/>
+  <xsl:choose>
+    <xsl:when test="count($Original) = 0">
+      <xsl:message terminate="yes">
+        <xsl:value-of select="concat('INTERNAL ERROR:',
+                                     name(), ': dangling @id-ref (',
+                                     @id-ref, '): no such @id found',
+                                     ' within the same element class')"/>
+      </xsl:message>
+    </xsl:when>
+    <xsl:when test="count($Original) != 1">
+      <xsl:message terminate="yes">
+        <xsl:value-of select="concat('INTERNAL ERROR:',
+                                     name(), ': dangling @id-ref (',
+                                     @id-ref, '): more than one @id found',
+                                     ' within the same element class')"/>
+      </xsl:message>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:copy>
+        <xsl:attribute name="id">
+          <xsl:value-of select="concat($cibtr:WrapSpecificPrefixInitialRoot,
+                                       $Original/@id)"/>
+        </xsl:attribute>
+        <xsl:apply-templates select="$Original/@*[name() != 'id']
+                                     |$Original/node()"
+                             mode="cibtr:enter">
+          <xsl:with-param name="TargetIdPrefix"
+                          select="concat('__', $cibtr:WrapSpecificPrefix, '_',
+                                         $Original/@id, '__')"/>
+        </xsl:apply-templates>
+      </xsl:copy>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<!--
+ (uniformity as an unattainable goal)
+ -->
+<xsl:template match="@id[
+                       name(..) != 'resource_ref'
+                     ]"
+              mode="cibtr:enter">
+  <xsl:param name="TargetIdPrefix"/>
+  <xsl:attribute name="{name()}">
+    <xsl:value-of select="concat($TargetIdPrefix, .)"/>
+  </xsl:attribute>
+</xsl:template>
+
+<xsl:template match="@*|node()" mode="cibtr:enter">
+  <xsl:param name="TargetIdPrefix" select="''"/>
+  <xsl:call-template name="cibtr:HelperIdentityEnter">
+    <xsl:with-param name="TargetIdPrefix" select="$TargetIdPrefix"/>
+  </xsl:call-template>
+</xsl:template>
+
+<!-- mode-less, easy to override kick-off -->
+<xsl:template match="/">
+  <xsl:call-template name="cibtr:HelperIdentityEnter"/>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/xml/upgrade-2.10-leave.xsl b/xml/upgrade-2.10-leave.xsl
new file mode 100644
index 0000000000..6e3fe65eda
--- /dev/null
+++ b/xml/upgrade-2.10-leave.xsl
@@ -0,0 +1,230 @@
+<!--
+ Copyright 2018 Red Hat, Inc.
+ Author: Jan Pokorny <jpokorny@redhat.com>
+ Part of pacemaker project
+ SPDX-License-Identifier: GPL-2.0-or-later
+ -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:cibtr="http://clusterlabs.org/ns/pacemaker/cibtr-2"
+                exclude-result-prefixes="cibtr"
+		cibtr:filename="upgrade-2.10-leave.xsl">
+<xsl:output method="xml" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
+
+<xsl:param name="cibtr:label-debug"   select="'DEBUG: '"/>
+
+<!--
+
+ GENERIC UTILITIES
+
+ -->
+
+<!--
+ Recursive implementation of "basename"
+
+ Merely parameter driven, no implicit context taken into account:
+ - Uri: input in it's current phase of processing
+-->
+<xsl:template name="cibtr:WrapSpecificBasename">
+  <xsl:param name="Uri"/>
+  <xsl:choose>
+    <xsl:when test="not(contains($Uri, '/'))">
+      <xsl:value-of select="$Uri"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:call-template name="cibtr:WrapSpecificBasename">
+        <xsl:with-param name="Uri"
+                        select="substring-after($Uri, '/')"/>
+      </xsl:call-template>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<!--
+ Id-mangling-enriched identity template.
+ -->
+<xsl:template name="cibtr:HelperIdentityLeave">
+  <xsl:copy>
+    <xsl:apply-templates select="@*|node()" mode="cibtr:leave"/>
+  </xsl:copy>
+</xsl:template>
+
+
+<!--
+
+ ACTUAL TRANSFORMATION
+
+ Extra modes: cibtr:leave
+              cibtr:leave-serialize
+
+ -->
+
+<xsl:variable name="cibtr:WrapSpecificPrefix">
+  <!-- no sleek way to fetch this, top-level xmlns:cibtr disappears early -->
+  <xsl:call-template name="cibtr:WrapSpecificBasename">
+    <xsl:with-param name="Uri"
+      select="namespace-uri(document('')/xsl:stylesheet/@cibtr:filename)"/>
+  </xsl:call-template>
+</xsl:variable>
+
+<xsl:variable name="cibtr:WrapSpecificPrefixInitialRoot"
+              select="concat('_', $cibtr:WrapSpecificPrefix, '_')"/>
+
+<!--
+ cibtr:leave-serialize mode
+ -->
+
+<xsl:template match="@*|node()" mode="cibtr:leave-serialize">
+  <xsl:choose>
+    <xsl:when test="count(.|../@*)=count(../@*)
+                    and
+                    name() = 'id'">
+      <!-- intentionally skip -->
+    </xsl:when>
+    <xsl:when test="count(.|../@*)=count(../@*)
+                    or
+                    self::processing-instruction()">
+      <xsl:variable name="Mark">
+        <xsl:if test="count(.|../@*)=count(../@*)">A</xsl:if>
+        <xsl:if test="self::processing-instruction()">P</xsl:if>
+      </xsl:variable>
+      <xsl:value-of select="concat($Mark, '(', name(), '=', ., '),')"/>
+    </xsl:when>
+    <xsl:when test="self::*">
+      <xsl:value-of select="concat('E(', name(), ',')"/>
+      <xsl:apply-templates select="@*|node()"
+                           mode="cibtr:leave-serialize"/>
+      <xsl:value-of select="'),'"/>
+    </xsl:when>
+    <xsl:when test="self::comment()|self::text()">
+      <xsl:variable name="Mark">
+        <xsl:if test="self::comment()">C</xsl:if>
+        <xsl:if test="self::text()">T</xsl:if>
+      </xsl:variable>
+      <xsl:value-of select="concat($Mark, '(', ., '),')"/>
+    </xsl:when>
+  </xsl:choose>
+</xsl:template>
+
+<!--
+ cibtr:leave mode
+ -->
+
+<!--
+ This is to cover elements with the internal structure characterized
+ with the following RelaxNG Compact encoded grammar:
+
+ > attribute id-ref { xsd:IDREF }
+ > | (attribute id { xsd:ID },
+ >    (rule?
+ >     & nvpair*
+ >     & attribute score {
+ >         xsd:integer
+ >         | xsd:token "INFINITY"
+ >         | xsd:token "+INFINITY"
+ >         | xsd:token "-INFINITY"
+ >       }?))
+
+ The context node corresponds to "@id-ref" branch prior to unfolding
+ in the preceding "unfold" XSLT counterpart, and Original to the other,
+ and the task here is to recursively (and deterministically) compare
+ the content of the two, and when there's a match, to collapse the
+ former back to a mere empty @id-ref link.
+
+ NOTE: name of this template may be a bit misleading, but it's meant
+       to really mean "after upgrade of the same trailing numbers",
+       which effectively means we are playing per 3.X CIB schema
+       rules, which needs to be considered, should any element be
+       renamed, etc.
+ -->
+<xsl:template match="*[
+                       contains(
+                         concat('|cluster_property_set',
+                                '|instance_attributes|',
+                                '|meta_attributes|'),
+                         concat('|', name(), '|')
+                       )
+                     ]"
+              mode="cibtr:leave">
+  <xsl:variable name="Original"
+                select="//*[
+                          name() = name(current())
+                          and
+                          @id = substring-after(current()/@id,
+                                                $cibtr:WrapSpecificPrefixInitialRoot)
+                        ]"/>
+  <xsl:choose>
+    <xsl:when test="not(
+                      starts-with(@id, $cibtr:WrapSpecificPrefixInitialRoot)
+                    )">
+      <xsl:copy>
+        <xsl:apply-templates select="@*|node()"
+                             mode="cibtr:leave"/>
+      </xsl:copy>
+    </xsl:when>
+    <xsl:when test="count($Original) = 0">
+      <xsl:if test="string($cibtr:label-debug) != string(false())">
+        <xsl:message>
+          <xsl:value-of select="concat($cibtr:label-debug, name(),
+                                       ': original element pointed to with',
+                                       ' @id-ref (',
+                                       substring-after(@id,
+                                                       $cibtr:WrapSpecificPrefixInitialRoot),
+                                       ') disappeared during upgrade')"/>
+        </xsl:message>
+      </xsl:if>
+      <xsl:copy>
+        <xsl:apply-templates select="@*|node()"
+                             mode="cibtr:leave"/>
+      </xsl:copy>
+    </xsl:when>
+    <xsl:when test="count($Original) != 1">
+      <xsl:message terminate="yes">
+        <xsl:value-of select="concat('INTERNAL ERROR:',
+                                     name(), ': found several elements',
+                                     ' that possibly were originally',
+                                     ' pointed to with @id-ref (',
+                                     substring-after(@id,
+                                                     $cibtr:WrapSpecificPrefixInitialRoot),
+                                     '); unexpected ambiguity')"/>
+      </xsl:message>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:variable name="SerializedOriginal">
+        <xsl:apply-templates select="$Original/@*[name() != 'id']
+                                     |$Original/node()"
+                             mode="cibtr:leave-serialize"/>
+      </xsl:variable>
+      <xsl:variable name="SerializedDependant">
+        <xsl:apply-templates select="@*[name() != 'id']
+                                     |node()"
+                             mode="cibtr:leave-serialize"/>
+      </xsl:variable>
+      <xsl:copy>
+        <xsl:choose>
+          <xsl:when test="$SerializedOriginal = $SerializedDependant">
+            <xsl:attribute name="id-ref">
+              <xsl:value-of select="substring-after(@id,
+                                                    $cibtr:WrapSpecificPrefixInitialRoot)"/>
+            </xsl:attribute>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:apply-templates select="@*|node()"
+                                 mode="cibtr:leave">
+            </xsl:apply-templates>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:copy>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="@*|node()" mode="cibtr:leave">
+  <xsl:call-template name="cibtr:HelperIdentityLeave"/>
+</xsl:template>
+
+<!-- mode-less, easy to override kick-off -->
+<xsl:template match="/">
+  <xsl:call-template name="cibtr:HelperIdentityLeave"/>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/xml/upgrade-2.10-roundtrip.xsl b/xml/upgrade-2.10-roundtrip.xsl
new file mode 100644
index 0000000000..18d73c8558
--- /dev/null
+++ b/xml/upgrade-2.10-roundtrip.xsl
@@ -0,0 +1,47 @@
+<!--
+ Copyright 2018 Red Hat, Inc.
+ Author: Jan Pokorny <jpokorny@redhat.com>
+ Part of pacemaker project
+ SPDX-License-Identifier: GPL-2.0-or-later
+ -->
+<!--
+ For experimenting and maintenance purposes only, pacemaker shall
+ split the transformation pipeline on its own.
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:cibtr="http://clusterlabs.org/ns/pacemaker/cibtr-2"
+                xmlns:exsl="http://exslt.org/common">
+<!-- NOTE: this is an exception from rule forbidding EXSLT's usage -->
+
+<xsl:import href="upgrade-2.10.xsl"/>
+<xsl:import href="upgrade-2.10-enter.xsl"/>
+<xsl:import href="upgrade-2.10-leave.xsl"/>
+
+<xsl:output method="xml" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
+
+
+<!--
+
+ ACTUAL TRANSFORMATION
+
+ Extra modes: cibtr:roundtrip
+
+ -->
+<xsl:template match="/"
+              mode="cibtr:roundtrip">
+  <xsl:variable name="pre-upgrade">
+    <xsl:apply-templates mode="cibtr:enter"/>
+  </xsl:variable>
+  <xsl:variable name="upgrade">
+    <xsl:apply-templates select="exsl:node-set($pre-upgrade)/node()" mode="cibtr:main"/>
+  </xsl:variable>
+
+  <xsl:apply-templates select="exsl:node-set($upgrade)/node()" mode="cibtr:leave"/>
+</xsl:template>
+
+<!-- mode-less, easy to override kick-off -->
+<xsl:template match="/">
+  <xsl:apply-templates select="." mode="cibtr:roundtrip"/>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/xml/upgrade-2.10.xsl b/xml/upgrade-2.10.xsl
index 321b3c22ba..526ef6d2d9 100644
--- a/xml/upgrade-2.10.xsl
+++ b/xml/upgrade-2.10.xsl
@@ -1,2532 +1,2569 @@
 <!--
  Copyright 2018 Red Hat, Inc.
  Author: Jan Pokorny <jpokorny@redhat.com>
  Part of pacemaker project
  SPDX-License-Identifier: GPL-2.0-or-later
  -->
+
+<!--
+ Not compatible with @id-ref occurrences!  Normalize generic 2.X-compatible
+ instances with upgrade-2.10-enter.xsl (optionally denormalize back akin
+ to the original with upgrade-2.10-leave.xsl once the upgrade is finished).
+-->
+
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xmlns:cibtr="http://clusterlabs.org/ns/pacemaker/cibtr-2"
                 exclude-result-prefixes="cibtr">
 <xsl:output method="xml" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
 
 <xsl:param name="cibtr:cib-min-ver" select="'3.0'"/>
+<xsl:param name="cibtr:label-warning" select="'WARNING: '"/>
+<xsl:param name="cibtr:label-info"    select="'INFO: '"/>
+<xsl:param name="cibtr:label-debug"   select="'DEBUG: '"/>
 
 <!--
 
  HELPER DEFINITIONS
 
  -->
 
 <cibtr:map>
 
   <!--
    Target tag:     cluster_property_set
    Object:         ./nvpair/@name
    Selector ctxt:  ./nvpair/@value
    Move ctxt:      op_defaults ~ /cib/configuration/op_defaults
                    rsc_defaults ~ /cib/configuration/rsc_defaults
    Related commit: c1c66fe13
                    +
                    7a9891f29
                    7d0d1b0eb
                    1f643d610
                    73a5d63a8
                    +
                    642a09b22
                    0c03e366d
                    a28a558f9
    -->
   <cibtr:table for="cluster-properties" msg-prefix="Cluster properties"
                where-cases="op_defaults|rsc_defaults">
     <cibtr:replace what="cluster-infrastructure"
                    with=""
                    in-case-of="heartbeat|openais|classic openais|classic openais (with plugin)|cman"
                    msg-extra="corosync (2+) infrastructure can be used instead, though the value is not of significance"/>
 
     <cibtr:replace what="cluster_recheck_interval"
                    with="cluster-recheck-interval"/>
     <cibtr:replace what="dc_deadtime"
                    with="dc-deadtime"/>
 
     <cibtr:replace what="default-action-timeout"
                    with="timeout"
                    where="op_defaults"/>
     <cibtr:replace what="default_action_timeout"
                    with="timeout"
                    where="op_defaults"/>
 
     <cibtr:replace what="default-migration-threshold"
                    with=""
                    msg-extra="migration-threshold in rsc_defaults can be configured instead"/>
     <cibtr:replace what="default_migration_threshold"
                    with=""
                    msg-extra="migration-threshold in rsc_defaults can be configured instead"/>
 
     <cibtr:replace what="default-resource-stickiness"
                    with="resource-stickiness"
                    where="rsc_defaults"/>
     <cibtr:replace what="default_resource_stickiness"
                    with="resource-stickiness"
                    where="rsc_defaults"/>
 
     <cibtr:replace what="default-resource-failure-stickiness"
                    with="migration-threshold"
                    where="rsc_defaults"
                    in-case-of="-INFINITY"
                    redefined-as="1"/>
     <cibtr:replace what="default-resource-failure-stickiness"
                    with=""
                    msg-extra="migration-threshold in rsc_defaults can be configured instead"/>
     <cibtr:replace what="default_resource_failure_stickiness"
                    with="migration-threshold"
                    where="rsc_defaults"
                    in-case-of="-INFINITY"
                    redefined-as="1"/>
     <cibtr:replace what="default_resource_failure_stickiness"
                    with=""
                    msg-extra="migration-threshold in rsc_defaults can be configured instead"/>
 
     <cibtr:replace what="election_timeout"
                    with="election-timeout"/>
     <cibtr:replace what="expected-quorum-votes"
                    with=""
                    msg-extra="corosync (2+) infrastructure tracks quorum on its own"/>
 
     <cibtr:replace what="is-managed-default"
                    with="is-managed"
                    where="rsc_defaults"/>
     <cibtr:replace what="is_managed_default"
                    with="is-managed"
                    where="rsc_defaults"/>
     <cibtr:replace what="no_quorum_policy"
                    with="no-quorum-policy"/>
 
     <cibtr:replace what="notification-agent"
                    with=""
                    msg-extra="standalone alerts can be configured instead"/>
     <cibtr:replace what="notification-recipient"
                    with=""
                    msg-extra="standalone alerts can be configured instead"/>
 
     <cibtr:replace what="remove_after_stop"
                    with="remove-after-stop"/>
     <cibtr:replace what="shutdown_escalation"
                    with="shutdown-escalation"/>
     <cibtr:replace what="startup_fencing"
                    with="startup-fencing"/>
     <cibtr:replace what="stonith_action"
                    with="stonith-action"/>
     <cibtr:replace what="stonith_enabled"
                    with="stonith-enabled"/>
     <cibtr:replace what="stop_orphan_actions"
                    with="stop-orphan-actions"/>
     <cibtr:replace what="stop_orphan_resources"
                    with="stop-orphan-resources"/>
     <cibtr:replace what="symmetric_cluster"
                    with="symmetric-cluster"/>
     <cibtr:replace what="transition_idle_timeout"
                    with="cluster-delay"/>
   </cibtr:table>
 
   <!--
    Target tag:     node
    Object:         ./@*
    Selector ctxt:  ./@*
    Move ctxt:      N/A
    Related commit: 55ab749bf
    -->
   <cibtr:table for="cluster-node" msg-prefix="Cluster node">
     <cibtr:replace what="type"
                    with="type"
                    in-case-of="normal"
                    redefined-as="member"/>
   </cibtr:table>
 
   <!--
    Target tag:     primitive
                    template
    Object:         ./instance_attributes/nvpair/@name
    Selector ctxt:  N/A
    Move ctxt:      N/A
    Related commit: 06d4559cb
                    +
                    6c8e0be20
    -->
   <cibtr:table for="resource-instance-attributes" msg-prefix="Resource instance_attributes">
     <cibtr:replace what="pcmk_arg_map"
                    with=""/>
     <!-- simplified as pcmk_arg_map can encode multiple
          comma-separated pairs (everything would be dropped then,
          except for a single dangling case: "port" coming first) -->
     <cibtr:replace what="pcmk_arg_map"
                    with="pcmk_host_argument"
                    in-case-of-droppable-prefix="port:"/>
 
     <cibtr:replace what="pcmk_list_cmd"
                    with="pcmk_list_action"/>
     <cibtr:replace what="pcmk_monitor_cmd"
                    with="pcmk_monitor_action"/>
     <cibtr:replace what="pcmk_off_cmd"
                    with="pcmk_off_action"/>
     <cibtr:replace what="pcmk_on_cmd"
                    with="pcmk_on_action"/>
     <cibtr:replace what="pcmk_reboot_cmd"
                    with="pcmk_reboot_action"/>
     <cibtr:replace what="pcmk_status_cmd"
                    with="pcmk_status_action"/>
   </cibtr:table>
 
   <!--
    Target tag:     primitive
                    template
    Object:         ./meta_attributes/nvpair/@name
    Selector ctxt:  N/A
    Move ctxt:      N/A
    Related commit: c713bbe39
                    +
                    6052ad6da
    -->
   <cibtr:table for="resource-meta-attributes" msg-prefix="Resource meta_attributes">
     <cibtr:replace what="isolation"
                    with="target-role"
                    redefined-as="Stopped"
-                   msg-extra="i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources"/>
+                   msg-extra="i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources"
+                   msg-severity="WARNING"/>
     <cibtr:replace what="isolation-host"
                    with="target-role"
                    redefined-as="Stopped"
-                   msg-extra="i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources"/>
+                   msg-extra="i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources"
+                   msg-severity="WARNING"/>
     <cibtr:replace what="isolation-instance"
                    with="target-role"
                    redefined-as="Stopped"
-                   msg-extra="i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources"/>
+                   msg-extra="i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources"
+                   msg-severity="WARNING"/>
     <cibtr:replace what="isolation-wrapper"
                    with="target-role"
                    redefined-as="Stopped"
-                   msg-extra="i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources"/>
+                   msg-extra="i.e. resource at hand disabled; isolation wrappers obsoleted with bundle resources"
+                   msg-severity="WARNING"/>
 
     <cibtr:replace what="resource-failure-stickiness"
                    with="migration-threshold"
                    in-case-of="-INFINITY"
                    redefined-as="1"/>
     <cibtr:replace what="resource-failure-stickiness"
                    with=""
                    msg-extra="migration-threshold can be configured instead"/>
     <cibtr:replace what="resource_failure_stickiness"
                    with="migration-threshold"
                    in-case-of="-INFINITY"
                    redefined-as="1"/>
     <cibtr:replace what="resource_failure_stickiness"
                    with=""
                    msg-extra="migration-threshold can be configured instead"/>
   </cibtr:table>
 
   <!--
    Target tag:     primitive
                    template
    Object:         ./operations/op/@*
                    ./operations/op/meta_attributes/nvpair/@name
                    ./operations/op/instance_attributes/nvpair/@name
    Selector ctxt:  ./operations/op/@name
    Move ctxt:      meta_attributes ~ ./meta_attributes/nvpair
    Related commit: 014a543d5
    -->
   <cibtr:table for="resources-operation" msg-prefix="Resources-operation"
                where-cases="meta_attributes">
     <!-- keep this in sync with resource-operation-instance-attributes table -->
     <cibtr:replace what="requires"
                    with=""
                    msg-extra="only start/promote operation taken into account"/>
     <cibtr:replace what="requires"
                    with="requires"
                    in-case-of="start|promote"
                    where="meta_attributes"/>
   </cibtr:table>
 
   <!--
    Target tag:     primitive
                    template
    Object:         ./operations/op/instance_attributes/nvpair/@name
    Selector ctxt:  ./operations/op/@name
    Move ctxt:      per-resource-meta_attributes ~ ./meta_attributes/nvpair
                    meta_attributes ~ ./operations/op/meta_attributes/nvpair
    Related commit: 023897afc
                    3100c0e8b
    -->
   <cibtr:table for="resource-operation-instance-attributes"
                msg-prefix="Resources-operation instance_attributes"
                where-cases="meta_attributes|per-resource-meta_attributes">
     <!-- this is easier to solve through resources-operation table handling,
          in the inverse mode, but for compatibility purposes, we need to have
          it tracked here, so mark it the same way as if we were moving it over
          to sibling per-op meta_attributes (while in fact we move it up to
          per-resource meta_attributes, as if it was specified in per-op
          meta_attributes already), just use a dedicated "where-case" other
          than "meta_attributes" reserved for proper local move as mentioned;
          otherwise keep it in sync with said table -->
     <cibtr:replace what="requires"
                    with=""
                    msg-extra="only start/promote operation taken into account"/>
     <cibtr:replace what="requires"
                    with="requires"
                    in-case-of="start|promote"
                    where="per-resource-meta_attributes"/>
 
     <!-- these must have been, due to the value sourcing predence arrangement,
          shadowed by immediate op's attributes, so simply preserve their
          non-meta meaning -->
     <!--
     <cibtr:replace what="name"
                    with="name"
                    where="meta_attributes"/>
     <cibtr:replace what="interval"
                    with="interval"
                    where="meta_attributes"/>
     -->
 
     <cibtr:replace what="interval-origin"
                    with="interval-origin"
                    where="meta_attributes"/>
     <cibtr:replace what="start-delay"
                    with="start-delay"
                    where="meta_attributes"/>
 
     <cibtr:replace what="enabled"
                    with="enabled"
                    where="meta_attributes"/>
     <cibtr:replace what="on-fail"
                    with="on-fail"
                    where="meta_attributes"/>
     <cibtr:replace what="record-pending"
                    with="record-pending"
                    where="meta_attributes"/>
     <cibtr:replace what="role"
                    with="role"
                    where="meta_attributes"/>
     <cibtr:replace what="timeout"
                    with="timeout"
                    where="meta_attributes"/>
   </cibtr:table>
 
   <!--
    Target tag:     rsc_colocation
    Object:         ./@*
    Selector ctxt:  N/A
    Move ctxt:      N/A
    Related commit: 96d7ffedf
    -->
   <cibtr:table for="constraints-colocation" msg-prefix="Constraints-colocation">
     <cibtr:replace what="score-attribute"
                    with=""
                    msg-extra="was actually never in effect"/>
     <cibtr:replace what="score-attribute-mangle"
                    with=""
                    msg-extra="was actually never in effect"/>
   </cibtr:table>
 
 </cibtr:map>
 
 <xsl:variable name="cibtr:MapClusterProperties"
               select="document('')/xsl:stylesheet
                         /cibtr:map/cibtr:table[
                           @for = 'cluster-properties'
                         ]"/>
 
 <xsl:variable name="cibtr:MapClusterNode"
               select="document('')/xsl:stylesheet
                         /cibtr:map/cibtr:table[
                           @for = 'cluster-node'
                         ]"/>
 
 <xsl:variable name="cibtr:MapResourceInstanceAttributes"
               select="document('')/xsl:stylesheet
                         /cibtr:map/cibtr:table[
                           @for = 'resource-instance-attributes'
                         ]"/>
 
 <xsl:variable name="cibtr:MapResourceMetaAttributes"
               select="document('')/xsl:stylesheet
                         /cibtr:map/cibtr:table[
                           @for = 'resource-meta-attributes'
                         ]"/>
 
 <xsl:variable name="cibtr:MapResourcesOperation"
               select="document('')/xsl:stylesheet
                         /cibtr:map/cibtr:table[
                           @for = 'resources-operation'
                         ]"/>
 
 <xsl:variable name="cibtr:MapResourcesOperationInstanceAttributes"
               select="document('')/xsl:stylesheet
                         /cibtr:map/cibtr:table[
                           @for = 'resource-operation-instance-attributes'
                         ]"/>
 
 <xsl:variable name="cibtr:MapConstraintsColocation"
               select="document('')/xsl:stylesheet
                         /cibtr:map/cibtr:table[
                           @for = 'constraints-colocation'
                         ]"/>
 
 <!--
 
  GENERIC UTILITIES
 
  -->
 
 <!--
  Plain identity template
 
  Merely implicit-context-driven, no arguments.
  -->
 <xsl:template name="cibtr:HelperIdentity">
   <xsl:copy>
     <xsl:apply-templates select="@*|node()"
                          mode="cibtr:main"/>
   </xsl:copy>
 </xsl:template>
 
 <!--
  Emit an message about the replacement, sanity checking the source definitions
 
  Merely parameter driven, no implicit context taken into account:
  - Context: optional message prefix
  - Replacement: selected subset of cibtr:map's leaves
                 (it's considered a hard error if consists of more than 1 item)
+
+ Explanation wrt. how target severity gets selected, ordered by priority:
+ - $Replacement/@msg-severity (WARNING/INFO/DEBUG)
+ - $Replacement/@msg-extra defined -> INFO
+ - otherwise -> DEBUG
  -->
 <xsl:template name="cibtr:MapMsg">
   <xsl:param name="Context" select="''"/>
   <xsl:param name="Replacement"/>
   <xsl:choose>
     <xsl:when test="not($Replacement)"/>
     <xsl:when test="count($Replacement) != 1">
       <xsl:message terminate="yes">
-        <xsl:value-of select="concat('INTERNAL ERROR:',
+        <xsl:value-of select="concat('INTERNAL ERROR: ',
                                      $Replacement/../@msg-prefix,
                                      ': count($Replacement) != 1',
                                      ' does not hold (',
                                      count($Replacement), ')')"/>
       </xsl:message>
     </xsl:when>
     <xsl:otherwise>
       <xsl:variable name="MsgPrefix" select="concat(
                                                ($Replacement|$Replacement/..)
                                                  /@msg-prefix, ': '
                                              )"/>
-      <xsl:message>
-        <xsl:value-of select="$MsgPrefix"/>
-        <xsl:if test="$Context">
-          <xsl:value-of select="concat($Context, ': ')"/>
-        </xsl:if>
+      <xsl:variable name="MsgSeverity">
         <xsl:choose>
-          <xsl:when test="string($Replacement/@with)">
-            <xsl:choose>
-              <xsl:when test="string($Replacement/@where)">
-                <xsl:if test="not(
-                                contains(
-                                  concat('|', $Replacement/../@where-cases, '|'),
-                                  concat('|', $Replacement/@where, '|')
-                                )
-                              )">
-                  <xsl:message terminate="yes">
-                    <xsl:value-of select="concat('INTERNAL ERROR:',
-                                                 $Replacement/../@msg-prefix,
-                                                 ': $Replacement/@where (',
-                                                 $Replacement/@where, ') not in ',
-                                                 concat('|',
-                                                 $Replacement/../@where-cases,
-                                                 '|'))"/>
-                  </xsl:message>
-                </xsl:if>
-                <xsl:value-of select="concat('moving ', $Replacement/@what,
-                                             ' under ', $Replacement/@where)"/>
-              </xsl:when>
-              <xsl:when test="$Replacement/@with = $Replacement/@what">
-                <xsl:value-of select="concat('keeping ', $Replacement/@what)"/>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:value-of select="concat('renaming ', $Replacement/@what)"/>
-              </xsl:otherwise>
-            </xsl:choose>
-            <xsl:value-of select="concat(' as ', $Replacement/@with)"/>
-            <xsl:if test="$Replacement/@where">
-              <xsl:value-of select="' unless already defined there'"/>
-            </xsl:if>
+          <xsl:when test="$Replacement/@msg-severity">
+            <xsl:value-of select="$Replacement/@msg-severity"/>
+          </xsl:when>
+          <xsl:when test="$Replacement/@msg-extra">
+            <xsl:value-of select="'INFO'"/>
           </xsl:when>
           <xsl:otherwise>
-            <xsl:value-of select="concat('dropping ', $Replacement/@what)"/>
+            <xsl:value-of select="'DEBUG'"/>
           </xsl:otherwise>
         </xsl:choose>
-        <xsl:if test="string($Replacement/@redefined-as)">
-          <xsl:value-of select="concat(', redefined as ',
-                                       $Replacement/@redefined-as)"/>
-          <xsl:if test="$Replacement/@in-case-of">
-            <xsl:value-of select="','"/>
-          </xsl:if>
-        </xsl:if>
+      </xsl:variable>
+      <xsl:variable name="MsgSeverityLabel">
         <xsl:choose>
-          <xsl:when test="string($Replacement/@in-case-of)">
-            <xsl:value-of select="concat(' for matching ',
-                                         $Replacement/@in-case-of)"/>
+          <xsl:when test="$MsgSeverity = 'WARNING'">
+            <xsl:value-of select="$cibtr:label-warning"/>
           </xsl:when>
-          <xsl:when test="$Replacement/@in-case-of">
-            <xsl:value-of select="' for matching &quot;empty string&quot;'"/>
+          <xsl:when test="$MsgSeverity = 'INFO'">
+            <xsl:value-of select="$cibtr:label-info"/>
           </xsl:when>
-          <xsl:when test="$Replacement/@in-case-of-droppable-prefix">
-            <xsl:value-of select="concat(' for matching ',
-                                    $Replacement/@in-case-of-droppable-prefix,
-                                    ' prefix that will, meanwhile, get dropped'
-                                  )"/>
+          <xsl:when test="$MsgSeverity = 'DEBUG'">
+            <xsl:value-of select="$cibtr:label-debug"/>
           </xsl:when>
+          <xsl:otherwise>
+            <xsl:message terminate="yes">
+              <xsl:value-of select="concat('INTERNAL ERROR: not a valid',
+                                           ' severity specification: ',
+                                           $MsgSeverity)"/>
+            </xsl:message>
+          </xsl:otherwise>
         </xsl:choose>
-      </xsl:message>
-      <xsl:if test="$Replacement/@msg-extra">
+      </xsl:variable>
+      <xsl:if test="string($MsgSeverityLabel) != string(false())">
         <xsl:message>
-          <xsl:value-of select="concat($MsgPrefix, '... ',
-                                       $Replacement/@msg-extra)"/>
+          <xsl:value-of select="concat($MsgSeverityLabel, $MsgPrefix)"/>
+          <xsl:if test="$Context">
+            <xsl:value-of select="concat($Context, ': ')"/>
+          </xsl:if>
+          <xsl:choose>
+            <xsl:when test="string($Replacement/@with)">
+              <xsl:choose>
+                <xsl:when test="string($Replacement/@where)">
+                  <xsl:if test="not(
+                                  contains(
+                                    concat('|', $Replacement/../@where-cases, '|'),
+                                    concat('|', $Replacement/@where, '|')
+                                  )
+                                )">
+                    <xsl:message terminate="yes">
+                      <xsl:value-of select="concat('INTERNAL ERROR:',
+                                                   $Replacement/../@msg-prefix,
+                                                   ': $Replacement/@where (',
+                                                   $Replacement/@where, ') not in ',
+                                                   concat('|',
+                                                   $Replacement/../@where-cases,
+                                                   '|'))"/>
+                    </xsl:message>
+                  </xsl:if>
+                  <xsl:value-of select="concat('moving ', $Replacement/@what,
+                                               ' under ', $Replacement/@where)"/>
+                </xsl:when>
+                <xsl:when test="$Replacement/@with = $Replacement/@what">
+                  <xsl:value-of select="concat('keeping ', $Replacement/@what)"/>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:value-of select="concat('renaming ', $Replacement/@what)"/>
+                </xsl:otherwise>
+              </xsl:choose>
+              <xsl:value-of select="concat(' as ', $Replacement/@with)"/>
+              <xsl:if test="$Replacement/@where">
+                <xsl:value-of select="' unless already defined there'"/>
+              </xsl:if>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="concat('dropping ', $Replacement/@what)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+          <xsl:if test="string($Replacement/@redefined-as)">
+            <xsl:value-of select="concat(', redefined as ',
+                                         $Replacement/@redefined-as)"/>
+            <xsl:if test="$Replacement/@in-case-of">
+              <xsl:value-of select="','"/>
+            </xsl:if>
+          </xsl:if>
+          <xsl:choose>
+            <xsl:when test="string($Replacement/@in-case-of)">
+              <xsl:value-of select="concat(' for matching ',
+                                           $Replacement/@in-case-of)"/>
+            </xsl:when>
+            <xsl:when test="$Replacement/@in-case-of">
+              <xsl:value-of select="' for matching &quot;empty string&quot;'"/>
+            </xsl:when>
+            <xsl:when test="$Replacement/@in-case-of-droppable-prefix">
+              <xsl:value-of select="concat(' for matching ',
+                                      $Replacement/@in-case-of-droppable-prefix,
+                                      ' prefix that will, meanwhile, get dropped'
+                                    )"/>
+            </xsl:when>
+          </xsl:choose>
         </xsl:message>
+        <xsl:if test="$Replacement/@msg-extra">
+          <xsl:message>
+            <xsl:value-of select="concat($MsgSeverityLabel, $MsgPrefix, '... ',
+                                         $Replacement/@msg-extra)"/>
+          </xsl:message>
+        </xsl:if>
       </xsl:if>
     </xsl:otherwise>
   </xsl:choose>
 </xsl:template>
 
 <!--
  Produce a denormalized space if not present in the input (cf. trick A.)
 
  Merely parameter driven, no implicit context taken into account:
  - Source: input selection or result tree fragment to evaluate
  - ResultTreeFragment: optional self-explanatory flag related to Source
  -->
 <xsl:template name="cibtr:HelperDenormalizedSpace">
   <xsl:param name="Source"/>
   <xsl:param name="ResultTreeFragment" select="false()"/>
   <xsl:param name="InnerSimulation" select="false()"/>
   <xsl:choose>
     <xsl:when test="not($ResultTreeFragment)">
       <!-- intention here is that immediately surrounding text (mostly expected
            to be just indenting whitespace) and comments will be preserved;
            in case no denormalized space is present, " " is injected -->
       <xsl:variable name="ExistingSpace"
                     select="$Source/preceding-sibling::node()[
                               (
                                 self::comment()
                                 or
                                 self::text()
                               )
                               and
                               generate-id(following-sibling::*[1])
                               = generate-id($Source)
                             ]"/>
       <xsl:copy-of select="$ExistingSpace"/>
       <xsl:if test="not(
                       $ExistingSpace/self::text()[
                         normalize-space(.) != string(.)
                       ]
                     ) and $InnerSimulation">
         <xsl:text> </xsl:text>
       </xsl:if>
     </xsl:when>
     <xsl:when test="normalize-space($Source)
                     != string($Source)">
       <xsl:text> </xsl:text>
     </xsl:when>
   </xsl:choose>
 </xsl:template>
 
 <!--
 
  TRANSFORMATION HELPERS
 
  considerations, limitations, etc.:
  1. the transformations tries to preserve as much of the original XML
     as possible, incl. whitespace text/indentation and comments, but
     at times (corner cases of tricks A. + B. below), this needs to be
     sacrificed, e.g., distorting nice indentation, hence if the
     perfection is the goal:
     - user of the transformation can feed the minimized version of
       the XML (no denormalized/any white-space present)
     - user of the transformation can (re-)pretty-print the outcome
       afterwards
 
  tricks and conventions used:
  A. callable templates only return Result Tree Fragments, which means
     the only operations allowed are those looking at the underlying,
     virtual node-set, and since we need to discern their non-void
     production (i.e. on successful match/es), we use this trick:
     - ensure the template will not propagate any denormalized whitespace
     - inject denormalized whitespace (superfluous space) artificially
       to mark successful production (but see B. below)
     - with the template production, here stored as Var variable,
       we test "normalize-space($Var) != $Var" condition to detect
       non-void production, mainly intended to see whether to emit
       the enclosing element at all (with the goal of not leaving
       superfluous elements behind needlessly)
  B. [extension over A.] to eliminate distorted indentation
     (cf. consideration 1.), additional reuse of these callable
     templates is introduced: the template can recursively call
     itself with a special flag (InnerSimulation) as an oracle to
     see to whether non-void production will ensue (all pre-existing
     denormalized whitespace is forcefully removed in this mode),
     and if positive, all such inner pre-existing whitespace is
     then preserved in this outer=main invocation
  C. [extension over B.] when checking the non-void production
     (via InnerSimulation), beside the injected denormalized whitespace,
     we can also inject particular strings, which the callsite of such
     simulation can, in addition, inspect for paricular string
     occurrences, e.g. to prevent clashes on the production coming
     from multiple sources
  D. not only to honour DRY principle and to avoid inner entropy, it's
     often useful to make callable template bimodal, e.g., when the
     production is generated in the "what's to stay in place" vs.
     "what's to be propagated (combined with previous, effectively
     moved) at this other part of the tree" contexts; for such cases,
     there's usually InverseMode parameter to be assigned true()
     (implicit default) and false(), respectively
  E. the common idiom that emerges is: evaluate simulation value,
     depending on the presence of the "success mark" (cf. A.),
     possibly emit non-simulation value; since it would (likely)
     re-evaluate the simulation anew (wastefully) or perhaps
     this sort of dependency injection can just come handy,
     common transformation helpers below offer InnerPass
     parameter to be optionally passed, either as a string (when
     no-denormalized-space is an internal criterium for the template)
     or, conventionally, the result tree fragment representing the
     output of the template at hand called with a simulation flag
     * established signaling strings accompanying InnerSimulation=true:
       - TRIGGER-MSG ... make the template execution emit messages
                         describing changes being performed
       - TRIGGER-RECURSION
                     ... currently used in the oracle-like evaluation
                         of what's the situation with the sibling
                         elements as a recursion guard so that such
                         nested runs won't revisit the new set of
                         siblings per the respective nested context
 
  -->
 
 <!--
  Source ctxt:    cluster_property_set
  Target ctxt:    cluster_property_set
  Target-inv ctxt:/cib/configuration/(op_defaults|rsc_defaults)
                  [cluster_property_set -> meta_attributes]
  Dependencies:   N/A
  -->
 <xsl:template name="cibtr:ProcessClusterProperties">
   <xsl:param name="Source"/>
   <xsl:param name="InverseMode" select="false()"/>
   <xsl:param name="InnerSimulation" select="false()"/>
   <xsl:param name="InnerPass">
     <xsl:choose>
       <xsl:when test="$InnerSimulation">
         <xsl:value-of select="''"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:ProcessClusterProperties">
           <xsl:with-param name="Source" select="$Source"/>
           <xsl:with-param name="InverseMode" select="$InverseMode"/>
           <xsl:with-param name="InnerSimulation" select="true()"/>
         </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:param>
 
   <xsl:for-each select="$Source/node()">
     <xsl:choose>
       <xsl:when test="self::text()">
         <!-- cf. trick A. (consideration 1.) -->
         <xsl:choose>
           <xsl:when test="normalize-space($InnerPass)
                           != $InnerPass
                           and
                           (
                             not(following-sibling::nvpair)
                             or
                             generate-id(following-sibling::nvpair[1])
                             != generate-id(following-sibling::*[1])
                           )">
             <xsl:value-of select="."/>
           </xsl:when>
           <xsl:otherwise>
             <xsl:value-of select="normalize-space(.)"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
       <xsl:when test="self::nvpair">
         <xsl:variable name="Replacement"
                       select="$cibtr:MapClusterProperties/cibtr:replace[
                                 @what = current()/@name
                                 and
                                 (
                                   (
                                     @in-case-of
                                     and
                                     contains(concat('|', @in-case-of, '|'),
                                              concat('|', current()/@value, '|'))
                                   )
                                   or
                                   (
                                     not(@in-case-of)
                                     and
                                     not(
                                       $cibtr:MapClusterProperties/cibtr:replace[
                                         @what = current()/@name
                                         and
                                         @in-case-of
                                         and
                                         contains(concat('|', @in-case-of, '|'),
                                                  concat('|', current()/@value, '|'))
                                       ]
                                     )
                                   )
                                 )
                               ]"/>
         <xsl:if test="$InnerPass = 'TRIGGER-MSG'">
           <xsl:call-template name="cibtr:MapMsg">
             <xsl:with-param name="Context" select="@id"/>
             <xsl:with-param name="Replacement" select="$Replacement"/>
           </xsl:call-template>
         </xsl:if>
         <xsl:choose>
           <xsl:when test="$Replacement
                           and
                           (
                             not(string($Replacement/@with))
                             or
                             $Replacement/@where
                           )">
             <!-- drop (possibly just move over) -->
             <xsl:if test="$Replacement/@where
                           and
                           (
                             (
                               normalize-space($InverseMode)
                               and
                               $Replacement/@where = $InverseMode
                             )
                             or
                             (
                               not(normalize-space($InverseMode))
                               and
                               (true() or count($InverseMode))
                               and
                               not(
                                 $InverseMode/nvpair[
                                   @name = $Replacement/@with
                                 ]
                               )
                               and
                               $Replacement/@where = name($InverseMode/..)
                             )
                           )">
               <xsl:call-template name="cibtr:HelperDenormalizedSpace">
                 <xsl:with-param name="Source" select="."/>
                 <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
               </xsl:call-template>
               <xsl:copy>
                 <xsl:for-each select="@*">
                   <xsl:choose>
                     <xsl:when test="name() = 'name'">
                       <xsl:attribute name="{name()}">
                         <xsl:value-of select="$Replacement/@with"/>
                       </xsl:attribute>
                     </xsl:when>
                     <xsl:when test="string($Replacement/@redefined-as)
                                     and
                                     name() = 'value'">
                       <xsl:attribute name="{name()}">
                         <xsl:value-of select="$Replacement/@redefined-as"/>
                       </xsl:attribute>
                     </xsl:when>
                     <xsl:otherwise>
                       <xsl:copy/>
                     </xsl:otherwise>
                   </xsl:choose>
                 </xsl:for-each>
               </xsl:copy>
             </xsl:if>
           </xsl:when>
           <xsl:when test="$InverseMode"/>
           <xsl:when test="$Replacement">
             <xsl:call-template name="cibtr:HelperDenormalizedSpace">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
             </xsl:call-template>
             <xsl:copy>
               <xsl:for-each select="@*">
                 <xsl:choose>
                   <xsl:when test="name() = 'name'">
                     <xsl:attribute name="{name()}">
                       <xsl:value-of select="$Replacement/@with"/>
                     </xsl:attribute>
                   </xsl:when>
                   <xsl:when test="string($Replacement/@redefined-as)
                                   and
                                   name() = 'value'">
                     <xsl:attribute name="{name()}">
                       <xsl:value-of select="$Replacement/@redefined-as"/>
                     </xsl:attribute>
                   </xsl:when>
                   <xsl:otherwise>
                     <xsl:copy/>
                   </xsl:otherwise>
                 </xsl:choose>
               </xsl:for-each>
             </xsl:copy>
           </xsl:when>
           <xsl:otherwise>
             <xsl:call-template name="cibtr:HelperDenormalizedSpace">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
             </xsl:call-template>
             <xsl:call-template name="cibtr:HelperIdentity"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
       <xsl:when test="$InverseMode
                       or
                       self::comment()">
         <!-- drop -->
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:HelperIdentity"/>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:for-each>
 </xsl:template>
 
 <!--
  Source ctxt:    (primitive|template)/instance_attributes
  Target ctxt:    (primitive|template)/instance_attributes
  Target-inv ctxt:N/A
  Dependencies:   N/A
  -->
 <xsl:template name="cibtr:ProcessRscInstanceAttributes">
   <xsl:param name="Source"/>
   <xsl:param name="InnerSimulation" select="false()"/>
   <xsl:param name="InnerPass">
     <xsl:choose>
       <xsl:when test="$InnerSimulation">
         <xsl:value-of select="''"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:ProcessRscInstanceAttributes">
           <xsl:with-param name="Source" select="$Source"/>
           <xsl:with-param name="InnerSimulation" select="true()"/>
         </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:param>
 
   <!-- B: special-casing nvpair -->
   <xsl:for-each select="$Source/node()">
     <xsl:choose>
       <xsl:when test="self::text()">
         <!-- cf. trick A. (consideration 1.) -->
         <xsl:choose>
           <xsl:when test="normalize-space($InnerPass)
                           != $InnerPass
                           and
                           (
                             not(following-sibling::nvpair)
                             or
                             generate-id(following-sibling::nvpair[1])
                             != generate-id(following-sibling::*[1])
                           )">
             <xsl:value-of select="."/>
           </xsl:when>
           <xsl:otherwise>
             <xsl:value-of select="normalize-space(.)"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
       <xsl:when test="self::nvpair">
         <xsl:variable name="Replacement"
                       select="$cibtr:MapResourceInstanceAttributes/cibtr:replace[
                                 @what = current()/@name
                                 and
                                 (
                                   (
                                     @in-case-of
                                     and
                                     contains(concat('|', @in-case-of, '|'),
                                              concat('|', current()/@value, '|'))
                                   )
                                   or
                                   (
                                     @in-case-of-droppable-prefix
                                     and
                                     starts-with(current()/@value,
                                                 @in-case-of-droppable-prefix)
                                     and
                                     not(
                                       contains(current()/@value, ',')
                                     )
                                   )
                                   or
                                   (
                                     not(@in-case-of)
                                     and
                                     not(@in-case-of-droppable-prefix)
                                     and
                                     not(
                                       $cibtr:MapResourceInstanceAttributes/cibtr:replace[
                                         @what = current()/@name
                                         and
                                         (
                                           (
                                             @in-case-of
                                             and
                                             contains(concat('|', @in-case-of, '|'),
                                                      concat('|', current()/@value, '|'))
                                           )
                                           or
                                           (
                                             @in-case-of-droppable-prefix
                                             and
                                             starts-with(current()/@value,
                                                         @in-case-of-droppable-prefix)
                                             and
                                             not(
                                               contains(current()/@value, ',')
                                             )
                                           )
                                         )
                                       ]
                                     )
                                   )
                                 )
                               ]"/>
         <xsl:if test="$InnerPass = 'TRIGGER-MSG'">
           <xsl:call-template name="cibtr:MapMsg">
             <xsl:with-param name="Context" select="@id"/>
             <xsl:with-param name="Replacement" select="$Replacement"/>
           </xsl:call-template>
         </xsl:if>
         <xsl:choose>
           <xsl:when test="$Replacement
                           and
                           not(string($Replacement/@with))">
             <!-- drop (move-over code missing) -->
           </xsl:when>
           <xsl:when test="$Replacement">
             <!-- plain rename -->
             <xsl:call-template name="cibtr:HelperDenormalizedSpace">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
             </xsl:call-template>
             <xsl:copy>
               <xsl:for-each select="@*">
                 <xsl:choose>
                   <xsl:when test="name() = 'name'">
                     <xsl:attribute name="{name()}">
                       <xsl:value-of select="$Replacement/@with"/>
                     </xsl:attribute>
                   </xsl:when>
                   <xsl:when test="string($Replacement/@redefined-as)
                                   and
                                   name() = 'value'">
                     <xsl:attribute name="{name()}">
                       <xsl:value-of select="$Replacement/@redefined-as"/>
                     </xsl:attribute>
                   </xsl:when>
                   <xsl:when test="string($Replacement/@in-case-of-droppable-prefix)
                                   and
                                   name() = 'value'">
                     <xsl:attribute name="{name()}">
                       <xsl:value-of select="substring-after(
                                               ., $Replacement/@in-case-of-droppable-prefix
                                             )"/>
                     </xsl:attribute>
                   </xsl:when>
                   <xsl:otherwise>
                     <xsl:copy/>
                   </xsl:otherwise>
                 </xsl:choose>
               </xsl:for-each>
             </xsl:copy>
           </xsl:when>
           <xsl:otherwise>
             <xsl:call-template name="cibtr:HelperDenormalizedSpace">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
             </xsl:call-template>
             <xsl:call-template name="cibtr:HelperIdentity"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:HelperIdentity"/>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:for-each>
   <!-- E: special-casing nvpair -->
 </xsl:template>
 
 <!--
  Source ctxt:    (primitive|template)/meta_attributes
  Target ctxt:    (primitive|template)/meta_attributes
  Target-inv ctxt:N/A
  Dependencies:   N/A
  -->
 <xsl:template name="cibtr:ProcessRscMetaAttributes">
   <xsl:param name="Source"/>
   <xsl:param name="InnerSimulation" select="false()"/>
   <xsl:param name="InnerPass">
     <xsl:choose>
       <xsl:when test="$InnerSimulation">
         <xsl:value-of select="''"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:ProcessRscMetaAttributes">
           <xsl:with-param name="Source" select="$Source"/>
           <xsl:with-param name="InnerSimulation" select="true()"/>
         </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:param>
 
   <!-- B: special-casing nvpair -->
   <xsl:for-each select="$Source/node()">
     <xsl:choose>
       <xsl:when test="self::text()">
         <!-- cf. trick A. (consideration 1.) -->
         <xsl:choose>
           <xsl:when test="normalize-space($InnerPass)
                           != $InnerPass
                           and
                           (
                             not(following-sibling::nvpair)
                             or
                             generate-id(following-sibling::nvpair[1])
                             != generate-id(following-sibling::*[1])
                           )">
             <xsl:value-of select="."/>
           </xsl:when>
           <xsl:otherwise>
             <xsl:value-of select="normalize-space(.)"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
       <xsl:when test="self::nvpair">
         <xsl:variable name="Replacement"
                       select="$cibtr:MapResourceMetaAttributes/cibtr:replace[
                                 @what = current()/@name
                                 and
                                 (
                                   (
                                     @in-case-of
                                     and
                                     contains(concat('|', @in-case-of, '|'),
                                              concat('|', current()/@value, '|'))
                                   )
                                   or
                                   (
                                     not(@in-case-of)
                                     and
                                     not(
                                       $cibtr:MapResourceMetaAttributes/cibtr:replace[
                                         @what = current()/@name
                                         and
                                         (
                                           @in-case-of
                                           and
                                           contains(concat('|', @in-case-of, '|'),
                                                    concat('|', current()/@value, '|'))
                                         )
                                       ]
                                     )
                                   )
                                 )
                               ]"/>
         <xsl:if test="$InnerPass = 'TRIGGER-MSG'">
           <xsl:call-template name="cibtr:MapMsg">
             <xsl:with-param name="Context"
                             select="concat(../../@id,
                                            ' (meta=', ../@id,
                                            ')')"/>
             <xsl:with-param name="Replacement" select="$Replacement"/>
           </xsl:call-template>
         </xsl:if>
         <xsl:choose>
           <xsl:when test="$Replacement
                           and
                           not(string($Replacement/@with))">
             <!-- drop (move-over code missing) -->
           </xsl:when>
           <xsl:when test="$Replacement">
             <!-- plain rename -->
             <xsl:variable name="SimulateFollowingSiblings">
               <!-- prevent generating redundant name-value pairs -->
               <xsl:for-each select="(..|../following-sibling::meta_attributes)[
                                       not(rule)
                                     ]">
                 <xsl:if test="$InnerPass != 'TRIGGER-RECURSION'">
                   <xsl:call-template name="cibtr:ProcessRscMetaAttributes">
                     <xsl:with-param name="Source" select="."/>
                     <xsl:with-param name="InnerSimulation" select="true()"/>
                     <xsl:with-param name="InnerPass" select="'TRIGGER-RECURSION'"/>
                   </xsl:call-template>
                 </xsl:if>
               </xsl:for-each>
             </xsl:variable>
             <xsl:choose>
               <!-- instead of HelperDenormalizedSpace -->
               <xsl:when test="$InnerSimulation">
                 <xsl:value-of select="concat(generate-id(), '@', $Replacement/@with, ' ')"/>
               </xsl:when>
               <xsl:otherwise>
                 <xsl:if test="not(
                                 contains($SimulateFollowingSiblings,
                                          concat($Replacement/@with, ' '))
                               )
                               or
                               generate-id()
                               =
                               substring-before($SimulateFollowingSiblings,
                                                concat('@', $Replacement/@with))">
                   <xsl:call-template name="cibtr:HelperDenormalizedSpace">
                     <xsl:with-param name="Source" select="."/>
                     <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
                   </xsl:call-template>
                   <xsl:copy>
                     <xsl:for-each select="@*">
                       <xsl:choose>
                         <xsl:when test="name() = 'name'">
                           <xsl:attribute name="{name()}">
                             <xsl:value-of select="$Replacement/@with"/>
                           </xsl:attribute>
                         </xsl:when>
                         <xsl:when test="string($Replacement/@redefined-as)
                                         and
                                         name() = 'value'">
                           <xsl:attribute name="{name()}">
                             <xsl:value-of select="$Replacement/@redefined-as"/>
                           </xsl:attribute>
                         </xsl:when>
                         <xsl:otherwise>
                           <xsl:copy/>
                         </xsl:otherwise>
                       </xsl:choose>
                     </xsl:for-each>
                   </xsl:copy>
                 </xsl:if>
               </xsl:otherwise>
             </xsl:choose>
           </xsl:when>
           <xsl:otherwise>
             <xsl:call-template name="cibtr:HelperDenormalizedSpace">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
             </xsl:call-template>
             <xsl:call-template name="cibtr:HelperIdentity"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:HelperIdentity"/>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:for-each>
   <!-- E: special-casing nvpair -->
 </xsl:template>
 
 <!--
  Source ctxt:    (primitive|template)/operations/op/instance_attributes
  Target ctxt:    (primitive|template)/operations/op/instance_attributes
  Target-inv ctxt:(primitive|template)/operations/op/meta_attributes
  Dependencies:   ProcessNonattrOpMetaAttributes [inverse only]
  -->
 <xsl:template name="cibtr:ProcessOpInstanceAttributes">
   <xsl:param name="Source"/>
   <xsl:param name="InverseMode" select="false()"/>
   <xsl:param name="InnerSimulation" select="false()"/>
   <xsl:param name="InnerPass">
     <xsl:choose>
       <xsl:when test="$InnerSimulation">
         <xsl:value-of select="''"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:ProcessOpInstanceAttributes">
           <xsl:with-param name="Source" select="$Source"/>
           <xsl:with-param name="InnerSimulation" select="true()"/>
         </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:param>
 
   <xsl:variable name="EnclosingTag" select="../../.."/>
 
   <!-- B: special-casing nvpair -->
   <xsl:for-each select="$Source/node()">
     <xsl:choose>
       <xsl:when test="self::text()">
         <!-- cf. trick A. (consideration 1.) -->
         <xsl:choose>
           <xsl:when test="normalize-space($InnerPass)
                           != $InnerPass
                           and
                           (
                             not(following-sibling::nvpair)
                             or
                             generate-id(following-sibling::nvpair[1])
                             != generate-id(following-sibling::*[1])
                           )">
             <xsl:value-of select="."/>
           </xsl:when>
           <xsl:otherwise>
             <xsl:value-of select="normalize-space(.)"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
       <xsl:when test="self::nvpair">
         <xsl:variable name="Replacement"
                       select="$cibtr:MapResourcesOperationInstanceAttributes/cibtr:replace[
                                 @what = current()/@name
                                 and
                                 (
                                   (
                                     @in-case-of
                                     and
                                     contains(concat('|', @in-case-of, '|'),
                                              concat('|', current()/../../@name, '|'))
                                   )
                                   or
                                   (
                                     not(@in-case-of)
                                     and
                                     not(
                                       $cibtr:MapResourcesOperationInstanceAttributes/cibtr:replace[
                                         @what = current()/@name
                                         and
                                         @in-case-of
                                         and
                                         contains(concat('|', @in-case-of, '|'),
                                                  concat('|', current()/../../@name, '|'))
                                       ]
                                     )
                                   )
                                 )
                               ]"/>
         <xsl:if test="$InnerPass = 'TRIGGER-MSG'">
           <xsl:call-template name="cibtr:MapMsg">
             <xsl:with-param name="Context"
                             select="concat(../../@id,
                                            ' (rsc=', $EnclosingTag/@id,
                                            ', meta=', ../@id,
                                            ')')"/>
             <xsl:with-param name="Replacement" select="$Replacement"/>
           </xsl:call-template>
         </xsl:if>
         <xsl:choose>
           <xsl:when test="$Replacement
                           and
                           (
                             not(string($Replacement/@with))
                             or
                             $Replacement/@where
                           )">
             <!-- drop (possibly just move over) -->
             <xsl:variable name="SimulateAttrOverrides">
               <xsl:for-each select="../../../op">
                 <xsl:call-template name="cibtr:ProcessAttrOpMetaAttributes">
                   <xsl:with-param name="Source" select="."/>
                   <xsl:with-param name="InverseMode" select="true()"/>
                   <xsl:with-param name="InnerSimulation" select="true()"/>
                 </xsl:call-template>
               </xsl:for-each>
             </xsl:variable>
             <xsl:if test="$InverseMode
                           and
                           not(
                             contains($SimulateAttrOverrides,
                                      concat(@name, ' '))
                           )">
               <!-- do not override; do not collide with:
                    - newly added from op/@* (see last condition above)
                    - existing - actually subsumed with the previous point
                    - successors sourced like this (see below) -->
               <xsl:variable name="SimulateFollowingSiblingsMeta">
                 <!-- cf. similar handling in ProcessAttrOpMetaAttributes,
                      but this is more convoluted -->
                 <xsl:for-each select="(../following-sibling::meta_attributes
                                        |../../following-sibling::op/meta_attributes)[
                                         not(rule)
                                       ]">
                   <xsl:call-template name="cibtr:ProcessNonattrOpMetaAttributes">
                     <xsl:with-param name="Source" select="."/>
                     <xsl:with-param name="InverseMode" select="true()"/>
                     <xsl:with-param name="InnerSimulation" select="true()"/>
                   </xsl:call-template>
                 </xsl:for-each>
               </xsl:variable>
               <xsl:variable name="SimulateFollowingSiblingsInstance">
                 <xsl:for-each select="../following-sibling::instance_attributes[
                                         not(rule)
                                       ]">
                   <xsl:call-template name="cibtr:ProcessOpInstanceAttributes">
                     <xsl:with-param name="Source" select="."/>
                     <xsl:with-param name="InverseMode" select="true()"/>
                     <xsl:with-param name="InnerSimulation" select="true()"/>
                   </xsl:call-template>
                 </xsl:for-each>
               </xsl:variable>
               <xsl:if test="$Replacement/@where = 'meta_attributes'
                             and
                             not(
                               $EnclosingTag/meta_attributes[
                                 not(rule)
                                 and
                                 nvpair/@name = $Replacement/@with
                               ]
                             )
                             and
                             not(
                               contains($SimulateFollowingSiblingsInstance,
                                        concat(@name, ' '))
                             )">
                 <!-- cf. trick C. (indicate for inverse mode) -->
                 <xsl:choose>
                   <xsl:when test="$InnerSimulation">
                     <!-- instead of HelperDenormalizedSpace -->
                     <xsl:value-of select="concat(@name, ' ')"/>
                   </xsl:when>
                   <xsl:otherwise>
                     <xsl:call-template name="cibtr:HelperDenormalizedSpace">
                       <xsl:with-param name="Source" select="."/>
                       <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
                     </xsl:call-template>
                     <xsl:copy>
                       <xsl:apply-templates select="@*"
                                            mode="cibtr:main"/>
                     </xsl:copy>
                   </xsl:otherwise>
                 </xsl:choose>
               </xsl:if>
             </xsl:if>
           </xsl:when>
           <xsl:when test="$Replacement">
             <xsl:message terminate="yes">
               <xsl:value-of select="concat('INTERNAL ERROR: ',
                                            $Replacement/../@msg-prefix,
                                            ': no in-situ rename',
                                            ' does not hold (',
                                            not(($InverseMode)), ')')"/>
             </xsl:message>
           </xsl:when>
           <xsl:when test="$InverseMode"/>
           <xsl:otherwise>
             <xsl:call-template name="cibtr:HelperDenormalizedSpace">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
             </xsl:call-template>
             <xsl:call-template name="cibtr:HelperIdentity"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
       <xsl:when test="$InverseMode
                       or
                       self::comment()">
         <!-- drop -->
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:HelperIdentity"/>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:for-each>
   <!-- E: special-casing nvpair -->
 </xsl:template>
 
 <!--
  Source ctxt:    (primitive|template)/operations/op/meta_attributes
                  (primitive|template)/operations/op/instance_attributes (inverse only)
  Target ctxt:    (primitive|template)/operations/op/meta_attributes
  Target-inv ctxt:(primitive|template)/meta_attributes
  Dependencies:   ProcessAttrOpMetaAttributes
                  ProcessNonattrOpMetaAttributes
  -->
 <xsl:template name="cibtr:ProcessNonattrOpMetaAttributes">
   <xsl:param name="Source"/>
   <xsl:param name="InverseMode" select="false()"/>
   <xsl:param name="InnerSimulation" select="false()"/>
   <xsl:param name="InnerPass">
     <xsl:choose>
       <xsl:when test="$InnerSimulation">
         <xsl:value-of select="''"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:ProcessNonattrOpMetaAttributes">
           <xsl:with-param name="Source" select="$Source"/>
           <xsl:with-param name="InnerSimulation" select="true()"/>
         </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:param>
 
   <xsl:variable name="EnclosingTag" select="../../.."/>
 
   <xsl:for-each select="$Source/node()">
     <xsl:choose>
       <xsl:when test="self::text()
                       and
                       not($InverseMode)">
         <!-- cf. trick A. (consideration 1.) -->
         <xsl:choose>
           <xsl:when test="normalize-space($InnerPass)
                           != $InnerPass
                           and
                           (
                             not(following-sibling::nvpair)
                             or
                             generate-id(following-sibling::nvpair[1])
                             != generate-id(following-sibling::*[1])
                           )">
             <xsl:value-of select="."/>
           </xsl:when>
           <xsl:otherwise>
             <xsl:value-of select="normalize-space(.)"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
       <xsl:when test="self::nvpair">
         <xsl:variable name="Replacement"
                       select="$cibtr:MapResourcesOperation/cibtr:replace[
                                 @what = current()/@name
                                 and
                                 (
                                   (
                                     @in-case-of
                                     and
                                     contains(concat('|', @in-case-of, '|'),
                                              concat('|', current()/../../@name, '|'))
                                   )
                                   or
                                   (
                                     not(@in-case-of)
                                     and
                                     not(
                                       $cibtr:MapResourcesOperation/cibtr:replace[
                                         @what = current()/@name
                                         and
                                         @in-case-of
                                         and
                                         contains(concat('|', @in-case-of, '|'),
                                                  concat('|', current()/../../@name, '|'))
                                       ]
                                     )
                                   )
                                 )
                               ]"/>
         <xsl:if test="$InnerPass = 'TRIGGER-MSG'">
           <xsl:call-template name="cibtr:MapMsg">
             <xsl:with-param name="Context"
                             select="concat(../../@id,
                                            ' (rsc=', $EnclosingTag/@id,
                                            ', meta=', ../@id,
                                            ')')"/>
             <xsl:with-param name="Replacement" select="$Replacement"/>
           </xsl:call-template>
         </xsl:if>
         <xsl:choose>
           <xsl:when test="$Replacement
                           and
                           (
                             not(string($Replacement/@with))
                             or
                             $Replacement/@where
                           )">
             <!-- drop (possibly just move over) -->
             <xsl:if test="$InverseMode">
               <xsl:variable name="SimulateAttrOverrides">
                 <xsl:for-each select="../../../op">
                   <xsl:call-template name="cibtr:ProcessAttrOpMetaAttributes">
                     <xsl:with-param name="Source" select="."/>
                     <xsl:with-param name="InverseMode" select="true()"/>
                     <xsl:with-param name="InnerSimulation" select="true()"/>
                   </xsl:call-template>
                 </xsl:for-each>
               </xsl:variable>
               <xsl:if test="not(
                               contains($SimulateAttrOverrides,
                                        concat(@name, ' '))
                             )">
                 <!-- do not override; do not collide with:
                      - newly added from op/@* (see last condition above)
                      - existing - actually subsumed with the previous point
                      - successors sourced like this (see below)
                      and if coming from op/instance_attributes, add also
                      - any meta_attributes sourced like this -->
                 <xsl:variable name="SimulateFollowingSiblings">
                   <!-- cf. similar handling in ProcessAttrOpMetaAttributes,
                        but this is more convoluted -->
                   <xsl:if test="name(..) = 'meta_attributes'">
                     <xsl:for-each select="(../following-sibling::meta_attributes
                                            |../../following-sibling::op/meta_attributes)[
                                             not(rule)
                                           ]">
                       <xsl:call-template name="cibtr:ProcessNonattrOpMetaAttributes">
                         <xsl:with-param name="Source" select="."/>
                         <xsl:with-param name="InverseMode" select="true()"/>
                         <xsl:with-param name="InnerSimulation" select="true()"/>
                       </xsl:call-template>
                     </xsl:for-each>
                   </xsl:if>
                   <xsl:if test="name(..) = 'instance_attributes'">
                     <xsl:for-each select="(../following-sibling::instance_attributes
                                            |../../following-sibling::op/instance_attributes
                                            |../../meta_attributes
                                            |../../../op/meta_attributes)[
                                             not(rule)
                                           ]">
                       <xsl:call-template name="cibtr:ProcessNonattrOpMetaAttributes">
                         <xsl:with-param name="Source" select="."/>
                         <xsl:with-param name="InverseMode" select="true()"/>
                         <xsl:with-param name="InnerSimulation" select="true()"/>
                       </xsl:call-template>
                     </xsl:for-each>
                   </xsl:if>
                 </xsl:variable>
                 <xsl:if test="$Replacement/@where = 'meta_attributes'
                               and
                               not(
                                 $EnclosingTag/meta_attributes[
                                   not(rule)
                                   and
                                   nvpair/@name = $Replacement/@with
                                 ]
                               )
                               and
                               not(
                                 contains($SimulateFollowingSiblings,
                                          concat(@name, ' '))
                               )">
                   <!-- cf. trick C. (indicate for inverse mode) -->
                   <xsl:choose>
                     <!-- instead of HelperDenormalizedSpace -->
                     <xsl:when test="$InnerSimulation">
                       <xsl:value-of select="concat(@name, ' ')"/>
                     </xsl:when>
                     <xsl:otherwise>
                       <xsl:copy>
                         <xsl:apply-templates select="@*"
                                              mode="cibtr:main"/>
                       </xsl:copy>
                     </xsl:otherwise>
                   </xsl:choose>
                 </xsl:if>
               </xsl:if>
             </xsl:if>
           </xsl:when>
           <xsl:when test="$Replacement">
             <xsl:message terminate="yes">
               <xsl:value-of select="concat('INTERNAL ERROR: ',
                                            $Replacement/../@msg-prefix,
                                            ': no in-situ rename',
                                            ' does not hold (',
                                            not(($InverseMode)), ')')"/>
             </xsl:message>
           </xsl:when>
           <xsl:when test="$InverseMode"/>
           <xsl:otherwise>
             <xsl:call-template name="cibtr:HelperDenormalizedSpace">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
             </xsl:call-template>
             <xsl:call-template name="cibtr:HelperIdentity"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:when>
       <xsl:when test="$InverseMode
                       or
                       self::comment()">
         <!-- drop -->
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:HelperIdentity"/>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:for-each>
 </xsl:template>
 
 <!--
  Source ctxt:    (primitive|template)/operations/op
  Target ctxt:    (primitive|template)/operations/op/meta_attributes
  Target-inv ctxt:(primitive|template)/meta_attributes
  Dependencies:   ProcessNonattrOpMetaAttributes [non-inverse only]
                  ProcessOpInstanceAttributes [non-inverse only]
  -->
 <xsl:template name="cibtr:ProcessAttrOpMetaAttributes">
   <xsl:param name="Source"/>
   <xsl:param name="InverseMode" select="false()"/>
   <xsl:param name="InnerSimulation" select="false()"/>
   <xsl:param name="InnerPass">
     <xsl:choose>
       <xsl:when test="$InnerSimulation">
         <xsl:value-of select="''"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:ProcessAttrOpMetaAttributes">
           <xsl:with-param name="Source" select="$Source"/>
           <xsl:with-param name="InverseMode" select="$InverseMode"/>
           <xsl:with-param name="InnerSimulation" select="true()"/>
         </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:param>
 
   <xsl:variable name="EnclosingTag" select="../.."/>
 
   <xsl:if test="(
                   $InverseMode
                   and
                   (
                     $InnerSimulation
                     or
                     normalize-space($InnerPass)
                     != string($InnerPass)
                   )
                 )
                 or
                 not($InverseMode)">
     <xsl:if test="$InverseMode
                   and
                   $InnerSimulation">
       <xsl:call-template name="cibtr:HelperDenormalizedSpace">
         <xsl:with-param name="Source" select="$InnerPass"/>
         <xsl:with-param name="ResultTreeFragment" select="true()"/>
       </xsl:call-template>
     </xsl:if>
 
     <!-- cannot combine "copy" with creating a new element, hence we mimic
          "copy" with recreating the element anew, while still using just
          a single for-each loop -->
     <xsl:variable name="ParentName">
       <xsl:choose>
         <xsl:when test="not($InverseMode)">
           <xsl:value-of select="name()"/>
         </xsl:when>
         <xsl:otherwise>
           <xsl:value-of select="'nvpair'"/>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:variable>
     <xsl:element name="{$ParentName}">
     <!-- B: special-casing @* -->
     <xsl:for-each select="@*">
       <xsl:variable name="Replacement"
                     select="$cibtr:MapResourcesOperation/cibtr:replace[
                               @what = name(current())
                               and
                               (
                                 (
                                   @in-case-of
                                   and
                                   contains(concat('|', @in-case-of, '|'),
                                            concat('|', current()/../@name, '|'))
                                 )
                                 or
                                 (
                                   not(@in-case-of)
                                   and
                                   not(
                                     $cibtr:MapResourcesOperation/cibtr:replace[
                                       @what = name(current())
                                       and
                                       @in-case-of
                                       and
                                       contains(concat('|', @in-case-of, '|'),
                                                concat('|', current()/../@name, '|'))
                                     ]
                                   )
                                 )
                               )
                             ]"/>
       <xsl:if test="$InnerPass = 'TRIGGER-MSG'">
         <xsl:call-template name="cibtr:MapMsg">
           <xsl:with-param name="Context"
                                 select="concat(../@id,
                                                ' (rsc=', $EnclosingTag/@id,
                                                ')')"/>
           <xsl:with-param name="Replacement" select="$Replacement"/>
         </xsl:call-template>
       </xsl:if>
       <xsl:choose>
         <!-- use inner simulation to find out if success,
              then emit also extra denormalized space -->
         <xsl:when test="$InverseMode
                         and
                         $Replacement/@where = 'meta_attributes'
                         and
                         not(
                           $EnclosingTag/meta_attributes[
                             not(rule)
                             and
                             nvpair/@name = $Replacement/@with
                           ]
                         )">
           <!-- do not override; do not collide with:
                - existing (see last condition above)
                - successors sourced like this (see below) -->
           <xsl:variable name="SimulateFollowingSiblings">
             <xsl:for-each select="../following-sibling::op">
               <xsl:call-template name="cibtr:ProcessAttrOpMetaAttributes">
                 <xsl:with-param name="Source" select="."/>
                 <xsl:with-param name="InverseMode" select="true()"/>
                 <xsl:with-param name="InnerSimulation" select="true()"/>
               </xsl:call-template>
             </xsl:for-each>
           </xsl:variable>
           <xsl:if test="not(contains($SimulateFollowingSiblings,
                                      concat(name(), ' ')))">
             <!-- fix concurrent op/@* sources (these themselves are winning
                  over sources from meta_attributes -->
             <xsl:choose>
               <xsl:when test="$InnerSimulation">
                 <!-- cf. trick C. (indicate for inverse mode) -->
                 <xsl:value-of select="concat(name(), ' ')"/>
               </xsl:when>
               <xsl:otherwise>
                 <xsl:attribute name="id">
                   <xsl:value-of select="concat('_2TO3_', ../@id, '-meta-',
                                                $Replacement/@with)"/>
                 </xsl:attribute>
                 <xsl:attribute name="name">
                   <xsl:value-of select="$Replacement/@with"/>
                 </xsl:attribute>
                 <xsl:attribute name="value">
                   <xsl:value-of select="."/>
                 </xsl:attribute>
               </xsl:otherwise>
             </xsl:choose>
           </xsl:if>
         </xsl:when>
         <xsl:when test="$InverseMode"/>
         <xsl:when test="$Replacement
                         and
                         (
                           not(string($Replacement/@with))
                           or
                           $Replacement/@where
                         )">
           <!-- drop (possibly just move over) -->
         </xsl:when>
         <xsl:when test="$Replacement">
           <xsl:message terminate="yes">
             <xsl:value-of select="concat('INTERNAL ERROR: ',
                                          $Replacement/../@msg-prefix,
                                          ': no in-situ rename',
                                          ' does not hold')"/>
           </xsl:message>
         </xsl:when>
         <xsl:otherwise>
           <xsl:copy/>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:for-each>
     <!-- E: special-casing @* -->
 
     <xsl:if test="not($InverseMode)">
       <!-- Look ahead if there are any meta-like instance_attibutes to
            be propagated next door, into existing/new meta_attributes -->
       <xsl:variable name="ProcessedInverseNonruleOpInstanceAttributes">
         <xsl:for-each select="instance_attributes[not(rule)]">
           <xsl:call-template name="cibtr:ProcessOpInstanceAttributes">
             <xsl:with-param name="Source" select="."/>
             <xsl:with-param name="InnerSimulation" select="true()"/>
             <xsl:with-param name="InverseMode" select="true()"/>
             <xsl:with-param name="InnerPass"
                             select="substring-after(
                                       concat(
                                         string($InnerSimulation),
                                         'TRIGGER-MSG'
                                       ),
                                      'true'
                                     )"/>
           </xsl:call-template>
         </xsl:for-each>
       </xsl:variable>
       <!-- B: special-casing instance_attributes|meta_attributes -->
       <xsl:for-each select="$Source/node()">
         <xsl:choose>
           <xsl:when test="self::text()">
             <!-- cf. trick A. (consideration 1.) -->
             <xsl:choose>
               <xsl:when test="normalize-space($InnerPass)
                               != $InnerPass
                               and
                               (
                                 not(following-sibling::nvpair)
                                 or
                                 generate-id(following-sibling::nvpair[1])
                                 != generate-id(following-sibling::*[1])
                               )">
                 <xsl:value-of select="."/>
               </xsl:when>
               <xsl:otherwise>
                 <xsl:value-of select="normalize-space(.)"/>
               </xsl:otherwise>
             </xsl:choose>
           </xsl:when>
           <xsl:when test="self::instance_attributes">
             <xsl:variable name="ProcessedOpInstanceAttributes">
               <xsl:call-template name="cibtr:ProcessOpInstanceAttributes">
                 <xsl:with-param name="Source" select="."/>
                 <xsl:with-param name="InnerSimulation" select="true()"/>
               </xsl:call-template>
             </xsl:variable>
             <!-- cf. trick A. -->
             <xsl:if test="normalize-space($ProcessedOpInstanceAttributes)
                           != $ProcessedOpInstanceAttributes">
               <xsl:copy>
                 <xsl:apply-templates select="@*"
                                      mode="cibtr:main"/>
                 <xsl:call-template name="cibtr:ProcessOpInstanceAttributes">
                   <xsl:with-param name="Source" select="."/>
                   <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
                   <!-- cf. trick E. -->
                   <xsl:with-param name="InnerPass" select="$ProcessedOpInstanceAttributes"/>
                 </xsl:call-template>
               </xsl:copy>
             </xsl:if>
           </xsl:when>
           <xsl:when test="self::meta_attributes">
             <xsl:variable name="ProcessedOpMetaAttributes">
               <xsl:call-template name="cibtr:ProcessNonattrOpMetaAttributes">
                 <xsl:with-param name="Source" select="."/>
                 <xsl:with-param name="InnerSimulation" select="true()"/>
                 <xsl:with-param name="InnerPass"
                                 select="substring-after(
                                           concat(
                                             string($InnerSimulation),
                                             'TRIGGER-MSG'
                                           ),
                                          'true'
                                         )"/>
               </xsl:call-template>
             </xsl:variable>
             <!-- cf. trick A.;
                  possibly piggy-back instance_attributes (if any per
                  above look ahead) to first suitable (not rules-driven)
                  meta_attributes set... -->
             <xsl:if test="normalize-space($ProcessedOpMetaAttributes)
                           != $ProcessedOpMetaAttributes
                           or
                           (
                             not(rule)
                             and
                             not(preceding-sibling::meta_attributes[not(rule)])
                             and
                             normalize-space($ProcessedInverseNonruleOpInstanceAttributes)
                             != $ProcessedInverseNonruleOpInstanceAttributes
                           )">
               <xsl:copy>
                 <xsl:apply-templates select="@*"
                                      mode="cibtr:main"/>
                 <xsl:if test="normalize-space($ProcessedOpMetaAttributes)
                               != $ProcessedOpMetaAttributes">
                   <xsl:call-template name="cibtr:ProcessNonattrOpMetaAttributes">
                     <xsl:with-param name="Source" select="."/>
                     <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
                     <!-- cf. trick E. -->
                     <xsl:with-param name="InnerPass" select="$ProcessedOpMetaAttributes"/>
                   </xsl:call-template>
                 </xsl:if>
                 <xsl:if test="not(rule)
                               and
                               not(preceding-sibling::meta_attributes[not(rule)])
                               and
                               normalize-space($ProcessedInverseNonruleOpInstanceAttributes)
                               != $ProcessedInverseNonruleOpInstanceAttributes">
                   <xsl:for-each select="../instance_attributes[not(rule)]">
                     <xsl:call-template name="cibtr:ProcessOpInstanceAttributes">
                       <xsl:with-param name="Source" select="."/>
                       <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
                       <xsl:with-param name="InverseMode" select="true()"/>
                     </xsl:call-template>
                   </xsl:for-each>
                 </xsl:if>
               </xsl:copy>
             </xsl:if>
           </xsl:when>
           <xsl:otherwise>
             <xsl:call-template name="cibtr:HelperIdentity"/>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:for-each>
       <!-- E: special-casing instance_attributes|meta_attributes -->
 
       <!-- ...or roll out brand new meta_attributes, first collectively
            for no-rules instances... -->
       <xsl:if test="not(meta_attributes[not(rule)])
                     and
                     normalize-space($ProcessedInverseNonruleOpInstanceAttributes)
                     != $ProcessedInverseNonruleOpInstanceAttributes">
         <meta_attributes id="{concat('_2TO3_', @id, '-meta')}">
           <xsl:for-each select="instance_attributes[not(rule)]">
             <xsl:call-template name="cibtr:ProcessOpInstanceAttributes">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
               <xsl:with-param name="InverseMode" select="true()"/>
             </xsl:call-template>
           </xsl:for-each>
           <xsl:apply-templates select="text()[position() = last()]"
                                mode="cibtr:main"/>
         </meta_attributes>
         <xsl:apply-templates select="text()[position() = last()]"
                              mode="cibtr:main"/>
       </xsl:if>
 
       <!-- ...then individually for rules-driven ones -->
       <xsl:for-each select="instance_attributes[rule]">
         <xsl:variable name="ProcessedInverseRuleOpInstanceAttributes">
           <xsl:call-template name="cibtr:ProcessOpInstanceAttributes">
             <xsl:with-param name="Source" select="."/>
             <xsl:with-param name="InnerSimulation" select="true()"/>
             <xsl:with-param name="InverseMode" select="true()"/>
             <xsl:with-param name="InnerPass"
                             select="substring-after(
                                       concat(
                                         string($InnerSimulation),
                                         'TRIGGER-MSG'
                                       ),
                                      'true'
                                     )"/>
           </xsl:call-template>
         </xsl:variable>
         <!-- cf. trick A. -->
         <xsl:if test="normalize-space($ProcessedInverseRuleOpInstanceAttributes)
                       != $ProcessedInverseRuleOpInstanceAttributes">
           <meta_attributes>
             <xsl:apply-templates select="@*[
                                            name() != 'id'
                                          ]"
                                  mode="cibtr:main"/>
             <xsl:attribute name='id'>
               <xsl:value-of select="concat('_2TO3_', @id)"/>
             </xsl:attribute>
             <xsl:apply-templates select="node()[
                                            name() != 'nvpair'
                                          ]"
                                  mode="cibtr:main"/>
             <xsl:call-template name="cibtr:ProcessOpInstanceAttributes">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InverseMode" select="true()"/>
               <!-- cf. trick E. -->
               <xsl:with-param name="InnerPass" select="$ProcessedInverseRuleOpInstanceAttributes"/>
             </xsl:call-template>
             <xsl:apply-templates select="text()[position() = last()]"
                                  mode="cibtr:main"/>
           </meta_attributes>
         </xsl:if>
       </xsl:for-each>
     </xsl:if>
     </xsl:element>
   </xsl:if>
 </xsl:template>
 
 <!--
  Source ctxt:    configuration
  Target ctxt:    {op,rsc}_defaults/meta_attributes [per $Variant, see below]
  Target-inv ctxt:N/A
  Dependencies:   ProcessClusterProperties
 
  Variant:        'op_defaults' | 'rsc_defaults'
  -->
 <xsl:template name="cibtr:ProcessDefaultsNonruleClusterProperties">
   <xsl:param name="Source"/>
   <xsl:param name="Variant"/>
   <xsl:param name="InnerSimulation" select="false()"/>
   <xsl:param name="InnerPass">
     <xsl:choose>
       <xsl:when test="$InnerSimulation">
         <xsl:value-of select="''"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:ProcessDefaultsNonruleClusterProperties">
           <xsl:with-param name="Source" select="$Source"/>
           <xsl:with-param name="Variant" select="$Variant"/>
           <xsl:with-param name="InnerSimulation" select="true()"/>
         </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:param>
 
   <xsl:choose>
     <xsl:when test="$Source/*[name() = $Variant]/meta_attributes[
-                      not(@id-ref)
-                      and
                       not(rule)
                     ]">
       <xsl:call-template name="cibtr:ProcessClusterProperties">
         <xsl:with-param name="Source"
                         select="$Source/crm_config/cluster_property_set[
-                                  not(@id-ref)
-                                  and
                                   not(rule)
                                 ]"/>
         <xsl:with-param name="InverseMode"
                         select="$Source/*[name() = $Variant]/meta_attributes[
-                                  not(@id-ref)
-                                  and
                                   not(rule)
                                 ]"/>
         <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise>
       <xsl:call-template name="cibtr:ProcessClusterProperties">
         <xsl:with-param name="Source"
                       select="$Source/crm_config/cluster_property_set[
-                                  not(@id-ref)
-                                  and
                                   not(rule)
                                 ]"/>
         <xsl:with-param name="InverseMode"
                         select="$Variant"/>
         <xsl:with-param name="InnerSimulation" select="$InnerSimulation"/>
       </xsl:call-template>
     </xsl:otherwise>
   </xsl:choose>
 </xsl:template>
 
 <!--
  Source ctxt:    configuration
  Target ctxt:    {op,rsc}_defaults/meta_attributes [per $Variant, see below]
  Target-inv ctxt:N/A
  Dependencies:   ProcessClusterProperties
 
  Variant:        'op_defaults' | 'rsc_defaults'
  -->
 <xsl:template name="cibtr:ProcessDefaultsRuleClusterProperties">
   <xsl:param name="Source"/>
   <xsl:param name="Variant"/>
   <xsl:param name="InnerSimulation" select="false()"/>
   <xsl:param name="InnerPass">
     <xsl:choose>
       <xsl:when test="$InnerSimulation">
         <xsl:value-of select="''"/>
       </xsl:when>
       <xsl:otherwise>
         <xsl:call-template name="cibtr:ProcessDefaultsRuleClusterProperties">
           <xsl:with-param name="Source" select="$Source"/>
           <xsl:with-param name="Variant" select="$Variant"/>
           <xsl:with-param name="InnerSimulation" select="true()"/>
         </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:param>
 
   <xsl:for-each select="crm_config/cluster_property_set[
-                          not(@id-ref)
-                          and
                           rule
                         ]">
     <xsl:variable name="ProcessedPartial">
       <xsl:call-template name="cibtr:ProcessClusterProperties">
         <xsl:with-param name="Source" select="$Source"/>
         <xsl:with-param name="InverseMode" select="$Variant"/>
         <xsl:with-param name="InnerSimulation" select="true()"/>
         <xsl:with-param name="InnerPass" select="'TRIGGER-MSG'"/>
       </xsl:call-template>
     </xsl:variable>
     <xsl:if test="normalize-space($ProcessedPartial)
                   != $ProcessedPartial">
       <meta_attributes id="{concat('_2TO3_', @id)}">
         <xsl-copy-of select="rule"/>
         <xsl:call-template name="cibtr:ProcessClusterProperties">
           <xsl:with-param name="Source" select="$Source"/>
           <xsl:with-param name="InverseMode" select="$Variant"/>
         </xsl:call-template>
       </meta_attributes>
     </xsl:if>
   </xsl:for-each>
 </xsl:template>
 
 <!--
 
  ACTUAL TRANSFORMATION
 
  -->
 
 <xsl:template match="cib" mode="cibtr:main">
   <xsl:copy>
     <xsl:apply-templates select="@*"
                          mode="cibtr:main"/>
     <xsl:attribute name="validate-with">
       <xsl:value-of select="concat('pacemaker-', $cibtr:cib-min-ver)"/>
     </xsl:attribute>
     <xsl:apply-templates select="node()"
                          mode="cibtr:main"/>
   </xsl:copy>
 </xsl:template>
 
 <xsl:template match="cluster_property_set" mode="cibtr:main">
   <xsl:variable name="ProcessedClusterProperties">
     <xsl:call-template name="cibtr:ProcessClusterProperties">
       <xsl:with-param name="Source" select="."/>
       <xsl:with-param name="InnerSimulation" select="true()"/>
       <xsl:with-param name="InnerPass" select="'TRIGGER-MSG'"/>
     </xsl:call-template>
   </xsl:variable>
   <xsl:if test="normalize-space($ProcessedClusterProperties)
                 != $ProcessedClusterProperties">
     <xsl:copy>
       <xsl:apply-templates select="@*"
                            mode="cibtr:main"/>
       <xsl:call-template name="cibtr:ProcessClusterProperties">
         <xsl:with-param name="Source" select="."/>
         <!-- cf. trick E. -->
         <xsl:with-param name="InnerPass" select="$ProcessedClusterProperties"/>
       </xsl:call-template>
     </xsl:copy>
   </xsl:if>
 </xsl:template>
 
 <xsl:template match="rsc_colocation" mode="cibtr:main">
   <xsl:copy>
     <xsl:for-each select="@*">
       <xsl:variable name="Replacement"
                     select="$cibtr:MapConstraintsColocation/cibtr:replace[
                               @what = name(current())
                             ]"/>
       <xsl:call-template name="cibtr:MapMsg">
         <xsl:with-param name="Context" select="../@id"/>
         <xsl:with-param name="Replacement" select="$Replacement"/>
       </xsl:call-template>
       <xsl:choose>
         <xsl:when test="$Replacement
                         and
                         not(string($Replacement/@with))">
           <!-- drop -->
         </xsl:when>
         <xsl:when test="$Replacement">
           <!-- rename -->
           <xsl:attribute name="{name()}">
             <xsl:value-of select="$Replacement/@with"/>
           </xsl:attribute>
         </xsl:when>
         <xsl:otherwise>
           <xsl:copy/>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:for-each>
     <xsl:apply-templates select="node()"
                          mode="cibtr:main"/>
   </xsl:copy>
 </xsl:template>
 
 <xsl:template match="node" mode="cibtr:main">
   <xsl:copy>
     <xsl:for-each select="@*">
       <xsl:variable name="Replacement"
                     select="$cibtr:MapClusterNode/cibtr:replace[
                               @what = name(current())
                               and
                               (
                                 (
                                   @in-case-of
                                   and
                                   contains(concat('|', @in-case-of, '|'),
                                            concat('|', current(), '|'))
                                 )
                                 or
                                 (
                                   not(@in-case-of)
                                   and
                                   not(
                                     $cibtr:MapClusterNode/cibtr:replace[
                                       @what = name(current())
                                       and
                                       @in-case-of
                                       and
                                       contains(concat('|', @in-case-of, '|'),
                                                concat('|', current(), '|'))
                                     ]
                                   )
                                 )
                               )
                             ]"/>
       <xsl:call-template name="cibtr:MapMsg">
         <xsl:with-param name="Context" select="concat(../@uname, ' (id=', ../@id, ')')"/>
         <xsl:with-param name="Replacement" select="$Replacement"/>
       </xsl:call-template>
       <xsl:choose>
         <xsl:when test="$Replacement
                         and
                         not(string($Replacement/@with))">
           <!-- drop -->
         </xsl:when>
         <xsl:when test="$Replacement">
           <!-- rename -->
           <xsl:attribute name="{$Replacement/@with}">
             <xsl:choose>
               <xsl:when test="$Replacement/@redefined-as">
                 <xsl:value-of select="$Replacement/@redefined-as"/>
               </xsl:when>
               <xsl:otherwise>
                 <xsl:value-of select="."/>
               </xsl:otherwise>
             </xsl:choose>
           </xsl:attribute>
         </xsl:when>
         <xsl:otherwise>
           <xsl:copy/>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:for-each>
     <xsl:apply-templates select="node()"
                          mode="cibtr:main"/>
   </xsl:copy>
 </xsl:template>
 
 <!--
  1a. propagate (primitive|template)/operations/
        op[name() = 'start' or name() = 'promote']/@requires
      under new ./meta_attributes/nvpair
 
  1b. "move" (primitive|template)/operations/
        op[name() = 'start' or name() = 'promote']/
        meta_attributes/nvpair[@requires]
      under ./meta_attributes
 
   otherwise, just
 
  2a.  drop (primitive|template)/operations/
         op/@requires
 
  2b.  drop (primitive|template)/operations/
         op/meta_attributes/nvpair[@requires]
-
- Not compatible with meta_attributes referenced via id-ref
- (would need external preprocessing).
  -->
 <xsl:template match="primitive|template" mode="cibtr:main">
   <xsl:copy>
     <xsl:apply-templates select="@*"
                          mode="cibtr:main"/>
     <!-- B: special-casing operations|instance_attributes|meta_attributes -->
     <xsl:for-each select="node()">
       <xsl:choose>
         <xsl:when test="self::operations">
           <xsl:copy>
             <xsl:apply-templates select="@*"
                                  mode="cibtr:main"/>
             <!-- B: special-casing op -->
             <xsl:for-each select="node()">
               <xsl:choose>
                 <xsl:when test="self::op">
                   <!-- process @*|meta_attributes/nvpair
                        (keep/drop/move elsewhere) -->
                   <xsl:call-template name="cibtr:ProcessAttrOpMetaAttributes">
                     <xsl:with-param name="Source" select="."/>
                   </xsl:call-template>
                 </xsl:when>
                 <xsl:otherwise>
                   <xsl:call-template name="cibtr:HelperIdentity"/>
                 </xsl:otherwise>
               </xsl:choose>
             </xsl:for-each>
             <!-- E: special-casing op -->
           </xsl:copy>
         </xsl:when>
         <xsl:when test="self::instance_attributes">
           <xsl:variable name="ProcessedRscInstanceAttributes">
             <xsl:call-template name="cibtr:ProcessRscInstanceAttributes">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InnerSimulation" select="true()"/>
               <xsl:with-param name="InnerPass" select="'TRIGGER-MSG'"/>
             </xsl:call-template>
           </xsl:variable>
           <!-- cf. trick A. -->
           <xsl:if test="normalize-space($ProcessedRscInstanceAttributes)
                         != $ProcessedRscInstanceAttributes">
             <xsl:copy>
               <xsl:apply-templates select="@*"
                                    mode="cibtr:main"/>
               <xsl:call-template name="cibtr:ProcessRscInstanceAttributes">
                 <xsl:with-param name="Source" select="."/>
                 <!-- cf. trick E. -->
                 <xsl:with-param name="InnerPass" select="$ProcessedRscInstanceAttributes"/>
               </xsl:call-template>
             </xsl:copy>
           </xsl:if>
         </xsl:when>
         <xsl:when test="self::meta_attributes">
           <xsl:variable name="ProcessedRscMetaAttributes">
             <xsl:call-template name="cibtr:ProcessRscMetaAttributes">
               <xsl:with-param name="Source" select="."/>
               <xsl:with-param name="InnerSimulation" select="true()"/>
               <xsl:with-param name="InnerPass" select="'TRIGGER-MSG'"/>
             </xsl:call-template>
           </xsl:variable>
           <!-- cf. trick A. -->
           <xsl:if test="normalize-space($ProcessedRscMetaAttributes)
                         != $ProcessedRscMetaAttributes">
             <xsl:copy>
               <xsl:apply-templates select="@*"
                                    mode="cibtr:main"/>
               <xsl:call-template name="cibtr:ProcessRscMetaAttributes">
                 <xsl:with-param name="Source" select="."/>
                 <!-- cf. trick E. -->
                 <xsl:with-param name="InnerPass" select="$ProcessedRscMetaAttributes"/>
               </xsl:call-template>
             </xsl:copy>
           </xsl:if>
         </xsl:when>
         <xsl:otherwise>
           <xsl:call-template name="cibtr:HelperIdentity"/>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:for-each>
     <!-- E: special-casing operations|instance_attributes|meta_attributes -->
 
     <!-- add as last meta_attributes block... -->
 
     <!-- ...indirectly from op attributes -->
     <xsl:variable name="ToPropagateFromOp">
       <xsl:for-each select="operations/op">
         <xsl:call-template name="cibtr:ProcessAttrOpMetaAttributes">
           <xsl:with-param name="Source" select="."/>
           <xsl:with-param name="InverseMode" select="true()"/>
           <xsl:with-param name="InnerSimulation" select="true()"/>
           <xsl:with-param name="InnerPass" select="'TRIGGER-MSG'"/>
         </xsl:call-template>
       </xsl:for-each>
     </xsl:variable>
     <!-- cf. trick A. -->
     <xsl:if test="normalize-space($ToPropagateFromOp)
                   != $ToPropagateFromOp">
       <meta_attributes id="{concat('_2TO3_', @id, '-meta')}">
         <xsl:for-each select="operations/op">
           <xsl:call-template name="cibtr:ProcessAttrOpMetaAttributes">
             <xsl:with-param name="Source" select="."/>
             <xsl:with-param name="InverseMode" select="true()"/>
           </xsl:call-template>
         </xsl:for-each>
         <xsl:apply-templates select="text()[position() = last()]"
                              mode="cibtr:main"/>
       </meta_attributes>
       <xsl:apply-templates select="text()[position() = last()]"
                            mode="cibtr:main"/>
     </xsl:if>
 
     <!-- ...directly by picking existing nvpairs of
          meta_attributes|instance_attributes -->
     <xsl:for-each select="operations/op/meta_attributes
                           |operations/op/instance_attributes">
       <xsl:variable name="ProcessedOpMetaAttributes">
         <xsl:call-template name="cibtr:ProcessNonattrOpMetaAttributes">
           <xsl:with-param name="Source" select="."/>
           <xsl:with-param name="InverseMode" select="true()"/>
           <xsl:with-param name="InnerSimulation" select="true()"/>
         </xsl:call-template>
       </xsl:variable>
       <!-- cf. trick A. -->
       <xsl:if test="normalize-space($ProcessedOpMetaAttributes)
                     != $ProcessedOpMetaAttributes">
         <!-- cannot xsl:copy, need to settle on meta_attributes -->
         <meta_attributes>
           <xsl:apply-templates select="@*[
                                          name() != 'id'
                                        ]"
                                mode="cibtr:main"/>
           <xsl:attribute name='id'>
             <xsl:value-of select="concat('_2TO3_', @id)"/>
           </xsl:attribute>
           <xsl:apply-templates select="node()[
                                          name() != 'nvpair'
                                        ]"
                                mode="cibtr:main"/>
           <xsl:call-template name="cibtr:ProcessNonattrOpMetaAttributes">
             <xsl:with-param name="Source" select="."/>
             <xsl:with-param name="InverseMode" select="true()"/>
             <!-- cf. trick E. -->
             <xsl:with-param name="InnerPass" select="$ProcessedOpMetaAttributes"/>
           </xsl:call-template>
           <xsl:apply-templates select="text()[position() = last()]"
                                mode="cibtr:main"/>
         </meta_attributes>
         <xsl:apply-templates select="text()[position() = last()]"
                              mode="cibtr:main"/>
       </xsl:if>
     </xsl:for-each>
   </xsl:copy>
 </xsl:template>
 
 <xsl:template match="configuration" mode="cibtr:main">
   <xsl:variable name="Configuration" select="."/>
   <xsl:variable name="ProcessedOpDefaultsNonruleClusterProperties">
     <xsl:call-template name="cibtr:ProcessDefaultsNonruleClusterProperties">
       <xsl:with-param name="Source" select="$Configuration"/>
       <xsl:with-param name="Variant" select="'op_defaults'"/>
       <xsl:with-param name="InnerSimulation" select="true()"/>
     </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="ProcessedRscDefaultsNonruleClusterProperties">
     <xsl:call-template name="cibtr:ProcessDefaultsNonruleClusterProperties">
       <xsl:with-param name="Source" select="$Configuration"/>
       <xsl:with-param name="Variant" select="'rsc_defaults'"/>
       <xsl:with-param name="InnerSimulation" select="true()"/>
     </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="ProcessedOpDefaultsRuleClusterProperties">
     <xsl:call-template name="cibtr:ProcessDefaultsNonruleClusterProperties">
       <xsl:with-param name="Source" select="$Configuration"/>
       <xsl:with-param name="Variant" select="'op_defaults'"/>
       <xsl:with-param name="InnerSimulation" select="true()"/>
     </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="ProcessedRscDefaultsRuleClusterProperties">
     <xsl:call-template name="cibtr:ProcessDefaultsNonruleClusterProperties">
       <xsl:with-param name="Source" select="$Configuration"/>
       <xsl:with-param name="Variant" select="'rsc_defaults'"/>
       <xsl:with-param name="InnerSimulation" select="true()"/>
     </xsl:call-template>
   </xsl:variable>
 
   <xsl:copy>
     <xsl:apply-templates select="@*"
                          mode="cibtr:main"/>
     <!-- B: special-casing {op,rsc}_defaults -->
     <xsl:for-each select="node()">
       <xsl:choose>
         <xsl:when test="self::op_defaults|self::rsc_defaults">
           <xsl:variable name="WhichDefaults" select="name()"/>
           <xsl:copy>
             <xsl:apply-templates select="@*"
                                  mode="cibtr:main"/>
             <!-- B: special-casing meta_attributes -->
             <xsl:for-each select="node()">
               <xsl:copy>
                 <xsl:choose>
                   <xsl:when test="self::meta_attributes[
-                                    not(@id-ref)
-                                    and
                                     not(rule)
                                     and
                                     not(
                                       preceding-sibling::meta_attributes[
-                                        not(@id-ref)
-                                        and
                                         not(rule)
                                       ]
                                     )
                                   ]">
                   <xsl:apply-templates select="@*|node()"
                                        mode="cibtr:main"/>
                     <xsl:if test="$WhichDefaults = 'op_defaults'
                                   or
                                   $WhichDefaults = 'rsc_defaults'">
                       <xsl:call-template name="cibtr:ProcessDefaultsNonruleClusterProperties">
                         <xsl:with-param name="Source" select="$Configuration"/>
                         <xsl:with-param name="Variant" select="$WhichDefaults"/>
                       </xsl:call-template>
                     </xsl:if>
                   </xsl:when>
                   <xsl:otherwise>
                     <xsl:apply-templates select="@*|node()"
                                          mode="cibtr:main"/>
                   </xsl:otherwise>
                 </xsl:choose>
                 <xsl:if test="(
                                 $WhichDefaults = 'op_defaults'
                                 and
                                 normalize-space($ProcessedOpDefaultsRuleClusterProperties)
                                 != $ProcessedOpDefaultsRuleClusterProperties
                               )
                               or
                               (
                                 $WhichDefaults = 'rsc_defaults'
                                 and
                                 normalize-space($ProcessedRscDefaultsRuleClusterProperties)
                                 != $ProcessedRscDefaultsRuleClusterProperties
                               )">
                   <xsl:call-template name="cibtr:ProcessDefaultsRuleClusterProperties">
                     <xsl:with-param name="Source" select="$Configuration"/>
                     <xsl:with-param name="Variant" select="$WhichDefaults"/>
                   </xsl:call-template>
                 </xsl:if>
               </xsl:copy>
             </xsl:for-each>
             <!-- E: special-casing meta_attributes -->
           </xsl:copy>
         </xsl:when>
         <xsl:otherwise>
           <xsl:call-template name="cibtr:HelperIdentity"/>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:for-each>
     <!-- E: special-casing {op,rsc}_defaults -->
     <xsl:if test="not(op_defaults)
                   and
                   (
                     normalize-space($ProcessedOpDefaultsNonruleClusterProperties)
                     != $ProcessedOpDefaultsNonruleClusterProperties
                     or
                     normalize-space($ProcessedOpDefaultsRuleClusterProperties)
                     != $ProcessedOpDefaultsRuleClusterProperties
                   )">
       <op_defaults>
         <xsl:if test="normalize-space($ProcessedOpDefaultsNonruleClusterProperties)
                       != $ProcessedOpDefaultsNonruleClusterProperties">
           <meta_attributes id="{concat('_2TO3_', '-op-defaults')}">
             <xsl:call-template name="cibtr:ProcessDefaultsNonruleClusterProperties">
               <xsl:with-param name="Source" select="$Configuration"/>
               <xsl:with-param name="Variant" select="'op_defaults'"/>
             </xsl:call-template>
           </meta_attributes>
         </xsl:if>
         <xsl:call-template name="cibtr:ProcessDefaultsRuleClusterProperties">
           <xsl:with-param name="Source" select="$Configuration"/>
           <xsl:with-param name="Variant" select="'op_defaults'"/>
         </xsl:call-template>
         <xsl:apply-templates select="text()[position() = last()]"
                              mode="cibtr:main"/>
       </op_defaults>
     </xsl:if>
     <xsl:if test="not(rsc_defaults)
                   and
                   (
                     normalize-space($ProcessedRscDefaultsNonruleClusterProperties)
                     != $ProcessedRscDefaultsNonruleClusterProperties
                     or
                     normalize-space($ProcessedRscDefaultsRuleClusterProperties)
                     != $ProcessedRscDefaultsRuleClusterProperties
                   )">
       <rsc_defaults>
         <xsl:if test="normalize-space($ProcessedRscDefaultsNonruleClusterProperties)
                       != $ProcessedRscDefaultsNonruleClusterProperties">
           <meta_attributes id="{concat('_2TO3_', '-rsc-defaults')}">
             <xsl:call-template name="cibtr:ProcessDefaultsNonruleClusterProperties">
               <xsl:with-param name="Source" select="$Configuration"/>
               <xsl:with-param name="Variant" select="'rsc_defaults'"/>
             </xsl:call-template>
           </meta_attributes>
         </xsl:if>
         <xsl:call-template name="cibtr:ProcessDefaultsRuleClusterProperties">
           <xsl:with-param name="Source" select="$Configuration"/>
           <xsl:with-param name="Variant" select="'rsc_defaults'"/>
         </xsl:call-template>
         <xsl:apply-templates select="text()[position() = last()]"
                              mode="cibtr:main"/>
       </rsc_defaults>
     </xsl:if>
   </xsl:copy>
 </xsl:template>
 
 <!-- used in test files to allow in-browser on-the-fly upgrade reports -->
 <xsl:template match="processing-instruction()[
                        name() = 'xml-stylesheet'
                        and
                        count(..|/) = 1
                      ]"
               mode="cibtr:main"/>
 
 <xsl:template match="@*|node()" mode="cibtr:main">
   <xsl:call-template name="cibtr:HelperIdentity"/>
 </xsl:template>
 
 <!-- mode-less, easy to override kick-off -->
 <xsl:template match="/">
   <xsl:call-template name="cibtr:HelperIdentity"/>
 </xsl:template>
 
 </xsl:stylesheet>