<?xml version="1.0" encoding="UTF-8"?>
<!--
  HarnessXML 1.0 — XML Schema for Executable Intelligent System Workflows

  Copyright 2026 VisML.
  SPDX-License-Identifier: Apache-2.0

  Canonical location: https://harnessxml.com/schema/v1.0/harnessxml-1.0.xsd
  Specification:      https://harnessxml.com/spec/v1.0/

  This schema is NORMATIVE for document structure. It is deliberately not the
  whole story: rules that XSD 1.0 cannot express (acyclicity of control flow,
  reachability, expression well-formedness, type compatibility across a data
  edge) are normative in the specification text and are checked by a conforming
  validator. Each such rule carries an HX-nnnn code — see spec/v1.0 §Validation.

  Structural rules ARE expressed here where XSD can carry them, including
  referential integrity between edges, nodes, resources and artifacts via
  xs:key / xs:keyref, so that a plain schema-validating parser already rejects
  a dangling reference.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:hx="https://harnessxml.com/spec/1.0"
           targetNamespace="https://harnessxml.com/spec/1.0"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified"
           version="1.0">

  <!-- ===================================================================
       Simple types
       =================================================================== -->

  <xs:simpleType name="Identifier">
    <xs:annotation><xs:documentation>
      Document-unique identifier. Constrained to a leading letter or underscore
      followed by letters, digits, underscore, hyphen or dot, so that an id is
      usable unmodified as an identifier in every target language an SDK might
      generate — and so it never needs escaping in an expression.
    </xs:documentation></xs:annotation>
    <xs:restriction base="xs:string">
      <xs:pattern value="[A-Za-z_][A-Za-z0-9_.\-]*"/>
      <xs:maxLength value="255"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Expression">
    <xs:annotation><xs:documentation>
      An expression in the HarnessXML expression language. Interpolated forms
      are wrapped in ${ }. See spec/v1.0 §Expressions. Not validated here —
      well-formedness is HX-3101, checked by the validator.
    </xs:documentation></xs:annotation>
    <xs:restriction base="xs:string"/>
  </xs:simpleType>

  <xs:simpleType name="Duration">
    <xs:annotation><xs:documentation>
      ISO 8601 duration, e.g. PT30S, PT5M, PT2H, P1D. Months and years are
      forbidden (HX-3401) because their length is not fixed and a scheduler
      cannot resolve them deterministically.
    </xs:documentation></xs:annotation>
    <xs:restriction base="xs:duration">
      <xs:pattern value="P(\d+D)?(T(\d+H)?(\d+M)?(\d+(\.\d+)?S)?)?"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="SpecVersion">
    <xs:restriction base="xs:string">
      <xs:pattern value="1\.\d+"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="NodeType">
    <xs:annotation><xs:documentation>
      CLOSED enumeration. A new node type is a minor-version addition (an
      implementation meeting an unknown type MUST fail with HX-1003, never
      skip the node). See GOVERNANCE §5.
    </xs:documentation></xs:annotation>
    <xs:restriction base="xs:string">
      <xs:enumeration value="task">
        <xs:annotation><xs:documentation>Generic unit of executable work.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="inference">
        <xs:annotation><xs:documentation>Invocation of a model resource.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="transform">
        <xs:annotation><xs:documentation>Pure function of its inputs. No side effects, therefore freely retryable and cacheable.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="decision">
        <xs:annotation><xs:documentation>Evaluates cases and routes control to exactly one successor.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="loop">
        <xs:annotation><xs:documentation>Repeats a body node.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="parallel">
        <xs:annotation><xs:documentation>Fans control out to all successors at once.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="barrier">
        <xs:annotation><xs:documentation>Join. Waits per its joinPolicy before releasing control.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="subworkflow">
        <xs:annotation><xs:documentation>Invokes another HarnessXML document.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="source">
        <xs:annotation><xs:documentation>Boundary node producing data into the workflow.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="sink">
        <xs:annotation><xs:documentation>Boundary node consuming data out of the workflow.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="wait">
        <xs:annotation><xs:documentation>Blocks on a duration or an external event.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="human">
        <xs:annotation><xs:documentation>Human-in-the-loop. Blocks for an out-of-band decision.</xs:documentation></xs:annotation>
      </xs:enumeration>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="EdgeType">
    <xs:annotation><xs:documentation>
      Typed relationship. The type determines what the edge means to the
      scheduler — this is the core of the execution model, not decoration.
    </xs:documentation></xs:annotation>
    <xs:restriction base="xs:string">
      <xs:enumeration value="control">
        <xs:annotation><xs:documentation>Ordering. Target becomes READY when the source reaches a terminal successful state.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="data">
        <xs:annotation><xs:documentation>Dataflow. Implies control, and additionally binds an output port to an input port.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="dependency">
        <xs:annotation><xs:documentation>Must-complete-before with no data transfer and no implied success — satisfied by any terminal state.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="error">
        <xs:annotation><xs:documentation>Taken only when the source reaches FAILED after retries are exhausted.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="compensation">
        <xs:annotation><xs:documentation>Rollback path. Traversed backwards during compensation, never during forward execution.</xs:documentation></xs:annotation>
      </xs:enumeration>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="ResourceType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="model"/>
      <xs:enumeration value="compute"/>
      <xs:enumeration value="datastore"/>
      <xs:enumeration value="queue"/>
      <xs:enumeration value="device"/>
      <xs:enumeration value="service"/>
      <xs:enumeration value="secretstore"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="ArtifactType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="dataset"/>
      <xs:enumeration value="model"/>
      <xs:enumeration value="document"/>
      <xs:enumeration value="image"/>
      <xs:enumeration value="binary"/>
      <xs:enumeration value="config"/>
      <xs:enumeration value="log"/>
      <xs:enumeration value="report"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="BackoffStrategy">
    <xs:restriction base="xs:string">
      <xs:enumeration value="none"/>
      <xs:enumeration value="fixed"/>
      <xs:enumeration value="linear"/>
      <xs:enumeration value="exponential"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="LoopKind">
    <xs:restriction base="xs:string">
      <xs:enumeration value="forEach"/>
      <xs:enumeration value="while"/>
      <xs:enumeration value="until"/>
      <xs:enumeration value="times"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="JoinPolicy">
    <xs:restriction base="xs:string">
      <xs:enumeration value="all">
        <xs:annotation><xs:documentation>Wait for every incoming edge. The default.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="any">
        <xs:annotation><xs:documentation>Release on the first. Siblings still in flight are CANCELLED.</xs:documentation></xs:annotation>
      </xs:enumeration>
      <xs:enumeration value="quorum">
        <xs:annotation><xs:documentation>Release when @quorum incoming edges are satisfied.</xs:documentation></xs:annotation>
      </xs:enumeration>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Classification">
    <xs:restriction base="xs:string">
      <xs:enumeration value="public"/>
      <xs:enumeration value="internal"/>
      <xs:enumeration value="confidential"/>
      <xs:enumeration value="restricted"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="DataType">
    <xs:annotation><xs:documentation>
      Port type. OPEN-ENDED: the listed values are the interoperable core, and
      an implementation MAY use a URI or a qualified name for a domain type.
      Compatibility across a data edge is HX-3201.
    </xs:documentation></xs:annotation>
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- ===================================================================
       Shared building blocks
       =================================================================== -->

  <xs:complexType name="Property">
    <xs:attribute name="name" type="hx:Identifier" use="required"/>
    <xs:attribute name="value" type="xs:string" use="required"/>
  </xs:complexType>

  <xs:complexType name="Extension">
    <xs:annotation><xs:documentation>
      Vendor extension point. See GOVERNANCE §6. required="true" means a
      runtime that does not understand this extension MUST refuse to execute
      the document (HX-1004) rather than execute it differently.
    </xs:documentation></xs:annotation>
    <xs:sequence>
      <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:attribute name="namespace" type="xs:anyURI" use="required"/>
    <xs:attribute name="required" type="xs:boolean" default="false"/>
  </xs:complexType>

  <xs:complexType name="Security">
    <xs:sequence>
      <xs:element name="permission" minOccurs="0" maxOccurs="unbounded">
        <xs:complexType>
          <xs:attribute name="action" type="xs:string" use="required"/>
          <xs:attribute name="resource" type="xs:string" use="required"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
    <xs:attribute name="principal" type="xs:string"/>
    <xs:attribute name="classification" type="hx:Classification"/>
    <xs:attribute name="isolation" type="xs:string">
      <xs:annotation><xs:documentation>Requested execution isolation, e.g. "process", "container", "vm". Advisory; a runtime that cannot honour it MUST fail rather than downgrade silently (HX-4201).</xs:documentation></xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <xs:complexType name="Retry">
    <xs:annotation><xs:documentation>
      Retry policy. Absent means no retry. A node with side effects that is not
      idempotent SHOULD declare idempotent="false" on the node so that a
      runtime can refuse to retry it rather than duplicate the effect.
    </xs:documentation></xs:annotation>
    <xs:attribute name="maxAttempts" use="required">
      <xs:simpleType>
        <xs:restriction base="xs:positiveInteger">
          <xs:maxInclusive value="1000"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:attribute>
    <xs:attribute name="backoff" type="hx:BackoffStrategy" default="exponential"/>
    <xs:attribute name="initialDelay" type="hx:Duration" default="PT1S"/>
    <xs:attribute name="maxDelay" type="hx:Duration"/>
    <xs:attribute name="multiplier" type="xs:decimal" default="2"/>
    <xs:attribute name="jitter" type="xs:boolean" default="true"/>
    <xs:attribute name="retryOn" type="xs:string">
      <xs:annotation><xs:documentation>Space-separated error classes to retry on. Absent means retry any failure.</xs:documentation></xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <xs:complexType name="Port">
    <xs:sequence>
      <xs:element name="description" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="name" type="hx:Identifier" use="required"/>
    <xs:attribute name="type" type="hx:DataType"/>
    <xs:attribute name="required" type="xs:boolean" default="true"/>
    <xs:attribute name="default" type="xs:string"/>
    <xs:attribute name="value" type="hx:Expression">
      <xs:annotation><xs:documentation>Literal or expression bound directly, for an input not fed by a data edge.</xs:documentation></xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <!-- ===================================================================
       Metadata and provenance
       =================================================================== -->

  <xs:complexType name="Metadata">
    <xs:all>
      <xs:element name="title" type="xs:string" minOccurs="0"/>
      <xs:element name="description" type="xs:string" minOccurs="0"/>
      <xs:element name="author" type="xs:string" minOccurs="0"/>
      <xs:element name="organization" type="xs:string" minOccurs="0"/>
      <xs:element name="created" type="xs:dateTime" minOccurs="0"/>
      <xs:element name="modified" type="xs:dateTime" minOccurs="0"/>
      <xs:element name="license" type="xs:string" minOccurs="0"/>
      <xs:element name="documentVersion" type="xs:string" minOccurs="0"/>
      <xs:element name="tags" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="tag" type="xs:string" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="provenance" minOccurs="0">
        <xs:annotation><xs:documentation>
          Where this document came from. The point of recording it is that a
          HarnessXML document is usually GENERATED from a visual graph — and an
          execution trace is only auditable if it can be tied back to the design
          that produced it.
        </xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:sequence>
            <xs:element name="generator" minOccurs="0">
              <xs:complexType>
                <xs:attribute name="name" type="xs:string" use="required"/>
                <xs:attribute name="version" type="xs:string"/>
                <xs:attribute name="vendor" type="xs:string"/>
              </xs:complexType>
            </xs:element>
            <xs:element name="source" minOccurs="0" maxOccurs="unbounded">
              <xs:complexType>
                <xs:attribute name="uri" type="xs:anyURI" use="required"/>
                <xs:attribute name="type" type="xs:string"/>
                <xs:attribute name="digest" type="xs:string"/>
              </xs:complexType>
            </xs:element>
            <xs:element name="signature" minOccurs="0">
              <xs:complexType>
                <xs:attribute name="algorithm" type="xs:string" use="required"/>
                <xs:attribute name="value" type="xs:string" use="required"/>
                <xs:attribute name="keyId" type="xs:string"/>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:all>
  </xs:complexType>

  <!-- ===================================================================
       Resources and artifacts
       =================================================================== -->

  <xs:complexType name="Resource">
    <xs:annotation><xs:documentation>
      A capability the workflow needs but does not contain: a model endpoint, a
      database, a robot arm. Declared once and referenced by nodes, so that
      moving a workflow between environments is a change to the resource block
      and nothing else.
    </xs:documentation></xs:annotation>
    <xs:sequence>
      <xs:element name="description" type="xs:string" minOccurs="0"/>
      <xs:element name="property" type="hx:Property" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="credential" minOccurs="0">
        <xs:annotation><xs:documentation>
          A REFERENCE to a secret, never the secret. A document containing a
          literal credential is invalid (HX-3501) — the specification refuses
          to make leaking one convenient.
        </xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:attribute name="ref" type="xs:string" use="required"/>
          <xs:attribute name="store" type="xs:string"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="extension" type="hx:Extension" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:attribute name="id" type="hx:Identifier" use="required"/>
    <xs:attribute name="type" type="hx:ResourceType" use="required"/>
    <xs:attribute name="name" type="xs:string"/>
    <xs:attribute name="provider" type="xs:string"/>
    <xs:attribute name="uri" type="xs:anyURI"/>
  </xs:complexType>

  <xs:complexType name="Artifact">
    <xs:sequence>
      <xs:element name="description" type="xs:string" minOccurs="0"/>
      <xs:element name="property" type="hx:Property" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="extension" type="hx:Extension" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:attribute name="id" type="hx:Identifier" use="required"/>
    <xs:attribute name="type" type="hx:ArtifactType" use="required"/>
    <xs:attribute name="name" type="xs:string"/>
    <xs:attribute name="uri" type="xs:anyURI"/>
    <xs:attribute name="mediaType" type="xs:string"/>
    <xs:attribute name="digest" type="xs:string">
      <xs:annotation><xs:documentation>Content digest, e.g. "sha256:abc…". Makes a run reproducible and an audit trail meaningful.</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="classification" type="hx:Classification"/>
  </xs:complexType>

  <!-- ===================================================================
       Node
       =================================================================== -->

  <xs:complexType name="Node">
    <xs:sequence>
      <xs:element name="description" type="xs:string" minOccurs="0"/>

      <xs:element name="inputs" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="input" type="hx:Port" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>

      <xs:element name="outputs" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="output" type="hx:Port" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>

      <xs:element name="config" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="property" type="hx:Property" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>

      <xs:element name="resourceRef" minOccurs="0" maxOccurs="unbounded">
        <xs:complexType>
          <xs:attribute name="ref" type="hx:Identifier" use="required"/>
          <xs:attribute name="role" type="xs:string"/>
        </xs:complexType>
      </xs:element>

      <xs:element name="artifactRef" minOccurs="0" maxOccurs="unbounded">
        <xs:complexType>
          <xs:attribute name="ref" type="hx:Identifier" use="required"/>
          <xs:attribute name="direction" default="in">
            <xs:simpleType>
              <xs:restriction base="xs:string">
                <xs:enumeration value="in"/>
                <xs:enumeration value="out"/>
                <xs:enumeration value="inout"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
        </xs:complexType>
      </xs:element>

      <xs:element name="guard" minOccurs="0">
        <xs:annotation><xs:documentation>
          Conditional execution of THIS node. If the expression is false the
          node enters SKIPPED, which is a terminal successful state — successors
          on control edges still run. This is distinct from a decision node,
          which routes between alternatives.
        </xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:attribute name="when" type="hx:Expression" use="required"/>
        </xs:complexType>
      </xs:element>

      <xs:element name="retry" type="hx:Retry" minOccurs="0"/>

      <xs:element name="timeout" minOccurs="0">
        <xs:complexType>
          <xs:attribute name="duration" type="hx:Duration" use="required"/>
          <xs:attribute name="onTimeout" default="fail">
            <xs:simpleType>
              <xs:restriction base="xs:string">
                <xs:enumeration value="fail"/>
                <xs:enumeration value="skip"/>
                <xs:enumeration value="retry"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
        </xs:complexType>
      </xs:element>

      <xs:element name="cases" minOccurs="0">
        <xs:annotation><xs:documentation>
          Required on type="decision", forbidden elsewhere (HX-2201). Cases are
          evaluated IN DOCUMENT ORDER and the first true one wins — ordering is
          normative, so that a decision is deterministic.
        </xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:sequence>
            <xs:element name="case" maxOccurs="unbounded">
              <xs:complexType>
                <xs:attribute name="when" type="hx:Expression" use="required"/>
                <xs:attribute name="to" type="hx:Identifier" use="required"/>
              </xs:complexType>
            </xs:element>
            <xs:element name="otherwise" minOccurs="0">
              <xs:complexType>
                <xs:attribute name="to" type="hx:Identifier" use="required"/>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>

      <xs:element name="loop" minOccurs="0">
        <xs:annotation><xs:documentation>
          Required on type="loop", forbidden elsewhere (HX-2202). maxIterations
          is REQUIRED: an unbounded loop in a workflow that may run unattended
          is a defect, not a feature.
        </xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:sequence>
            <xs:element name="body">
              <xs:complexType>
                <xs:attribute name="ref" type="hx:Identifier" use="required"/>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
          <xs:attribute name="kind" type="hx:LoopKind" use="required"/>
          <xs:attribute name="over" type="hx:Expression"/>
          <xs:attribute name="var" type="hx:Identifier" default="item"/>
          <xs:attribute name="indexVar" type="hx:Identifier" default="index"/>
          <xs:attribute name="while" type="hx:Expression"/>
          <xs:attribute name="count" type="xs:positiveInteger"/>
          <xs:attribute name="maxIterations" type="xs:positiveInteger" use="required"/>
          <xs:attribute name="maxConcurrency" type="xs:positiveInteger" default="1"/>
          <xs:attribute name="onItemFailure" default="fail">
            <xs:simpleType>
              <xs:restriction base="xs:string">
                <xs:enumeration value="fail"/>
                <xs:enumeration value="continue"/>
                <xs:enumeration value="break"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
        </xs:complexType>
      </xs:element>

      <xs:element name="subworkflow" minOccurs="0">
        <xs:annotation><xs:documentation>Required on type="subworkflow", forbidden elsewhere (HX-2203).</xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:attribute name="href" type="xs:anyURI" use="required"/>
          <xs:attribute name="digest" type="xs:string"/>
          <xs:attribute name="specVersion" type="hx:SpecVersion"/>
        </xs:complexType>
      </xs:element>

      <xs:element name="wait" minOccurs="0">
        <xs:annotation><xs:documentation>Required on type="wait", forbidden elsewhere (HX-2204).</xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:attribute name="duration" type="hx:Duration"/>
          <xs:attribute name="until" type="hx:Expression"/>
          <xs:attribute name="event" type="xs:string"/>
        </xs:complexType>
      </xs:element>

      <xs:element name="security" type="hx:Security" minOccurs="0"/>
      <xs:element name="extension" type="hx:Extension" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>

    <xs:attribute name="id" type="hx:Identifier" use="required"/>
    <xs:attribute name="type" type="hx:NodeType" use="required"/>
    <xs:attribute name="name" type="xs:string"/>
    <xs:attribute name="impl" type="xs:string">
      <xs:annotation><xs:documentation>
        Implementation handle the runtime resolves — a function name, an image
        reference, a URI. Deliberately opaque to the specification: HarnessXML
        describes the WORKFLOW, and stops at the boundary of what a step does.
      </xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="idempotent" type="xs:boolean" default="true">
      <xs:annotation><xs:documentation>False means a runtime MUST NOT retry this node automatically (HX-3301 if combined with a retry policy).</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="joinPolicy" type="hx:JoinPolicy" default="all"/>
    <xs:attribute name="quorum" type="xs:positiveInteger"/>
    <xs:attribute name="compensates" type="hx:Identifier">
      <xs:annotation><xs:documentation>Marks this node as the compensating action for another node.</xs:documentation></xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <!-- ===================================================================
       Edge
       =================================================================== -->

  <xs:complexType name="Edge">
    <xs:sequence>
      <xs:element name="description" type="xs:string" minOccurs="0"/>
      <xs:element name="extension" type="hx:Extension" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:attribute name="id" type="hx:Identifier"/>
    <xs:attribute name="from" type="hx:Identifier" use="required"/>
    <xs:attribute name="to" type="hx:Identifier" use="required"/>
    <xs:attribute name="type" type="hx:EdgeType" default="control"/>
    <xs:attribute name="fromPort" type="hx:Identifier">
      <xs:annotation><xs:documentation>Required when type="data" (HX-2301).</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="toPort" type="hx:Identifier">
      <xs:annotation><xs:documentation>Required when type="data" (HX-2301).</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="condition" type="hx:Expression">
      <xs:annotation><xs:documentation>Guard on traversal. The edge is taken only if this evaluates true.</xs:documentation></xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <!-- ===================================================================
       Root
       =================================================================== -->

  <xs:element name="harness">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="metadata" type="hx:Metadata" minOccurs="0"/>
        <xs:element name="security" type="hx:Security" minOccurs="0"/>
        <xs:element name="resources" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="resource" type="hx:Resource" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="artifacts" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="artifact" type="hx:Artifact" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="nodes">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="node" type="hx:Node" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="edges" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="edge" type="hx:Edge" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="extension" type="hx:Extension" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>

      <xs:attribute name="id" type="hx:Identifier" use="required"/>
      <xs:attribute name="specVersion" type="hx:SpecVersion" use="required"/>
      <xs:attribute name="name" type="xs:string"/>
      <xs:attribute name="entry" type="hx:Identifier">
        <xs:annotation><xs:documentation>
          Explicit entry node. If absent, the entry set is every node with no
          incoming control, data or dependency edge (HX-3001 if that set is empty).
        </xs:documentation></xs:annotation>
      </xs:attribute>
    </xs:complexType>

    <!-- Referential integrity. A dangling reference is caught by a plain
         schema-validating parser, before any HarnessXML-aware tool runs. -->

    <xs:key name="nodeKey">
      <xs:selector xpath="hx:nodes/hx:node"/>
      <xs:field xpath="@id"/>
    </xs:key>

    <xs:keyref name="edgeFromRef" refer="hx:nodeKey">
      <xs:selector xpath="hx:edges/hx:edge"/>
      <xs:field xpath="@from"/>
    </xs:keyref>

    <xs:keyref name="edgeToRef" refer="hx:nodeKey">
      <xs:selector xpath="hx:edges/hx:edge"/>
      <xs:field xpath="@to"/>
    </xs:keyref>

    <xs:keyref name="caseToRef" refer="hx:nodeKey">
      <xs:selector xpath="hx:nodes/hx:node/hx:cases/hx:case"/>
      <xs:field xpath="@to"/>
    </xs:keyref>

    <xs:keyref name="otherwiseToRef" refer="hx:nodeKey">
      <xs:selector xpath="hx:nodes/hx:node/hx:cases/hx:otherwise"/>
      <xs:field xpath="@to"/>
    </xs:keyref>

    <xs:keyref name="loopBodyRef" refer="hx:nodeKey">
      <xs:selector xpath="hx:nodes/hx:node/hx:loop/hx:body"/>
      <xs:field xpath="@ref"/>
    </xs:keyref>

    <xs:key name="resourceKey">
      <xs:selector xpath="hx:resources/hx:resource"/>
      <xs:field xpath="@id"/>
    </xs:key>

    <xs:keyref name="resourceRefRef" refer="hx:resourceKey">
      <xs:selector xpath="hx:nodes/hx:node/hx:resourceRef"/>
      <xs:field xpath="@ref"/>
    </xs:keyref>

    <xs:key name="artifactKey">
      <xs:selector xpath="hx:artifacts/hx:artifact"/>
      <xs:field xpath="@id"/>
    </xs:key>

    <xs:keyref name="artifactRefRef" refer="hx:artifactKey">
      <xs:selector xpath="hx:nodes/hx:node/hx:artifactRef"/>
      <xs:field xpath="@ref"/>
    </xs:keyref>
  </xs:element>

</xs:schema>
