diff --git a/include/crm/msg_xml.h b/include/crm/msg_xml.h
index 8c210625da..88b49dde5c 100644
--- a/include/crm/msg_xml.h
+++ b/include/crm/msg_xml.h
@@ -1,297 +1,298 @@
 /*
  * 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_MSG_XML__H
 #  define PCMK__CRM_MSG_XML__H
 
 #  include <crm/common/xml.h>
 
 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
 #include <crm/msg_xml_compat.h>
 #endif
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /* This file defines constants for various XML syntax (mainly element and
  * attribute names).
  *
  * For consistency, new constants should start with "PCMK_", followed by:
  * * "XE" for XML element names
  * * "XA" for XML attribute names
  * * "OPT" for cluster option (property) names
  * * "META" for meta-attribute names
  * * "VALUE" for enumerated values for various options
  *
  * Old names that don't follow this policy should eventually be deprecated and
  * replaced with names that do.
  *
  * Symbols should be public if the user may specify them somewhere (especially
  * the CIB) or if they're part of a well-defined structure that a user may need
  * to parse. They should be internal if they're used only internally to
  * Pacemaker (such as daemon IPC/CPG message XML).
  *
  * Constants belong in the following locations:
  * * Public "XE" and "XA": msg_xml.h
  * * Internal "XE" and "XA": crm_internal.h
  * * Public "OPT", "META", and "VALUE": options.h
  * * Internal "OPT", "META", and "VALUE": options_internal.h
  *
  * For meta-attributes that can be specified as either XML attributes or nvpair
  * names, use "META" unless using both "XA" and "META" constants adds clarity.
  * An example is operation attributes, which can be specified either as
  * attributes of the PCMK_XE_OP element or as nvpairs in a meta-attribute set
  * beneath the PCMK_XE_OP element.
  */
 
 /*
  * XML elements
  */
 
 #define PCMK_XE_CONTENT                     "content"
 #define PCMK_XE_DATE_EXPRESSION             "date_expression"
 #define PCMK_XE_LONGDESC                    "longdesc"
 #define PCMK_XE_OP                          "op"
 #define PCMK_XE_OPERATION                   "operation"
 #define PCMK_XE_OP_EXPRESSION               "op_expression"
 #define PCMK_XE_OPTION                      "option"
 #define PCMK_XE_ROLE                        "role"
 #define PCMK_XE_PARAMETER                   "parameter"
 #define PCMK_XE_PARAMETERS                  "parameters"
 #define PCMK_XE_RESOURCE_AGENT              "resource-agent"
 #define PCMK_XE_RSC_EXPRESSION              "rsc_expression"
 #define PCMK_XE_SHORTDESC                   "shortdesc"
 #define PCMK_XE_VERSION                     "version"
 
 
 /*
  * XML attributes
  */
 
 #define PCMK_XA_ADMIN_EPOCH                 "admin_epoch"
 #define PCMK_XA_ATTRIBUTE                   "attribute"
 #define PCMK_XA_BOOLEAN_OP                  "boolean-op"
 #define PCMK_XA_CIB_LAST_WRITTEN            "cib-last-written"
 #define PCMK_XA_CLASS                       "class"
 #define PCMK_XA_CRM_DEBUG_ORIGIN            "crm-debug-origin"
 #define PCMK_XA_CRM_FEATURE_SET             "crm_feature_set"
 #define PCMK_XA_CRM_TIMESTAMP               "crm-timestamp"
 #define PCMK_XA_DC_UUID                     "dc-uuid"
 #define PCMK_XA_DEFAULT                     "default"
 #define PCMK_XA_DESCRIPTION                 "description"
 #define PCMK_XA_DEVICES                     "devices"
 #define PCMK_XA_EPOCH                       "epoch"
 #define PCMK_XA_EXEC_TIME                   "exec-time"
 #define PCMK_XA_EXIT_REASON                 "exit-reason"
 #define PCMK_XA_FIRST                       "first"
 #define PCMK_XA_FIRST_ACTION                "first-action"
 #define PCMK_XA_FORMAT                      "format"
 #define PCMK_XA_HAVE_QUORUM                 "have-quorum"
 #define PCMK_XA_ID                          "id"
 #define PCMK_XA_ID_REF                      "id-ref"
 #define PCMK_XA_INDEX                       "index"
 #define PCMK_XA_INFLUENCE                   "influence"
 #define PCMK_XA_KIND                        "kind"
-#define PCMK_XA_LAST_RC_CHANGE              "last-rc-change"
 #define PCMK_XA_LANG                        "lang"
+#define PCMK_XA_LAST_RC_CHANGE              "last-rc-change"
+#define PCMK_XA_LOSS_POLICY                 "loss-policy"
 #define PCMK_XA_NAME                        "name"
 #define PCMK_XA_NO_QUORUM_PANIC             "no-quorum-panic"
 #define PCMK_XA_NODE_ATTRIBUTE              "node-attribute"
 #define PCMK_XA_NUM_UPDATES                 "num_updates"
 #define PCMK_XA_OP                          "op"
 #define PCMK_XA_OPERATION                   "operation"
 #define PCMK_XA_ORIGIN                      "origin"
 #define PCMK_XA_PATH                        "path"
 #define PCMK_XA_PROVIDER                    "provider"
 #define PCMK_XA_QUEUE_TIME                  "queue-time"
 #define PCMK_XA_REASON                      "reason"
 #define PCMK_XA_REFERENCE                   "reference"
 #define PCMK_XA_REQUEST                     "request"
 #define PCMK_XA_RESOURCE_DISCOVERY          "resource-discovery"
 #define PCMK_XA_RESULT                      "result"
 #define PCMK_XA_ROLE                        "role"
 #define PCMK_XA_RSC                         "rsc"
 #define PCMK_XA_RSC_PATTERN                 "rsc-pattern"
 #define PCMK_XA_RSC_ROLE                    "rsc-role"
 #define PCMK_XA_SCORE                       "score"
 #define PCMK_XA_SCORE_ATTRIBUTE             "score-attribute"
 #define PCMK_XA_SYMMETRICAL                 "symmetrical"
 #define PCMK_XA_TARGET                      "target"
 #define PCMK_XA_TARGET_ATTRIBUTE            "target-attribute"
 #define PCMK_XA_TARGET_PATTERN              "target-pattern"
 #define PCMK_XA_TARGET_VALUE                "target-value"
 #define PCMK_XA_TICKET                      "ticket"
 #define PCMK_XA_THEN                        "then"
 #define PCMK_XA_THEN_ACTION                 "then-action"
 #define PCMK_XA_TYPE                        "type"
 #define PCMK_XA_UNAME                       "uname"
 #define PCMK_XA_UPDATE_CLIENT               "update-client"
 #define PCMK_XA_UPDATE_ORIGIN               "update-origin"
 #define PCMK_XA_UPDATE_USER                 "update-user"
 #define PCMK_XA_VALIDATE_WITH               "validate-with"
 #define PCMK_XA_VALUE                       "value"
 #define PCMK_XA_VALUE_SOURCE                "value-source"
 #define PCMK_XA_VERSION                     "version"
 #define PCMK_XA_WITH_RSC                    "with-rsc"
 #define PCMK_XA_WITH_RSC_ROLE               "with-rsc-role"
 
 
 /*
  * Older constants that don't follow current naming
  */
 
 #  ifndef T_CRM
 #    define T_CRM     "crmd"
 #  endif
 
 #  ifndef T_ATTRD
 #    define T_ATTRD     "attrd"
 #  endif
 
 #  define CIB_OPTIONS_FIRST "cib-bootstrap-options"
 
 #  define F_CRM_DATA			"crm_xml"
 
 /*---- Common tags/attrs */
 #  define XML_DIFF_MARKER		"__crm_diff_marker__"
 #  define XML_TAG_CIB			"cib"
 #  define XML_TAG_FAILED		"failed"
 
 #  define XML_TAG_OPTIONS		"options"
 
 /*---- top level tags/attrs */
 #  define XML_CRM_TAG_PING		"ping_response"
 #  define XML_PING_ATTR_PACEMAKERDSTATE_INIT "init"
 #  define XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS "starting_daemons"
 #  define XML_PING_ATTR_PACEMAKERDSTATE_WAITPING "wait_for_ping"
 #  define XML_PING_ATTR_PACEMAKERDSTATE_RUNNING "running"
 #  define XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN "shutting_down"
 #  define XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE "shutdown_complete"
 #  define XML_PING_ATTR_PACEMAKERDSTATE_REMOTE "remote"
 
 #  define XML_FAIL_TAG_CIB		"failed_update"
 
 /*---- CIB specific tags/attrs */
 #  define XML_CIB_TAG_SECTION_ALL	"all"
 #  define XML_CIB_TAG_CONFIGURATION	"configuration"
 #  define XML_CIB_TAG_STATUS       	"status"
 #  define XML_CIB_TAG_RESOURCES		"resources"
 #  define XML_CIB_TAG_NODES         	"nodes"
 #  define XML_CIB_TAG_CONSTRAINTS   	"constraints"
 #  define XML_CIB_TAG_CRMCONFIG   	"crm_config"
 #  define XML_CIB_TAG_OPCONFIG		"op_defaults"
 #  define XML_CIB_TAG_RSCCONFIG   	"rsc_defaults"
 #  define XML_CIB_TAG_ACLS   		"acls"
 #  define XML_CIB_TAG_ALERTS    	"alerts"
 #  define XML_CIB_TAG_ALERT   		"alert"
 #  define XML_CIB_TAG_ALERT_RECIPIENT	"recipient"
 #  define XML_CIB_TAG_ALERT_SELECT      "select"
 #  define XML_CIB_TAG_ALERT_ATTRIBUTES  "select_attributes"
 #  define XML_CIB_TAG_ALERT_FENCING     "select_fencing"
 #  define XML_CIB_TAG_ALERT_NODES       "select_nodes"
 #  define XML_CIB_TAG_ALERT_RESOURCES   "select_resources"
 #  define XML_CIB_TAG_ALERT_ATTR        "attribute"
 
 #  define XML_CIB_TAG_STATE         	"node_state"
 #  define XML_CIB_TAG_NODE          	"node"
 #  define XML_CIB_TAG_NVPAIR        	"nvpair"
 
 #  define XML_CIB_TAG_PROPSET	   	"cluster_property_set"
 #  define XML_TAG_ATTR_SETS	   	"instance_attributes"
 #  define XML_TAG_META_SETS	   	"meta_attributes"
 #  define XML_TAG_ATTRS			"attributes"
 #  define XML_TAG_PARAM			"param"
 #  define XML_TAG_UTILIZATION		"utilization"
 
 #  define XML_TAG_RESOURCE_REF		"resource_ref"
 #  define XML_CIB_TAG_RESOURCE	  	"primitive"
 #  define XML_CIB_TAG_GROUP	  	"group"
 #  define XML_CIB_TAG_INCARNATION	"clone"
 #  define XML_CIB_TAG_CONTAINER		"bundle"
 
 #  define XML_CIB_TAG_RSC_TEMPLATE	"template"
 
 #  define XML_CIB_TAG_LRM		"lrm"
 #  define XML_LRM_TAG_RESOURCES     	"lrm_resources"
 #  define XML_LRM_TAG_RESOURCE     	"lrm_resource"
 #  define XML_LRM_TAG_RSC_OP		"lrm_rsc_op"
 
 #  define XML_NODE_IS_REMOTE    	"remote_node"
 #  define XML_NODE_IS_FENCED		"node_fenced"
 #  define XML_NODE_IS_MAINTENANCE   "node_in_maintenance"
 
 #  define XML_CIB_ATTR_SHUTDOWN       	"shutdown"
 
 #  define XML_TAG_GRAPH			"transition_graph"
 #  define XML_GRAPH_TAG_RSC_OP		"rsc_op"
 #  define XML_GRAPH_TAG_PSEUDO_EVENT	"pseudo_event"
 #  define XML_GRAPH_TAG_CRM_EVENT	"crm_event"
 #  define XML_GRAPH_TAG_DOWNED            "downed"
 #  define XML_GRAPH_TAG_MAINTENANCE       "maintenance"
 
 #  define XML_TAG_RULE			"rule"
 
 #  define XML_TAG_EXPRESSION		"expression"
 
 #  define XML_CONS_TAG_RSC_DEPEND	"rsc_colocation"
 #  define XML_CONS_TAG_RSC_ORDER	"rsc_order"
 #  define XML_CONS_TAG_RSC_LOCATION	"rsc_location"
 #  define XML_CONS_TAG_RSC_TICKET	"rsc_ticket"
 #  define XML_CONS_TAG_RSC_SET		"resource_set"
 
-#  define XML_TICKET_ATTR_LOSS_POLICY	"loss-policy"
+#  define XML_TICKET_ATTR_LOSS_POLICY	PCMK_XA_LOSS_POLICY
 
 #  define XML_NODE_ATTR_RSC_DISCOVERY   "resource-discovery-enabled"
 
 #  define XML_CIB_TAG_GENERATION_TUPPLE	"generation_tuple"
 
 #  define XML_TAG_TRANSIENT_NODEATTRS	"transient_attributes"
 
 #  define XML_ACL_TAG_USER		"acl_target"
 #  define XML_ACL_TAG_USERv1		"acl_user"
 #  define XML_ACL_TAG_GROUP		"acl_group"
 #  define XML_ACL_TAG_ROLE		"acl_role"
 #  define XML_ACL_TAG_PERMISSION	"acl_permission"
 #  define XML_ACL_TAG_ROLE_REFv1	"role_ref"
 #  define XML_ACL_TAG_READ		"read"
 #  define XML_ACL_TAG_WRITE		"write"
 #  define XML_ACL_TAG_DENY		"deny"
 #  define XML_ACL_ATTR_REFv1		"ref"
 #  define XML_ACL_ATTR_TAG		"object-type"
 #  define XML_ACL_ATTR_TAGv1		"tag"
 #  define XML_ACL_ATTR_XPATH		"xpath"
 
 #  define XML_CIB_TAG_TICKETS		"tickets"
 #  define XML_CIB_TAG_TICKET_STATE	"ticket_state"
 
 #  define XML_CIB_TAG_TAGS   		"tags"
 #  define XML_CIB_TAG_TAG   		"tag"
 #  define XML_CIB_TAG_OBJ_REF 		"obj_ref"
 
 #  define XML_TAG_FENCING_TOPOLOGY      "fencing-topology"
 #  define XML_TAG_FENCING_LEVEL         "fencing-level"
 
 #  define XML_TAG_DIFF                  "diff"
 #  define XML_DIFF_VERSION              PCMK_XE_VERSION
 #  define XML_DIFF_VSOURCE              "source"
 #  define XML_DIFF_VTARGET              "target"
 #  define XML_DIFF_CHANGE               "change"
 #  define XML_DIFF_LIST                 "change-list"
 #  define XML_DIFF_ATTR                 "change-attr"
 #  define XML_DIFF_RESULT               "change-result"
 #  define XML_DIFF_POSITION             "position"
 
 #  define ID(x) crm_element_value(x, PCMK_XA_ID)
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif
diff --git a/lib/pacemaker/pcmk_sched_tickets.c b/lib/pacemaker/pcmk_sched_tickets.c
index 475b65edea..0d04258572 100644
--- a/lib/pacemaker/pcmk_sched_tickets.c
+++ b/lib/pacemaker/pcmk_sched_tickets.c
@@ -1,531 +1,530 @@
 /*
  * 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 General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <stdbool.h>
 #include <glib.h>
 
 #include <crm/crm.h>
 #include <crm/common/scheduler_internal.h>
 #include <crm/pengine/status.h>
 #include <pacemaker-internal.h>
 
 #include "libpacemaker_private.h"
 
 enum loss_ticket_policy {
     loss_ticket_stop,
     loss_ticket_demote,
     loss_ticket_fence,
     loss_ticket_freeze
 };
 
 typedef struct {
     const char *id;
     pcmk_resource_t *rsc;
     pcmk_ticket_t *ticket;
     enum loss_ticket_policy loss_policy;
     int role;
 } rsc_ticket_t;
 
 /*!
  * \brief Check whether a ticket constraint matches a resource by role
  *
  * \param[in] rsc_ticket  Ticket constraint
  * \param[in] rsc         Resource to compare with ticket
  *
  * \param[in] true if constraint has no role or resource's role matches
  *            constraint's, otherwise false
  */
 static bool
 ticket_role_matches(const pcmk_resource_t *rsc, const rsc_ticket_t *rsc_ticket)
 {
     if ((rsc_ticket->role == pcmk_role_unknown)
         || (rsc_ticket->role == rsc->role)) {
         return true;
     }
     pcmk__rsc_trace(rsc, "Skipping constraint: \"%s\" state filter",
                     role2text(rsc_ticket->role));
     return false;
 }
 
 /*!
  * \brief Create location constraints and fencing as needed for a ticket
  *
  * \param[in,out] rsc         Resource affected by ticket
  * \param[in]     rsc_ticket  Ticket
  */
 static void
 constraints_for_ticket(pcmk_resource_t *rsc, const rsc_ticket_t *rsc_ticket)
 {
     GList *iter = NULL;
 
     CRM_CHECK((rsc != NULL) && (rsc_ticket != NULL), return);
 
     if (rsc_ticket->ticket->granted && !rsc_ticket->ticket->standby) {
         return;
     }
 
     if (rsc->children) {
         pcmk__rsc_trace(rsc, "Processing ticket dependencies from %s", rsc->id);
         for (iter = rsc->children; iter != NULL; iter = iter->next) {
             constraints_for_ticket((pcmk_resource_t *) iter->data, rsc_ticket);
         }
         return;
     }
 
     pcmk__rsc_trace(rsc, "%s: Processing ticket dependency on %s (%s, %s)",
                     rsc->id, rsc_ticket->ticket->id, rsc_ticket->id,
                     role2text(rsc_ticket->role));
 
     if (!rsc_ticket->ticket->granted && (rsc->running_on != NULL)) {
 
         switch (rsc_ticket->loss_policy) {
             case loss_ticket_stop:
                 resource_location(rsc, NULL, -INFINITY, "__loss_of_ticket__",
                                   rsc->cluster);
                 break;
 
             case loss_ticket_demote:
                 // Promotion score will be set to -INFINITY in promotion_order()
                 if (rsc_ticket->role != pcmk_role_promoted) {
                     resource_location(rsc, NULL, -INFINITY,
                                       "__loss_of_ticket__", rsc->cluster);
                 }
                 break;
 
             case loss_ticket_fence:
                 if (!ticket_role_matches(rsc, rsc_ticket)) {
                     return;
                 }
 
                 resource_location(rsc, NULL, -INFINITY, "__loss_of_ticket__",
                                   rsc->cluster);
 
                 for (iter = rsc->running_on; iter != NULL; iter = iter->next) {
                     pe_fence_node(rsc->cluster, (pcmk_node_t *) iter->data,
                                   "deadman ticket was lost", FALSE);
                 }
                 break;
 
             case loss_ticket_freeze:
                 if (!ticket_role_matches(rsc, rsc_ticket)) {
                     return;
                 }
                 if (rsc->running_on != NULL) {
                     pcmk__clear_rsc_flags(rsc, pcmk_rsc_managed);
                     pcmk__set_rsc_flags(rsc, pcmk_rsc_blocked);
                 }
                 break;
         }
 
     } else if (!rsc_ticket->ticket->granted) {
 
         if ((rsc_ticket->role != pcmk_role_promoted)
             || (rsc_ticket->loss_policy == loss_ticket_stop)) {
             resource_location(rsc, NULL, -INFINITY, "__no_ticket__",
                               rsc->cluster);
         }
 
     } else if (rsc_ticket->ticket->standby) {
 
         if ((rsc_ticket->role != pcmk_role_promoted)
             || (rsc_ticket->loss_policy == loss_ticket_stop)) {
             resource_location(rsc, NULL, -INFINITY, "__ticket_standby__",
                               rsc->cluster);
         }
     }
 }
 
 static void
 rsc_ticket_new(const char *id, pcmk_resource_t *rsc, pcmk_ticket_t *ticket,
                const char *state, const char *loss_policy)
 {
     rsc_ticket_t *new_rsc_ticket = NULL;
 
     if (rsc == NULL) {
         pcmk__config_err("Ignoring ticket '%s' because resource "
                          "does not exist", id);
         return;
     }
 
     new_rsc_ticket = calloc(1, sizeof(rsc_ticket_t));
     if (new_rsc_ticket == NULL) {
         return;
     }
 
     if (pcmk__str_eq(state, PCMK__ROLE_STARTED,
                      pcmk__str_null_matches|pcmk__str_casei)) {
         state = PCMK__ROLE_UNKNOWN;
     }
 
     new_rsc_ticket->id = id;
     new_rsc_ticket->ticket = ticket;
     new_rsc_ticket->rsc = rsc;
     new_rsc_ticket->role = text2role(state);
 
     if (pcmk__str_eq(loss_policy, "fence", pcmk__str_casei)) {
         if (pcmk_is_set(rsc->cluster->flags, pcmk_sched_fencing_enabled)) {
             new_rsc_ticket->loss_policy = loss_ticket_fence;
         } else {
-            pcmk__config_err("Resetting '" XML_TICKET_ATTR_LOSS_POLICY
-                             "' for ticket '%s' to 'stop' "
+            pcmk__config_err("Resetting '" PCMK_XA_LOSS_POLICY "' "
+                             "for ticket '%s' to 'stop' "
                              "because fencing is not configured", ticket->id);
             loss_policy = "stop";
         }
     }
 
     if (new_rsc_ticket->loss_policy == loss_ticket_fence) {
         crm_debug("On loss of ticket '%s': Fence the nodes running %s (%s)",
                   new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
                   role2text(new_rsc_ticket->role));
 
     } else if (pcmk__str_eq(loss_policy, "freeze", pcmk__str_casei)) {
         crm_debug("On loss of ticket '%s': Freeze %s (%s)",
                   new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
                   role2text(new_rsc_ticket->role));
         new_rsc_ticket->loss_policy = loss_ticket_freeze;
 
     } else if (pcmk__str_eq(loss_policy, PCMK_ACTION_DEMOTE, pcmk__str_casei)) {
         crm_debug("On loss of ticket '%s': Demote %s (%s)",
                   new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
                   role2text(new_rsc_ticket->role));
         new_rsc_ticket->loss_policy = loss_ticket_demote;
 
     } else if (pcmk__str_eq(loss_policy, "stop", pcmk__str_casei)) {
         crm_debug("On loss of ticket '%s': Stop %s (%s)",
                   new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
                   role2text(new_rsc_ticket->role));
         new_rsc_ticket->loss_policy = loss_ticket_stop;
 
     } else {
         if (new_rsc_ticket->role == pcmk_role_promoted) {
             crm_debug("On loss of ticket '%s': Default to demote %s (%s)",
                       new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
                       role2text(new_rsc_ticket->role));
             new_rsc_ticket->loss_policy = loss_ticket_demote;
 
         } else {
             crm_debug("On loss of ticket '%s': Default to stop %s (%s)",
                       new_rsc_ticket->ticket->id, new_rsc_ticket->rsc->id,
                       role2text(new_rsc_ticket->role));
             new_rsc_ticket->loss_policy = loss_ticket_stop;
         }
     }
 
     pcmk__rsc_trace(rsc, "%s (%s) ==> %s",
                     rsc->id, role2text(new_rsc_ticket->role), ticket->id);
 
     rsc->rsc_tickets = g_list_append(rsc->rsc_tickets, new_rsc_ticket);
 
     rsc->cluster->ticket_constraints = g_list_append(
         rsc->cluster->ticket_constraints, new_rsc_ticket);
 
     if (!(new_rsc_ticket->ticket->granted) || new_rsc_ticket->ticket->standby) {
         constraints_for_ticket(rsc, new_rsc_ticket);
     }
 }
 
 // \return Standard Pacemaker return code
 static int
 unpack_rsc_ticket_set(xmlNode *set, pcmk_ticket_t *ticket,
                       const char *loss_policy, pcmk_scheduler_t *scheduler)
 {
     const char *set_id = NULL;
     const char *role = NULL;
 
     CRM_CHECK(set != NULL, return EINVAL);
     CRM_CHECK(ticket != NULL, return EINVAL);
 
     set_id = ID(set);
     if (set_id == NULL) {
         pcmk__config_err("Ignoring <" XML_CONS_TAG_RSC_SET "> without "
                          PCMK_XA_ID);
         return pcmk_rc_unpack_error;
     }
 
     role = crm_element_value(set, PCMK_XA_ROLE);
 
     for (xmlNode *xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
          xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
 
         pcmk_resource_t *resource = NULL;
 
         resource = pcmk__find_constraint_resource(scheduler->resources,
                                                   ID(xml_rsc));
         if (resource == NULL) {
             pcmk__config_err("%s: No resource found for %s",
                              set_id, ID(xml_rsc));
             return pcmk_rc_unpack_error;
         }
         pcmk__rsc_trace(resource, "Resource '%s' depends on ticket '%s'",
                         resource->id, ticket->id);
         rsc_ticket_new(set_id, resource, ticket, role, loss_policy);
     }
 
     return pcmk_rc_ok;
 }
 
 static void
 unpack_simple_rsc_ticket(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
 {
     const char *id = NULL;
     const char *ticket_str = crm_element_value(xml_obj, PCMK_XA_TICKET);
-    const char *loss_policy = crm_element_value(xml_obj,
-                                                XML_TICKET_ATTR_LOSS_POLICY);
+    const char *loss_policy = crm_element_value(xml_obj, PCMK_XA_LOSS_POLICY);
 
     pcmk_ticket_t *ticket = NULL;
 
     const char *rsc_id = crm_element_value(xml_obj, PCMK_XA_RSC);
     const char *state = crm_element_value(xml_obj, PCMK_XA_RSC_ROLE);
 
     // @COMPAT: Deprecated since 2.1.5
     const char *instance = crm_element_value(xml_obj, PCMK__XA_RSC_INSTANCE);
 
     pcmk_resource_t *rsc = NULL;
 
     if (instance != NULL) {
         pcmk__warn_once(pcmk__wo_coloc_inst,
                         "Support for " PCMK__XA_RSC_INSTANCE " is deprecated "
                         "and will be removed in a future release");
     }
 
     CRM_CHECK(xml_obj != NULL, return);
 
     id = ID(xml_obj);
     if (id == NULL) {
         pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
                          xml_obj->name);
         return;
     }
 
     if (ticket_str == NULL) {
         pcmk__config_err("Ignoring constraint '%s' without ticket specified",
                          id);
         return;
     } else {
         ticket = g_hash_table_lookup(scheduler->tickets, ticket_str);
     }
 
     if (ticket == NULL) {
         pcmk__config_err("Ignoring constraint '%s' because ticket '%s' "
                          "does not exist", id, ticket_str);
         return;
     }
 
     if (rsc_id == NULL) {
         pcmk__config_err("Ignoring constraint '%s' without resource", id);
         return;
     } else {
         rsc = pcmk__find_constraint_resource(scheduler->resources, rsc_id);
     }
 
     if (rsc == NULL) {
         pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
                          "does not exist", id, rsc_id);
         return;
 
     } else if ((instance != NULL) && !pe_rsc_is_clone(rsc)) {
         pcmk__config_err("Ignoring constraint '%s' because resource '%s' "
                          "is not a clone but instance '%s' was requested",
                          id, rsc_id, instance);
         return;
     }
 
     if (instance != NULL) {
         rsc = find_clone_instance(rsc, instance);
         if (rsc == NULL) {
             pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
                               "does not have an instance '%s'",
                               "'%s'", id, rsc_id, instance);
             return;
         }
     }
 
     rsc_ticket_new(id, rsc, ticket, state, loss_policy);
 }
 
 // \return Standard Pacemaker return code
 static int
 unpack_rsc_ticket_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
                        pcmk_scheduler_t *scheduler)
 {
     const char *id = NULL;
     const char *rsc_id = NULL;
     const char *state = NULL;
 
     pcmk_resource_t *rsc = NULL;
     pcmk_tag_t *tag = NULL;
 
     xmlNode *rsc_set = NULL;
 
     *expanded_xml = NULL;
 
     CRM_CHECK(xml_obj != NULL, return EINVAL);
 
     id = ID(xml_obj);
     if (id == NULL) {
         pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
                          xml_obj->name);
         return pcmk_rc_unpack_error;
     }
 
     // Check whether there are any resource sets with template or tag references
     *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, scheduler);
     if (*expanded_xml != NULL) {
         crm_log_xml_trace(*expanded_xml, "Expanded rsc_ticket");
         return pcmk_rc_ok;
     }
 
     rsc_id = crm_element_value(xml_obj, PCMK_XA_RSC);
     if (rsc_id == NULL) {
         return pcmk_rc_ok;
     }
 
     if (!pcmk__valid_resource_or_tag(scheduler, rsc_id, &rsc, &tag)) {
         pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
                          "valid resource or tag", id, rsc_id);
         return pcmk_rc_unpack_error;
 
     } else if (rsc != NULL) {
         // No template or tag is referenced
         return pcmk_rc_ok;
     }
 
     state = crm_element_value(xml_obj, PCMK_XA_RSC_ROLE);
 
     *expanded_xml = copy_xml(xml_obj);
 
     // Convert any template or tag reference in "rsc" into ticket resource_set
     if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, PCMK_XA_RSC, false,
                           scheduler)) {
         free_xml(*expanded_xml);
         *expanded_xml = NULL;
         return pcmk_rc_unpack_error;
     }
 
     if (rsc_set != NULL) {
         if (state != NULL) {
             /* Move PCMK_XA_RSC_ROLE into converted resource_set as a
              * PCMK_XA_ROLE attribute
              */
             crm_xml_add(rsc_set, PCMK_XA_ROLE, state);
             xml_remove_prop(*expanded_xml, PCMK_XA_RSC_ROLE);
         }
 
     } else {
         free_xml(*expanded_xml);
         *expanded_xml = NULL;
     }
 
     return pcmk_rc_ok;
 }
 
 void
 pcmk__unpack_rsc_ticket(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
 {
     xmlNode *set = NULL;
     bool any_sets = false;
 
     const char *id = NULL;
     const char *ticket_str = NULL;
 
     pcmk_ticket_t *ticket = NULL;
 
     xmlNode *orig_xml = NULL;
     xmlNode *expanded_xml = NULL;
 
     CRM_CHECK(xml_obj != NULL, return);
 
     id = ID(xml_obj);
     if (id == NULL) {
         pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
                          xml_obj->name);
         return;
     }
 
     if (scheduler->tickets == NULL) {
         scheduler->tickets = pcmk__strkey_table(free, destroy_ticket);
     }
 
     ticket_str = crm_element_value(xml_obj, PCMK_XA_TICKET);
     if (ticket_str == NULL) {
         pcmk__config_err("Ignoring constraint '%s' without ticket", id);
         return;
     } else {
         ticket = g_hash_table_lookup(scheduler->tickets, ticket_str);
     }
 
     if (ticket == NULL) {
         ticket = ticket_new(ticket_str, scheduler);
         if (ticket == NULL) {
             return;
         }
     }
 
     if (unpack_rsc_ticket_tags(xml_obj, &expanded_xml,
                                scheduler) != pcmk_rc_ok) {
         return;
     }
     if (expanded_xml != NULL) {
         orig_xml = xml_obj;
         xml_obj = expanded_xml;
     }
 
     for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET); set != NULL;
          set = crm_next_same_xml(set)) {
 
         const char *loss_policy = NULL;
 
         any_sets = true;
         set = expand_idref(set, scheduler->input);
-        loss_policy = crm_element_value(xml_obj, XML_TICKET_ATTR_LOSS_POLICY);
+        loss_policy = crm_element_value(xml_obj, PCMK_XA_LOSS_POLICY);
 
         if ((set == NULL) // Configuration error, message already logged
             || (unpack_rsc_ticket_set(set, ticket, loss_policy,
                                       scheduler) != pcmk_rc_ok)) {
             if (expanded_xml != NULL) {
                 free_xml(expanded_xml);
             }
             return;
         }
     }
 
     if (expanded_xml) {
         free_xml(expanded_xml);
         xml_obj = orig_xml;
     }
 
     if (!any_sets) {
         unpack_simple_rsc_ticket(xml_obj, scheduler);
     }
 }
 
 /*!
  * \internal
  * \brief Ban resource from a node if it doesn't have a promotion ticket
  *
  * If a resource has tickets for the promoted role, and the ticket is either not
  * granted or set to standby, then ban the resource from all nodes.
  *
  * \param[in,out] rsc  Resource to check
  */
 void
 pcmk__require_promotion_tickets(pcmk_resource_t *rsc)
 {
     for (GList *item = rsc->rsc_tickets; item != NULL; item = item->next) {
         rsc_ticket_t *rsc_ticket = (rsc_ticket_t *) item->data;
 
         if ((rsc_ticket->role == pcmk_role_promoted)
             && (!rsc_ticket->ticket->granted || rsc_ticket->ticket->standby)) {
             resource_location(rsc, NULL, -INFINITY,
                               "__stateful_without_ticket__", rsc->cluster);
         }
     }
 }
diff --git a/tools/crm_ticket.c b/tools/crm_ticket.c
index 848c87da4d..06c7eec691 100644
--- a/tools/crm_ticket.c
+++ b/tools/crm_ticket.c
@@ -1,1014 +1,1015 @@
 /*
  * Copyright 2012-2024 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 
 #include <crm/crm.h>
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
 
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/ipc.h>
 #include <crm/common/cmdline_internal.h>
 
 #include <crm/cib.h>
 #include <crm/cib/internal.h>
 #include <crm/pengine/rules.h>
 #include <crm/pengine/status.h>
 #include <crm/pengine/internal.h>
 
 #include <pacemaker-internal.h>
 
 GError *error = NULL;
 
 #define SUMMARY "Perform tasks related to cluster tickets\n\n" \
                 "Allows ticket attributes to be queried, modified and deleted."
 
 struct {
     gchar *attr_default;
     gchar *attr_id;
     char *attr_name;
     char *attr_value;
     gboolean force;
     char *get_attr_name;
     gboolean quiet;
     gchar *set_name;
     char ticket_cmd;
     gchar *ticket_id;
     gchar *xml_file;
 } options = {
     .ticket_cmd = 'S'
 };
 
 GList *attr_delete;
 GHashTable *attr_set;
 bool modified = false;
 int cib_options = cib_sync_call;
 
 #define INDENT "                               "
 
 static gboolean
 attr_value_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     pcmk__str_update(&options.attr_value, optarg);
 
     if (!options.attr_name || !options.attr_value) {
         return TRUE;
     }
 
     g_hash_table_insert(attr_set, strdup(options.attr_name), strdup(options.attr_value));
     pcmk__str_update(&options.attr_name, NULL);
     pcmk__str_update(&options.attr_value, NULL);
 
     modified = true;
 
     return TRUE;
 }
 
 static gboolean
 command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     if (pcmk__str_any_of(option_name, "--info", "-l", NULL)) {
         options.ticket_cmd = 'l';
     } else if (pcmk__str_any_of(option_name, "--details", "-L", NULL)) {
         options.ticket_cmd = 'L';
     } else if (pcmk__str_any_of(option_name, "--raw", "-w", NULL)) {
         options.ticket_cmd = 'w';
     } else if (pcmk__str_any_of(option_name, "--query-xml", "-q", NULL)) {
         options.ticket_cmd = 'q';
     } else if (pcmk__str_any_of(option_name, "--constraints", "-c", NULL)) {
         options.ticket_cmd = 'c';
     } else if (pcmk__str_any_of(option_name, "--cleanup", "-C", NULL)) {
         options.ticket_cmd = 'C';
     }
 
     return TRUE;
 }
 
 static gboolean
 delete_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     attr_delete = g_list_append(attr_delete, strdup(optarg));
     modified = true;
     return TRUE;
 }
 
 static gboolean
 get_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     pcmk__str_update(&options.get_attr_name, optarg);
     options.ticket_cmd = 'G';
     return TRUE;
 }
 
 static gboolean
 grant_standby_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     if (pcmk__str_any_of(option_name, "--grant", "-g", NULL)) {
         g_hash_table_insert(attr_set, strdup("granted"),
                             strdup(PCMK_VALUE_TRUE));
         modified = true;
     } else if (pcmk__str_any_of(option_name, "--revoke", "-r", NULL)) {
         g_hash_table_insert(attr_set, strdup("granted"),
                             strdup(PCMK_VALUE_FALSE));
         modified = true;
     } else if (pcmk__str_any_of(option_name, "--standby", "-s", NULL)) {
         g_hash_table_insert(attr_set, strdup("standby"),
                             strdup(PCMK_VALUE_TRUE));
         modified = true;
     } else if (pcmk__str_any_of(option_name, "--activate", "-a", NULL)) {
         g_hash_table_insert(attr_set, strdup("standby"),
                             strdup(PCMK_VALUE_FALSE));
         modified = true;
     }
 
     return TRUE;
 }
 
 static gboolean
 set_attr_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
     pcmk__str_update(&options.attr_name, optarg);
 
     if (!options.attr_name || !options.attr_value) {
         return TRUE;
     }
 
     g_hash_table_insert(attr_set, strdup(options.attr_name), strdup(options.attr_value));
     pcmk__str_update(&options.attr_name, NULL);
     pcmk__str_update(&options.attr_value, NULL);
 
     modified = true;
 
     return TRUE;
 }
 
 static GOptionEntry query_entries[] = {
     { "info", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
       "Display the information of ticket(s)",
       NULL },
 
     { "details", 'L', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
       "Display the details of ticket(s)",
       NULL },
 
     { "raw", 'w', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
       "Display the IDs of ticket(s)",
       NULL },
 
     { "query-xml", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
       "Query the XML of ticket(s)",
       NULL },
 
     { "constraints", 'c', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
       "Display the rsc_ticket constraints that apply to ticket(s)",
       NULL },
 
     { NULL }
 };
 
 static GOptionEntry command_entries[] = {
     { "grant", 'g', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
       "Grant a ticket to this cluster site",
       NULL },
 
     { "revoke", 'r', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
       "Revoke a ticket from this cluster site",
       NULL },
 
     { "standby", 's', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
       "Tell this cluster site this ticket is standby",
       NULL },
 
     { "activate", 'a', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, grant_standby_cb,
       "Tell this cluster site this ticket is active",
       NULL },
 
     { NULL }
 };
 
 static GOptionEntry advanced_entries[] = {
     { "get-attr", 'G', 0, G_OPTION_ARG_CALLBACK, get_attr_cb,
       "Display the named attribute for a ticket",
       "ATTRIBUTE" },
 
     { "set-attr", 'S', 0, G_OPTION_ARG_CALLBACK, set_attr_cb,
       "Set the named attribute for a ticket",
       "ATTRIBUTE" },
 
     { "delete-attr", 'D', 0, G_OPTION_ARG_CALLBACK, delete_attr_cb,
       "Delete the named attribute for a ticket",
       "ATTRIBUTE" },
 
     { "cleanup", 'C', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
       "Delete all state of a ticket at this cluster site",
       NULL },
 
     { NULL}
 };
 
 static GOptionEntry addl_entries[] = {
     { "attr-value", 'v', 0, G_OPTION_ARG_CALLBACK, attr_value_cb,
       "Attribute value to use with -S",
       "VALUE" },
 
     { "default", 'd', 0, G_OPTION_ARG_STRING, &options.attr_default,
       "(Advanced) Default attribute value to display if none is found\n"
       INDENT "(for use with -G)",
       "VALUE" },
 
     { "force", 'f', 0, G_OPTION_ARG_NONE, &options.force,
       "(Advanced) Force the action to be performed",
       NULL },
 
     { "ticket", 't', 0, G_OPTION_ARG_STRING, &options.ticket_id,
       "Ticket ID",
       "ID" },
 
     { "xml-file", 'x', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &options.xml_file,
       NULL,
       NULL },
 
     { NULL }
 };
 
 static GOptionEntry deprecated_entries[] = {
     { "set-name", 'n', 0, G_OPTION_ARG_STRING, &options.set_name,
       "(Advanced) ID of the instance_attributes object to change",
       "ID" },
 
     { "nvpair", 'i', 0, G_OPTION_ARG_STRING, &options.attr_id,
       "(Advanced) ID of the nvpair object to change/delete",
       "ID" },
 
     { "quiet", 'Q', 0, G_OPTION_ARG_NONE, &options.quiet,
       "Print only the value on stdout",
       NULL },
 
     { NULL }
 };
 
 static pcmk_ticket_t *
 find_ticket(gchar *ticket_id, pcmk_scheduler_t *scheduler)
 {
     return g_hash_table_lookup(scheduler->tickets, ticket_id);
 }
 
 static void
 print_date(time_t time)
 {
     int lpc = 0;
     char date_str[26];
 
     asctime_r(localtime(&time), date_str);
     for (; lpc < 26; lpc++) {
         if (date_str[lpc] == '\n') {
             date_str[lpc] = 0;
         }
     }
     fprintf(stdout, "'%s'", date_str);
 }
 
 static void
 print_ticket(pcmk_ticket_t *ticket, bool raw, bool details)
 {
     if (raw) {
         fprintf(stdout, "%s\n", ticket->id);
         return;
     }
 
     fprintf(stdout, "%s\t%s %s",
             ticket->id, ticket->granted ? "granted" : "revoked",
             ticket->standby ? "[standby]" : "         ");
 
     if (details && g_hash_table_size(ticket->state) > 0) {
         GHashTableIter iter;
         const char *name = NULL;
         const char *value = NULL;
         int lpc = 0;
 
         fprintf(stdout, " (");
 
         g_hash_table_iter_init(&iter, ticket->state);
         while (g_hash_table_iter_next(&iter, (void **)&name, (void **)&value)) {
             if (lpc > 0) {
                 fprintf(stdout, ", ");
             }
             fprintf(stdout, "%s=", name);
             if (pcmk__str_any_of(name, "last-granted", "expires", NULL)) {
                 long long time_ll;
 
                 pcmk__scan_ll(value, &time_ll, 0);
                 print_date((time_t) time_ll);
             } else {
                 fprintf(stdout, "%s", value);
             }
             lpc++;
         }
 
         fprintf(stdout, ")\n");
 
     } else {
         if (ticket->last_granted > -1) {
             fprintf(stdout, " last-granted=");
             print_date(ticket->last_granted);
         }
         fprintf(stdout, "\n");
     }
 
     return;
 }
 
 static void
 print_ticket_list(pcmk_scheduler_t *scheduler, bool raw, bool details)
 {
     GHashTableIter iter;
     pcmk_ticket_t *ticket = NULL;
 
     g_hash_table_iter_init(&iter, scheduler->tickets);
 
     while (g_hash_table_iter_next(&iter, NULL, (void **)&ticket)) {
         print_ticket(ticket, raw, details);
     }
 }
 
 static int
 find_ticket_state(cib_t * the_cib, gchar *ticket_id, xmlNode ** ticket_state_xml)
 {
     int rc = pcmk_rc_ok;
     xmlNode *xml_search = NULL;
 
     GString *xpath = NULL;
 
     CRM_ASSERT(ticket_state_xml != NULL);
     *ticket_state_xml = NULL;
 
     xpath = g_string_sized_new(1024);
     g_string_append(xpath,
                     "/" XML_TAG_CIB "/" XML_CIB_TAG_STATUS
                     "/" XML_CIB_TAG_TICKETS);
 
     if (ticket_id != NULL) {
         pcmk__g_strcat(xpath,
                        "/" XML_CIB_TAG_TICKET_STATE
                        "[@" PCMK_XA_ID "=\"", ticket_id, "\"]", NULL);
     }
 
     rc = the_cib->cmds->query(the_cib, (const char *) xpath->str, &xml_search,
                               cib_sync_call | cib_scope_local | cib_xpath);
     rc = pcmk_legacy2rc(rc);
     g_string_free(xpath, TRUE);
 
     if (rc != pcmk_rc_ok) {
         return rc;
     }
 
     crm_log_xml_debug(xml_search, "Match");
     if (xml_search->children != NULL) {
         if (ticket_id) {
             fprintf(stdout, "Multiple ticket_states match ticket_id=%s\n", ticket_id);
         }
         *ticket_state_xml = xml_search;
     } else {
         *ticket_state_xml = xml_search;
     }
     return rc;
 }
 
 static int
 find_ticket_constraints(cib_t * the_cib, gchar *ticket_id, xmlNode ** ticket_cons_xml)
 {
     int rc = pcmk_rc_ok;
     xmlNode *xml_search = NULL;
 
     GString *xpath = NULL;
     const char *xpath_base = NULL;
 
     CRM_ASSERT(ticket_cons_xml != NULL);
     *ticket_cons_xml = NULL;
 
     xpath_base = pcmk_cib_xpath_for(XML_CIB_TAG_CONSTRAINTS);
     if (xpath_base == NULL) {
         crm_err(XML_CIB_TAG_CONSTRAINTS " CIB element not known (bug?)");
         return -ENOMSG;
     }
 
     xpath = g_string_sized_new(1024);
     pcmk__g_strcat(xpath, xpath_base, "/" XML_CONS_TAG_RSC_TICKET, NULL);
 
     if (ticket_id != NULL) {
         pcmk__g_strcat(xpath, "[@" PCMK_XA_TICKET "=\"", ticket_id, "\"]",
                        NULL);
     }
 
     rc = the_cib->cmds->query(the_cib, (const char *) xpath->str, &xml_search,
                               cib_sync_call | cib_scope_local | cib_xpath);
     rc = pcmk_legacy2rc(rc);
     g_string_free(xpath, TRUE);
 
     if (rc != pcmk_rc_ok) {
         return rc;
     }
 
     crm_log_xml_debug(xml_search, "Match");
     *ticket_cons_xml = xml_search;
 
     return rc;
 }
 
 static int
 dump_ticket_xml(cib_t * the_cib, gchar *ticket_id)
 {
     int rc = pcmk_rc_ok;
     xmlNode *state_xml = NULL;
 
     rc = find_ticket_state(the_cib, ticket_id, &state_xml);
 
     if (state_xml == NULL) {
         return rc;
     }
 
     fprintf(stdout, "State XML:\n");
     if (state_xml) {
         char *state_xml_str = NULL;
 
         state_xml_str = dump_xml_formatted(state_xml);
         fprintf(stdout, "\n%s", state_xml_str);
         free_xml(state_xml);
         free(state_xml_str);
     }
 
     return rc;
 }
 
 static int
 dump_constraints(cib_t * the_cib, gchar *ticket_id)
 {
     int rc = pcmk_rc_ok;
     xmlNode *cons_xml = NULL;
     char *cons_xml_str = NULL;
 
     rc = find_ticket_constraints(the_cib, ticket_id, &cons_xml);
 
     if (cons_xml == NULL) {
         return rc;
     }
 
     cons_xml_str = dump_xml_formatted(cons_xml);
     fprintf(stdout, "Constraints XML:\n\n%s", cons_xml_str);
     free_xml(cons_xml);
     free(cons_xml_str);
 
     return rc;
 }
 
 static int
 get_ticket_state_attr(gchar *ticket_id, const char *attr_name, const char **attr_value,
                       pcmk_scheduler_t *scheduler)
 {
     pcmk_ticket_t *ticket = NULL;
 
     CRM_ASSERT(attr_value != NULL);
     *attr_value = NULL;
 
     ticket = g_hash_table_lookup(scheduler->tickets, ticket_id);
     if (ticket == NULL) {
         return ENXIO;
     }
 
     *attr_value = g_hash_table_lookup(ticket->state, attr_name);
     if (*attr_value == NULL) {
         return ENXIO;
     }
 
     return pcmk_rc_ok;
 }
 
 static void
 ticket_warning(gchar *ticket_id, const char *action)
 {
     GString *warning = g_string_sized_new(1024);
     const char *word = NULL;
 
     CRM_ASSERT(action != NULL);
 
     if (strcmp(action, "grant") == 0) {
         pcmk__g_strcat(warning,
                        "This command cannot help you verify whether '",
                        ticket_id,
                        "' has been already granted elsewhere.\n", NULL);
         word = "to";
 
     } else {
         pcmk__g_strcat(warning,
                        "Revoking '", ticket_id, "' can trigger the specified "
-                       "'loss-policy'(s) relating to '", ticket_id, "'.\n\n"
+                       "'" PCMK_XA_LOSS_POLICY "'(s) "
+                       "relating to '", ticket_id, "'.\n\n"
                        "You can check that with:\n"
                        "crm_ticket --ticket ", ticket_id, " --constraints\n\n"
                        "Otherwise before revoking '", ticket_id, "', "
                        "you may want to make '", ticket_id, "' "
                        "standby with:\n"
                        "crm_ticket --ticket ", ticket_id, " --standby\n\n",
                        NULL);
         word = "from";
     }
 
     pcmk__g_strcat(warning,
                    "If you really want to ", action, " '", ticket_id, "' ",
                    word, " this site now, and you know what you are doing,\n"
                    "please specify --force.", NULL);
 
     fprintf(stdout, "%s\n", (const char *) warning->str);
 
     g_string_free(warning, TRUE);
 }
 
 static bool
 allow_modification(gchar *ticket_id)
 {
     const char *value = NULL;
     GList *list_iter = NULL;
 
     if (options.force) {
         return true;
     }
 
     if (g_hash_table_lookup_extended(attr_set, "granted", NULL, (gpointer *) & value)) {
         if (crm_is_true(value)) {
             ticket_warning(ticket_id, "grant");
             return false;
 
         } else {
             ticket_warning(ticket_id, "revoke");
             return false;
         }
     }
 
     for(list_iter = attr_delete; list_iter; list_iter = list_iter->next) {
         const char *key = (const char *)list_iter->data;
 
         if (pcmk__str_eq(key, "granted", pcmk__str_casei)) {
             ticket_warning(ticket_id, "revoke");
             return false;
         }
     }
 
     return true;
 }
 
 static int
 modify_ticket_state(gchar *ticket_id, cib_t *cib, pcmk_scheduler_t *scheduler)
 {
     int rc = pcmk_rc_ok;
     xmlNode *xml_top = NULL;
     xmlNode *ticket_state_xml = NULL;
     bool found = false;
 
     GList *list_iter = NULL;
     GHashTableIter hash_iter;
 
     char *key = NULL;
     char *value = NULL;
 
     pcmk_ticket_t *ticket = NULL;
 
     rc = find_ticket_state(cib, ticket_id, &ticket_state_xml);
     if (rc == pcmk_rc_ok) {
         crm_debug("Found a match state for ticket: id=%s", ticket_id);
         xml_top = ticket_state_xml;
         found = true;
 
     } else if (rc != ENXIO) {
         return rc;
 
     } else if (g_hash_table_size(attr_set) == 0){
         return pcmk_rc_ok;
 
     } else {
         xmlNode *xml_obj = NULL;
 
         xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS);
         xml_obj = create_xml_node(xml_top, XML_CIB_TAG_TICKETS);
         ticket_state_xml = create_xml_node(xml_obj, XML_CIB_TAG_TICKET_STATE);
         crm_xml_add(ticket_state_xml, PCMK_XA_ID, ticket_id);
     }
 
     for(list_iter = attr_delete; list_iter; list_iter = list_iter->next) {
         const char *key = (const char *)list_iter->data;
         xml_remove_prop(ticket_state_xml, key);
     }
 
     ticket = find_ticket(ticket_id, scheduler);
 
     g_hash_table_iter_init(&hash_iter, attr_set);
     while (g_hash_table_iter_next(&hash_iter, (gpointer *) & key, (gpointer *) & value)) {
         crm_xml_add(ticket_state_xml, key, value);
 
         if (pcmk__str_eq(key, "granted", pcmk__str_casei)
             && (ticket == NULL || ticket->granted == FALSE)
             && crm_is_true(value)) {
 
             char *now = pcmk__ttoa(time(NULL));
 
             crm_xml_add(ticket_state_xml, "last-granted", now);
             free(now);
         }
     }
 
     if (found && (attr_delete != NULL)) {
         crm_log_xml_debug(xml_top, "Replace");
         rc = cib->cmds->replace(cib, XML_CIB_TAG_STATUS, ticket_state_xml, cib_options);
         rc = pcmk_legacy2rc(rc);
 
     } else {
         crm_log_xml_debug(xml_top, "Update");
         rc = cib->cmds->modify(cib, XML_CIB_TAG_STATUS, xml_top, cib_options);
         rc = pcmk_legacy2rc(rc);
     }
 
     free_xml(xml_top);
     return rc;
 }
 
 static int
 delete_ticket_state(gchar *ticket_id, cib_t * cib)
 {
     xmlNode *ticket_state_xml = NULL;
 
     int rc = pcmk_rc_ok;
 
     rc = find_ticket_state(cib, ticket_id, &ticket_state_xml);
 
     if (rc == ENXIO) {
         return pcmk_rc_ok;
 
     } else if (rc != pcmk_rc_ok) {
         return rc;
     }
 
     crm_log_xml_debug(ticket_state_xml, "Delete");
 
     rc = cib->cmds->remove(cib, XML_CIB_TAG_STATUS, ticket_state_xml, cib_options);
     rc = pcmk_legacy2rc(rc);
 
     if (rc == pcmk_rc_ok) {
         fprintf(stdout, "Cleaned up %s\n", ticket_id);
     }
 
     free_xml(ticket_state_xml);
     return rc;
 }
 
 static GOptionContext *
 build_arg_context(pcmk__common_args_t *args) {
     GOptionContext *context = NULL;
 
     const char *description = "Examples:\n\n"
                               "Display the info of tickets:\n\n"
                               "\tcrm_ticket --info\n\n"
                               "Display the detailed info of tickets:\n\n"
                               "\tcrm_ticket --details\n\n"
                               "Display the XML of 'ticketA':\n\n"
                               "\tcrm_ticket --ticket ticketA --query-xml\n\n"
                               "Display the rsc_ticket constraints that apply to 'ticketA':\n\n"
                               "\tcrm_ticket --ticket ticketA --constraints\n\n"
                               "Grant 'ticketA' to this cluster site:\n\n"
                               "\tcrm_ticket --ticket ticketA --grant\n\n"
                               "Revoke 'ticketA' from this cluster site:\n\n"
                               "\tcrm_ticket --ticket ticketA --revoke\n\n"
                               "Make 'ticketA' standby (the cluster site will treat a granted\n"
                               "'ticketA' as 'standby', and the dependent resources will be\n"
                               "stopped or demoted gracefully without triggering loss-policies):\n\n"
                               "\tcrm_ticket --ticket ticketA --standby\n\n"
                               "Activate 'ticketA' from being standby:\n\n"
                               "\tcrm_ticket --ticket ticketA --activate\n\n"
                               "Get the value of the 'granted' attribute for 'ticketA':\n\n"
                               "\tcrm_ticket --ticket ticketA --get-attr granted\n\n"
                               "Set the value of the 'standby' attribute for 'ticketA':\n\n"
                               "\tcrm_ticket --ticket ticketA --set-attr standby --attr-value true\n\n"
                               "Delete the 'granted' attribute for 'ticketA':\n\n"
                               "\tcrm_ticket --ticket ticketA --delete-attr granted\n\n"
                               "Erase the operation history of 'ticketA' at this cluster site,\n"
                               "causing the cluster site to 'forget' the existing ticket state:\n\n"
                               "\tcrm_ticket --ticket ticketA --cleanup\n\n";
 
     context = pcmk__build_arg_context(args, NULL, NULL, NULL);
     g_option_context_set_description(context, description);
 
     pcmk__add_arg_group(context, "queries", "Queries:",
                         "Show queries", query_entries);
     pcmk__add_arg_group(context, "commands", "Commands:",
                         "Show command options", command_entries);
     pcmk__add_arg_group(context, "advanced", "Advanced Options:",
                         "Show advanced options", advanced_entries);
     pcmk__add_arg_group(context, "additional", "Additional Options:",
                         "Show additional options", addl_entries);
     pcmk__add_arg_group(context, "deprecated", "Deprecated Options:",
                         "Show deprecated options", deprecated_entries);
 
     return context;
 }
 
 int
 main(int argc, char **argv)
 {
     pcmk_scheduler_t *scheduler = NULL;
     xmlNode *cib_xml_copy = NULL;
 
     cib_t *cib_conn = NULL;
     crm_exit_t exit_code = CRM_EX_OK;
     int rc = pcmk_rc_ok;
 
     pcmk__common_args_t *args = NULL;
     GOptionContext *context = NULL;
     gchar **processed_args = NULL;
 
     attr_set = pcmk__strkey_table(free, free);
     attr_delete = NULL;
 
     args = pcmk__new_common_args(SUMMARY);
     context = build_arg_context(args);
     processed_args = pcmk__cmdline_preproc(argv, "dintvxCDGS");
 
     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
         exit_code = CRM_EX_USAGE;
         goto done;
     }
 
     pcmk__cli_init_logging("crm_ticket", args->verbosity);
 
     if (args->version) {
         g_strfreev(processed_args);
         pcmk__free_arg_context(context);
         /* FIXME:  When crm_ticket is converted to use formatted output, this can go. */
         pcmk__cli_help('v');
     }
 
     scheduler = pe_new_working_set();
     if (scheduler == NULL) {
         rc = errno;
         exit_code = pcmk_rc2exitc(rc);
         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                     "Could not allocate scheduler data: %s", pcmk_rc_str(rc));
         goto done;
     }
     pcmk__set_scheduler_flags(scheduler,
                               pcmk_sched_no_counts|pcmk_sched_no_compat);
 
     cib_conn = cib_new();
     if (cib_conn == NULL) {
         exit_code = CRM_EX_DISCONNECT;
         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not connect to the CIB manager");
         goto done;
     }
 
     rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
     rc = pcmk_legacy2rc(rc);
 
     if (rc != pcmk_rc_ok) {
         exit_code = pcmk_rc2exitc(rc);
         g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not connect to the CIB: %s",
                     pcmk_rc_str(rc));
         goto done;
     }
 
     if (options.xml_file != NULL) {
         cib_xml_copy = filename2xml(options.xml_file);
 
     } else {
         rc = cib_conn->cmds->query(cib_conn, NULL, &cib_xml_copy, cib_scope_local | cib_sync_call);
         rc = pcmk_legacy2rc(rc);
 
         if (rc != pcmk_rc_ok) {
             exit_code = pcmk_rc2exitc(rc);
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Could not get local CIB: %s",
                         pcmk_rc_str(rc));
             goto done;
         }
     }
 
     if (!cli_config_update(&cib_xml_copy, NULL, FALSE)) {
         exit_code = CRM_EX_CONFIG;
         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                     "Could not update local CIB to latest schema version");
         goto done;
     }
 
     scheduler->input = cib_xml_copy;
     scheduler->now = crm_time_new(NULL);
 
     cluster_status(scheduler);
 
     /* For recording the tickets that are referenced in rsc_ticket constraints
      * but have never been granted yet. */
     pcmk__unpack_constraints(scheduler);
 
     if (options.ticket_cmd == 'l' || options.ticket_cmd == 'L' || options.ticket_cmd == 'w') {
         bool raw = false;
         bool details = false;
 
         if (options.ticket_cmd == 'L') {
             details = true;
         } else if (options.ticket_cmd == 'w') {
             raw = true;
         }
 
         if (options.ticket_id) {
             pcmk_ticket_t *ticket = find_ticket(options.ticket_id, scheduler);
 
             if (ticket == NULL) {
                 exit_code = CRM_EX_NOSUCH;
                 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                             "No such ticket '%s'", options.ticket_id);
                 goto done;
             }
             print_ticket(ticket, raw, details);
 
         } else {
             print_ticket_list(scheduler, raw, details);
         }
 
     } else if (options.ticket_cmd == 'q') {
         rc = dump_ticket_xml(cib_conn, options.ticket_id);
         exit_code = pcmk_rc2exitc(rc);
 
         if (rc != pcmk_rc_ok) {
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Could not query ticket XML: %s", pcmk_rc_str(rc));
         }
 
     } else if (options.ticket_cmd == 'c') {
         rc = dump_constraints(cib_conn, options.ticket_id);
         exit_code = pcmk_rc2exitc(rc);
 
         if (rc != pcmk_rc_ok) {
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Could not show ticket constraints: %s", pcmk_rc_str(rc));
         }
 
     } else if (options.ticket_cmd == 'G') {
         const char *value = NULL;
 
         if (options.ticket_id == NULL) {
             exit_code = CRM_EX_NOSUCH;
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Must supply ticket ID with -t");
             goto done;
         }
 
         rc = get_ticket_state_attr(options.ticket_id, options.get_attr_name,
                                    &value, scheduler);
         if (rc == pcmk_rc_ok) {
             fprintf(stdout, "%s\n", value);
         } else if (rc == ENXIO && options.attr_default) {
             fprintf(stdout, "%s\n", options.attr_default);
             rc = pcmk_rc_ok;
         }
         exit_code = pcmk_rc2exitc(rc);
 
     } else if (options.ticket_cmd == 'C') {
         if (options.ticket_id == NULL) {
             exit_code = CRM_EX_USAGE;
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Must supply ticket ID with -t");
             goto done;
         }
 
         if (options.force == FALSE) {
             pcmk_ticket_t *ticket = NULL;
 
             ticket = find_ticket(options.ticket_id, scheduler);
             if (ticket == NULL) {
                 exit_code = CRM_EX_NOSUCH;
                 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                             "No such ticket '%s'", options.ticket_id);
                 goto done;
             }
 
             if (ticket->granted) {
                 ticket_warning(options.ticket_id, "revoke");
                 exit_code = CRM_EX_INSUFFICIENT_PRIV;
                 goto done;
             }
         }
 
         rc = delete_ticket_state(options.ticket_id, cib_conn);
         exit_code = pcmk_rc2exitc(rc);
 
         if (rc != pcmk_rc_ok) {
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Could not clean up ticket: %s", pcmk_rc_str(rc));
         }
 
     } else if (modified) {
         if (options.ticket_id == NULL) {
             exit_code = CRM_EX_USAGE;
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Must supply ticket ID with -t");
             goto done;
         }
 
         if (options.attr_value
             && (pcmk__str_empty(options.attr_name))) {
             exit_code = CRM_EX_USAGE;
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Must supply attribute name with -S for -v %s", options.attr_value);
             goto done;
         }
 
         if (options.attr_name
             && (pcmk__str_empty(options.attr_value))) {
             exit_code = CRM_EX_USAGE;
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Must supply attribute value with -v for -S %s", options.attr_value);
             goto done;
         }
 
         if (!allow_modification(options.ticket_id)) {
             exit_code = CRM_EX_INSUFFICIENT_PRIV;
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Ticket modification not allowed");
             goto done;
         }
 
         rc = modify_ticket_state(options.ticket_id, cib_conn, scheduler);
         exit_code = pcmk_rc2exitc(rc);
 
         if (rc != pcmk_rc_ok) {
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Could not modify ticket: %s", pcmk_rc_str(rc));
         }
 
     } else if (options.ticket_cmd == 'S') {
         /* Correct usage was handled in the "if (modified)" block above, so
          * this is just for reporting usage errors
          */
 
         if (pcmk__str_empty(options.attr_name)) {
             // We only get here if ticket_cmd was left as default
             exit_code = CRM_EX_USAGE;
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Must supply a command");
             goto done;
         }
 
         if (options.ticket_id == NULL) {
             exit_code = CRM_EX_USAGE;
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Must supply ticket ID with -t");
             goto done;
         }
 
         if (pcmk__str_empty(options.attr_value)) {
             exit_code = CRM_EX_USAGE;
             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                         "Must supply value with -v for -S %s", options.attr_name);
             goto done;
         }
 
     } else {
         exit_code = CRM_EX_USAGE;
         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
                     "Unknown command: %c", options.ticket_cmd);
     }
 
  done:
     if (attr_set) {
         g_hash_table_destroy(attr_set);
     }
     attr_set = NULL;
 
     if (attr_delete) {
         g_list_free_full(attr_delete, free);
     }
     attr_delete = NULL;
 
     pe_free_working_set(scheduler);
     scheduler = NULL;
 
     cib__clean_up_connection(&cib_conn);
 
     g_strfreev(processed_args);
     pcmk__free_arg_context(context);
     g_free(options.attr_default);
     g_free(options.attr_id);
     free(options.attr_name);
     free(options.attr_value);
     free(options.get_attr_name);
     g_free(options.set_name);
     g_free(options.ticket_id);
     g_free(options.xml_file);
 
     pcmk__output_and_clear_error(&error, NULL);
 
     crm_exit(exit_code);
 }