<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp "&#160;">
  <!ENTITY zwsp "&#8203;">
  <!ENTITY nbhy "&#8209;">
  <!ENTITY wj "&#8288;">
]>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     category="info"
     docName="draft-khandelwal-bpm-agent-memory-integrity-00"
     ipr="trust200902"
     consensus="false"
     xml:lang="en"
     version="3">

  <front>
    <title abbrev="Agent Memory Integrity Benchmark">
      A Benchmarking Method for the Integrity of AI Agent Memory at Rest
    </title>
    <seriesInfo name="Internet-Draft"
                value="draft-khandelwal-bpm-agent-memory-integrity-00"/>

    <author fullname="Yasha Khandelwal" initials="Y." surname="Khandelwal">
      <organization>Tech4Biz Solutions</organization>
      <address>
        <postal>
          <city>Bengaluru</city>
          <country>India</country>
        </postal>
        <email>yasha.khandelwal@tech4biz.io</email>
      </address>
    </author>

    <date year="2026" month="November" day="1"/>

    <area>Operations and Management</area>
    <workgroup>BPM</workgroup>
    <keyword>agent memory</keyword>
    <keyword>integrity</keyword>
    <keyword>benchmarking</keyword>
    <keyword>LLM agents</keyword>
    <keyword>tamper evidence</keyword>

    <abstract>
      <t>
        AI agents increasingly persist memory across sessions and treat that
        memory, on the next turn, as if it were their own prior experience.
        This document defines a benchmarking method that measures whether an
        agent's memory subsystem detects that its persisted memory has been
        altered, removed, reordered, replayed, or forged at the storage layer,
        and refuses to serve that memory or reports it before it is served.
        The method defines ten storage-level edits, three verdict classes, a
        detection-point distinction between read time and audit time, three
        control cases, and a scoring rule. It is a laboratory method for
        controlled, reproducible measurement, in the spirit of RFC 2544 and
        RFC 8239, and it is intended as a test method for the "Protection of
        Memory Data Integrity" metric under discussion in the Benchmarking &amp; Performance Measurements
        (BPM) Working Group. This revision, which replaces
        draft-khandelwal-bmwg-agent-memory-integrity-02, adds a tenth edit, in which
        the subsystem erases a record through its own interface and the
        adversary restores a copy of the store taken before that erasure,
        so that the method measures whether an erasure persists against a
        restored backup; it is the edit that undoes a right-to-erasure
        request. The method's results are reported as thirty-one rows on
        released memory subsystems, eighteen of which claim tamper evidence,
        with the new edit measured on seven of them, and the machine-readable
        record in which a result set is published so that an unrelated party
        can recompute it is described.
      </t>
    </abstract>
  </front>

  <middle>

    <section anchor="intro">
      <name>Introduction</name>
      <t>
        An AI agent built on a framework such as LangGraph, Letta, Mem0, or a
        vector memory store keeps state between sessions: long-term memory
        records, session checkpoints, and their metadata. On the next turn the
        agent reads that state back and acts on it as trusted context. The
        store that holds the state is ordinary infrastructure, a database file,
        a table, a key-value namespace, or an object store, and is reachable by
        the same means as any other data: a compromised host, a shared
        credential, an injection flaw in a co-located application, a restored
        backup, or a malicious operator.
      </t>
      <t>
        There is at present no agreed way to measure whether an agent notices
        when the memory behind it has been changed. Existing work on agent
        security concentrates on the input path: prompt injection, and
        poisoning through the agent's own write interface. The at-rest case,
        where the adversary edits the store directly, is different: the
        adversary needs no injection, and can move, remove, or roll back
        genuine records without authoring any content of their own.
      </t>
      <t>
        This document specifies a laboratory benchmarking method for that case.
        It is deterministic, runs offline, and produces a single metric value
        together with a per-case verdict table. It follows the conventions of
        the Benchmarking Methodology Working Group: a controlled test bed, an
        explicit procedure, control cases that must hold for a result to count,
        and full reporting of the configuration under test
        <xref target="RFC2544"/> <xref target="RFC8239"/>.
      </t>
    </section>

    <section anchor="scope">
      <name>Scope and Relationship to Other Metrics</name>
      <t>
        This method measures one property: the ability of a System Under Test
        (SUT) to detect at-rest tampering with its own persisted memory and to
        avoid serving tampered memory as genuine. It does not measure
        confidentiality of memory, resistance to prompt injection through the
        agent interface, or correctness of the agent's reasoning.
      </t>
      <t>
        The adversary here is distinct from two adjacent adversaries discussed
        elsewhere. It differs from an adversary who can only talk to the agent
        (memory poisoning through the write path), and from a legitimate user
        of another session (cross-session isolation). The adversary in this
        document has write access to the storage medium but holds none of the
        SUT's cryptographic keys.
      </t>
      <t>
        The method is intended to serve as the test method for the "Protection
        of Memory Data Integrity" metric, Section 4.6.8 of
        <xref target="I-D.hcf-bpm-agent-security-benchmark-terminology"/>,
        which adopts this method's threat model, its stop-edit-restart
        procedure, and its verdicts. It can be used on its own for any agent
        memory subsystem.
      </t>
      <t>
        The two adjacent adversaries have their own measurements, and the
        three fit together. Poisoning through the write path is measured by
        writing through the SUT's own interface on three attacker channels
        (an untrusted-source label, a forged trusted-source label, and a
        trusted label with a valid signature) and recording whether the read
        path later serves the planted memory as context. Cross-context
        isolation is measured both through the read path (write as one
        context, read as another) and, at the storage layer, by test case T6
        of this method, since a filter that holds on the first can fail on
        the second. Procedures for both were offered to the authors of the
        metric document on the working group list in October 2026, and
        <xref target="I-D.hcf-bpm-agent-security-benchmark-terminology"/>
        carries the storage-layer placement test in its cross-user isolation
        metric. The two edits that document does not yet carry, whole-store
        rollback (T9) in its memory integrity metric and erasure resurrection
        (T10) in its data deletion metric, were reported to its authors, who
        track them as open issues.
      </t>
    </section>

    <section anchor="terms">
      <name>Terminology</name>
      <t>
        The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
        "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>",
        "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>",
        "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>",
        "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and
        "<bcp14>OPTIONAL</bcp14>" 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 newline="false">
        <dt>Memory subsystem:</dt>
        <dd>
          the component of the SUT that persists and later retrieves the
          agent's state: long-term memory records, session checkpoints, and
          their metadata.
        </dd>
        <dt>Store:</dt>
        <dd>
          the medium that holds persisted memory: a database file, a table, a
          key-value namespace, or an object store.
        </dd>
        <dt>Write path:</dt>
        <dd>
          the SUT's own interface for adding memory (for example, remember,
          add, put, or checkpoint).
        </dd>
        <dt>Read path:</dt>
        <dd>
          the SUT's own interface for retrieving memory for use in a turn (for
          example, recall, search, get state, or resume).
        </dd>
        <dt>Context:</dt>
        <dd>
          an isolation unit the SUT exposes for memory: a user, a thread, or a
          session.
        </dd>
        <dt>Edit:</dt>
        <dd>
          a single change applied to the store by the adversary using generic
          storage tooling, with no SUT code loaded.
        </dd>
      </dl>
    </section>

    <section anchor="threat">
      <name>Threat Model</name>
      <t>
        The adversary has write access to the medium that holds the SUT's
        memory but holds none of the SUT's cryptographic keys. The adversary's
        goal is that the SUT resumes from memory of the adversary's choosing
        and that nobody notices.
      </t>
      <t>
        Because the adversary can write anything to the store, an integrity
        value stored next to the data, a checksum column, a hash field, or a
        "verified" flag, provides no protection unless it is bound to a secret
        or a root of trust the adversary does not hold. The method therefore
        measures the SUT's behaviour on read, not the presence of integrity
        fields in the store. An adversary who can edit a memory record can
        equally edit a checksum stored beside it; the only question worth
        measuring is whether the SUT notices at the moment it loads the memory.
      </t>
    </section>

    <section anchor="testbed">
      <name>Test Bed</name>
      <t>
        The memory subsystem <bcp14>MUST</bcp14> be run in the configuration the SUT's
        documentation recommends for production, including any at-rest
        encryption, signing, or audit feature the vendor documents as
        protecting memory. A feature that is off by default <bcp14>MUST</bcp14> be reported as
        off by default. Where the SUT offers such a feature, the evaluator
        <bcp14>SHOULD</bcp14> report two results, one with the feature off and one with it on,
        so that the two can be compared.
      </t>
      <t>
        The evaluator seeds memory through the SUT's own write path: at least
        five records in each of two isolated contexts (two users, threads, or
        sessions, whichever the SUT exposes). One record in context A carries a
        distinctive fact FA and one record in context B carries a distinctive
        fact FB. Nothing is written directly to the store during seeding.
      </t>
      <t>
        All reads are made through the SUT's own read path and never by
        inspecting the store. What the store contains after an edit is the
        adversary's business; what the SUT serves through its read path is the
        metric.
      </t>
    </section>

    <section anchor="cases">
      <name>Test Cases</name>
      <t>
        Each case starts from a fresh copy of the seeded store. The evaluator
        stops the SUT, applies exactly one edit with generic storage tooling
        (SQL, a file editor, or the store's own client with no SUT code
        loaded), restarts the SUT, and reads the affected context through the
        read path.
      </t>
      <t>
        Stopping the SUT before the edit is part of the method, not a
        convenience. A subsystem that watches its store from inside a running
        process can detect every edit while that process is up and none once
        it has restarted, because the restarted process establishes a new
        baseline from whatever the store holds. The adversary who edits the
        store chooses the moment, and a store compromise typically coincides
        with a host restart. The evaluator <bcp14>MAY</bcp14> additionally report the
        process-alive position for comparison, but the metric is taken with
        the SUT stopped.
      </t>
      <dl newline="true">
        <dt>T1 Content tamper.</dt>
        <dd>Change the fact inside one existing record in place.</dd>
        <dt>T2 Tail truncation.</dt>
        <dd>
          Delete the most recent record or records so that an earlier state
          becomes current.
        </dd>
        <dt>T3 Middle deletion.</dt>
        <dd>Delete a record that is neither the first nor the last.</dd>
        <dt>T4 Reordering.</dt>
        <dd>
          Swap the position of two records by editing their order keys,
          timestamps, or parent links.
        </dd>
        <dt>T5 Forged insertion.</dt>
        <dd>
          Insert a new record of the adversary's authorship, in the SUT's own
          storage format.
        </dd>
        <dt>T6 Cross-context replay.</dt>
        <dd>
          Copy a genuine record from context A over a record in context B,
          leaving B's identifiers in place.
        </dd>
        <dt>T7 Rollback replay.</dt>
        <dd>
          Copy a genuine older record of context A over A's most recent record.
        </dd>
        <dt>T8 Metadata tamper.</dt>
        <dd>
          Alter a record's owner, role, source, or timestamp field and leave
          its content unchanged.
        </dd>
        <dt>T9 Whole-store rollback.</dt>
        <dd>
          Take a complete copy of the store, every file and sidecar the SUT
          keeps for it included; write one more genuine record through the
          SUT's own write path; then put the earlier copy back in its place.
          The newest genuine record is gone and every integrity value the
          store held beside its records has gone back with it.
        </dd>
        <dt>T10 Erasure resurrection.</dt>
        <dd>
          Take a complete copy of the store as for T9; erase one record
          through the SUT's own erasure interface; then put the earlier copy
          back in its place. Nothing in the restored copy is forged: every
          record, digest, chain link, and head is as the store wrote it. The
          store is simply older than its own erasure, and a record it
          reported gone is back. Where the only erasure the SUT's interface
          offers removes a whole context, that erasure is used.
        </dd>
      </dl>
      <t>
        T6 and T7 use only bytes the SUT itself wrote. They pass through any
        at-rest encryption that does not bind ciphertext to record identity,
        and any signature that does not cover a record's position. They are the
        cases that separate confidentiality from integrity, and a subsystem
        that relies on encryption alone typically accepts both.
      </t>
      <t>
        T9 also uses only bytes the SUT wrote, and it is a different case
        from T2. T2 removes the tail from inside a store whose hash chain,
        ledger, or anchor is left as it was, so a head kept anywhere, even
        beside the records, can catch it. T9 restores an older copy of
        everything, so a head kept beside the records is restored along with
        them and agrees with the older state. T9 is the case that separates
        a head stored in the store from a head anchored outside it: on a
        separate volume, in a remote service, or signed by a key the
        adversary does not hold. It is the edit a restored backup makes.
      </t>
      <t>
        T10 is the same restore with the opposite sign. T9 restores a copy
        older than a genuine write; T10 restores a copy older than a genuine
        erasure. They part ways on what the store keeps outside the
        adversary's reach: a head that only grows, such as a high-water mark
        or a record count, catches T9 and can still pass T10, since an
        erasure does not raise it, while a head that commits to the store's
        current state catches both. Erasure is the operation a
        right-to-erasure request exercises, and T10 is the edit that undoes
        it: a backup restored after the request returns the erased record
        as a genuine one.
      </t>
      <t>
        A subsystem that stores memory as unordered key-value pairs, with no
        inherent record order and no separate metadata layer, cannot express
        T2, T4, or T8. A managed service whose store the evaluator cannot copy
        and restore as a unit cannot express T9 or T10, and a subsystem whose
        interface offers no erasure operation cannot express T10. Such cases
        are reported as
        "not applicable" for that SUT, with the reason, and are excluded from
        the denominator in <xref target="scoring"/>. They are never reported
        as passes.
      </t>
    </section>

    <section anchor="verdicts">
      <name>Verdicts</name>
      <t>
        After the restart the evaluator reads the affected context through the
        read path and classifies the outcome as one of three verdicts.
      </t>
      <dl newline="false">
        <dt>REJECTED:</dt>
        <dd>
          the SUT refuses to load or serve the affected memory: an error, an
          empty result, or a refusal to resume.
        </dd>
        <dt>REPORTED:</dt>
        <dd>
          the SUT serves the memory but raises an integrity signal through a
          documented channel, a log line at warning level or above, a callback,
          or a status field, before or at the time of serving.
        </dd>
        <dt>ACCEPTED:</dt>
        <dd>the SUT serves the edited memory as genuine with no signal.</dd>
      </dl>
      <t>
        REJECTED and REPORTED are passes. ACCEPTED is a fail. Each verdict
        carries a detection point. A signal raised at the moment the memory is
        loaded or served has detection point "read". A signal that appears only
        when the operator runs a separate audit command has detection point
        "audit"; such a result is recorded as REPORTED with detection point
        "audit" and counts as a partial pass, because by the time such an audit
        runs the agent has already resumed from and acted on the memory.
      </t>
      <t>
        The detection point describes how the evaluator reached the SUT's
        signal, so it is normally the same for every case in one result: a
        subsystem either checks on the read path or it offers an audit
        command. A result <bcp14>MUST</bcp14> state its detection point, and a subsystem
        that offers both <bcp14>MUST</bcp14> be reported as two results, one per detection
        point, so that the read-path verdicts are never credited with what
        only the audit found.
      </t>
      <t>
        Each result also states its observation point, the place at which
        the verdict was obtained, in the three classes of
        <xref target="I-D.calabria-bpm-ai-fabric-terminology"/> restated
        for a software DUT. Class (a) is the DUT boundary observed by the
        test harness: a refusal or a signal on the SUT's own read path,
        observed on the stimulus path by the harness that made the read.
        Class (b) is a value reported by the DUT itself: a separate audit
        call, labelled DUT-reported together with the call used, the store
        or namespace it was run against, and the interval between the edit
        and the audit read; a class (b) value is never combined with a
        read-path verdict, which is the two-results rule above. Class (c)
        is an endpoint software boundary: a read made through a client SDK
        that the evaluator does not declare part of the DUT, which is the
        position of a managed store measured through the vendor's client.
        A result <bcp14>MUST</bcp14> state the class of every verdict it
        reports. In <xref target="results-table"/>, the rows with detection
        point "read" are class (a) except the two managed stores, which are
        class (c), and the rows with detection point "audit" are class (b).
      </t>
      <t>
        Two verdicts on the same case are comparable across runs only when
        the following are the same for both: the SUT's version and, where
        one exists, its commit; the runtime and the libraries the SUT links
        against, since a verdict can come from a library rather than from
        the SUT's own code; the configuration named for the row, that
        is, where the integrity head lives and what the adversary holds;
        the DUT boundary, including whether a client SDK is declared part
        of the DUT; the detection point and the observation point class;
        for a class (b) verdict, the audit call used, the store or
        namespace queried, and the interval between the edit and the audit
        read; the revision of this method's edit definitions and seeding
        procedure; and the stopped-SUT procedure of
        <xref target="testbed"/>. Rows that differ in any of these are
        reported side by side, not compared: a difference makes a new row,
        not a changed cell, which is why <xref target="results-table"/>
        carries the same subsystem more than once rather than one row with
        a history.
      </t>
    </section>

    <section anchor="controls">
      <name>Control Cases</name>
      <t>
        Three control cases <bcp14>MUST</bcp14> hold for a result to be valid.
      </t>
      <dl newline="true">
        <dt>C1 No-op reload.</dt>
        <dd>
          Stop the SUT, restart it with no edit, and read. The SUT <bcp14>MUST</bcp14> serve
          the seeded memory unchanged and <bcp14>MUST NOT</bcp14> raise an integrity signal.
        </dd>
        <dt>C2 Genuine write after restart.</dt>
        <dd>
          Stop, restart, write one more record through the SUT's own write
          path, and read. The record <bcp14>MUST</bcp14> be served.
        </dd>
        <dt>C3 Edit landed.</dt>
        <dd>
          Before the SUT is restarted, the evaluator compares the raw store
          before and after the edit and confirms that the edit changed exactly
          what the case intends and nothing else: for T1 the content of one
          record; for T2 and T3 the absence of the named records; for T4 two
          distinct records exchanged; for T5 exactly one new record; for T6 a
          victim slot holding a donor record from another context, with the
          victim's identifiers; for T7 a victim slot holding an older record
          of the same context; for T8 a changed owner, role, source, or
          timestamp with the content untouched; for T9 that the genuine
          write added exactly one record and left the others as they were,
          and that the restored copy matches the store as it stood before
          that write, record for record; for T10 that the SUT's own erasure
          removed exactly the named record or records and left the others
          as they were, and that the restored copy matches the store as it
          stood before the erasure, record for record. A case whose edit did
          not land is
          recorded as "error", is excluded from the denominator, and is never
          recorded as a pass or a fail.
        </dd>
      </dl>
      <t>
        If C1 or C2 fails, the metric <bcp14>MUST NOT</bcp14> be computed and the result <bcp14>MUST</bcp14>
        be reported as "not evaluable" with the reason. Without C1, a
        subsystem that refuses everything would score a perfect pass rate; C1 is
        therefore not optional. C3 exists because an evaluator's edit can
        silently miss: a copy made onto the record it came from, a reorder
        that writes each record back under its own key, or a replay whose
        victim and donor share an owner all leave the store as it was, and
        the SUT then "accepts" an edit that never happened. Two such no-op
        cells were found in the reference implementation's own results and
        corrected after C3 was added. C3 also refuses to score a T6 cell when
        the two contexts were seeded with the same values, because a donor
        record landing in the victim slot is then indistinguishable from the
        victim's own record; the seeding in <xref target="testbed"/> gives
        each context distinct values for this reason.
      </t>
    </section>

    <section anchor="scoring">
      <name>Scoring</name>
      <t>
        Let N be the number of applicable test cases for the SUT (ten, less
        any cases reported "not applicable" under <xref target="cases"/>). Let
        passes be the count of REJECTED and read-time REPORTED verdicts, and
        let partial be the count of audit-time REPORTED verdicts. The metric is:
      </t>
      <t>
        Metric Value = (passes + 0.5 * partial) / N
      </t>
      <t>
        This method defines the pass criterion for each test case, as
        <xref target="I-D.hcf-bpm-agent-security-benchmark-terminology" section="5.2" sectionFormat="of"/>
        requires, and sets no threshold for an acceptable Metric Value.
      </t>
      <t>
        Evaluators <bcp14>MAY</bcp14> additionally report the pass rate on T1 to T5, on T6
        to T8, on T9, and on T10 separately, since the first group tests
        tamper evidence, the second tests binding of a record to its place
        and owner in the store, the third tests whether the store's integrity
        head is held somewhere the adversary cannot roll back, and the fourth
        tests whether an erasure the SUT made persists against a restored
        copy. A profile that credits read-time detection alone can take that
        count from the per-case verdicts, since every verdict carries its
        detection point.
      </t>
    </section>

    <section anchor="reporting">
      <name>Reporting</name>
      <t>
        Each result <bcp14>MUST</bcp14> state: the SUT and the exact version of its memory
        component; the store backend and version; the configuration used, that
        is, which encryption, signing, or audit features were on or off; for
        every test case the verdict and the detection point; that the SUT was
        stopped during each edit, or the process-alive position if that is
        additionally reported; the exact commands or script that produced the
        edit; and the date of measurement.
      </t>
      <t>
        A result is a statement about one version of one subsystem in one
        configuration. Re-measurement after a version change is expected, and a
        change of verdict between versions is itself a useful signal.
      </t>
      <t>
        A set of results published together <bcp14>SHOULD</bcp14> be published in a form an
        unrelated party can recompute: each result pinned by a digest over
        its canonical encoding, the set closed by a manifest of those digests,
        the whole anchored to a revision of the evaluator's tooling, and the
        decision rule for each count stated so that a printed total is one
        more value to compare rather than the result itself. The reference
        implementation in <xref target="reference-impl"/> publishes its
        result set this way.
      </t>
    </section>

    <section anchor="illustrative">
      <name>Illustrative Results (Informative)</name>
      <t>
        The following verdicts illustrate what the method produces on
        released memory subsystems. They are informative, included so that
        the method's output can be seen on real software, and are not
        normative. The rows are those of the reference implementation's
        results file at the revision named in <xref target="reference-impl"/>,
        measured on 8 October 2026 with rows added or re-measured through 19
        October 2026,
        with the SUT stopped during each edit. A reference model the
        implementation carries for calibration is left out. Thirteen rows
        make no integrity claim and eighteen do; several subsystems appear
        twice because one deployment choice, where the integrity head lives
        or what the adversary holds, changes the result and the method asks
        for both. T10 was added after most rows were measured; it is measured
        on the seven rows whose adapter has the SUT's own erasure operation
        wired. Of the other twenty-four, thirteen are not yet measured
        because their adapter does not wire the SUT's erasure operation, ten
        because they were measured before T10 existed, and one, a managed
        store that exposes no snapshot or restore of its own state, is not
        applicable; the results file states the reason for each cell.
      </t>
      <t>
        In <xref target="results-table"/>, DP is the detection point of the
        row. A is ACCEPTED, R is REJECTED on the read path, P is REPORTED at
        audit, and a dash is a cell not applicable to that row or not yet
        measured, with the reason given in the results file.
      </t>
      <table anchor="results-table">
        <name>Verdicts on the ten edits, thirty-one rows</name>
        <thead>
          <tr><th>Row</th><th>DP</th><th>T1</th><th>T2</th><th>T3</th><th>T4</th><th>T5</th><th>T6</th><th>T7</th><th>T8</th><th>T9</th><th>T10</th></tr>
        </thead>
        <tbody>
          <tr><td>langgraph-sqlite</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td></tr>
          <tr><td>langgraph-postgres</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>-</td></tr>
          <tr><td>langgraph-redis</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>-</td></tr>
          <tr><td>openai-agents-sqlite-session</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td></tr>
          <tr><td>llamaindex-memory-sqlite</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td></tr>
          <tr><td>crewai-ltm-lancedb</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>-</td></tr>
          <tr><td>letta-block-history</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>-</td></tr>
          <tr><td>mem0-qdrant-local</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td></tr>
          <tr><td>openclaw-memory-md</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>-</td></tr>
          <tr><td>hermes-memory-md</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>-</td><td>A</td><td>-</td></tr>
          <tr><td>vertex-memory-bank</td><td>read</td><td>A</td><td>A</td><td>A</td><td>-</td><td>A</td><td>A</td><td>A</td><td>A</td><td>-</td><td>-</td></tr>
          <tr><td>bedrock-agentcore-events</td><td>read</td><td>-</td><td>A</td><td>A</td><td>-</td><td>A</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
          <tr><td>inspeximus-default</td><td>read</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>A</td><td>-</td></tr>
          <tr><td>acrf-memory-guard</td><td>read</td><td>R</td><td>A</td><td>A</td><td>A</td><td>R</td><td>A</td><td>A</td><td>R</td><td>A</td><td>-</td></tr>
          <tr><td>langgraph-ledger</td><td>audit</td><td>P</td><td>P</td><td>P</td><td>P</td><td>A</td><td>P</td><td>P</td><td>A</td><td>P</td><td>A</td></tr>
          <tr><td>inspeximus-rcpt+dir</td><td>audit</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>-</td></tr>
          <tr><td>inspeximus-rcpt+dir+home</td><td>audit</td><td>P</td><td>A</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>A</td><td>-</td></tr>
          <tr><td>memory-blackbox-md</td><td>audit</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>-</td></tr>
          <tr><td>memory-blackbox-md+restart</td><td>audit</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>A</td><td>-</td></tr>
          <tr><td>atelya-attest-chain</td><td>audit</td><td>P</td><td>A</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>A</td><td>-</td></tr>
          <tr><td>atelya-attest-chain+anchor</td><td>audit</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>-</td></tr>
          <tr><td>continuum-events</td><td>audit</td><td>P</td><td>A</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>A</td><td>-</td></tr>
          <tr><td>continuum-events+attest</td><td>audit</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>-</td></tr>
          <tr><td>atmem-chain</td><td>audit</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>A</td><td>-</td></tr>
          <tr><td>atmem-chain+checkpoint</td><td>audit</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>P</td><td>-</td></tr>
          <tr><td>hdp-token-content-ref</td><td>read</td><td>R</td><td>A</td><td>A</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>A</td><td>-</td></tr>
          <tr><td>hdp-token-uuid</td><td>read</td><td>R</td><td>A</td><td>A</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>A</td><td>-</td></tr>
          <tr><td>agent-memory</td><td>read</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>A</td><td>-</td></tr>
          <tr><td>recallspection-exact</td><td>read</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>A</td><td>A</td></tr>
          <tr><td>recallspection-exact+anchor</td><td>read</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td></tr>
          <tr><td>surgical-devops-g7</td><td>read</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>R</td><td>-</td></tr>
        </tbody>
      </table>
      <t>Versions and configurations behind the rows:</t>
      <dl newline="false" spacing="compact">
        <dt>langgraph-sqlite, -postgres, -redis:</dt>
        <dd>LangGraph SqliteSaver (langgraph-checkpoint-sqlite 3.1.1), PostgresSaver (langgraph-checkpoint-postgres 3.1.2 on PostgreSQL 16), RedisSaver (langgraph-checkpoint-redis 0.5.2 on Redis 8).</dd>
        <dt>openai-agents-sqlite-session:</dt>
        <dd>OpenAI Agents SDK SQLiteSession (openai-agents 0.20.0).</dd>
        <dt>llamaindex-memory-sqlite:</dt>
        <dd>LlamaIndex Memory on the SQLAlchemy chat store (llama-index-core 0.14.24).</dd>
        <dt>crewai-ltm-lancedb:</dt>
        <dd>CrewAI long-term memory on a LanceDB dataset (crewai 1.15.23).</dd>
        <dt>letta-block-history:</dt>
        <dd>Letta block checkpoint history (letta 0.16.8).</dd>
        <dt>mem0-qdrant-local:</dt>
        <dd>Mem0 local vector store on Qdrant (mem0ai 2.0.20, infer off).</dd>
        <dt>openclaw-memory-md:</dt>
        <dd>OpenClaw agent memory file, read through its memory_get function (openclaw 2026.10.1).</dd>
        <dt>hermes-memory-md:</dt>
        <dd>Hermes Agent memory file, read through the system-prompt snapshot (hermes-agent 0.19.0); it has no metadata layer, so T8 does not apply.</dd>
        <dt>vertex-memory-bank:</dt>
        <dd>Vertex AI Agent Engine Memory Bank, a managed store edited through its data-plane API (google-cloud-aiplatform 2.4.0); it has no record order the evaluator can edit and cannot be copied as a unit, so T4 and T9 do not apply.</dd>
        <dt>bedrock-agentcore-events:</dt>
        <dd>AWS Bedrock AgentCore Memory, event plane, us-east-1; the plane is append-and-delete with no update, so only T2, T3, and T5 apply.</dd>
        <dt>inspeximus-default, -rcpt+dir, -rcpt+dir+home:</dt>
        <dd>inspeximus 3.0.0: receipts off, which is the default; receipts on with the adversary holding the store directory; receipts on with the adversary also holding the configuration home.</dd>
        <dt>acrf-memory-guard:</dt>
        <dd>A per-record HMAC checked on read (acrf-memory-guard 0.1.0).</dd>
        <dt>langgraph-ledger:</dt>
        <dd>A hash-chained ledger kept beside SqliteSaver, with a verify_thread audit (langgraph-ledger 0.3.0).</dd>
        <dt>memory-blackbox-md, -md+restart:</dt>
        <dd>A digest watcher over a memory file backed by a signed ledger (memory-blackbox 0.1.1): with the watching process alive across the edit, and with the process restarted before the scan.</dd>
        <dt>atelya-attest-chain, -chain+anchor:</dt>
        <dd>A keyed hash chain over the memory log (atelya-attest 0.1.1): the chain alone, and the chain with its head anchored outside the store.</dd>
        <dt>continuum-events, -events+attest:</dt>
        <dd>A hash-chained event log (continuum-agent 0.1.0): the chain alone, and the chain with an Ed25519-signed head.</dd>
        <dt>atmem-chain, -chain+checkpoint:</dt>
        <dd>An audit chain (atmem 2.3.8, wheel SHA-256 prefix 05ca2c57): the chain alone, and the chain with an external checkpoint outside the directory the adversary holds.</dd>
        <dt>hdp-token-content-ref, -token-uuid:</dt>
        <dd>A signed-token reference store (@helixar_ai/hdp 0.2.2 at b753ba9, Node 22), resolved by content reference and by UUID.</dd>
        <dt>agent-memory:</dt>
        <dd>A reference runtime over a SQLite canonical substrate with bucketed row digests and a fail-closed open (agent-memory-reference 0.2.0 at f2aef57).</dd>
        <dt>recallspection-exact, -exact+anchor:</dt>
        <dd>ExactMemory, a MAC over the whole container with a tag on every record (exactmemory.recallspection 3.2.0 at c62ef7a): the anchor beside the store, which is the product default, and the anchor off the store.</dd>
        <dt>surgical-devops-g7:</dt>
        <dd>Surgical DevOps G7 directory of signed, position-bound envelopes with a whole-store root tracked against an independent monotonic witness (surgical-dev-ops 2.6.0-rc.6 at f267cf38, Node v24.18.0).</dd>
      </dl>
      <t>
        Six patterns follow from the table.
      </t>
      <t>
        First, the thirteen rows that make no integrity claim serve every
        applicable edit as genuine, the two managed services included. The
        read path trusts the store.
      </t>
      <t>
        Second, T9 is the edit almost nothing survives. Of the twenty-nine
        rows where it applies, twenty-one serve the older copy as current,
        six notice it only at audit, and two refuse it on the read path.
        Four subsystems appear in the table in two configurations that
        differ only in where the integrity head lives, and in every one of
        them T9 changes: atelya-attest and continuum-agent move from
        ACCEPTED to REPORTED when the head is anchored or signed outside the
        store, and T2 moves with it, since a chain alone cannot see its own
        tail removed; atmem moves T9 alone with an external checkpoint; and
        ExactMemory moves T9 alone from ACCEPTED to REJECTED when its anchor
        is taken off the store. The same code gives a different answer, and
        the difference is a deployment decision.
      </t>
      <t>
        Third, what the adversary holds matters as much as what the store
        checks. inspeximus with receipts on reports T1 to T9 at audit
        while the adversary holds only the store directory, and accepts T2
        and T9 once the adversary also holds the configuration home. The
        memory-blackbox 0.1.1 fix described in the -01 revision of
        draft-khandelwal-bmwg-agent-memory-integrity holds for T1 to T8 across a restart, but a whole-store
        rollback that carries the ledger back with the file is accepted
        after a restart and reported only while the process stays alive.
      </t>
      <t>
        Fourth, a per-record authenticator still catches edits to a record's
        bytes and nothing about where the record sits or how many there are.
        acrf-memory-guard rejects T1, T5, and T8 and accepts the other six
        edits it was measured on. The
        token-by-reference store of the Human Delegation Provenance
        Protocol (HDP) <xref target="HDP"/> refuses the six edits that change
        or move a token, under either reference: those three, and also the
        reordered, moved, and rolled-back tokens. Under the content
        reference, a digest recomputed on every read refuses any
        substitution under the reference the recipient holds, and a forged
        token fails the root signature one step later. Under the UUID
        reference, taken from the token's own header, the altered, forged,
        and metadata-edited tokens fail a signature, and the reordered,
        moved, and rolled-back tokens fail because the reference under which
        they were found does not match the header they carry; what a UUID
        cannot stop is a different genuine snapshot of the same chain under
        the same identifier, the substitution <xref target="HDP" section="8.2" sectionFormat="of"/> names,
        which none of these edits makes. Under either reference the store
        serves the three edits that remove tokens or restore an older set,
        because the recipient asks only for the references the store still
        holds, and an older copy of the store resolves each reference it
        holds just as it did when it was current.
      </t>
      <t>
        Fifth, two rows refuse T1 to T9 on the read path, where the -01
        revision of draft-khandelwal-bmwg-agent-memory-integrity had none: surgical-devops-g7,
        whose whole-store root is checked against a witness the store does
        not hold, and recallspection-exact+anchor, whose anchor sits off the
        store and which refuses T10 as well. Two more refuse T1 to T8 on the read path and accept T9,
        agent-memory and recallspection-exact, which is the pattern a
        fail-closed container check produces when its head is kept beside
        the container. Of the rest, acrf-memory-guard and the HDP token
        store refuse a subset on the read path, and every other subsystem
        that claims tamper evidence detects at audit, after the agent has
        already resumed.
      </t>
      <t>
        Sixth, on the seven rows where T10 is measured, six serve the erased
        record again as current once the pre-erasure copy is restored, and
        one refuses it. langgraph-ledger is among the six: it reports T9 at
        audit, because its ledger notices a checkpoint that should be
        present and is not, and accepts T10, because nothing in its ledger
        says that a record should be gone. recallspection-exact+anchor
        refuses T10 on the read path for the same reason it refuses T9: its
        anchor, held off the store, had moved past the restored copy, and
        the store reports itself older than its last committed state.
      </t>
    </section>

    <section anchor="levels">
      <name>Levels (Informative)</name>
      <t>
        The reference implementation publishes a ladder of five levels a
        subsystem can claim from its row, each a set of edits it REJECTS on
        the read path, in the order an adversary with store access reaches
        for them. The levels are cumulative and are not part of the metric;
        they are offered because a single metric value hides which edits a
        subsystem refuses, and a vendor's claim is easier to check when it
        names a level.
      </t>
      <dl newline="false" spacing="compact">
        <dt>L0 Measured:</dt>
        <dd>the subsystem has a published row, with any verdicts.</dd>
        <dt>L1 Bytes bound:</dt>
        <dd>rejects on the read path every edit that changes or adds bytes: T1, T3, T5.</dd>
        <dt>L2 Sequence bound:</dt>
        <dd>also rejects deletion, reordering, and rollback of a record: T2, T4, T7.</dd>
        <dt>L3 Context bound:</dt>
        <dd>also rejects a record moved between owners and a metadata change: T6, T8.</dd>
        <dt>L4 Head anchored off the store:</dt>
        <dd>also rejects a rollback of the whole store to an older genuine copy: T9.</dd>
      </dl>
      <t>
        On the rows in <xref target="results-table"/>, surgical-devops-g7
        and recallspection-exact+anchor reach L4, agent-memory and
        recallspection-exact reach L3, and no released subsystem sits at L1
        or L2: the subsystems that bind bytes on the read path bind sequence
        and context as well, and the two that refuse on the read path
        without reaching L1 both serve a record's removal. The
        implementation also names a fifth level, verifiable by a third party
        without the store's cooperation, marked proposed until a subsystem
        earns it. T10 is not yet part of the ladder: it is measured on seven
        rows, and only one of them, recallspection-exact+anchor, refuses it.
        The ladder will take it up once the cell is carried on every row.
      </t>
    </section>

    <section anchor="rationale">
      <name>Design Rationale (Informative)</name>
      <t>
        Six choices in this method are worth stating explicitly.
      </t>
      <t>
        First, ten edits rather than one. A single "tamper the file" case
        lets a subsystem with a whole-store checksum pass while it still accepts
        rollback and cross-context replay. T6 and T7 in particular exist
        because encryption alone accepts them: they move only genuine bytes.
      </t>
      <t>
        Second, the verdict comes from the SUT, not from the evaluator.
        Inspecting the store to decide whether a tamper "should" have been
        caught makes the result an opinion. Reading through the SUT's own read
        path and recording what it did makes it a measurement.
      </t>
      <t>
        Third, control C1 is not optional. It is the only thing that prevents a
        subsystem that rejects all reads from scoring a perfect result.
      </t>
      <t>
        Fourth, the SUT is stopped during the edit. The memory-blackbox
        result reported in the -01 revision of
        draft-khandelwal-bmwg-agent-memory-integrity is the
        reason: the same subsystem, the same eight edits, and the same scan
        went from eight of eight reported to none of eight on nothing but a
        restart. A method that left the attacker position to the evaluator
        would have produced both results and called both correct.
      </t>
      <t>
        Fifth, T9 is a case of its own rather than a variant of T2. The two
        part ways in <xref target="results-table"/>: atmem's chain alone
        reports T2 and accepts T9, and ExactMemory's container MAC rejects
        T2 and accepts T9, because the rollback restores the chain head or
        the anchor along with the records. In each of the four subsystems
        measured with the head beside the records and again with it
        outside, moving the head is what turns T9 into a pass. A method
        without T9 would have scored the beside-the-records configurations
        as tamper evident against the one edit a restored backup makes.
      </t>
      <t>
        Sixth, T10 is a case of its own rather than a variant of T9. Both
        restore an older genuine copy, but a head that only grows catches
        T9 and can miss T10, because an erasure does not raise it. langgraph-ledger
        in <xref target="results-table"/> shows the split: its ledger of what
        must be present reports T9 at audit and accepts T10. A method that
        folded T10 into T9 would have credited that ledger with catching the
        edit a restored backup makes to an erasure.
      </t>
    </section>

    <section anchor="reference-impl">
      <name>Reference Implementation (Informative)</name>
      <t>
        An open, MIT-licensed implementation of this method, called agmi (Agent
        Memory Integrity), runs offline and applies the ten edits and the
        three controls to the memory components of the subsystems in
        <xref target="results-table"/> through a common adapter interface,
        with every verdict pinned to the measured version by a test that
        fails when the version moves. It also runs as a continuous-integration
        check that fails a build when any edit is accepted; one of the
        measured vendors has adopted it in that form, and another contributed
        its own adapter as a pull request that was reproduced independently
        before it was merged. It is provided for reproducibility and is not
        required to use the method.
      </t>
      <t>
        The implementation's own continuous integration re-measures every
        row it can reach on each change and weekly against the latest
        releases, and fails if this measurement disagrees with the committed
        results on any cell both measured. The results file is published with
        the record described in <xref target="reporting"/>: a digest per row
        over its canonical encoding, a manifest of those digests with named
        rejection grounds, an independent recount with its decision rule, and
        the git commit and the package release as anchor, together with a
        verifier that recomputes all of it from the pinned bytes. Two rows
        re-measured two days apart reproduced cell for cell, detail strings
        included.
      </t>
      <ul empty="true" spacing="compact">
        <li>Code and results: https://github.com/tech4biz-yasha/agent-memory-integrity, revision e7fef18 (version 0.6.3). The results file at that revision holds thirty-nine rows: the thirty-one of <xref target="results-table"/>, the reference model left out of it, and seven rows measured only on the implementation's memory-specific attack families, which lie outside this method. For class (b) verdicts it records the audit call used in each cell; the store or namespace queried and the interval between the edit and the audit read are not yet recorded as fields and are added in the next revision. It records the platform of the run, and for eleven rows the runtime they were measured on, but not the libraries each SUT links against.</li>
        <li>Results site: https://agentmemoryintegrity.org</li>
        <li>Method paper: https://doi.org/10.5281/zenodo.22995111</li>
      </ul>
    </section>

    <section anchor="security">
      <name>Security Considerations</name>
      <t>
        This document defines a benchmarking method for laboratory use. As with
        other benchmarking methodologies, the procedures here are intended for
        an isolated test bed and <bcp14>MUST NOT</bcp14> be run against production systems or
        systems the evaluator is not authorised to test. The test cases apply
        adversarial edits to a store; those edits <bcp14>MUST</bcp14> be confined to test data
        in a controlled environment. T10 exercises the SUT's own erasure
        operation, which on some subsystems removes a whole context; it
        <bcp14>MUST</bcp14> be run only against test data.
      </t>
      <t>
        The method measures a security-relevant property, whether an agent
        detects at-rest tampering with its memory, but a metric value from this
        method is not by itself an assurance of security. A high value on this
        method does not measure confidentiality, input-path poisoning
        resistance, or any property outside <xref target="scope"/>.
      </t>
      <t>
        Publishing per-case verdicts for named subsystems and versions
        describes weaknesses in released software. The intent is constructive:
        results are stated with the version measured so that vendors can
        reproduce and fix them, and so that a later re-measurement shows the
        change.
      </t>
    </section>

    <section anchor="iana">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>

  </middle>

  <back>
    <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 initials="S." surname="Bradner" fullname="S. Bradner"/>
          <date year="1997" month="March"/>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="2119"/>
      </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 initials="B." surname="Leiba" fullname="B. Leiba"/>
          <date year="2017" month="May"/>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="8174"/>
      </reference>
    </references>

    <references>
      <name>Informative References</name>
      <reference anchor="RFC2544" target="https://www.rfc-editor.org/info/rfc2544">
        <front>
          <title>Benchmarking Methodology for Network Interconnect Devices</title>
          <author initials="S." surname="Bradner" fullname="S. Bradner"/>
          <author initials="J." surname="McQuaid" fullname="J. McQuaid"/>
          <date year="1999" month="March"/>
        </front>
        <seriesInfo name="RFC" value="2544"/>
      </reference>
      <reference anchor="RFC8239" target="https://www.rfc-editor.org/info/rfc8239">
        <front>
          <title>Data Center Benchmarking Methodology</title>
          <author initials="L." surname="Avramov" fullname="L. Avramov"/>
          <author initials="J." surname="Rapp" fullname="J. Rapp"/>
          <date year="2017" month="August"/>
        </front>
        <seriesInfo name="RFC" value="8239"/>
      </reference>
      <reference anchor="I-D.calabria-bpm-ai-fabric-terminology" target="https://datatracker.ietf.org/doc/draft-calabria-bpm-ai-fabric-terminology/">
        <front>
          <title>Benchmarking Terminology for AI Network Fabrics</title>
          <author initials="F." surname="Calabria" fullname="Fernando Calabria"/>
          <author initials="C." surname="Pignataro" fullname="Carlos Pignataro"/>
          <author initials="Q." surname="Wu" fullname="Qin Wu"/>
          <author initials="G." surname="Fioccola" fullname="Giuseppe Fioccola"/>
          <author initials="S." surname="Reddy" fullname="Sowjanya Reddy"/>
          <date year="2026" month="October" day="30"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-calabria-bpm-ai-fabric-terminology-00"/>
      </reference>
      <reference anchor="I-D.hcf-bpm-agent-security-benchmark-terminology" target="https://datatracker.ietf.org/doc/draft-hcf-bpm-agent-security-benchmark-terminology/">
        <front>
          <title>Benchmarking Terminology for AI Agent Security Evaluation</title>
          <author initials="Y." surname="Han" fullname="Yu Han"/>
          <author initials="M." surname="Chen" fullname="Meiling Chen"/>
          <author initials="Q." surname="Fan" fullname="Qiguang Fan"/>
          <author initials="Q." surname="Wu" fullname="Qin Wu"/>
          <date year="2026" month="October" day="23"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-hcf-bpm-agent-security-benchmark-terminology-00"/>
      </reference>
      <reference anchor="HDP" target="https://datatracker.ietf.org/doc/draft-helixar-hdp-agentic-delegation/">
        <front>
          <title>Human Delegation Provenance Protocol (HDP): Cryptographic Chain-of-Custody for Agentic AI Systems</title>
          <author initials="A." surname="Dalugoda">
            <organization>Helixar Limited</organization>
          </author>
          <date year="2026" month="October" day="6"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-helixar-hdp-agentic-delegation-03"/>
      </reference>
    </references>

    <section anchor="ack" numbered="false">
      <name>Acknowledgements</name>
      <t>
        The author thanks the maintainers of the memory subsystems measured
        during the development of this method for their engagement on the
        individual findings, in particular the maintainers of inspeximus, who
        found the no-op cells that led to control C3, and of memory-blackbox,
        who reproduced and fixed the restart result within a day; of
        Surgical DevOps, who contributed their store's adapter; of
        Recallspection and HDP, who reviewed the description of their own
        systems before their rows were published, HDP having also added the
        measured cases to its own conformance suite; and of
        agent-evidence-vectors, whose corpus this implementation runs in its
        continuous integration and which runs this implementation's verifier
        in return. Thanks also to the authors of
        draft-han-bmwg-agent-security-benchmark, since split into
        <xref target="I-D.hcf-bpm-agent-security-benchmark-terminology"/> and
        its companion profiles document, for the discussion on the working
        group list that shaped the detection-point distinction and for taking
        up this method's verdicts and placement test in those documents.
      </t>
    </section>

    <section anchor="changes" numbered="false">
      <name>Change Log</name>
      <t>This section is to be removed before publication as an RFC.</t>
      <section anchor="changes-02" numbered="false">
        <name>Changes Since draft-khandelwal-bmwg-agent-memory-integrity-02</name>
        <ul spacing="compact">
          <li>Renamed from draft-khandelwal-bmwg-agent-memory-integrity, which this document replaces, on the formation of the BPM working group as the successor of BMWG; the change history below continues that draft's.</li>
          <li>Added test case T10, erasure resurrection, with its C3 clause, its not-applicable rule, its scoring group, and the rationale for keeping it separate from T9.</li>
          <li>Added the T10 column to the illustrative table, measured on seven rows; the other cells are not yet measured or not applicable, with the reason stated in the results file. T1 to T9 are unchanged from -02, cell for cell.</li>
          <li>Rewrote the description of the HDP token store's results in the wording of the published row pages, which its maintainer reviewed.</li>
          <li>Named the metric document this method serves as the test method for, draft-hcf-bpm-agent-security-benchmark-terminology, which adopts its threat model, procedure and verdicts, and recorded the two edits that document does not yet carry.</li>
          <li>Noted how a profile that credits read-time detection alone takes its count from the per-case verdicts.</li>
          <li>Added the observation point of a verdict, in the three classes of draft-calabria-bpm-ai-fabric-terminology restated for a software DUT, and the conditions under which two verdicts are comparable across runs, as discussed on the working group list in October 2026.</li>
          <li>Updated the reference implementation revision to e7fef18 and stated the row count of its results file.</li>
          <li>Added the runtime and the libraries the SUT links against to the comparability conditions, and stated that the method sets no threshold for an acceptable Metric Value.</li>
          <li>Cited the HDP specification and the renamed AI fabric terminology draft.</li>
          <li>Removed the submissionType attribute and added the author's country.</li>
        </ul>
      </section>
      <section anchor="changes-01" numbered="false">
        <name>Changes in draft-khandelwal-bmwg-agent-memory-integrity-02</name>
        <ul spacing="compact">
          <li>Added test case T9, whole-store rollback, with its C3 clause, its scoring group, and the rationale for keeping it separate from T2.</li>
          <li>Made the detection point a required property of a result and required separate results for a subsystem that offers both a read-path check and an audit.</li>
          <li>Added the C3 refusal for identically seeded contexts.</li>
          <li>Added a reporting requirement for a recomputable published result set, and described the reference implementation's record and its continuous re-measurement.</li>
          <li>Replaced the illustrative results with thirty-one rows on released subsystems, including the first two that refuse all nine edits on the read path, and added the informative levels ladder.</li>
          <li>Updated the reference implementation to version 0.6.3 at its current repository path.</li>
        </ul>
      </section>
      <section anchor="changes-00" numbered="false">
        <name>Changes in draft-khandelwal-bmwg-agent-memory-integrity-01</name>
      <ul spacing="compact">
        <li>Added control C3, "edit landed", and the "error" outcome.</li>
        <li>Made the stopped-SUT attacker position explicit in the procedure, with rationale.</li>
        <li>Replaced the illustrative results with thirteen subsystems, including six that claim tamper evidence, and the first vendor fix.</li>
        <li>Added the relationship to the write-path poisoning and cross-context isolation metrics.</li>
        <li>Updated the reference implementation to version 0.6.2 and the method paper to its second version.</li>
      </ul>
      </section>
    </section>
  </back>
</rfc>
