///|
/// Strictly parses a Relationships part for a byte-preserving mutation under
/// the caller's cumulative budget. Semantic readers may consume the effective
/// MCE projection, but a writer that replaces or splices the raw part must not
/// silently discard consumer-specific branches. Resource failures retain their
/// typed XML error; malformed or compatibility-dependent input fails closed.
fn read_mutation_relationships(
  part : String,
  bytes : BytesView,
  xml_budget : @xml.XmlReadBudget,
) -> XmlElement raise DocxError {
  let (raw_root, root) = @opc.read_opc_relationships_xml_with_roots_limited(
    bytes, xml_budget,
  ) catch {
    ResourceLimit(..) as error => raise error
    InvalidXml(message~) => {
      if message == "XML source is not valid UTF-8" {
        raise Unsupported(message="'\{part}' is not UTF-8; refusing")
      }
      raise Unsupported(message="'\{part}' is not well-formed XML; refusing")
    }
    _ => raise Unsupported(message="'\{part}' is not well-formed XML; refusing")
  }
  if root.name != PACKAGE_RELATIONSHIPS_ROOT {
    raise Unsupported(
      message="'\{part}' has root '\{root.name}', expected '\{PACKAGE_RELATIONSHIPS_ROOT}'; refusing",
    )
  }
  if raw_root.name != PACKAGE_RELATIONSHIPS_ROOT {
    raise Unsupported(
      message="'\{part}' selects its Relationships root through Markup Compatibility; byte-preserving mutation is unsupported; refusing",
    )
  }
  if relationship_tree_contains_mce_markup(raw_root) {
    raise Unsupported(
      message="'\{part}' contains Markup Compatibility branches or directives; byte-preserving relationship mutation is unsupported; refusing",
    )
  }
  root
}

///|
/// A direct insertion or whole-part rewrite becomes visible beside a different
/// set of preserved children for each MCE-aware consumer. Refuse that edit when
/// the raw tree contains active MCE markup; an unused namespace declaration is
/// represented in the XMLNS namespace and is intentionally harmless.
fn relationship_tree_contains_mce_markup(element : XmlElement) -> Bool {
  let mce_prefix = "{\{MC_NAMESPACE}}"
  if element.name.has_prefix(mce_prefix) {
    return true
  }
  for name, _ in element.attributes {
    if name.has_prefix(mce_prefix) {
      return true
    }
  }
  for child in element.children {
    match child {
      XmlElement(inner) =>
        if relationship_tree_contains_mce_markup(inner) {
          return true
        }
      XmlText(_) => ()
    }
  }
  false
}