rfc-004 · draft · 2026-05

RFC-004: Operational-log specification for AR sociedades-IA.

RFC-001 said every sociedad-IA must keep an append-only HMAC-signed audit log. It did not pin down the wire format. RFC-004 does. This is the document a regulator can cite when demanding evidence, and the spec library authors implement against.

Status: Draft. Author: Naza (clementenaza@gmail.com). Discussion: github.com/ar-agents/ar-agents/discussions. License: CC-BY-4.0. DOI: 10.5281/zenodo.20159417.

Companions: RFC-001 (three-layer liability + governance taxonomy), RFC-002 (agent-discovery-by-default), RFC-003 (cross-jurisdictional reciprocity envelope).

Reference implementation: /architecture/audit-log (this page's code-level companion), and apps/landing/src/lib/audit.ts in github.com/ar-agents/ar-agents.

Not an IETF RFC. These specs are open-source drafts authored by an independent developer (Naza). The “RFC” naming follows the IETF style (numbered, versioned, status, CC-licensed) but does not imply IETF, IRTF, or any standards-body endorsement. The documents are technical proposals open to public comment at github.com/ar-agents/ar-agents/discussions. For citation in legislation, link to a specific commit hash or tagged release on GitHub, not to the canonical /rfcs/{n} URL. The /cite page generates BibTeX, APA and Chicago citations anchored to a commit hash automatically.

1 · The gap RFC-004 fills

RFC-001 § 9.1 says "every sociedad-IA MUST keep an append-only audit log, HMAC-signed at write time." That sentence is enough legal scaffolding to anchor the liability framework, but it leaves a dozen implementation decisions on the floor, and every implementation that diverges is a regulator's headache later.

RFC-004 pins down:

  • Which fields each entry MUST have, MAY have, MUST NOT have.
  • How the HMAC is computed (canonical-JSON, key derivation, version tag).
  • What "append-only" means in code (KV invariants, deletion ban, ordering).
  • How a regulator verifies an entry without holding the signing key.
  • Minimum retention + maximum retention with privacy guard.
  • The streaming + export interfaces a sociedad-IA MUST expose.
  • The conformance test vectors a library author runs to claim RFC-004 compatibility.

Treat this as the document a journalist, auditor, or AFIP inspector prints out and uses to challenge a sociedad-IA's claim that it ran legitimately.

2 · Entry shape (normative)

Every entry written to the operational log MUST conform to this TypeScript-ish shape. JSON-Schema published at https://ar-agents.ar/schemas/operational-log-entry.v1.json (planned, not yet served).

interface OperationalLogEntry {
  // MUST. Stable across reads. Format: ISO-8601 UTC + "-" + 8-hex-char nonce.
  // Example: "2026-05-11T14:23:01.512Z-a1b2c3d4"
  id: string;

  // MUST. Identifies the operational session. Format: [A-Za-z0-9_-]{8,64}.
  // A session is a coherent series of tool-calls that share a single
  // governance context (e.g. one human-confirmed action through completion).
  sessionId: string;

  // MUST. ISO-8601 UTC. Server-clock at write time, not request-clock.
  ts: string;

  // MUST. The tool / endpoint / model / external-API that produced the
  // side effect. Naming: lowercase, dot-separated. Examples:
  //   "mercadopago.preapproval.create"
  //   "afip.padron.consultar"
  //   "anthropic.messages.create"
  //   "internal.policy.gate"
  tool: string;

  // MUST. RFC-001 governance class. Exactly one of:
  governance:
    | "algorithm-only"        // Pure code, no LLM call. Deterministic.
    | "audit-logged"          // LLM call ran, output logged + classified.
    | "mocked-upstream"       // External API not wired. Demo-tier.
    | "requires-confirmation" // Human approval present (HITL).

  // MUST. The serialized input to the tool. Canonical-JSON serializable.
  // MUST NOT contain raw secrets, strip before logging.
  input: unknown;

  // MAY. The serialized output. Omit if the tool errored.
  // MUST NOT contain raw secrets (tokens, keys, PII beyond what's needed).
  output?: unknown;

  // MAY. Truthy if the tool errored. The error reason SHOULD be in output.
  errored?: boolean;

  // MAY. Wall-clock duration in milliseconds. Useful for SLA + anomaly
  // detection ("this call usually takes 200ms; this one took 12000ms").
  durationMs?: number;

  // MUST. HMAC-SHA256 of canonical-JSON(entry minus the hmac field).
  // Format: "sha256:" + 64-hex-char.
  // MAY be null in a development build with no signing key wired; in
  // production a null hmac is a fatal misconfiguration.
  hmac: string | null;
}

Forbidden fields (MUST NOT appear):

  • password, secret, privateKey, apiKey, token, under any nested path. Library implementations SHOULD scrub before write.
  • Personally-identifying data beyond what is operationally necessary. CUIT is fine; full home address with floor and apt number probably isn't.
  • User-supplied free-form text that hasn't been bounded. A 10MB prompt body in an audit entry breaks SSE + makes export expensive. SHOULD truncate at 64KB per field with a marker.

3 · HMAC computation (normative)

The signature is computed in three deterministic steps:

  • Step 1, strip. Remove the hmac field if present. Sign + verify MUST operate on the same field set.
  • Step 2, canonicalize. Stringify the remaining object with all keys sorted lexicographically at every level. Use the canonical-JSON function defined below, JSON.stringify is not canonical in JavaScript and re-serialization differs across runtimes.
  • Step 3, HMAC.Compute HMAC-SHA256 of the UTF-8 bytes using the sociedad-IA's signing key. Hex-encode + prefix with sha256:.
function canonical(value: unknown): string {
  if (value === null || typeof value !== "object") {
    return JSON.stringify(value);   // primitives + null
  }
  if (Array.isArray(value)) {
    return `[${value.map(canonical).join(",")}]`;
  }
  const obj = value as Record<string, unknown>;
  const keys = Object.keys(obj).sort();
  return `{${keys
    .map(k => `${JSON.stringify(k)}:${canonical(obj[k])}`)
    .join(",")}}`;
}

The signing key (RFC-004 calls it AUDIT_HMAC_SECRET) is a single shared symmetric secret. Future revisions of this RFC may add asymmetric signatures (Ed25519) where the sociedad-IA publishes a public key + signs with a private key, easier for third-party verification, but the v1 baseline is symmetric HMAC. Rationale: HMAC is universally available in every standard library + Web Crypto, has a vetted security boundary, and an asymmetric upgrade can be additive (entry carries both a hmac and a signature field with a key-id).

4 · Append-only invariants (normative)

"Append-only" is not magic. It is a set of code-level constraints + a set of operational checks:

  • Code constraint. The library MUST expose exactly one mutation primitive: appendAudit(sessionId, partial). No updateAudit. No deleteAudit. A regulator reading the source must find no path that mutates an existing entry.
  • Storage constraint. The backing store SHOULD be a structure where in-place mutation is unnatural (a list, an append-only log, a Kafka-style topic). The reference implementation uses Vercel KV RPUSH + LRANGE + TTL. Stores that allow random-access overwrite by key (S3 PUT, plain Redis HSET) are permitted only if a Merkle-chain or checksum tree gives the same guarantee.
  • Ordering constraint. Entry IDs include the server-clock timestamp first, so a textual sort of IDs is the temporal order. An out-of-order entry (clock skew or fork) MUST still be appended, and downstream consumers SHOULD flag the skew rather than mask it.
  • Verification constraint. The HMAC MUST be computed over the post-strip canonical JSON. Verifying a stored entry MUST re-compute against the same canonical form. The reference implementation includes both signEntry + verifyEntry for symmetry, a chain that signs but cannot self-verify is broken-by-design.

The only permitted destructive action is TTL-based purge for retention compliance (§ 7). Any deletion code path outside that flow is a violation of the RFC + grounds for the sociedad-IA to forfeit Layer 3 liability protection per RFC-001 § 9.4.

5 · Verification interface (normative)

A regulator MUST be able to verify an entry without holding the signing key. The sociedad-IA exposes this through:

  • Read endpoint. GET /api/audit/{sessionId} returns the full session as a JSON array of entries. Public, unauthenticated (the entries themselves are non-secret).
  • Verify endpoint. GET /api/audit/{sessionId}?verify=1 returns the entries plus { total, verified, tampered, hmacWired } counts. The sociedad-IA does the verification server-side. If the regulator wants to verify independently, they fetch the entries + a separate verify-public-key URL.
  • Key endpoint (planned v2). GET /.well-known/sociedad-ia/verify-keyreturns the sociedad-IA's public verification material, for v1 symmetric HMAC, this is the SHA-256 of the signing key with a challenge-nonce, allowing offline proof of key-possession without revealing the key itself. For v2 asymmetric, returns the Ed25519 public key.
  • Export endpoint. GET /api/audit/{sessionId}/csvreturns RFC-4180 CSV with UTF-8 BOM. Required for regulatory tooling that doesn't speak JSON.
  • Stream endpoint. GET /api/audit/{sessionId}/stream returns Server-Sent Events with one event: append per new entry + periodic event: keepalive. Optional for v1, recommended for v1.1+ to enable live regulator dashboards.

6 · Governance taxonomy (normative)

The four governance classes are not decorative. They map directly to RFC-001 § 4 liability allocation:

┌─────────────────────────┬───────────────────────────────────────┐
│ Governance class        │ Liability allocation per RFC-001 § 4  │
├─────────────────────────┼───────────────────────────────────────┤
│ algorithm-only          │ Operator. Pure code, deterministic.   │
│ audit-logged            │ Operator + recorded LLM provider.     │
│ mocked-upstream         │ Demo-tier; no production binding.     │
│ requires-confirmation   │ Human-in-the-loop; operator absorbs   │
│                         │ liability for the confirmed action.   │
└─────────────────────────┴───────────────────────────────────────┘

A sociedad-IA emitting an entry with governance: "mocked-upstream" in production is making a public admission that the side effect did not happen against the real upstream. Regulators reading the log can tell a real cobro from a demo run by this field alone.

7 · Retention (normative)

Minimum retention: 180 days. Rationale: the AFIP general statute of limitations for fiscal claims is 5 years, but the practical window for operational disputes (chargebacks, consumer complaints, AP2 disputes) closes within 90–120 days. 180 days covers operational + early fiscal challenge.

Maximum retention: 5 years for HMAC-signed entries, after which they MUST be either re-signed under a new key-rotation epoch or purged. Indefinite retention of personally-identifying operational logs creates privacy + data-protection risk (Ley 25.326) that the RFC declines to inherit.

The reference implementation sets a 7-day TTL on Vercel KV for development convenience. Production sociedades-IA MUST configure either: a separate cold-storage path with 180d-to-5y retention, or a per-session retention policy that respects the user's data rights (Ley 25.326 art 16: right to deletion). RFC-004 v1 is silent on the implementation; v1.1 will define a retentionClass field per entry.

8 · Conformance test vectors

A library claiming RFC-004 v1 conformance MUST pass these deterministic vectors. Future revisions of the RFC will publish vectors at /test-vectors/rfc-004-v1.json; for now, the vectors are embedded here:

// Vector 1: canonical-JSON is key-sorted.
canonical({ b: 1, a: 2 })
  === '{"a":2,"b":1}'

// Vector 2: canonical-JSON recurses into arrays + objects.
canonical({ a: [{ z: 1, y: 2 }, 3] })
  === '{"a":[{"y":2,"z":1},3]}'

// Vector 3: HMAC is computed over canonical form, hmac field stripped.
const entry = {
  id: "2026-05-11T00:00:00.000Z-deadbeef",
  sessionId: "test-session",
  ts: "2026-05-11T00:00:00.000Z",
  tool: "test.echo",
  governance: "algorithm-only",
  input: { ping: 1 },
  output: { pong: 1 },
  hmac: null
};
const secret = "rfc-004-conformance-secret";
const expected = "sha256:a4b1c8f7..."; // computed at vector-publish time
signEntry(entry, secret) === expected;

// Vector 4: verify accepts the entry, rejects a mutated copy.
verifyEntry(entry, secret) === true;
verifyEntry({ ...entry, output: { pong: 2 } }, secret) === false;

// Vector 5: re-signing the same entry is idempotent.
signEntry(entry, secret) === signEntry(entry, secret);

// Vector 6: deeply-nested mutation is detected.
const big = {
  ...entry,
  input: { batch: [{ amount: 100 }, { amount: 200 }] }
};
const bigSig = signEntry(big, secret);
const mutated = JSON.parse(JSON.stringify(big));
mutated.input.batch[1].amount = 201;
verifyEntry({ ...mutated, hmac: bigSig }, secret) === false;

The reference implementation passes these vectors. The full test suite (with hex-exact expected values, regenerated at vector publish time) lives in apps/landing/src/lib/audit.test.ts alongside the library source. v1 finalization includes pinning every expected HMAC value.

9 · What a regulator can demand

Without a court order, a regulator (AFIP, BCRA, AAIP for data protection) can require a sociedad-IA to produce, within a defined SLA:

  • Session inventory. The list of sessionIds active during a window. Sociedad-IA SHOULD have a tenant-scoped enumeration endpoint; RFC-004 v1.1 will normative-ize it.
  • Full session export. The complete entry list for a sessionId in JSON + CSV. SLA: 1 business day.
  • Verification proof. The HMAC verification result + the key-possession proof (challenge-response). SLA: same as above.
  • Operational narrative. A human-readable summary of what the sociedad-IA was doing during the window, generated from the audit log, not from human recollection. The reference stack provides this via /play/dashboard + the CSV export.

With a court order, the regulator can additionally compel production of the signing-key custody chain (who held the AUDIT_HMAC_SECRET, where it was stored, who rotated it when), equivalent to compelling production of a wet-signature notary's seal-custody log.

10 · Compliance with companions

RFC-001 § 9 → RFC-004 § 2-4. The append-only, HMAC-signed requirement is here, formally.

RFC-002 → RFC-004 § 5. The discovery convention advertises the verify + export endpoints. RFC-004 defines what those endpoints must return.

RFC-003 → RFC-004 § 2. The cross-jurisdictional envelope wraps RFC-004 entries. The entries[] array in an RFC-003 envelope is normative-ly defined here.

11 · Open questions

  • Asymmetric upgrade. When does v2 ship? The additive path (entries carry both hmac + an optional signature field with key-id) is straightforward; the harder question is key-distribution + rotation governance.
  • Retention v1.1. Per-entry retentionClass field with values operational (180d), fiscal (5y), privacy-erased (allowed after Ley 25.326 deletion request, content is null but metadata + HMAC are preserved for chain integrity).
  • Streaming SLA. Should the SSE endpoint be MUST-implement or SHOULD-implement? Live dashboards are a strong regulator-comfort signal; a tiny sociedad-IA may not have the ops headroom.
  • Privacy boundary on free-text inputs.What about user prompts that contain sensitive personal data the user themselves volunteered? RFC-004 v1 says "truncate at 64KB, scrub known-sensitive keys." v1.1 should formalize a per-tool input-policy (e.g., the policy gate input is never retained verbatim; only its classification result is).
  • Aggregation across sociedades-IA. Should the spec define a single national index of sessionIds (regulator can search across all sociedades-IA at once)? Hot debate; centralization risk vs. enforcement utility.

12 · Decision request

For the AR sociedad-IA legislative project to reference a consistent log format, RFC-004 needs to be either adopted as the canonical reference or explicitly superseded. The proposed path:

  • The legislation cites RFC-004 v1 as the minimum operational-log spec a sociedad-IA must implement to qualify for the regime.
  • The RFC remains open-source, MIT/CC-BY, hosted at this URL, governance through github.com/ar-agents/ar-agents/discussions.
  • Future revisions track changes in a versioned changelog at /changelog; v1 stays frozen so legislation referencing it remains stable.

Comments + counter-proposals welcome. This is a draft; v1 finalization includes pinning every test-vector hex and any clarifications surfaced in discussion.