<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp "&#160;">
  <!ENTITY zwsp "&#8203;">
  <!ENTITY nbhy "&#8209;">
  <!ENTITY wj "&#8288;">
]>
<?xml-stylesheet type='text/xsl' href='rfc2629.xslt' ?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     category="info"
     docName="draft-vandemeent-rvp-continuous-verification-03"
     ipr="trust200902"
     submissionType="IETF"
     consensus="true"
     version="3">

  <front>
    <title abbrev="RVP">RVP: Real-time Verification Protocol for Requirement-Bound Evidence</title>

    <seriesInfo name="Internet-Draft"
                value="draft-vandemeent-rvp-continuous-verification-03"/>

    <author fullname="Jasper van de Meent" initials="J."
            surname="van de Meent">
      <organization>Humotica</organization>
      <address>
        <postal>
          <city>Den Dolder</city>
          <country>Netherlands</country>
        </postal>
        <email>jasper@humotica.com</email>
        <uri>https://humotica.com</uri>
      </address>
    </author>

    <author fullname="Root AI" surname="Root AI">
      <organization>Humotica</organization>
      <address>
        <email>root_ai@humotica.nl</email>
        <uri>https://humotica.com</uri>
      </address>
    </author>

    <date year="2026" month="September" day="29"/>

    <area>Security</area>
    <workgroup>Internet Engineering Task Force</workgroup>

    <keyword>verification evidence</keyword>
    <keyword>fresh presence</keyword>
    <keyword>authentication</keyword>
    <keyword>policy</keyword>
    <keyword>local-first</keyword>

    <abstract>
      <t>This document defines RVP, a protocol for asking a bounded
      verification question, carrying that question through one of several
      possible verification mechanisms, and producing evidence that is bound
      to the exact question. RVP separates five concerns that are often
      collapsed: the consumer policy that decides whether evidence is needed,
      the frozen evidence requirement, the lifecycle of the question, the
      carrier that obtains a response, and the later act of consuming the
      evidence.</t>

      <t>RVP does not grant authority, establish admission, or replace account
      authentication and session policy. A successful result means only that
      the presented evidence satisfied the referenced requirement for the
      referenced question. The consumer and target system remain responsible
      for deciding what, if anything, may happen next.</t>

      <t>The protocol supports local biometric checks, signed companion-device
      responses, WebAuthn, authenticated-session evidence, recovery standing,
      and future carriers without assigning ceremony semantics or authority to
      those carriers. It is transport-independent and can operate locally
      without a central identity provider.</t>
    </abstract>
  </front>

  <middle>
    <section anchor="introduction">
      <name>Introduction</name>

      <t>Security systems frequently use one word, such as "verification" or
      "presence", for several different facts. An account may be authenticated,
      a session may still be valid, a human may be freshly present, a device may
      be enrolled, and a recovery key may permit repair. These facts can all be
      useful, but they are not interchangeable.</t>

      <t>RVP represents verification as a question with a bounded lifecycle. A
      consumer freezes the evidence requirement, opens a request, and selects
      or offers one or more carriers. A carrier obtains a response. RVP verifies
      whether that response satisfies the frozen requirement. A consumer binds
      the result only when it actually uses the evidence. Policy and admission
      remain outside RVP.</t>

      <t>This separation permits both high-friction and low-friction policies.
      One deployment can accept an OAuth-authenticated session with MFA for a
      workday, require fresh human presence after a pause, and require a stronger
      device-bound method for a sensitive transition. Another deployment can
      require fresh evidence for every transition. RVP carries the evidence for
      either policy; it does not choose between them.</t>

      <section anchor="problem-statement">
        <name>Problem Statement</name>
        <t>Existing verification integrations commonly fail in one or more of
        the following ways:</t>
        <ul>
          <li>A session is treated as proof of fresh human presence.</li>
          <li>A recovery credential is treated as if it were a fresh biometric
          measurement.</li>
          <li>A transport challenge is treated as the question itself.</li>
          <li>A response is recorded as consumed before any consumer uses it.</li>
          <li>A reference or record address is treated as authority.</li>
          <li>A local confidence score is interpreted as a portable policy
          decision.</li>
          <li>Carrier-specific failures silently become ceremony outcomes.</li>
          <li>A valid signature is accepted for a different operation, target,
          actor, requirement, or deadline than the one shown to the signer.</li>
        </ul>
      </section>

      <section anchor="design-principles">
        <name>Design Principles</name>
        <dl>
          <dt>Evidence is not authority:</dt>
          <dd>RVP describes what was measured. It does not grant, admit, or
          authorize.</dd>

          <dt>The requirement is frozen:</dt>
          <dd>The exact requirement, including its version and digest, is bound
          before a response is accepted.</dd>

          <dt>The lane owns the question:</dt>
          <dd>The verification lane owns the request lifecycle and terminal
          vocabulary. A carrier only carries the question and response.</dd>

          <dt>Response is not consumption:</dt>
          <dd>A matching response can remain unconsumed. The consumer records a
          separate bind when it uses that evidence.</dd>

          <dt>Different state axes stay different:</dt>
          <dd>Authentication, session standing, presence, device state,
          recovery standing, and admission MUST NOT be inferred from one
          another unless an explicit consumer policy says how they compose.</dd>

          <dt>Local-first operation:</dt>
          <dd>A deployment can verify evidence locally and offline. Central
          identity providers and network services MAY supply evidence, but are
          not required by the protocol.</dd>
        </dl>
      </section>

      <section anchor="scope">
        <name>Scope</name>
        <t>This document defines:</t>
        <ul>
          <li>A requirement-bound verification lifecycle.</li>
          <li>The boundary between a lane and its carriers.</li>
          <li>Canonical request, response, and consumption records.</li>
          <li>Terminal outcomes and fail-closed handling.</li>
          <li>Question commitment, freshness, and replay requirements.</li>
          <li>How RVP evidence relates to sessions, recovery, policy, and
          provenance.</li>
        </ul>

        <t>This document does not define:</t>
        <ul>
          <li>Account enrolment or account authentication protocols.</li>
          <li>Biometric matching algorithms or portable confidence formulas.</li>
          <li>Authorization, admission, role assignment, or grants.</li>
          <li>A required transport or user-interface flow.</li>
          <li>A universal duration for a carrier wait, challenge, evidence
          freshness period, session, or standing.</li>
        </ul>
      </section>
    </section>

    <section anchor="conventions">
      <name>Conventions and Terminology</name>
      <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL",
      "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT
      RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
      interpreted as described in BCP 14 <xref target="RFC2119"/>
      <xref target="RFC8174"/> when, and only when, they appear in all
      capitals, as shown here.</t>

      <dl>
        <dt>Consumer</dt>
        <dd>The component that decides whether evidence is required and later
        decides whether to consume a result. A consumer is not necessarily the
        target of the requested operation.</dd>

        <dt>Evidence Requirement</dt>
        <dd>An immutable, versioned description of the evidence needed for one
        purpose. It is referenced by identifier, version, and digest.</dd>

        <dt>Verification Lane</dt>
        <dd>The scoped lifecycle that owns one verification question and its
        terminal outcome.</dd>

        <dt>Carrier</dt>
        <dd>A mechanism that presents a question and obtains a response, such
        as a local fingerprint reader, WebAuthn, or a signed companion-device
        exchange. A carrier does not own policy, authority, or the lane
        lifecycle.</dd>

        <dt>Window</dt>
        <dd>A bounded carrier opportunity associated with exactly one request.
        A window reference is an address, not a permission.</dd>

        <dt>Challenge</dt>
        <dd>A one-time value used to prevent replay within a carrier exchange.
        A challenge is not the whole question.</dd>

        <dt>Question Commitment</dt>
        <dd>A digest over the canonical security-relevant fields of the exact
        question shown to the responder.</dd>

        <dt>Evidence Response</dt>
        <dd>A signed or otherwise verifiable response to a request. A response
        is not yet consumed and does not grant authority.</dd>

        <dt>Bound Evidence</dt>
        <dd>A successful response that a named consumer has actually consumed
        for a named purpose and binding reference.</dd>

        <dt>Session Standing</dt>
        <dd>A policy fact established by an authentication system, such as an
        OAuth, OpenID Connect, SSH, or local login session. Session standing is
        not fresh human-presence evidence.</dd>

        <dt>Recovery Standing</dt>
        <dd>A fact that permits a recovery or repair procedure. Recovery
        standing is not fresh human-presence evidence and does not itself
        restore ordinary admission.</dd>

        <dt>Admission</dt>
        <dd>A target-local decision about whether an actor or request may
        proceed. Admission is outside RVP.</dd>
      </dl>
    </section>

    <section anchor="architecture">
      <name>Protocol Architecture</name>

      <section anchor="ownership-boundaries">
        <name>Ownership Boundaries</name>
        <artwork type="ascii-art"><![CDATA[
consumer policy
    |  decides WHETHER evidence is required
    v
frozen evidence requirement
    |  states WHAT evidence satisfies this purpose
    v
verification lane
    |  owns request, lifetime, and terminal outcome
    v
carrier
    |  presents the exact question and returns evidence
    v
RVP evaluator
    |  verifies the response against the frozen requirement
    v
consumer bind
    |  records actual consumption
    v
target policy / admission
       decides what may happen next
        ]]></artwork>

        <t>An implementation MAY combine these components in one process, but
        it MUST preserve their semantic boundaries. In particular, a carrier
        success MUST NOT directly produce admission, and a lane MUST NOT infer
        a terminal outcome from an unmapped carrier-specific result.</t>
      </section>

      <section anchor="independent-axes">
        <name>Independent State Axes</name>
        <t>The following facts are independent and MUST be represented
        separately:</t>
        <ul>
          <li>Account authentication and session standing.</li>
          <li>Fresh human-presence evidence.</li>
          <li>Device enrolment and device-binding state.</li>
          <li>Substrate or hardware attestation.</li>
          <li>Recovery standing.</li>
          <li>Authorization or admission.</li>
          <li>Causal continuation and provenance.</li>
        </ul>

        <t>A policy MAY require any conjunction or disjunction of these facts.
        For example, a policy can require a valid workday session and fresh
        presence after a pause. The policy MUST state that composition; RVP
        MUST NOT infer it from method strength or a scalar score.</t>
      </section>

      <section anchor="one-question">
        <name>One Window, One Question</name>
        <t>A carrier window MUST carry exactly one request. Attaching the same
        window to a second request, including a request in another lane, MUST
        fail. A responder and verifier MUST reject a response if the window or
        challenge resolves to zero or more than one request.</t>

        <t>Multiple carriers MAY be offered for one request. Their responses
        still terminate the same lane, and a terminal lane MUST reject later
        responses as stale.</t>
      </section>
    </section>

    <section anchor="data-model">
      <name>Data Model</name>
      <t>RVP records are JSON objects as defined by <xref target="RFC8259"/>.
      Deployments MAY use another serialization if it preserves every field and
      defines an equivalent canonical representation. The examples in this
      section omit deployment-specific signatures and provenance fields for
      readability. The kind identifiers and assurance labels in these examples
      are illustrative; an interoperable profile MUST define the meaning of
      any assurance labels it uses. Draft revision -03 and record version 2
      identify different version spaces.</t>

      <section anchor="requirement-object">
        <name>Evidence Requirement</name>
        <t>An evidence requirement is immutable after publication. A reference
        MUST contain all of:</t>
        <ul>
          <li><tt>evidence_requirement_id</tt>: a stable local or globally
          scoped identifier;</li>
          <li><tt>evidence_requirement_version</tt>: an immutable revision;</li>
          <li><tt>evidence_requirement_digest</tt>: a digest of the canonical
          requirement bytes.</li>
        </ul>

        <t>A requirement body SHOULD state its purpose, evidence class,
        accepted method or assurance constraints, freshness rule, and an
        explicit statement that satisfying the requirement grants nothing.</t>

        <figure anchor="requirement-example">
          <name>Example Evidence Requirement</name>
          <sourcecode type="json"><![CDATA[
{
  "kind": "org.example.rvp.evidence-requirement.v1",
  "evidence_requirement_id": "admin_ctx_entry_presence",
  "evidence_requirement_version": 1,
  "purpose": "admin.enter",
  "evidence_class": "fresh_human_presence",
  "accepted_assurance": ["H1", "H2"],
  "freshness": {"type": "inside_request_window"},
  "grants": "nothing"
}
          ]]></sourcecode>
        </figure>

        <t>A bare identifier that can silently resolve to a newer version MUST
        NOT be used in a request. A digest mismatch makes the requirement
        unresolved and the request unanswerable.</t>
      </section>

      <section anchor="request-object">
        <name>Verification Request</name>
        <t>A request MUST contain:</t>
        <ul>
          <li>A protocol and request format version.</li>
          <li>A unique <tt>request_id</tt> and scoped <tt>lane_ref</tt>.</li>
          <li>The frozen <tt>window_ref</tt> and <tt>challenge_ref</tt>.</li>
          <li>The operation and target.</li>
          <li>The subject whose evidence is requested.</li>
          <li>The actor or role, when distinct from the subject.</li>
          <li>The consumer and purpose.</li>
          <li>The complete evidence-requirement reference.</li>
          <li>The creation time and request deadline.</li>
          <li>A question-commitment version and digest.</li>
        </ul>

        <figure anchor="request-example">
          <name>Example Verification Request</name>
          <sourcecode type="json"><![CDATA[
{
  "protocol": "RVP",
  "version": 2,
  "kind": "org.example.rvp.request.v2",
  "request_id": "pr-8a41b7c2",
  "lane_ref": "presence:admin-entry:17",
  "window_ref": "win-f04ac811",
  "challenge_ref": "cid-ef86b3d0",
  "op": "admin.enter",
  "target": "box:raint-a46acdf5",
  "subject": "jasper.aint",
  "actor": "jasper-admin.aint",
  "on_behalf_of": "jasper.aint",
  "consumer": "iab-admin",
  "purpose": "admin.enter",
  "evidence_requirement": {
    "evidence_requirement_id": "admin_ctx_entry_presence",
    "evidence_requirement_version": 1,
    "evidence_requirement_digest": "sha256:..."
  },
  "created_at": "2026-09-25T10:00:00Z",
  "deadline": "2026-09-25T10:00:45Z",
  "question_commitment": {
    "version": 2,
    "algorithm": "sha-256",
    "digest": "sha256:..."
  }
}
          ]]></sourcecode>
        </figure>

        <t>The <tt>on_behalf_of</tt> field, when present, names the principal on
        whose behalf the actor operates. It MUST NOT be used in the reverse
        direction. Absent optional identity fields MUST be represented as
        explicit null values in the question commitment.</t>
      </section>

      <section anchor="response-object">
        <name>Evidence Response</name>
        <t>A successful response MUST identify the request, lane, window,
        challenge, evidence method and class, subject or presenter, issue time,
        expiry or freshness boundary, requirement digest, and question
        commitment. It MUST contain or reference cryptographic evidence that
        covers these fields.</t>

        <figure anchor="response-example">
          <name>Example Evidence Response</name>
          <sourcecode type="json"><![CDATA[
{
  "protocol": "RVP",
  "version": 2,
  "kind": "org.example.rvp.evidence-response.v2",
  "response_id": "re-19d1e4c7",
  "request_id": "pr-8a41b7c2",
  "lane_ref": "presence:admin-entry:17",
  "window_ref": "win-f04ac811",
  "challenge_ref": "cid-ef86b3d0",
  "subject": "jasper.aint",
  "presenter": "device:phone-7",
  "evidence_class": "fresh_human_presence",
  "method": "passkey-smartphone",
  "assurance": "H2",
  "issued_at": "2026-09-25T10:00:12Z",
  "expires_at": "2026-09-25T10:00:45Z",
  "evidence_requirement_digest": "sha256:...",
  "question_commitment": {
    "version": 2,
    "digest": "sha256:..."
  },
  "signature": {
    "key_ref": "jis:phone-7.aint#ed25519",
    "suite": "ed25519",
    "value": "base64url:..."
  },
  "grants": "nothing"
}
          ]]></sourcecode>
        </figure>

        <t>A local biometric carrier MAY use a locally attested result instead
        of a portable signature, but it MUST bind the result to the same
        request and question commitment. A claim that a biometric check
        occurred is not equivalent to a measured biometric result.</t>
      </section>

      <section anchor="binding-object">
        <name>Consumption Binding</name>
        <t>A matching response does not mean that any consumer used it. When a
        consumer uses a successful response, it MUST write or return a separate
        binding containing:</t>
        <ul>
          <li>The request and response references.</li>
          <li>The consumer and purpose.</li>
          <li>The exact target object, transition, or artifact digest to which
          the evidence was applied.</li>
          <li>The bind time.</li>
          <li>A statement that the binding itself grants nothing.</li>
        </ul>

        <t>A response MUST NOT be bound more than once unless the requirement
        explicitly permits multiple named consumers. Such a requirement MUST
        list those consumers and each consumption MUST produce its own binding.
        The permitted purposes and target scopes for each consumer MUST also be
        frozen in the requirement; consumers MUST NOT add a new purpose after
        the response. Consumption MUST be serialized or otherwise made atomic
        so concurrent consumers cannot bypass these limits.</t>

        <t>Before binding, the consumer MUST check that the evidence remains
        usable under the frozen freshness rule and that the referenced target
        transition is still current. Expiry, revocation, or replacement of the
        target state MUST NOT be hidden by a historical match. A profile MUST
        define how these checks are coordinated with consumption and how a
        retry identifies an existing binding without consuming again.</t>
      </section>

      <section anchor="canonicalization">
        <name>Canonicalization and Digests</name>
        <t>JSON-based profiles of RVP SHOULD use the JSON Canonicalization
        Scheme <xref target="RFC8785"/> before hashing or signing. A profile
        that uses another canonicalization MUST identify it in the signed data.
        Digest and signature algorithm identifiers MUST be explicit.</t>
      </section>
    </section>

    <section anchor="question-commitment">
      <name>Question Commitment</name>
      <t>A transport challenge proves freshness only for that challenge. It
      does not prove what operation or target was shown to the responder. RVP
      therefore requires a question commitment for every signed response.</t>

      <t>Question commitment version 2 covers at least:</t>
      <ul>
        <li>A domain separator identifying RVP and the commitment version.</li>
        <li><tt>request_id</tt>, <tt>lane_ref</tt>, <tt>window_ref</tt>, and
        <tt>challenge_ref</tt>.</li>
        <li><tt>op</tt>, <tt>target</tt>, <tt>subject</tt>, <tt>actor</tt>,
        and <tt>on_behalf_of</tt>, including explicit null values.</li>
        <li>The consumer and purpose.</li>
        <li>The evidence-requirement identifier, version, and digest.</li>
        <li>The request creation time and deadline.</li>
      </ul>

      <t>The window and challenge references MUST be allocated before the
      commitment is frozen. Multiple carriers offered for that request MUST
      bind to this same question; carrier-specific challenges, if any, MUST
      be verifiably bound to it by the carrier profile. A profile MUST define
      the exact commitment object, its canonical bytes, domain separator, and
      digest construction. The commitment digest itself and response signature
      are not inputs to that commitment.</t>

      <t>For human approval, the responder MUST derive both the commitment and
      an unambiguous rendering from the same frozen question fields. An
      automated evidence carrier MUST bind to those same fields without
      claiming that human approval occurred. The verifier MUST recompute it from
      its own request record. A mismatch MUST terminate the lane without binding.</t>

      <t>A verifier that requires question commitment version 2 MUST NOT
      silently accept a version 1 response that signs only a challenge. Version
      negotiation MUST happen before the question is presented, and a downgrade
      MUST be visible to the consumer.</t>
    </section>

    <section anchor="lifecycle">
      <name>Verification Lifecycle</name>

      <section anchor="arm-phase">
        <name>Arm</name>
        <t>An implementation MAY arm a scoped lane before a request arrives.
        Arming states that a verification path is prepared; it does not state
        that a human is present, that a request has been made, or that a carrier
        is reachable.</t>

        <t>The canonical lifecycle event name for this phase is
        <tt>presence.arm</tt> when the evidence class is human presence. Other
        evidence classes SHOULD use an equally scoped event name rather than
        overloading presence.</t>
      </section>

      <section anchor="request-phase">
        <name>Request</name>
        <t>The consumer creates a request after freezing the requirement and
        question commitment. The request enters the proposed state. The
        canonical human-presence event name is <tt>presence.request</tt>.</t>

        <t>Creating or persisting a request does not prove that any carrier is
        serving it. A system that tells a human that a question is answerable
        SHOULD measure that at least one selected carrier is serving the same
        window and request.</t>
      </section>

      <section anchor="response-phase">
        <name>Response and Terminal Outcomes</name>
        <t>A lane reaches exactly one of the following terminal outcomes:</t>
        <dl>
          <dt>match</dt>
          <dd>Evidence was received and satisfies the frozen requirement. This
          outcome is eligible for later consumption; it is not yet a bind.</dd>

          <dt>no_match_in_this_lane</dt>
          <dd>Evidence was measured but did not match the subject or constraint
          for this lane.</dd>

          <dt>refused</dt>
          <dd>The responder explicitly declined the question.</dd>

          <dt>timed_out</dt>
          <dd>No terminal carrier response arrived before the request or
          carrier window closed.</dd>

          <dt>unreachable</dt>
          <dd>The selected carrier could not present the question or return a
          response.</dd>

          <dt>superseded</dt>
          <dd>A newer request explicitly replaced this request.</dd>

          <dt>stale</dt>
          <dd>While the lane was pending, a response was evaluated as outside
          the relevant freshness boundary. A response arriving after an existing
          terminal outcome is rejected as stale without changing that outcome.</dd>

          <dt>cancelled</dt>
          <dd>The request was explicitly withdrawn. A profile MUST distinguish
          this from a policy choice not to require evidence.</dd>
        </dl>

        <t>Carrier-specific outcomes MUST be mapped explicitly into this set.
        An unknown carrier or unmapped carrier outcome MUST fail closed. Only
        <tt>match</tt> is eligible for binding. The canonical human-presence
        response event is <tt>presence.response</tt>, and it records the typed
        terminal outcome.</t>

        <t>A lane terminal outcome is immutable. Implementations MUST arbitrate
        competing responses and deadline events so only one terminal outcome
        is committed. Rejected late responses MAY be recorded separately but
        MUST NOT replace an earlier match, refusal, or other terminal result.</t>
      </section>

      <section anchor="bind-phase">
        <name>Bind</name>
        <t>A consumer binds a matched response only when it actually applies
        the evidence to its named purpose. The canonical human-presence event
        is <tt>presence.bind</tt>. A lane closure with any other outcome MUST
        NOT emit a bind.</t>

        <t>A bind does not imply admission. For example, fresh human presence
        can satisfy the evidence requirement for entering a read context.
        Access to protected information still requires the applicable read
        authorization; the evidence does not create that authorization.</t>
      </section>

      <section anchor="blocking-offer">
        <name>Blocking and Non-Blocking Offers</name>
        <t>Interactive and headless operation MAY share one request and one
        carrier window. An interactive caller can wait for the terminal result;
        a headless caller can return while the same request remains pending.
        These are caller behaviors, not different ceremonies.</t>

        <t>A persisted window is not proof that its carrier service survived a
        process or system restart. An implementation that resumes a persisted
        request MUST re-establish and measure the carrier for the same window,
        or report the carrier as unreachable. It MUST NOT create a second
        question merely to restart transport.</t>
      </section>
    </section>

    <section anchor="time-model">
      <name>Time and Freshness Model</name>
      <t>RVP separates the following time domains:</t>
      <ul>
        <li>Carrier wait: how long an implementation waits for a reader,
        network peer, or user interaction.</li>
        <li>Request window: how long this question remains answerable.</li>
        <li>Challenge validity: how long a one-time challenge is accepted.</li>
        <li>Evidence freshness: how long a successful result can satisfy a
        requirement.</li>
        <li>Session lifetime: how long an authentication system keeps session
        standing.</li>
        <li>Standing lifetime: how long a previously established non-session
        fact remains usable under policy.</li>
      </ul>

      <t>These durations answer different questions and MUST NOT be derived from
      one another without an explicit profile rule. RVP defines no universal
      default duration. A process timeout such as the time spent waiting for a
      fingerprint reader is not, by itself, an evidence-freshness policy.</t>

      <t>Implementations SHOULD use a monotonic clock for local waiting and an
      authenticated or causally ordered record for protocol events. Wall-clock
      timestamps are useful for interchange but MUST NOT be the only replay
      defense.</t>
    </section>

    <section anchor="evidence-classes">
      <name>Evidence Classes and Methods</name>
      <t>Evidence class describes what a result means. Method describes how the
      result was obtained. Assurance and anchoring describe additional
      properties. These fields MUST remain separate.</t>

      <section anchor="presence-class">
        <name>Fresh Human Presence</name>
        <t>Fresh human-presence evidence states that a qualifying measurement
        associated a human with this request inside the required window. Local
        fingerprint matching, a hardware-backed authenticator with user
        verification, and a signed companion-device approval can be methods for
        this class when the frozen requirement accepts their measured
        properties. A device signature alone MUST NOT be treated as evidence
        that a human acted during the request window.</t>

        <t>Being root, holding a process position, setting an environment
        variable, or possessing an unsigned record is not a human-presence
        method.</t>
      </section>

      <section anchor="session-class">
        <name>Authenticated Session</name>
        <t>An authenticated session can be evidence that an account completed a
        login ceremony and remains inside a policy-defined session. OAuth, MFA,
        SSH, and local login systems can establish such standing. This evidence
        MAY satisfy requirements designed for session standing. It MUST NOT be
        relabelled as fresh human presence.</t>
      </section>

      <section anchor="recovery-class">
        <name>Recovery Standing</name>
        <t>A recovery key or recovery procedure can establish the right to
        address an unresolved binding or restore state. It does not prove fresh
        presence and does not necessarily grant ordinary operation. A consumer
        MAY require recovery standing together with fresh presence or session
        evidence.</t>
      </section>

      <section anchor="scores">
        <name>Local Scores</name>
        <t>An implementation MAY use numeric scores to select or evaluate local
        methods. Such scores are method- and deployment-specific metadata. They
        MUST NOT be added across unrelated evidence classes, interpreted as
        portable admission decisions, or compared between deployments unless a
        profile defines the complete calibration and semantics.</t>

        <t>A requirement SHOULD prefer explicit accepted methods, assurance
        classes, anchoring properties, and freshness rules over an unqualified
        scalar threshold.</t>
      </section>
    </section>

    <section anchor="carriers">
      <name>Carrier Requirements</name>
      <t>A carrier MUST:</t>
      <ul>
        <li>Identify the request and window it serves.</li>
        <li>Preserve the security-relevant question fields and, when human
        approval is requested, present an unambiguous human-readable rendering
        derived from them.</li>
        <li>Bind its response to the complete question commitment.</li>
        <li>Return a carrier-specific result that has an explicit lane mapping.</li>
        <li>Reject expired, already-consumed, unknown, or mismatched challenges.</li>
      </ul>

      <t>A carrier MUST NOT:</t>
      <ul>
        <li>Choose the evidence requirement or admission policy.</li>
        <li>Treat possession of a request reference as authority.</li>
        <li>Report a request as answerable merely because a persisted window
        record exists.</li>
        <li>Create a second request when resuming service for an existing
        request.</li>
        <li>Convert an unknown carrier result into a successful lane outcome.</li>
      </ul>
    </section>

    <section anchor="provenance">
      <name>Provenance and Causal Records</name>
      <t>RVP lifecycle events can be recorded in a provenance system such as
      TIBET <xref target="TIBET"/>. A typical sequence is:</t>

      <artwork type="ascii-art"><![CDATA[
presence.arm
presence.request
presence.response outcome=match|refused|timed_out|...
presence.bind only after successful consumer consumption
      ]]></artwork>

      <t>The provenance writer can serialize, hash-chain, sign, and durably
      append these records. That mechanical inscription does not decide the
      evidence result or grant authority. A chain hash proves record integrity
      and ordering; it is not a substitute for the responder's signature or
      the target's admission decision.</t>

      <t>Missing history MUST NOT be rewritten as a successful history. A
      deployment that imports a pending request created before lifecycle
      recording existed can describe its opening as unrecorded and still record
      an honest later closure.</t>
    </section>

    <section anchor="interoperability">
      <name>Interoperability Requirements</name>
      <t>Two implementations conform to this document for a profile only if
      they agree on:</t>
      <ul>
        <li>The record versions and canonicalization.</li>
        <li>The evidence-requirement reference and digest.</li>
        <li>The question-commitment version and covered fields.</li>
        <li>The carrier result to lane-outcome mapping.</li>
        <li>The signature or local-attestation verification method.</li>
        <li>The relevant freshness and replay boundaries.</li>
        <li>Consumption atomicity, retry behavior, and target-state binding.</li>
      </ul>

      <t>A conformance suite SHOULD include at least the following hostile
      cases:</t>
      <ul>
        <li>One window attached to two questions.</li>
        <li>A response delivered to another lane or consumer.</li>
        <li>An expired or replayed challenge.</li>
        <li>A changed operation, target, subject, actor, requirement, or
        deadline with an otherwise valid signature.</li>
        <li>A changed server-side request record.</li>
        <li>A response after a terminal outcome, without changing that outcome.</li>
        <li>Concurrent responses or consumption attempts.</li>
        <li>A matched response consumed after its freshness boundary or after
        the referenced target state was replaced.</li>
        <li>A second consumer or purpose absent from the frozen requirement.</li>
        <li>An unknown carrier and an unmapped carrier outcome.</li>
        <li>A match recorded as bound before consumption.</li>
        <li>A session token presented for a fresh-presence requirement.</li>
        <li>A recovery credential presented as ordinary admission.</li>
      </ul>

      <t>Test reporting MUST distinguish a verified measurement harness from
      protocol conformance. A harness can operate correctly while exposing a
      contract gap; this is not full conformance.</t>
    </section>

    <section anchor="local-first">
      <name>Local-First Operation</name>
      <t>RVP does not require a central verifier. Requirements, request records,
      enrolled device keys, local biometric results, and consumer bindings can
      all remain under the target operator's control.</t>

      <t>Offline operation does not mean weakening an unresolved requirement.
      If the required carrier or validation material is unavailable, the lane
      terminates as unreachable or remains pending according to policy. It MUST
      NOT silently become a match.</t>

      <t>Raw biometric data SHOULD be processed on the measuring device and
      SHOULD NOT appear in an RVP response. The response should contain the
      minimum method, assurance, anchoring, and result data needed to verify the
      requirement.</t>
    </section>

    <section anchor="transport">
      <name>Transport Considerations</name>
      <t>RVP is transport-independent. Records can be carried over local IPC,
      HTTP, QR-mediated companion-device exchanges, message queues, removable
      media, or other transports. The transport MUST preserve the bytes covered
      by question commitments and signatures.</t>

      <t>Transport reachability is not evidence. TLS authenticates and protects
      a channel, but it does not by itself satisfy an RVP evidence requirement.
      Likewise, an HTTP success response does not imply that the lane bound the
      result.</t>
    </section>

    <section anchor="privacy">
      <name>Privacy Considerations</name>
      <t>Continuous collection can become continuous surveillance. RVP does not
      require continuous telemetry. A deployment SHOULD request evidence only
      at policy-defined transitions and SHOULD disclose the purpose before the
      responder acts.</t>

      <t>Implementations MUST minimize evidence records. Raw fingerprints,
      facial images, voice recordings, keystrokes, and behavioral traces MUST
      NOT be included merely to make a response independently auditable. Local
      verifiers should instead attest the result and retain only what the
      requirement and incident policy need.</t>

      <t>Stable subject, device, lane, and key identifiers enable correlation.
      Profiles SHOULD support scoped or pairwise identifiers where global
      linkage is unnecessary. Retention periods for requests, failed outcomes,
      and bindings SHOULD be independently configurable.</t>
    </section>

    <section anchor="security">
      <name>Security Considerations</name>

      <section anchor="evidence-laundering">
        <name>Evidence Laundering and Class Confusion</name>
        <t>A strong method does not make every evidence class true. A passkey
        can establish a signed device response and user verification, but it
        does not prove a local fingerprint was measured. A recovery key can
        permit repair, but it does not become fresh presence. Verifiers MUST
        compare the evidence class and requirement, not only an assurance
        label.</t>
      </section>

      <section anchor="question-substitution">
        <name>Question Substitution</name>
        <t>If a responder signs only a challenge, a compromised or buggy server
        can show one operation and apply the signature to another. The complete
        question commitment in <xref target="question-commitment"/> is REQUIRED
        to prevent this attack.</t>
      </section>

      <section anchor="replay">
        <name>Replay and Late Responses</name>
        <t>Challenges MUST be one-time, windows MUST carry one question, and a
        terminal lane MUST reject later responses. Expiry is necessary but not
        sufficient: replay protection also requires durable consumption or
        closure state.</t>
      </section>

      <section anchor="response-bind">
        <name>Response-Bind Confusion</name>
        <t>Binding at response time creates authority leakage: evidence can be
        recorded as used even when the consumer rejected or never observed it.
        Implementations MUST keep match and bind as separate state transitions.</t>
      </section>

      <section anchor="carrier-liveness">
        <name>Carrier Liveness</name>
        <t>A persisted carrier window can outlive the process serving it.
        Implementations SHOULD probe the service against the same request or
        otherwise prove that it serves that exact window. Starting a process
        and recording its process identifier is not sufficient proof that it
        successfully bound a socket or can verify the request.</t>
      </section>

      <section anchor="key-continuity">
        <name>Key Continuity</name>
        <t>Key rotation SHOULD preserve a relationship only when a verifiable
        continuity link connects the old and new keys, as described by JIS
        <xref target="JIS"/>. A new key without such a link is a new or forked
        identity, not a silent rotation. Even a valid rotation can trigger a
        policy requirement for fresh evidence; RVP carries that evidence but
        does not mandate the policy.</t>
      </section>

      <section anchor="provenance-authority">
        <name>Provenance Is Not Authority</name>
        <t>A hash chain, causal tick, signed receipt, or durable append can prove
        what was recorded and in what order. None of these facts alone decides
        who may act. Implementations MUST verify responder evidence and target
        policy separately from provenance integrity.</t>
      </section>
    </section>

    <section anchor="iana">
      <name>IANA Considerations</name>
      <t>This document requests registration of the
      <tt>application/rvp+json</tt> media type in the Standards Tree using the
      procedure in <xref target="RFC6838"/>. This is a registration request;
      publication of this Internet-Draft does not itself register the media
      type.</t>

      <dl>
        <dt>Type name:</dt><dd>application</dd>
        <dt>Subtype name:</dt><dd>rvp+json</dd>
        <dt>Required parameters:</dt><dd>none</dd>
        <dt>Optional parameters:</dt><dd>none</dd>
        <dt>Encoding considerations:</dt><dd>binary; the representation is a
        JSON object encoded as UTF-8</dd>
        <dt>Security considerations:</dt><dd>See <xref target="security"/>.</dd>
        <dt>Interoperability considerations:</dt><dd>See
        <xref target="interoperability"/> and
        <xref target="canonicalization"/>.</dd>
        <dt>Published specification:</dt><dd>This document.</dd>
        <dt>Applications that use this media type:</dt><dd>Verification
        consumers, local presence services, companion-device carriers, and
        provenance systems.</dd>
        <dt>Fragment identifier considerations:</dt><dd>none</dd>
        <dt>Additional information:</dt><dd>Magic number(s): none; File
        extension(s): .rvp.json; Macintosh file type code(s): none</dd>
        <dt>Person and email address to contact for further information:</dt>
        <dd>Jasper van de Meent, jasper@humotica.com</dd>
        <dt>Intended usage:</dt><dd>COMMON</dd>
        <dt>Restrictions on usage:</dt><dd>none</dd>
        <dt>Author:</dt><dd>Jasper van de Meent</dd>
        <dt>Change controller:</dt><dd>IETF</dd>
      </dl>
    </section>
  </middle>

  <back>
    <references>
      <name>References</name>

      <references>
        <name>Normative References</name>

        <reference anchor="RFC2119"
                   target="https://www.rfc-editor.org/info/rfc2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author fullname="S. Bradner" initials="S." surname="Bradner"/>
            <date month="March" year="1997"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
        </reference>

        <reference anchor="RFC6838"
                   target="https://www.rfc-editor.org/info/rfc6838">
          <front>
            <title>Media Type Specifications and Registration Procedures</title>
            <author fullname="N. Freed" initials="N." surname="Freed"/>
            <author fullname="J. Klensin" initials="J." surname="Klensin"/>
            <author fullname="T. Hansen" initials="T." surname="Hansen"/>
            <date month="January" year="2013"/>
          </front>
          <seriesInfo name="BCP" value="13"/>
          <seriesInfo name="RFC" value="6838"/>
        </reference>

        <reference anchor="RFC8174"
                   target="https://www.rfc-editor.org/info/rfc8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author fullname="B. Leiba" initials="B." surname="Leiba"/>
            <date month="May" year="2017"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
        </reference>

        <reference anchor="RFC8259"
                   target="https://www.rfc-editor.org/info/rfc8259">
          <front>
            <title>The JavaScript Object Notation (JSON) Data Interchange Format</title>
            <author fullname="T. Bray" initials="T." surname="Bray"/>
            <date month="December" year="2017"/>
          </front>
          <seriesInfo name="STD" value="90"/>
          <seriesInfo name="RFC" value="8259"/>
        </reference>

        <reference anchor="RFC8785"
                   target="https://www.rfc-editor.org/info/rfc8785">
          <front>
            <title>JSON Canonicalization Scheme (JCS)</title>
            <author fullname="A. Rundgren" initials="A." surname="Rundgren"/>
            <author fullname="B. Jordan" initials="B." surname="Jordan"/>
            <author fullname="S. Erdtman" initials="S." surname="Erdtman"/>
            <date month="June" year="2020"/>
          </front>
          <seriesInfo name="RFC" value="8785"/>
        </reference>
      </references>

      <references>
        <name>Informative References</name>

        <reference anchor="TIBET">
          <front>
            <title>TIBET: Transaction/Interaction-Based Evidence Trail</title>
            <author fullname="J. van de Meent" initials="J." surname="van de Meent"/>
            <author fullname="Root AI" surname="Root AI"/>
            <date month="June" year="2026"/>
          </front>
          <seriesInfo name="Internet-Draft"
                      value="draft-vandemeent-tibet-provenance-02"/>
        </reference>

        <reference anchor="JIS">
          <front>
            <title>JIS: JTel Identity Standard</title>
            <author fullname="J. van de Meent" initials="J." surname="van de Meent"/>
            <author fullname="Root AI" surname="Root AI"/>
            <date month="June" year="2026"/>
          </front>
          <seriesInfo name="Internet-Draft"
                      value="draft-vandemeent-jis-identity-02"/>
        </reference>
      </references>
    </references>

    <section anchor="migration">
      <name>Migration from RVP Version 1</name>
      <t>RVP version 1 tokens can contain a method, scalar confidence,
      threshold, resolution, and transport challenge without committing to the
      complete question. Such a token MUST NOT be accepted where a version 2
      requirement demands operation and target binding.</t>

      <t>A deployment can retain version 1 records as historical evidence. It
      SHOULD label them as not carrying question commitment version 2. A
      version 2 verifier MUST NOT manufacture missing fields from its local
      state and then claim that the signer approved them.</t>
    </section>

    <section anchor="changes-02">
      <name>Changes from -02</name>
      <ol>
        <li>Replaced the mandatory five-layer cascade and portable confidence
        sum with a requirement-bound evidence model.</li>
        <li>Removed the claim that every interaction is a verification moment
        and that trusted sessions do not exist. Session standing and fresh
        evidence are now separate composable facts.</li>
        <li>Separated consumer policy, frozen requirements, lane lifecycle,
        carriers, evidence evaluation, consumption, and admission.</li>
        <li>Defined the arm, request, response, and bind lifecycle, including
        eight typed terminal outcomes.</li>
        <li>Specified that only a matching response can later bind, and that a
        response is not consumption.</li>
        <li>Added question commitment version 2 covering operation, target,
        subject, actor, requirement, window, challenge, and deadline.</li>
        <li>Added explicit handling for login sessions, fresh human presence,
        recovery standing, device state, attestation, and admission as
        independent axes.</li>
        <li>Separated carrier wait, request window, challenge validity,
        evidence freshness, session lifetime, and standing lifetime.</li>
        <li>Recast numeric confidence as optional local method metadata rather
        than an interoperable policy or admission decision.</li>
        <li>Added hostile interoperability cases and separate harness and
        conformance verdicts.</li>
        <li>Expanded privacy guidance to avoid continuous telemetry and
        cross-context correlation.</li>
        <li>Updated the media-type registration and companion-draft references.</li>
      </ol>
    </section>

    <section anchor="acknowledgements" numbered="false">
      <name>Acknowledgements</name>
      <t>The authors thank Codex (codex.aint) for the implementation crosswalk,
      hostile protocol analysis, and architecture rewrite that informed this
      revision. The separation between policy, requirements, lanes, carriers,
      evidence, and binding was refined through implementation and testing in
      AInternet-in-a-box.</t>
    </section>
  </back>
</rfc>
