<?xml version="1.0" encoding="utf-8"?>
<?xml-model href="rfc7991bis.rnc"?>
<!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-noctem-cogitator-witness-protocol-00"
     ipr="trust200902"
     obsoletes=""
     updates=""
     submissionType="independent"
     xml:lang="en"
     version="3">

  <front>
    <title abbrev="COGITATOR Witness Protocol">
      COGITATOR Witness Protocol: Cryptographically Verifiable Audit Records for AI Agent Execution
    </title>

    <seriesInfo name="Internet-Draft" value="draft-noctem-cogitator-witness-protocol-00"/>

    <author fullname="George G" initials="G." surname="G">
      <organization/>
      <address>
        <email>george.g@tuta.io</email>
      </address>
    </author>

    <date year="2026" month="April" day="9"/>

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

    <keyword>AI</keyword>
    <keyword>agent</keyword>
    <keyword>audit</keyword>
    <keyword>tamper-evident</keyword>
    <keyword>witness</keyword>
    <keyword>BLAKE3</keyword>
    <keyword>compliance</keyword>
    <keyword>EU AI Act</keyword>
    <keyword>SCITT</keyword>
    <keyword>supply chain</keyword>

    <abstract>
      <t>
        This document specifies the COGITATOR Witness Protocol -- a scheme for producing
        cryptographically verifiable, tamper-evident records of AI agent execution. A conforming
        implementation produces a single witness root value that any third party can independently
        recompute from the same inputs to verify the record was not altered after the fact.
      </t>
      <t>
        The protocol is implementation-agnostic. The reference implementation is COGITATOR (Rust),
        but any language or framework can produce conforming witness bundles.
      </t>
      <t>
        This document also describes how the COGITATOR Witness Protocol relates to the IETF SCITT
        architecture, with which it is designed to be used as a payload inside SCITT Signed
        Statements.
      </t>
    </abstract>

  </front>

  <middle>

    <section anchor="intro">
      <name>Introduction</name>
      <t>
        AI agents deployed in regulated or high-stakes environments issue tool calls with
        real-world consequences. Existing audit approaches -- log ingestion, post-hoc summaries,
        model cards -- are reconstructive. They describe what probably happened, not what
        provably happened. Logs are mutable. Post-hoc summaries are interpretations.
      </t>
      <t>
        The COGITATOR Witness Protocol takes the position that agent execution should be as
        auditable as a compiled binary in a reproducible build system. The witness root is the
        runtime equivalent of a content-addressed store path: a cryptographic commitment that
        ties a specific output to a specific, verifiable execution.
      </t>
      <t>
        This specification is intended to complement, not replace, the SCITT architecture
        (draft-ietf-scitt-architecture). SCITT provides the outer envelope: a Signed Statement
        registered on a Transparency Service with a verifiable Receipt. The COGITATOR Witness
        Protocol provides the inner payload: a structured, hash-chained record of what the agent
        did, attempted, and was blocked from doing.
      </t>

      <section anchor="requirements">
        <name>Requirements Language</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 (RFC 2119) (RFC 8174) when, and only when, they appear in all
          capitals, as shown here.
        </t>
      </section>
    </section>

    <section anchor="definitions">
      <name>Definitions</name>
      <dl>
        <dt>Run</dt>
        <dd>A single end-to-end execution of an agent against a set of inputs.</dd>
        <dt>Tool call</dt>
        <dd>A discrete action dispatched by the agent to an external or internal tool.</dd>
        <dt>Phantom entry</dt>
        <dd>A record of a tool call that was intercepted and blocked before dispatch.</dd>
        <dt>Witness root</dt>
        <dd>A single BLAKE3 hex digest committing the entire run record.</dd>
        <dt>Policy digest</dt>
        <dd>A SHA-256 hex digest of the policy file in effect during the run.</dd>
        <dt>Canonical JSON</dt>
        <dd>JSON serialised according to RFC 8785 (deterministic key ordering, no insignificant whitespace).</dd>
        <dt>Witness bundle</dt>
        <dd>The complete set of artefact files for a single run.</dd>
        <dt>Signed Statement</dt>
        <dd>As defined in draft-ietf-scitt-architecture: a COSE-signed envelope carrying a payload and subject claim, registered on a SCITT Transparency Service.</dd>
        <dt>Receipt</dt>
        <dd>As defined in draft-ietf-scitt-architecture: a proof of inclusion issued by a Transparency Service confirming a Signed Statement was registered on its ledger.</dd>
      </dl>
    </section>

    <section anchor="bundle-structure">
      <name>Witness Bundle Structure</name>
      <t>A conforming witness bundle MUST contain the following files:</t>
      <artwork><![CDATA[
run_<id>/
+-- agent_trace.json        # Agent steps: inputs, tool requests, outputs
+-- tool_transcript.json    # All tool calls (real and phantom) with outcomes
+-- chaos_profile.json      # Fault injection schedule (may be empty)
+-- drift_report.json       # Replay mismatch report (empty if no drift)
+-- hash_chain.txt          # Per-call BLAKE3 hashes, one per line
+-- meta.json               # Witnessed metadata
+-- witness_manifest.json   # Per-file hashes and bundle hash
+-- witness_root.txt        # Single hex string -- the tamper-evident root
      ]]></artwork>
      <t>All JSON files MUST be serialised as RFC 8785 canonical JSON before hashing.</t>
    </section>

    <section anchor="schema">
      <name>Schema Definitions</name>

      <section anchor="schema-meta">
        <name>meta.json</name>
        <artwork><![CDATA[
{
  "schema_version": 4,
  "run_id": "<string>",
  "agent_id": "<string>",
  "seed": "<uint64>",
  "policy_digest": "<sha256-hex | null>",
  "started_at": "<ISO 8601 datetime>",
  "finished_at": "<ISO 8601 datetime>",
  "cogitator_version": "<semver string>"
}
        ]]></artwork>
        <ul>
          <li>schema_version MUST be 4 for this version of the protocol.</li>
          <li>policy_digest MUST be the SHA-256 hex digest of the policy file bytes, or null if no policy was in effect.</li>
          <li>seed MUST be the fixed random seed used for the run, enabling deterministic replay.</li>
        </ul>
      </section>

      <section anchor="schema-transcript">
        <name>tool_transcript.json</name>
        <artwork><![CDATA[
{
  "schema_version": 4,
  "entries": [ /* ToolCall[] */ ],
  "phantom_entries": [ /* PhantomEntry[] */ ],
  "policy_digest": "<sha256-hex | null>"
}
        ]]></artwork>

        <section anchor="schema-toolcall">
          <name>ToolCall Object</name>
          <artwork><![CDATA[
{
  "step": "<uint>",
  "tool_call_idx": "<uint>",
  "tool_name": "<string>",
  "request": { },
  "response": { },
  "chaos_fault": "<string | null>",
  "call_hash": "<blake3-hex>"
}
          ]]></artwork>
          <t>
            call_hash MUST be the BLAKE3 digest of the RFC 8785 canonical JSON of this
            object, with call_hash set to the empty string before hashing.
          </t>
        </section>

        <section anchor="schema-phantom">
          <name>PhantomEntry Object</name>
          <artwork><![CDATA[
{
  "step": "<uint>",
  "tool_call_idx": "<uint>",
  "tool_name": "<string>",
  "request": { },
  "disposition": "Blocked | Phantom",
  "rule_id": "<string | null>",
  "reason": "<string | null>",
  "entry_hash": "<blake3-hex>"
}
          ]]></artwork>
          <ul>
            <li>entry_hash MUST be the BLAKE3 digest of the RFC 8785 canonical JSON of this object, with entry_hash set to the empty string before hashing.</li>
            <li>disposition MUST be one of Blocked (tool call explicitly denied by policy) or Phantom (tool call silently observed but not dispatched).</li>
          </ul>
        </section>
      </section>

      <section anchor="schema-hashchain">
        <name>hash_chain.txt</name>
        <t>
          A newline-delimited text file. Each line is the call_hash or entry_hash of one
          record in the order they were produced, interleaving real calls and phantom entries
          chronologically.
        </t>
      </section>

      <section anchor="schema-manifest">
        <name>witness_manifest.json</name>
        <artwork><![CDATA[
{
  "files": {
    "agent_trace.json": "<blake3-hex>",
    "tool_transcript.json": "<blake3-hex>",
    "chaos_profile.json": "<blake3-hex>",
    "drift_report.json": "<blake3-hex>",
    "hash_chain.txt": "<blake3-hex>",
    "meta.json": "<blake3-hex>"
  },
  "bundle_hash": "<blake3-hex>"
}
        ]]></artwork>
        <ul>
          <li>Each file hash is the BLAKE3 digest of the raw file bytes.</li>
          <li>bundle_hash is the BLAKE3 digest of the RFC 8785 canonical JSON of the files object.</li>
        </ul>
      </section>

      <section anchor="schema-root">
        <name>witness_root.txt</name>
        <t>
          A single line containing the BLAKE3 hex digest of the RFC 8785 canonical JSON of
          the complete witness_manifest.json object (including bundle_hash). This is the only
          value that needs to be published for a third party to verify the entire bundle.
        </t>
      </section>
    </section>

    <section anchor="computation">
      <name>Witness Root Computation</name>
      <t>The witness root is computed as follows:</t>
      <ol>
        <li>Serialise each bundle file to RFC 8785 canonical JSON (or raw bytes for text files).</li>
        <li>Compute BLAKE3(file_bytes) for each file to produce the files map.</li>
        <li>Compute BLAKE3(RFC8785(files)) to produce bundle_hash.</li>
        <li>Serialise witness_manifest.json including bundle_hash.</li>
        <li>Compute BLAKE3(RFC8785(witness_manifest)) to produce witness_root.</li>
        <li>Write witness_root as a single lowercase hex string to witness_root.txt.</li>
      </ol>
      <t>
        A verifier replays steps 1-6 from the bundle files and asserts the computed root
        matches the published witness_root.txt.
      </t>
    </section>

    <section anchor="policy">
      <name>Policy Protocol</name>
      <t>
        The policy layer is optional. If no policy file is provided, all tool calls are
        implicitly allowed and policy_digest MUST be null in both meta.json and
        tool_transcript.json.
      </t>
      <t>When a policy file is provided:</t>
      <ol>
        <li>The policy file bytes MUST be SHA-256 digested before any run begins.</li>
        <li>The digest MUST be committed to meta.json and tool_transcript.json before the first tool call.</li>
        <li>Every tool call MUST be evaluated against the policy before dispatch.</li>
        <li>Blocked or phantomed calls MUST produce a PhantomEntry committed to the witness chain.</li>
        <li>The CallHistory MUST be updated after every verdict, including blocked calls.</li>
      </ol>

      <section anchor="policy-verdicts">
        <name>Policy Verdicts</name>
        <table>
          <thead>
            <tr><th>Verdict</th><th>Tool dispatched?</th><th>Agent receives</th><th>Chain entry</th></tr>
          </thead>
          <tbody>
            <tr><td>allow</td><td>Yes</td><td>Real tool response</td><td>ToolCall</td></tr>
            <tr><td>block</td><td>No</td><td>blocked: true</td><td>PhantomEntry(Blocked)</td></tr>
            <tr><td>phantom</td><td>No</td><td>blocked: true</td><td>PhantomEntry(Phantom)</td></tr>
          </tbody>
        </table>
      </section>
    </section>

    <section anchor="replay">
      <name>Deterministic Replay</name>
      <t>
        A conforming implementation MUST support replay mode. Given the original
        agent_trace.json, chaos_profile.json, policy file (identified by policy_digest),
        and seed, a replay run MUST produce an identical witness_root to the original run.
        Any deviation MUST be reported as a DriftIssue in drift_report.json.
      </t>
    </section>

    <section anchor="conformance">
      <name>Conformance</name>
      <t>An implementation is conforming if:</t>
      <ol>
        <li>It produces all required bundle files.</li>
        <li>All JSON files are RFC 8785 canonical before hashing.</li>
        <li>The witness root computation follows the algorithm in Section 6 exactly.</li>
        <li>Phantom entries are produced for all blocked and phantomed calls.</li>
        <li>The policy digest is committed before the first tool call when a policy is in effect.</li>
        <li>Replay of the same inputs produces an identical witness root.</li>
      </ol>
    </section>

    <section anchor="scitt-integration">
      <name>Integration with SCITT</name>
      <t>
        The COGITATOR Witness Protocol is designed to be used as a payload within the SCITT
        architecture (draft-ietf-scitt-architecture). The RECOMMENDED integration pattern is:
      </t>
      <ol>
        <li>After a run completes, the witness bundle is produced as specified in this document.</li>
        <li>The witness_root value and run_id from meta.json are embedded as the payload of a COSE-signed SCITT Signed Statement, with the subject header set to the agent identifier.</li>
        <li>The Signed Statement is registered with a SCITT Transparency Service via the SCRAPI interface (draft-ietf-scitt-scrapi).</li>
        <li>The resulting Receipt is stored alongside the witness bundle.</li>
      </ol>
      <t>
        This provides two independently verifiable guarantees: the SCITT Receipt proves the
        witness root was registered at a specific time; the witness root proves the bundle
        contents have not been altered since computation.
      </t>
    </section>

    <section anchor="regulatory">
      <name>Relation to Regulatory Frameworks</name>
      <t>The COGITATOR Witness Protocol is designed to address requirements of:</t>
      <ul>
        <li>EU AI Act (2024) Articles 12 and 9 -- tamper-evident record-keeping and risk management for high-risk AI.</li>
        <li>FCA AI and machine learning guidance -- audit trails for automated decision systems in financial services.</li>
        <li>NIST AI RMF (2023) -- traceability and accountability for AI systems.</li>
      </ul>
    </section>

    <section anchor="versioning">
      <name>Versioning</name>
      <t>
        This document describes protocol version 1.0, corresponding to schema_version 4 in
        bundle files. Breaking changes will increment both version numbers together.
      </t>
    </section>

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

    <section anchor="security">
      <name>Security Considerations</name>
      <t>
        The integrity guarantees of the witness root depend on the collision resistance of
        BLAKE3. As of the date of this document, BLAKE3 is not known to have practical
        collision attacks.
      </t>
      <t>
        The protocol does not provide confidentiality. Witness bundles may contain sensitive
        agent inputs and outputs. Implementors are responsible for access controls on bundle
        storage and transmission.
      </t>
      <t>
        The policy digest commits to the policy file bytes but does not authenticate the
        provenance of the policy file itself. Deployments requiring policy provenance guarantees
        should sign policy files independently before committing the digest.
      </t>
    </section>

  </middle>

  <back>
    <references>
      <name>Normative References</name>
      <reference anchor="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="RFC" value="2119"/>
      </reference>
      <reference anchor="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="RFC" value="8174"/>
      </reference>
      <reference anchor="RFC8785">
        <front>
          <title>JSON Canonicalization Scheme (JCS)</title>
          <author initials="A." surname="Rundgren" fullname="A. Rundgren"/>
          <author initials="B." surname="Jordan" fullname="B. Jordan"/>
          <author initials="S." surname="Erdtman" fullname="S. Erdtman"/>
          <date year="2020" month="June"/>
        </front>
        <seriesInfo name="RFC" value="8785"/>
      </reference>
    </references>

    <references>
      <name>Informative References</name>
      <reference anchor="I-D.draft-ietf-scitt-architecture">
        <front>
          <title>An Architecture for Trustworthy and Transparent Digital Supply Chains</title>
          <author initials="H." surname="Birkholz" fullname="Henk Birkholz"/>
          <author initials="A." surname="Delignat-Lavaud" fullname="Antoine Delignat-Lavaud"/>
          <author initials="C." surname="Fournet" fullname="Cedric Fournet"/>
          <author initials="Y." surname="Deshpande" fullname="Yogesh Deshpande"/>
          <author initials="S." surname="Lasker" fullname="Steve Lasker"/>
          <date year="2025" month="October"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-ietf-scitt-architecture-22"/>
      </reference>
      <reference anchor="I-D.draft-ietf-scitt-scrapi">
        <front>
          <title>SCITT Reference APIs</title>
          <author initials="H." surname="Birkholz" fullname="Henk Birkholz"/>
          <author initials="J." surname="Geater" fullname="Jon Geater"/>
          <date year="2026" month="March"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-ietf-scitt-scrapi-07"/>
      </reference>
      <reference anchor="RFC9162">
        <front>
          <title>Certificate Transparency Version 2.0</title>
          <author initials="B." surname="Laurie" fullname="B. Laurie"/>
          <author initials="E." surname="Messeri" fullname="E. Messeri"/>
          <author initials="R." surname="Stradling" fullname="R. Stradling"/>
          <date year="2021" month="December"/>
        </front>
        <seriesInfo name="RFC" value="9162"/>
      </reference>
    </references>
  </back>

</rfc>
