diff --git a/include/crm/cib/cib_types.h b/include/crm/cib/cib_types.h
index dad3c8f45d..8662dac56a 100644
--- a/include/crm/cib/cib_types.h
+++ b/include/crm/cib/cib_types.h
@@ -1,359 +1,364 @@
 /*
  * Copyright 2004-2023 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #ifndef PCMK__CRM_CIB_CIB_TYPES__H
 #  define PCMK__CRM_CIB_CIB_TYPES__H
 
 #  include <glib.h>             // gboolean, GList
 #  include <libxml/tree.h>      // xmlNode
 #  include <crm/common/ipc.h>
 #  include <crm/common/xml.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
  * \file
  * \brief Data types for Cluster Information Base access
  * \ingroup cib
  */
 
 enum cib_variant {
     cib_undefined = 0,
     cib_native    = 1,
     cib_file      = 2,
     cib_remote    = 3,
 
 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
     //! \deprecated This value will be removed in a future release
     cib_database  = 4,
 #endif // !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
 };
 
 enum cib_state {
     cib_connected_command,
     cib_connected_query,
     cib_disconnected
 };
 
 enum cib_conn_type {
     cib_command,
     cib_query,
     cib_no_connection,
     cib_command_nonblocking,
 };
 
 enum cib_call_options {
     cib_none            = 0,
     cib_verbose         = (1 << 0),  //!< Prefer stderr to logs
     cib_xpath           = (1 << 1),
     cib_multiple        = (1 << 2),
     cib_can_create      = (1 << 3),
     cib_discard_reply   = (1 << 4),
     cib_no_children     = (1 << 5),
     cib_xpath_address   = (1 << 6),
 
     //! \deprecated This value will be removed in a future release
     cib_mixed_update    = (1 << 7),
 
     /* @COMPAT: cib_scope_local is processed only in the legacy function
      * parse_local_options_v1().
      *
      * If (host == NULL):
      * * In legacy mode, the CIB manager forwards a request to the primary
      *   instance unless cib_scope_local is set or the local node is primary.
      * * Outside of legacy mode:
      *   * If a request modifies the CIB, the CIB manager forwards it to all
      *     nodes.
      *   * Otherwise, the CIB manager processes the request locally.
      *
      * There is no current use case for this implementing this flag in
      * non-legacy mode.
      */
 
     //! \deprecated This value will be removed in a future release
     cib_scope_local     = (1 << 8),
 
     cib_dryrun          = (1 << 9),
 
     /*!
      * \brief Process request when the client commits the active transaction
      *
      * Add the request to the client's active transaction instead of processing
      * it immediately. If the client has no active transaction, or if the
      * request is not supported in transactions, the call will fail.
      *
      * The request is added to the transaction synchronously, and the return
      * value indicates whether it was added successfully.
      *
      * Refer to \p cib_api_operations_t:init_transaction() and
      * \p cib_api_operations_t:end_transaction() for more details on CIB
      * transactions.
      */
     cib_transaction     = (1 << 10),
 
     cib_sync_call       = (1 << 12),
     cib_no_mtime        = (1 << 13),
 
 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
     //! \deprecated This value will be removed in a future release
     cib_zero_copy       = (1 << 14),
 #endif // !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
 
     cib_inhibit_notify  = (1 << 16),
 
 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
     //! \deprecated This value will be removed in a future release
     cib_quorum_override = (1 << 20),
 #endif // !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
 
     //! \deprecated This value will be removed in a future release
     cib_inhibit_bcast   = (1 << 24),
 
     cib_force_diff      = (1 << 28),
 };
 
 typedef struct cib_s cib_t;
 
 typedef struct cib_api_operations_s {
     int (*signon) (cib_t *cib, const char *name, enum cib_conn_type type);
 
     //! \deprecated This method will be removed and should not be used
     int (*signon_raw) (cib_t *cib, const char *name, enum cib_conn_type type,
                        int *event_fd);
 
     int (*signoff) (cib_t *cib);
     int (*free) (cib_t *cib);
 
     //! \deprecated This method will be removed and should not be used
     int (*set_op_callback) (cib_t *cib, void (*callback) (const xmlNode *msg,
                                                           int callid, int rc,
                                                           xmlNode *output));
 
     int (*add_notify_callback) (cib_t *cib, const char *event,
                                 void (*callback) (const char *event,
                                                   xmlNode *msg));
     int (*del_notify_callback) (cib_t *cib, const char *event,
                                 void (*callback) (const char *event,
                                                   xmlNode *msg));
     int (*set_connection_dnotify) (cib_t *cib,
                                    void (*dnotify) (gpointer user_data));
 
     //! \deprecated This method will be removed and should not be used
     int (*inputfd) (cib_t *cib);
 
     //! \deprecated This method will be removed and should not be used
     int (*noop) (cib_t *cib, int call_options);
 
     int (*ping) (cib_t *cib, xmlNode **output_data, int call_options);
     int (*query) (cib_t *cib, const char *section, xmlNode **output_data,
                   int call_options);
     int (*query_from) (cib_t *cib, const char *host, const char *section,
                        xmlNode **output_data, int call_options);
 
     //! \deprecated This method will be removed and should not be used
     int (*is_master) (cib_t *cib);
 
     //! \deprecated Use the set_primary() method instead
     int (*set_master) (cib_t *cib, int call_options);
 
     //! \deprecated Use the set_secondary() method instead
     int (*set_slave) (cib_t *cib, int call_options);
 
     //! \deprecated This method will be removed and should not be used
     int (*set_slave_all) (cib_t *cib, int call_options);
 
     int (*sync) (cib_t *cib, const char *section, int call_options);
     int (*sync_from) (cib_t *cib, const char *host, const char *section,
                       int call_options);
     int (*upgrade) (cib_t *cib, int call_options);
     int (*bump_epoch) (cib_t *cib, int call_options);
+
+    /*!
+     * The \c <failed> element in the reply to a failed creation call is
+     * deprecated since 2.1.8.
+     */
     int (*create) (cib_t *cib, const char *section, xmlNode *data,
                    int call_options);
     int (*modify) (cib_t *cib, const char *section, xmlNode *data,
                    int call_options);
 
     //! \deprecated Use the \p modify() method instead
     int (*update) (cib_t *cib, const char *section, xmlNode *data,
                    int call_options);
 
     int (*replace) (cib_t *cib, const char *section, xmlNode *data,
                     int call_options);
     int (*remove) (cib_t *cib, const char *section, xmlNode *data,
                    int call_options);
     int (*erase) (cib_t *cib, xmlNode **output_data, int call_options);
 
     //! \deprecated This method does nothing and should not be called
     int (*delete_absolute) (cib_t *cib, const char *section, xmlNode *data,
                             int call_options);
 
     //! \deprecated This method is not implemented and should not be used
     int (*quit) (cib_t *cib, int call_options);
 
     int (*register_notification) (cib_t *cib, const char *callback,
                                   int enabled);
     gboolean (*register_callback) (cib_t *cib, int call_id, int timeout,
                                    gboolean only_success, void *user_data,
                                    const char *callback_name,
                                    void (*callback) (xmlNode*, int, int,
                                                      xmlNode*, void *));
     gboolean (*register_callback_full)(cib_t *cib, int call_id, int timeout,
                                        gboolean only_success, void *user_data,
                                        const char *callback_name,
                                        void (*callback)(xmlNode *, int, int,
                                                         xmlNode *, void *),
                                        void (*free_func)(void *));
 
     /*!
      * \brief Set the local CIB manager as the cluster's primary instance
      *
      * \param[in,out] cib           CIB connection
      * \param[in]     call_options  Group of enum cib_call_options flags
      *
      * \return Legacy Pacemaker return code (in particular, pcmk_ok on success)
      */
     int (*set_primary)(cib_t *cib, int call_options);
 
     /*!
      * \brief Set the local CIB manager as a secondary instance
      *
      * \param[in,out] cib           CIB connection
      * \param[in]     call_options  Group of enum cib_call_options flags
      *
      * \return Legacy Pacemaker return code (in particular, pcmk_ok on success)
      */
     int (*set_secondary)(cib_t *cib, int call_options);
 
     /*!
      * \brief Get the given CIB connection's unique client identifier(s)
      *
      * These can be used to check whether this client requested the action that
      * triggered a CIB notification.
      *
      * \param[in]  cib       CIB connection
      * \param[out] async_id  If not \p NULL, where to store asynchronous client
      *                       ID
      * \param[out] sync_id   If not \p NULL, where to store synchronous client
      *                       ID
      *
      * \return Legacy Pacemaker return code
      *
      * \note Some variants may have only one client for both asynchronous and
      *       synchronous requests.
      */
     int (*client_id)(const cib_t *cib, const char **async_id,
                      const char **sync_id);
 
     /*!
      * \brief Initiate an atomic CIB transaction for this client
      *
      * If the client has initiated a transaction and a new request's call
      * options contain \p cib_transaction, the new request is appended to the
      * transaction for later processing.
      *
      * Supported requests are those that meet the following conditions:
      * * can be processed synchronously (with any changes applied to a working
      *   CIB copy)
      * * are not queries
      * * do not involve other nodes
      * * do not affect the state of pacemaker-based itself
      *
      * Currently supported CIB API functions include:
      * * \p bump_epoch()
      * * \p create()
      * * \p erase()
      * * \p modify()
      * * \p remove()
      * * \p replace()
      * * \p upgrade()
      *
      * Because the transaction is atomic, individual requests do not trigger
      * callbacks or notifications when they are processed, and they do not
      * receive output XML. The commit request itself can trigger callbacks and
      * notifications if any are registered.
      *
      * An \c init_transaction() call is always synchronous.
      *
      * \param[in,out] cib           CIB connection
      *
      * \return Legacy Pacemaker return code
      */
     int (*init_transaction)(cib_t *cib);
 
     /*!
      * \brief End and optionally commit this client's CIB transaction
      *
      * When a client commits a transaction, all requests in the transaction are
      * processed in a FIFO manner until either a request fails or all requests
      * have been processed. Changes are applied to a working copy of the CIB.
      * If a request fails, the transaction and working CIB copy are discarded,
      * and an error is returned. If all requests succeed, the working CIB copy
      * replaces the initial CIB copy.
      *
      * Callbacks and notifications can be triggered by the commit request itself
      * but not by the individual requests in a transaction.
      *
      * An \c end_transaction() call with \p commit set to \c false is always
      * synchronous.
      *
      * \param[in,out] cib           CIB connection
      * \param[in]     commit        If \p true, commit transaction; otherwise,
      *                              discard it
      * \param[in]     call_options  Group of <tt>enum cib_call_options</tt>
      *                              flags
      *
      * \return Legacy Pacemaker return code
      */
     int (*end_transaction)(cib_t *cib, bool commit, int call_options);
 
     /*!
      * \brief Set the user as whom all CIB requests via methods will be executed
      *
      * By default, the value of the \c CIB_user environment variable is used if
      * set. Otherwise, the current effective user is used.
      *
      * \param[in,out] cib   CIB connection
      * \param[in]     user  Name of user whose permissions to use when
      *                      processing requests
      */
     void (*set_user)(cib_t *cib, const char *user);
 
     int (*fetch_schemas)(cib_t *cib, xmlNode **output_data, const char *after_ver,
                          int call_options);
 } cib_api_operations_t;
 
 struct cib_s {
     enum cib_state state;
     enum cib_conn_type type;
     enum cib_variant variant;
 
     int call_id;
     int call_timeout;
     void *variant_opaque;
     void *delegate_fn;
 
     GList *notify_list;
 
     //! \deprecated This method will be removed in a future release
     void (*op_callback) (const xmlNode *msg, int call_id, int rc,
                          xmlNode *output);
 
     cib_api_operations_t *cmds;
 
     xmlNode *transaction;
 
     char *user;
 };
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif // PCMK__CRM_CIB_CIB_TYPES__H
diff --git a/include/crm/common/xml_names_internal.h b/include/crm/common/xml_names_internal.h
index d8eb2f28d5..8989c0ef33 100644
--- a/include/crm/common/xml_names_internal.h
+++ b/include/crm/common/xml_names_internal.h
@@ -1,349 +1,351 @@
 /*
  * Copyright 2004-2024 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #ifndef PCMK__CRM_COMMON_XML_NAMES_INTERNAL__H
 #  define PCMK__CRM_COMMON_XML_NAMES_INTERNAL__H
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /*
  * XML element names used only by internal code
  */
 
 #define PCMK__XE_ACK                    "ack"
 #define PCMK__XE_ATTRIBUTES             "attributes"
 #define PCMK__XE_CIB_CALLBACK           "cib-callback"
 #define PCMK__XE_CIB_CALLDATA           "cib_calldata"
 #define PCMK__XE_CIB_COMMAND            "cib_command"
 #define PCMK__XE_CIB_REPLY              "cib-reply"
 #define PCMK__XE_CIB_RESULT             "cib_result"
 #define PCMK__XE_CIB_TRANSACTION        "cib_transaction"
 #define PCMK__XE_CIB_UPDATE_RESULT      "cib_update_result"
 #define PCMK__XE_COPY                   "copy"
 #define PCMK__XE_CRM_EVENT              "crm_event"
 #define PCMK__XE_CRM_XML                "crm_xml"
 #define PCMK__XE_DIV                    "div"
 #define PCMK__XE_DOWNED                 "downed"
 #define PCMK__XE_EXIT_NOTIFICATION      "exit-notification"
-#define PCMK__XE_FAILED                 "failed"
 #define PCMK__XE_FAILED_UPDATE          "failed_update"
 #define PCMK__XE_GENERATION_TUPLE       "generation_tuple"
 #define PCMK__XE_LRM                    "lrm"
 #define PCMK__XE_LRM_RESOURCE           "lrm_resource"
 #define PCMK__XE_LRM_RESOURCES          "lrm_resources"
 #define PCMK__XE_LRM_RSC_OP             "lrm_rsc_op"
 #define PCMK__XE_LRMD_ALERT             "lrmd_alert"
 #define PCMK__XE_LRMD_CALLDATA          "lrmd_calldata"
 #define PCMK__XE_LRMD_COMMAND           "lrmd_command"
 #define PCMK__XE_LRMD_IPC_MSG           "lrmd_ipc_msg"
 #define PCMK__XE_LRMD_IPC_PROXY         "lrmd_ipc_proxy"
 #define PCMK__XE_LRMD_NOTIFY            "lrmd_notify"
 #define PCMK__XE_LRMD_REPLY             "lrmd_reply"
 #define PCMK__XE_LRMD_RSC               "lrmd_rsc"
 #define PCMK__XE_LRMD_RSC_OP            "lrmd_rsc_op"
 #define PCMK__XE_MAINTENANCE            "maintenance"
 #define PCMK__XE_META                   "meta"
 #define PCMK__XE_NACK                   "nack"
 #define PCMK__XE_NODE_STATE             "node_state"
 #define PCMK__XE_NOTIFY                 "notify"
 #define PCMK__XE_OPTIONS                "options"
 #define PCMK__XE_PARAM                  "param"
 #define PCMK__XE_PING                   "ping"
 #define PCMK__XE_PING_RESPONSE          "ping_response"
 #define PCMK__XE_PSEUDO_EVENT           "pseudo_event"
 #define PCMK__XE_RSC_OP                 "rsc_op"
 #define PCMK__XE_SHUTDOWN               "shutdown"
 #define PCMK__XE_SPAN                   "span"
 #define PCMK__XE_ST_ASYNC_TIMEOUT_VALUE "st-async-timeout-value"
 #define PCMK__XE_ST_CALLDATA            "st_calldata"
 #define PCMK__XE_ST_DEVICE_ACTION       "st_device_action"
 #define PCMK__XE_ST_DEVICE_ID           "st_device_id"
 #define PCMK__XE_ST_HISTORY             "st_history"
 #define PCMK__XE_ST_NOTIFY_FENCE        "st_notify_fence"
 #define PCMK__XE_ST_REPLY               "st-reply"
 #define PCMK__XE_STONITH_COMMAND        "stonith_command"
 #define PCMK__XE_TICKET_STATE           "ticket_state"
 #define PCMK__XE_TRANSIENT_ATTRIBUTES   "transient_attributes"
 #define PCMK__XE_TRANSITION_GRAPH       "transition_graph"
 #define PCMK__XE_XPATH_QUERY            "xpath-query"
 #define PCMK__XE_XPATH_QUERY_PATH       "xpath-query-path"
 
 // @COMPAT Deprecated since 1.1.12
 #define PCMK__XE_ACL_USER               "acl_user"
 
 /* @COMPAT Deprecate somehow. It's undocumented and behaves the same as
  * PCMK__XE_CIB in places where it's recognized.
  */
 #define PCMK__XE_ALL                    "all"
 
 // @COMPAT Deprecated since 2.1.8
 #define PCMK__XE_CIB_GENERATION         "cib_generation"
 
 // @COMPAT Deprecated since 2.1.8
 #define PCMK__XE_CIB_UPDATE             "cib_update"
 
 // @COMPAT Deprecated since 2.1.7
 #define PCMK__XE_DIFF_ADDED             "diff-added"
 
 // @COMPAT Deprecated since 2.1.7
 #define PCMK__XE_DIFF_REMOVED           "diff-removed"
 
+// @COMPAT Deprecated since 2.1.8
+#define PCMK__XE_FAILED                 "failed"
+
 // @COMPAT Deprecated since 1.0.8 (commit 4cb100f)
 #define PCMK__XE_LIFETIME               "lifetime"
 
 /* @COMPAT Deprecated since 2.0.0; alias for <clone> with PCMK_META_PROMOTABLE
  * set to "true"
  */
 #define PCMK__XE_PROMOTABLE_LEGACY      "master"
 
 // @COMPAT Support for rkt is deprecated since 2.1.8
 #define PCMK__XE_RKT                    "rkt"
 
 // @COMPAT Deprecated since 1.1.12
 #define PCMK__XE_ROLE_REF               "role_ref"
 
 
 /*
  * XML attribute names used only by internal code
  */
 
 #define PCMK__XA_ATTR_CLEAR_INTERVAL    "attr_clear_interval"
 #define PCMK__XA_ATTR_CLEAR_OPERATION   "attr_clear_operation"
 #define PCMK__XA_ATTR_DAMPENING         "attr_dampening"
 #define PCMK__XA_ATTR_HOST              "attr_host"
 #define PCMK__XA_ATTR_HOST_ID           "attr_host_id"
 #define PCMK__XA_ATTR_IS_PRIVATE        "attr_is_private"
 #define PCMK__XA_ATTR_IS_REMOTE         "attr_is_remote"
 #define PCMK__XA_ATTR_NAME              "attr_name"
 #define PCMK__XA_ATTR_REGEX             "attr_regex"
 #define PCMK__XA_ATTR_RESOURCE          "attr_resource"
 #define PCMK__XA_ATTR_SECTION           "attr_section"
 #define PCMK__XA_ATTR_SET               "attr_set"
 #define PCMK__XA_ATTR_SET_TYPE          "attr_set_type"
 #define PCMK__XA_ATTR_SYNC_POINT        "attr_sync_point"
 #define PCMK__XA_ATTR_USER              "attr_user"
 #define PCMK__XA_ATTR_VALUE             "attr_value"
 #define PCMK__XA_ATTR_VERSION           "attr_version"
 #define PCMK__XA_ATTR_WRITER            "attr_writer"
 #define PCMK__XA_ATTRD_IS_FORCE_WRITE   "attrd_is_force_write"
 #define PCMK__XA_CALL_ID                "call-id"
 #define PCMK__XA_CIB_CALLID             "cib_callid"
 #define PCMK__XA_CIB_CALLOPT            "cib_callopt"
 #define PCMK__XA_CIB_CLIENTID           "cib_clientid"
 #define PCMK__XA_CIB_CLIENTNAME         "cib_clientname"
 #define PCMK__XA_CIB_DELEGATED_FROM     "cib_delegated_from"
 #define PCMK__XA_CIB_HOST               "cib_host"
 #define PCMK__XA_CIB_ISREPLYTO          "cib_isreplyto"
 #define PCMK__XA_CIB_NOTIFY_ACTIVATE    "cib_notify_activate"
 #define PCMK__XA_CIB_NOTIFY_TYPE        "cib_notify_type"
 #define PCMK__XA_CIB_OP                 "cib_op"
 #define PCMK__XA_CIB_PING_ID            "cib_ping_id"
 #define PCMK__XA_CIB_RC                 "cib_rc"
 #define PCMK__XA_CIB_SCHEMA_MAX         "cib_schema_max"
 #define PCMK__XA_CIB_SECTION            "cib_section"
 #define PCMK__XA_CIB_UPDATE             "cib_update"
 #define PCMK__XA_CIB_UPGRADE_RC         "cib_upgrade_rc"
 #define PCMK__XA_CIB_USER               "cib_user"
 #define PCMK__XA_CLIENT_NAME            "client_name"
 #define PCMK__XA_CLIENT_UUID            "client_uuid"
 #define PCMK__XA_CONFIG_ERRORS          "config-errors"
 #define PCMK__XA_CONFIG_WARNINGS        "config-warnings"
 #define PCMK__XA_CONFIRM                "confirm"
 #define PCMK__XA_CONNECTION_HOST        "connection_host"
 #define PCMK__XA_CONTENT                "content"
 #define PCMK__XA_CRMD_STATE             "crmd_state"
 #define PCMK__XA_CRM_HOST_TO            "crm_host_to"
 #define PCMK__XA_CRM_LIMIT_MAX          "crm-limit-max"
 #define PCMK__XA_CRM_LIMIT_MODE         "crm-limit-mode"
 #define PCMK__XA_CRM_SUBSYSTEM          "crm_subsystem"
 #define PCMK__XA_CRM_SYS_FROM           "crm_sys_from"
 #define PCMK__XA_CRM_SYS_TO             "crm_sys_to"
 #define PCMK__XA_CRM_TASK               "crm_task"
 #define PCMK__XA_CRM_TGRAPH_IN          "crm-tgraph-in"
 #define PCMK__XA_CRM_USER               "crm_user"
 #define PCMK__XA_DC_LEAVING             "dc-leaving"
 #define PCMK__XA_DIGEST                 "digest"
 #define PCMK__XA_ELECTION_AGE_SEC       "election-age-sec"
 #define PCMK__XA_ELECTION_AGE_NANO_SEC  "election-age-nano-sec"
 #define PCMK__XA_ELECTION_ID            "election-id"
 #define PCMK__XA_ELECTION_OWNER         "election-owner"
 #define PCMK__XA_GRANTED                "granted"
 #define PCMK__XA_GRAPH_ERRORS           "graph-errors"
 #define PCMK__XA_GRAPH_WARNINGS         "graph-warnings"
 #define PCMK__XA_HIDDEN                 "hidden"
 #define PCMK__XA_HTTP_EQUIV             "http-equiv"
 #define PCMK__XA_IN_CCM                 "in_ccm"
 #define PCMK__XA_JOIN                   "join"
 #define PCMK__XA_JOIN_ID                "join_id"
 #define PCMK__XA_LINE                   "line"
 #define PCMK__XA_LONG_ID                "long-id"
 #define PCMK__XA_LRMD_ALERT_ID          "lrmd_alert_id"
 #define PCMK__XA_LRMD_ALERT_PATH        "lrmd_alert_path"
 #define PCMK__XA_LRMD_CALLID            "lrmd_callid"
 #define PCMK__XA_LRMD_CALLOPT           "lrmd_callopt"
 #define PCMK__XA_LRMD_CLASS             "lrmd_class"
 #define PCMK__XA_LRMD_CLIENTID          "lrmd_clientid"
 #define PCMK__XA_LRMD_CLIENTNAME        "lrmd_clientname"
 #define PCMK__XA_LRMD_EXEC_OP_STATUS    "lrmd_exec_op_status"
 #define PCMK__XA_LRMD_EXEC_RC           "lrmd_exec_rc"
 #define PCMK__XA_LRMD_EXEC_TIME         "lrmd_exec_time"
 #define PCMK__XA_LRMD_IPC_CLIENT        "lrmd_ipc_client"
 #define PCMK__XA_LRMD_IPC_MSG_FLAGS     "lrmd_ipc_msg_flags"
 #define PCMK__XA_LRMD_IPC_MSG_ID        "lrmd_ipc_msg_id"
 #define PCMK__XA_LRMD_IPC_OP            "lrmd_ipc_op"
 #define PCMK__XA_LRMD_IPC_SERVER        "lrmd_ipc_server"
 #define PCMK__XA_LRMD_IPC_SESSION       "lrmd_ipc_session"
 #define PCMK__XA_LRMD_IPC_USER          "lrmd_ipc_user"
 #define PCMK__XA_LRMD_IS_IPC_PROVIDER   "lrmd_is_ipc_provider"
 #define PCMK__XA_LRMD_OP                "lrmd_op"
 #define PCMK__XA_LRMD_ORIGIN            "lrmd_origin"
 #define PCMK__XA_LRMD_PROTOCOL_VERSION  "lrmd_protocol_version"
 #define PCMK__XA_LRMD_PROVIDER          "lrmd_provider"
 #define PCMK__XA_LRMD_QUEUE_TIME        "lrmd_queue_time"
 #define PCMK__XA_LRMD_RC                "lrmd_rc"
 #define PCMK__XA_LRMD_RCCHANGE_TIME     "lrmd_rcchange_time"
 #define PCMK__XA_LRMD_REMOTE_MSG_ID     "lrmd_remote_msg_id"
 #define PCMK__XA_LRMD_REMOTE_MSG_TYPE   "lrmd_remote_msg_type"
 #define PCMK__XA_LRMD_RSC_ACTION        "lrmd_rsc_action"
 #define PCMK__XA_LRMD_RSC_DELETED       "lrmd_rsc_deleted"
 #define PCMK__XA_LRMD_RSC_EXIT_REASON   "lrmd_rsc_exit_reason"
 #define PCMK__XA_LRMD_RSC_ID            "lrmd_rsc_id"
 #define PCMK__XA_LRMD_RSC_INTERVAL      "lrmd_rsc_interval"
 #define PCMK__XA_LRMD_RSC_OUTPUT        "lrmd_rsc_output"
 #define PCMK__XA_LRMD_RSC_START_DELAY   "lrmd_rsc_start_delay"
 #define PCMK__XA_LRMD_RSC_USERDATA_STR  "lrmd_rsc_userdata_str"
 #define PCMK__XA_LRMD_RUN_TIME          "lrmd_run_time"
 #define PCMK__XA_LRMD_TIMEOUT           "lrmd_timeout"
 #define PCMK__XA_LRMD_TYPE              "lrmd_type"
 #define PCMK__XA_LRMD_WATCHDOG          "lrmd_watchdog"
 #define PCMK__XA_MAJOR_VERSION          "major_version"
 #define PCMK__XA_MINOR_VERSION          "minor_version"
 #define PCMK__XA_MODE                   "mode"
 #define PCMK__XA_MOON                   "moon"
 #define PCMK__XA_NAMESPACE              "namespace"
 #define PCMK__XA_NODE_FENCED            "node_fenced"
 #define PCMK__XA_NODE_IN_MAINTENANCE    "node_in_maintenance"
 #define PCMK__XA_NODE_START_STATE       "node_start_state"
 #define PCMK__XA_NODE_STATE             "node_state"
 #define PCMK__XA_OP_DIGEST              "op-digest"
 #define PCMK__XA_OP_FORCE_RESTART       "op-force-restart"
 #define PCMK__XA_OP_RESTART_DIGEST      "op-restart-digest"
 #define PCMK__XA_OP_SECURE_DIGEST       "op-secure-digest"
 #define PCMK__XA_OP_SECURE_PARAMS       "op-secure-params"
 #define PCMK__XA_OP_STATUS              "op-status"
 #define PCMK__XA_OPERATION_KEY          "operation_key"
 #define PCMK__XA_ORIGINAL_CIB_OP        "original_cib_op"
 #define PCMK__XA_PACEMAKERD_STATE       "pacemakerd_state"
 #define PCMK__XA_PASSWORD               "password"
 #define PCMK__XA_PRIORITY               "priority"
 #define PCMK__XA_RC_CODE                "rc-code"
 #define PCMK__XA_REAP                   "reap"
 
 /* Actions to be executed on Pacemaker Remote nodes are routed through the
  * controller on the cluster node hosting the remote connection. That cluster
  * node is considered the router node for the action.
  */
 #define PCMK__XA_ROUTER_NODE            "router_node"
 
 #define PCMK__XA_RSC_ID                 "rsc-id"
 #define PCMK__XA_RSC_PROVIDES           "rsc_provides"
 #define PCMK__XA_SCHEMA                 "schema"
 #define PCMK__XA_SCHEMAS                "schemas"
 #define PCMK__XA_SRC                    "src"
 #define PCMK__XA_ST_ACTION_DISALLOWED   "st_action_disallowed"
 #define PCMK__XA_ST_ACTION_TIMEOUT      "st_action_timeout"
 #define PCMK__XA_ST_AVAILABLE_DEVICES   "st-available-devices"
 #define PCMK__XA_ST_CALLID              "st_callid"
 #define PCMK__XA_ST_CALLOPT             "st_callopt"
 #define PCMK__XA_ST_CLIENTID            "st_clientid"
 #define PCMK__XA_ST_CLIENTNAME          "st_clientname"
 #define PCMK__XA_ST_CLIENTNODE          "st_clientnode"
 #define PCMK__XA_ST_DATE                "st_date"
 #define PCMK__XA_ST_DATE_NSEC           "st_date_nsec"
 #define PCMK__XA_ST_DELAY               "st_delay"
 #define PCMK__XA_ST_DELAY_BASE          "st_delay_base"
 #define PCMK__XA_ST_DELAY_MAX           "st_delay_max"
 #define PCMK__XA_ST_DELEGATE            "st_delegate"
 #define PCMK__XA_ST_DEVICE_ACTION       "st_device_action"
 #define PCMK__XA_ST_DEVICE_ID           "st_device_id"
 #define PCMK__XA_ST_DEVICE_SUPPORT_FLAGS    "st_device_support_flags"
 #define PCMK__XA_ST_DIFFERENTIAL        "st_differential"
 #define PCMK__XA_ST_MONITOR_VERIFIED    "st_monitor_verified"
 #define PCMK__XA_ST_NOTIFY_ACTIVATE     "st_notify_activate"
 #define PCMK__XA_ST_NOTIFY_DEACTIVATE   "st_notify_deactivate"
 #define PCMK__XA_ST_OP                  "st_op"
 #define PCMK__XA_ST_OP_MERGED           "st_op_merged"
 #define PCMK__XA_ST_ORIGIN              "st_origin"
 #define PCMK__XA_ST_OUTPUT              "st_output"
 #define PCMK__XA_ST_RC                  "st_rc"
 #define PCMK__XA_ST_REMOTE_OP           "st_remote_op"
 #define PCMK__XA_ST_REMOTE_OP_RELAY     "st_remote_op_relay"
 #define PCMK__XA_ST_REQUIRED            "st_required"
 #define PCMK__XA_ST_STATE               "st_state"
 #define PCMK__XA_ST_TARGET              "st_target"
 #define PCMK__XA_ST_TIMEOUT             "st_timeout"
 #define PCMK__XA_ST_TOLERANCE           "st_tolerance"
 #define PCMK__XA_SUBT                   "subt"                  // subtype
 #define PCMK__XA_T                      "t"                     // type
 #define PCMK__XA_TRANSITION_KEY         "transition-key"
 #define PCMK__XA_TRANSITION_MAGIC       "transition-magic"
 #define PCMK__XA_UPTIME                 "uptime"
 
 // @COMPAT Deprecated since 2.1.8
 #define PCMK__XA_CIB_OBJECT             "cib_object"
 
 // @COMPAT Deprecated since 2.1.8
 #define PCMK__XA_CIB_OBJECT_TYPE        "cib_object_type"
 
 // @COMPAT Deprecated since 1.1.12; used with legacy CIB updates
 #define PCMK__XA_CIB_LOCAL_NOTIFY_ID    "cib_local_notify_id"
 
 // @COMPAT Deprecated since 1.1.12; used with legacy CIB updates
 #define PCMK__XA_CIB_UPDATE_DIFF        "cib_update_diff"
 
 // @COMPAT Used only with v1 patchsets
 #define PCMK__XA_CRM_DIFF_MARKER        "__crm_diff_marker__"
 
 // @COMPAT Deprecated since 2.1.5
 #define PCMK__XA_FIRST_INSTANCE         "first-instance"
 
 // @COMPAT Deprecated since 2.1.7
 #define PCMK__XA_ORDERING               "ordering"
 
 // @COMPAT Deprecated alias for PCMK_XA_PROMOTED_MAX since 2.0.0
 #define PCMK__XA_PROMOTED_MAX_LEGACY    "masters"
 
 // @COMPAT Deprecated alias for PCMK_XA_PROMOTED_ONLY since 2.0.0
 #define PCMK__XA_PROMOTED_ONLY_LEGACY   "master_only"
 
 // @COMPAT Deprecated since 1.1.12
 #define PCMK__XA_REF                    "ref"
 
 // @COMPAT Deprecated since 2.1.6
 #define PCMK__XA_REPLACE                "replace"
 
 // @COMPAT Deprecated alias for \c PCMK_XA_AUTOMATIC since 1.1.14
 #define PCMK__XA_REQUIRED               "required"
 
 // @COMPAT Deprecated since 2.1.5
 #define PCMK__XA_RSC_INSTANCE           "rsc-instance"
 
 // @COMPAT Deprecated since 2.1.5
 #define PCMK__XA_THEN_INSTANCE          "then-instance"
 
 // @COMPAT Deprecated since 2.1.5
 #define PCMK__XA_WITH_RSC_INSTANCE      "with-rsc-instance"
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif // PCMK__CRM_COMMON_XML_NAMES_INTERNAL__H
diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c
index cbe82f8101..593d6c97fd 100644
--- a/lib/cib/cib_ops.c
+++ b/lib/cib/cib_ops.c
@@ -1,903 +1,904 @@
 /*
  * Copyright 2004-2024 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * 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 <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <time.h>
 
 #include <sys/param.h>
 #include <sys/types.h>
 
 #include <glib.h>
 #include <libxml/tree.h>
 
 #include <crm/crm.h>
 #include <crm/cib/internal.h>
 
 #include <crm/common/xml.h>
 #include <crm/common/xml_internal.h>
 
 // @TODO: Free this via crm_exit() when libcib gets merged with libcrmcommon
 static GHashTable *operation_table = NULL;
 
 static const cib__operation_t cib_ops[] = {
     {
         PCMK__CIB_REQUEST_ABS_DELETE, cib__op_abs_delete,
         cib__op_attr_modifies|cib__op_attr_privileged
     },
     {
         PCMK__CIB_REQUEST_APPLY_PATCH, cib__op_apply_patch,
         cib__op_attr_modifies
         |cib__op_attr_privileged
         |cib__op_attr_transaction
     },
     {
         PCMK__CIB_REQUEST_BUMP, cib__op_bump,
         cib__op_attr_modifies
         |cib__op_attr_privileged
         |cib__op_attr_transaction
     },
     {
         PCMK__CIB_REQUEST_COMMIT_TRANSACT, cib__op_commit_transact,
         cib__op_attr_modifies
         |cib__op_attr_privileged
         |cib__op_attr_replaces
         |cib__op_attr_writes_through
     },
     {
         PCMK__CIB_REQUEST_CREATE, cib__op_create,
         cib__op_attr_modifies
         |cib__op_attr_privileged
         |cib__op_attr_transaction
     },
     {
         PCMK__CIB_REQUEST_DELETE, cib__op_delete,
         cib__op_attr_modifies
         |cib__op_attr_privileged
         |cib__op_attr_transaction
     },
     {
         PCMK__CIB_REQUEST_ERASE, cib__op_erase,
         cib__op_attr_modifies
         |cib__op_attr_privileged
         |cib__op_attr_replaces
         |cib__op_attr_transaction
     },
     {
         PCMK__CIB_REQUEST_IS_PRIMARY, cib__op_is_primary,
         cib__op_attr_privileged
     },
     {
         PCMK__CIB_REQUEST_MODIFY, cib__op_modify,
         cib__op_attr_modifies
         |cib__op_attr_privileged
         |cib__op_attr_transaction
     },
     {
         PCMK__CIB_REQUEST_NOOP, cib__op_noop, cib__op_attr_none
     },
     {
         CRM_OP_PING, cib__op_ping, cib__op_attr_none
     },
     {
         // @COMPAT: Drop cib__op_attr_modifies when we drop legacy mode support
         PCMK__CIB_REQUEST_PRIMARY, cib__op_primary,
         cib__op_attr_modifies|cib__op_attr_privileged|cib__op_attr_local
     },
     {
         PCMK__CIB_REQUEST_QUERY, cib__op_query, cib__op_attr_none
     },
     {
         PCMK__CIB_REQUEST_REPLACE, cib__op_replace,
         cib__op_attr_modifies
         |cib__op_attr_privileged
         |cib__op_attr_replaces
         |cib__op_attr_writes_through
         |cib__op_attr_transaction
     },
     {
         PCMK__CIB_REQUEST_SECONDARY, cib__op_secondary,
         cib__op_attr_privileged|cib__op_attr_local
     },
     {
         PCMK__CIB_REQUEST_SHUTDOWN, cib__op_shutdown, cib__op_attr_privileged
     },
     {
         PCMK__CIB_REQUEST_SYNC_TO_ALL, cib__op_sync_all, cib__op_attr_privileged
     },
     {
         PCMK__CIB_REQUEST_SYNC_TO_ONE, cib__op_sync_one, cib__op_attr_privileged
     },
     {
         PCMK__CIB_REQUEST_UPGRADE, cib__op_upgrade,
         cib__op_attr_modifies
         |cib__op_attr_privileged
         |cib__op_attr_writes_through
         |cib__op_attr_transaction
     },
     {
         PCMK__CIB_REQUEST_SCHEMAS, cib__op_schemas, cib__op_attr_local
     }
 };
 
 /*!
  * \internal
  * \brief Get the \c cib__operation_t object for a given CIB operation name
  *
  * \param[in]  op         CIB operation name
  * \param[out] operation  Where to store CIB operation object
  *
  * \return Standard Pacemaker return code
  */
 int
 cib__get_operation(const char *op, const cib__operation_t **operation)
 {
     CRM_ASSERT((op != NULL) && (operation != NULL));
 
     if (operation_table == NULL) {
         operation_table = pcmk__strkey_table(NULL, NULL);
 
         for (int lpc = 0; lpc < PCMK__NELEM(cib_ops); lpc++) {
             const cib__operation_t *oper = &(cib_ops[lpc]);
 
             g_hash_table_insert(operation_table, (gpointer) oper->name,
                                 (gpointer) oper);
         }
     }
 
     *operation = g_hash_table_lookup(operation_table, op);
     if (*operation == NULL) {
         crm_err("Operation %s is invalid", op);
         return EINVAL;
     }
     return pcmk_rc_ok;
 }
 
 int
 cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                   xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     xmlNode *obj_root = NULL;
     int result = pcmk_ok;
 
     crm_trace("Processing %s for %s section",
               op, pcmk__s(section, "unspecified"));
 
     if (options & cib_xpath) {
         return cib_process_xpath(op, options, section, req, input,
                                  existing_cib, result_cib, answer);
     }
 
     CRM_CHECK(*answer == NULL, free_xml(*answer));
     *answer = NULL;
 
     if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
         section = NULL;
     }
 
     obj_root = pcmk_find_cib_element(existing_cib, section);
 
     if (obj_root == NULL) {
         result = -ENXIO;
 
     } else if (options & cib_no_children) {
         xmlNode *shallow = pcmk__xe_create(*answer,
                                            (const char *) obj_root->name);
 
         copy_in_properties(shallow, obj_root);
         *answer = shallow;
 
     } else {
         *answer = obj_root;
     }
 
     if (result == pcmk_ok && *answer == NULL) {
         crm_err("Error creating query response");
         result = -ENOMSG;
     }
 
     return result;
 }
 
 static int
 update_counter(xmlNode *xml_obj, const char *field, bool reset)
 {
     char *new_value = NULL;
     char *old_value = NULL;
     int int_value = -1;
 
     if (!reset && crm_element_value(xml_obj, field) != NULL) {
         old_value = crm_element_value_copy(xml_obj, field);
     }
     if (old_value != NULL) {
         int_value = atoi(old_value);
         new_value = pcmk__itoa(++int_value);
     } else {
         new_value = pcmk__str_copy("1");
     }
 
     crm_trace("Update %s from %s to %s",
               field, pcmk__s(old_value, "unset"), new_value);
     crm_xml_add(xml_obj, field, new_value);
 
     free(new_value);
     free(old_value);
 
     return pcmk_ok;
 }
 
 int
 cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                   xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     int result = pcmk_ok;
 
     crm_trace("Processing \"%s\" event", op);
 
     if (*result_cib != existing_cib) {
         free_xml(*result_cib);
     }
     *result_cib = createEmptyCib(0);
     copy_in_properties(*result_cib, existing_cib);
     update_counter(*result_cib, PCMK_XA_ADMIN_EPOCH, false);
     *answer = NULL;
 
     return result;
 }
 
 int
 cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
                     xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
                     xmlNode ** answer)
 {
     int rc = 0;
     int new_version = 0;
     int current_version = 0;
     int max_version = 0;
     const char *max = crm_element_value(req, PCMK__XA_CIB_SCHEMA_MAX);
     const char *value = crm_element_value(existing_cib, PCMK_XA_VALIDATE_WITH);
 
     *answer = NULL;
     crm_trace("Processing \"%s\" event with max=%s", op, max);
 
     if (value != NULL) {
         current_version = get_schema_version(value);
     }
 
     if (max) {
         max_version = get_schema_version(max);
     }
 
     rc = update_validation(result_cib, &new_version, max_version, TRUE,
                            !(options & cib_verbose));
     if (new_version > current_version) {
         update_counter(*result_cib, PCMK_XA_ADMIN_EPOCH, false);
         update_counter(*result_cib, PCMK_XA_EPOCH, true);
         update_counter(*result_cib, PCMK_XA_NUM_UPDATES, true);
         return pcmk_ok;
     }
 
     return rc;
 }
 
 int
 cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     int result = pcmk_ok;
 
     crm_trace("Processing %s for epoch='%s'", op,
               pcmk__s(crm_element_value(existing_cib, PCMK_XA_EPOCH), ""));
 
     *answer = NULL;
     update_counter(*result_cib, PCMK_XA_EPOCH, false);
 
     return result;
 }
 
 int
 cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
                     xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
                     xmlNode ** answer)
 {
     int result = pcmk_ok;
 
     crm_trace("Processing %s for %s section",
               op, pcmk__s(section, "unspecified"));
 
     if (options & cib_xpath) {
         return cib_process_xpath(op, options, section, req, input,
                                  existing_cib, result_cib, answer);
     }
 
     *answer = NULL;
 
     if (input == NULL) {
         return -EINVAL;
     }
 
     if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
         section = NULL;
 
     } else if (pcmk__xe_is(input, section)) {
         section = NULL;
     }
 
     if (pcmk__xe_is(input, PCMK_XE_CIB)) {
         int updates = 0;
         int epoch = 0;
         int admin_epoch = 0;
 
         int replace_updates = 0;
         int replace_epoch = 0;
         int replace_admin_epoch = 0;
 
         const char *reason = NULL;
         const char *peer = crm_element_value(req, PCMK__XA_SRC);
         const char *digest = crm_element_value(req, PCMK__XA_DIGEST);
 
         if (digest) {
             const char *version = crm_element_value(req,
                                                     PCMK_XA_CRM_FEATURE_SET);
             char *digest_verify = calculate_xml_versioned_digest(input, FALSE, TRUE,
                                                                  version ? version :
                                                                  CRM_FEATURE_SET);
 
             if (!pcmk__str_eq(digest_verify, digest, pcmk__str_casei)) {
                 crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
                         digest_verify, digest);
                 reason = "digest mismatch";
 
             } else {
                 crm_info("Digest matched on replace from %s: %s", peer, digest);
             }
             free(digest_verify);
 
         } else {
             crm_trace("No digest to verify");
         }
 
         cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
         cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
 
         if (replace_admin_epoch < admin_epoch) {
             reason = PCMK_XA_ADMIN_EPOCH;
 
         } else if (replace_admin_epoch > admin_epoch) {
             /* no more checks */
 
         } else if (replace_epoch < epoch) {
             reason = PCMK_XA_EPOCH;
 
         } else if (replace_epoch > epoch) {
             /* no more checks */
 
         } else if (replace_updates < updates) {
             reason = PCMK_XA_NUM_UPDATES;
         }
 
         if (reason != NULL) {
             crm_info("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
                      " current %s is greater than the replacement",
                      replace_admin_epoch, replace_epoch,
                      replace_updates, peer, admin_epoch, epoch, updates, reason);
             result = -pcmk_err_old_data;
         } else {
             crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
                      admin_epoch, epoch, updates,
                      replace_admin_epoch, replace_epoch, replace_updates, peer);
         }
 
         if (*result_cib != existing_cib) {
             free_xml(*result_cib);
         }
         *result_cib = pcmk__xml_copy(NULL, input);
 
     } else {
         xmlNode *obj_root = NULL;
 
         obj_root = pcmk_find_cib_element(*result_cib, section);
         result = pcmk__xe_replace_match(obj_root, input);
         result = pcmk_rc2legacy(result);
         if (result != pcmk_ok) {
             crm_trace("No matching object to replace");
         }
     }
 
     return result;
 }
 
 static int
 delete_child(xmlNode *child, void *userdata)
 {
     xmlNode *obj_root = userdata;
 
     if (pcmk__xe_delete_match(obj_root, child) != pcmk_rc_ok) {
         crm_trace("No matching object to delete: %s=%s",
                   child->name, pcmk__xe_id(child));
     }
 
     return pcmk_rc_ok;
 }
 
 int
 cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     xmlNode *obj_root = NULL;
 
     crm_trace("Processing \"%s\" event", op);
 
     if (options & cib_xpath) {
         return cib_process_xpath(op, options, section, req, input,
                                  existing_cib, result_cib, answer);
     }
 
     if (input == NULL) {
         crm_err("Cannot perform modification with no data");
         return -EINVAL;
     }
 
     obj_root = pcmk_find_cib_element(*result_cib, section);
     if (pcmk__xe_is(input, section)) {
         pcmk__xe_foreach_child(input, NULL, delete_child, obj_root);
     } else {
         delete_child(input, obj_root);
     }
 
     return pcmk_ok;
 }
 
 int
 cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     xmlNode *obj_root = NULL;
 
     crm_trace("Processing \"%s\" event", op);
 
     if (options & cib_xpath) {
         return cib_process_xpath(op, options, section, req, input,
                                  existing_cib, result_cib, answer);
     }
 
     if (input == NULL) {
         crm_err("Cannot perform modification with no data");
         return -EINVAL;
     }
 
     obj_root = pcmk_find_cib_element(*result_cib, section);
     if (obj_root == NULL) {
         xmlNode *tmp_section = NULL;
         const char *path = pcmk_cib_parent_name_for(section);
 
         if (path == NULL) {
             return -EINVAL;
         }
 
         tmp_section = pcmk__xe_create(NULL, section);
         cib_process_xpath(PCMK__CIB_REQUEST_CREATE, 0, path, NULL, tmp_section,
                           NULL, result_cib, answer);
         free_xml(tmp_section);
 
         obj_root = pcmk_find_cib_element(*result_cib, section);
     }
 
     CRM_CHECK(obj_root != NULL, return -EINVAL);
 
     if (pcmk__xe_update_match(obj_root, input) != pcmk_rc_ok) {
         if (options & cib_can_create) {
             pcmk__xml_copy(obj_root, input);
         } else {
             return -ENXIO;
         }
     }
 
     // @COMPAT cib_mixed_update is deprecated as of 2.1.7
     if (pcmk_is_set(options, cib_mixed_update)) {
         int max = 0, lpc;
         xmlXPathObjectPtr xpathObj = xpath_search(*result_cib, "//@__delete__");
 
         if (xpathObj) {
             max = numXpathResults(xpathObj);
             crm_log_xml_trace(*result_cib, "Mixed result");
         }
 
         for (lpc = 0; lpc < max; lpc++) {
             xmlNode *match = getXpathResult(xpathObj, lpc);
             xmlChar *match_path = xmlGetNodePath(match);
 
             crm_debug("Destroying %s", match_path);
             free(match_path);
             free_xml(match);
         }
 
         freeXpathObject(xpathObj);
     }
     return pcmk_ok;
 }
 
 static int
 add_cib_object(xmlNode * parent, xmlNode * new_obj)
 {
     const char *object_name = NULL;
     const char *object_id = NULL;
 
     if ((parent == NULL) || (new_obj == NULL)) {
         return -EINVAL;
     }
 
     object_name = (const char *) new_obj->name;
     if (object_name == NULL) {
         return -EINVAL;
     }
 
     object_id = pcmk__xe_id(new_obj);
     if (pcmk__xe_first_child(parent, object_name,
                              ((object_id != NULL)? PCMK_XA_ID : NULL),
                              object_id)) {
         return -EEXIST;
     }
 
     if (object_id != NULL) {
         crm_trace("Processing creation of <%s " PCMK_XA_ID "='%s'>",
                   object_name, object_id);
     } else {
         crm_trace("Processing creation of <%s>", object_name);
     }
 
     /* @COMPAT PCMK__XA_REPLACE is deprecated since 2.1.6. Due to a legacy use
      * case, PCMK__XA_REPLACE has special meaning and should not be included in
      * the newly created object until we can break behavioral backward
      * compatibility.
      *
      * At a compatibility break, drop this and drop the definition of
      * PCMK__XA_REPLACE. Treat it like any other attribute.
      */
     pcmk__xml_tree_foreach(new_obj, pcmk__xe_remove_attr_cb,
                            (void *) PCMK__XA_REPLACE);
 
     pcmk__xml_copy(parent, new_obj);
     return pcmk_ok;
 }
 
 static bool
 update_results(xmlNode *failed, xmlNode *target, const char *operation,
                int return_code)
 {
     xmlNode *xml_node = NULL;
     bool was_error = false;
     const char *error_msg = NULL;
 
     if (return_code != pcmk_ok) {
         error_msg = pcmk_strerror(return_code);
 
         was_error = true;
         xml_node = pcmk__xe_create(failed, PCMK__XE_FAILED_UPDATE);
         pcmk__xml_copy(xml_node, target);
 
         crm_xml_add(xml_node, PCMK_XA_ID, pcmk__xe_id(target));
         crm_xml_add(xml_node, PCMK_XA_OBJECT_TYPE, (const char *) target->name);
         crm_xml_add(xml_node, PCMK_XA_OPERATION, operation);
         crm_xml_add(xml_node, PCMK_XA_REASON, error_msg);
 
         crm_warn("Action %s failed: %s (cde=%d)",
                  operation, error_msg, return_code);
     }
 
     return was_error;
 }
 
 int
 cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     xmlNode *failed = NULL;
     int result = pcmk_ok;
     xmlNode *update_section = NULL;
 
     crm_trace("Processing %s for %s section",
               op, pcmk__s(section, "unspecified"));
     if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
         section = NULL;
 
     } else if (pcmk__str_eq(section, PCMK_XE_CIB, pcmk__str_casei)) {
         section = NULL;
 
     } else if (pcmk__xe_is(input, PCMK_XE_CIB)) {
         section = NULL;
     }
 
     CRM_CHECK(strcmp(op, PCMK__CIB_REQUEST_CREATE) == 0, return -EINVAL);
 
     if (input == NULL) {
         crm_err("Cannot perform modification with no data");
         return -EINVAL;
     }
 
     if (section == NULL) {
         return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
                                   answer);
     }
 
+    // @COMPAT Deprecated since 2.1.8
     failed = pcmk__xe_create(NULL, PCMK__XE_FAILED);
 
     update_section = pcmk_find_cib_element(*result_cib, section);
     if (pcmk__xe_is(input, section)) {
         xmlNode *a_child = NULL;
 
         for (a_child = pcmk__xml_first_child(input); a_child != NULL;
              a_child = pcmk__xml_next(a_child)) {
             result = add_cib_object(update_section, a_child);
             if (update_results(failed, a_child, op, result)) {
                 break;
             }
         }
 
     } else {
         result = add_cib_object(update_section, input);
         update_results(failed, input, op, result);
     }
 
     if ((result == pcmk_ok) && (failed->children != NULL)) {
         result = -EINVAL;
     }
 
     if (result != pcmk_ok) {
         crm_log_xml_err(failed, "CIB Update failures");
         *answer = failed;
 
     } else {
         free_xml(failed);
     }
 
     return result;
 }
 
 int
 cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 {
     const char *originator = NULL;
 
     if (req != NULL) {
         originator = crm_element_value(req, PCMK__XA_SRC);
     }
 
     crm_trace("Processing \"%s\" event from %s%s",
               op, originator,
               (pcmk_is_set(options, cib_force_diff)? " (global update)" : ""));
 
     if (*result_cib != existing_cib) {
         free_xml(*result_cib);
     }
     *result_cib = pcmk__xml_copy(NULL, existing_cib);
 
     return xml_apply_patchset(*result_cib, input, TRUE);
 }
 
 // @COMPAT: v1-only
 bool
 cib__config_changed_v1(xmlNode *last, xmlNode *next, xmlNode **diff)
 {
     int lpc = 0, max = 0;
     bool config_changes = false;
     xmlXPathObject *xpathObj = NULL;
     int format = 1;
 
     CRM_ASSERT(diff != NULL);
 
     if (*diff == NULL && last != NULL && next != NULL) {
         *diff = pcmk__diff_v1_xml_object(last, next, false);
     }
 
     if (*diff == NULL) {
         goto done;
     }
 
     crm_element_value_int(*diff, PCMK_XA_FORMAT, &format);
     CRM_LOG_ASSERT(format == 1);
 
     xpathObj = xpath_search(*diff, "//" PCMK_XE_CONFIGURATION);
     if (numXpathResults(xpathObj) > 0) {
         config_changes = true;
         goto done;
     }
     freeXpathObject(xpathObj);
 
     /*
      * Do not check PCMK__XE_DIFF_ADDED "//" PCMK_XE_CIB
      * This always contains every field and would produce a false positive
      * every time if the checked value existed
      */
     xpathObj = xpath_search(*diff, "//" PCMK__XE_DIFF_REMOVED "//" PCMK_XE_CIB);
     max = numXpathResults(xpathObj);
 
     for (lpc = 0; lpc < max; lpc++) {
         xmlNode *top = getXpathResult(xpathObj, lpc);
 
         if (crm_element_value(top, PCMK_XA_EPOCH) != NULL) {
             config_changes = true;
             goto done;
         }
         if (crm_element_value(top, PCMK_XA_ADMIN_EPOCH) != NULL) {
             config_changes = true;
             goto done;
         }
 
         if (crm_element_value(top, PCMK_XA_VALIDATE_WITH) != NULL) {
             config_changes = true;
             goto done;
         }
         if (crm_element_value(top, PCMK_XA_CRM_FEATURE_SET) != NULL) {
             config_changes = true;
             goto done;
         }
         if (crm_element_value(top, PCMK_XA_REMOTE_CLEAR_PORT) != NULL) {
             config_changes = true;
             goto done;
         }
         if (crm_element_value(top, PCMK_XA_REMOTE_TLS_PORT) != NULL) {
             config_changes = true;
             goto done;
         }
     }
 
   done:
     freeXpathObject(xpathObj);
     return config_changes;
 }
 
 int
 cib_process_xpath(const char *op, int options, const char *section,
                   const xmlNode *req, xmlNode *input, xmlNode *existing_cib,
                   xmlNode **result_cib, xmlNode **answer)
 {
     int lpc = 0;
     int max = 0;
     int rc = pcmk_ok;
     bool is_query = pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none);
 
     xmlXPathObjectPtr xpathObj = NULL;
 
     crm_trace("Processing \"%s\" event", op);
 
     if (is_query) {
         xpathObj = xpath_search(existing_cib, section);
     } else {
         xpathObj = xpath_search(*result_cib, section);
     }
 
     max = numXpathResults(xpathObj);
 
     if ((max < 1)
         && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
         crm_debug("%s was already removed", section);
 
     } else if (max < 1) {
         crm_debug("%s: %s does not exist", op, section);
         rc = -ENXIO;
 
     } else if (is_query) {
         if (max > 1) {
             *answer = pcmk__xe_create(NULL, PCMK__XE_XPATH_QUERY);
         }
     }
 
     if (pcmk_is_set(options, cib_multiple)
         && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
         dedupXpathResults(xpathObj);
     }
 
     for (lpc = 0; lpc < max; lpc++) {
         xmlChar *path = NULL;
         xmlNode *match = getXpathResult(xpathObj, lpc);
 
         if (match == NULL) {
             continue;
         }
 
         path = xmlGetNodePath(match);
         crm_debug("Processing %s op for %s with %s", op, section, path);
         free(path);
 
         if (pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
             if (match == *result_cib) {
                 /* Attempting to delete the whole "/cib" */
                 crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
                 rc = -EINVAL;
                 break;
             }
 
             free_xml(match);
             if ((options & cib_multiple) == 0) {
                 break;
             }
 
         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_MODIFY, pcmk__str_none)) {
             if (pcmk__xe_update_match(match, input) != pcmk_rc_ok) {
                 rc = -ENXIO;
             } else if ((options & cib_multiple) == 0) {
                 break;
             }
 
         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_CREATE, pcmk__str_none)) {
             pcmk__xml_copy(match, input);
             break;
 
         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none)) {
 
             if (options & cib_no_children) {
                 xmlNode *shallow = pcmk__xe_create(*answer,
                                                    (const char *) match->name);
 
                 copy_in_properties(shallow, match);
 
                 if (*answer == NULL) {
                     *answer = shallow;
                 }
 
             } else if (options & cib_xpath_address) {
                 char *path = NULL;
                 xmlNode *parent = match;
 
                 while (parent && parent->type == XML_ELEMENT_NODE) {
                     const char *id = crm_element_value(parent, PCMK_XA_ID);
                     char *new_path = NULL;
 
                     if (id) {
                         new_path = crm_strdup_printf("/%s[@" PCMK_XA_ID "='%s']"
                                                      "%s",
                                                      parent->name, id,
                                                      pcmk__s(path, ""));
                     } else {
                         new_path = crm_strdup_printf("/%s%s", parent->name,
                                                      pcmk__s(path, ""));
                     }
                     free(path);
                     path = new_path;
                     parent = parent->parent;
                 }
                 crm_trace("Got: %s", path);
 
                 if (*answer == NULL) {
                     *answer = pcmk__xe_create(NULL, PCMK__XE_XPATH_QUERY);
                 }
                 parent = pcmk__xe_create(*answer, PCMK__XE_XPATH_QUERY_PATH);
                 crm_xml_add(parent, PCMK_XA_ID, path);
                 free(path);
 
             } else if (*answer) {
                 pcmk__xml_copy(*answer, match);
 
             } else {
                 *answer = match;
             }
 
         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE,
                                 pcmk__str_none)) {
             xmlNode *parent = match->parent;
 
             free_xml(match);
             pcmk__xml_copy(parent, input);
 
             if ((options & cib_multiple) == 0) {
                 break;
             }
         }
     }
 
     freeXpathObject(xpathObj);
     return rc;
 }