Universal verification correlation convention. Any primary event can be paired with
X.verify.<mechanism>.<observation> sub-events from independent observers.
Matrix-native correlation via m.relates_to. Divergence is itself audit signal.
Every event in foundation.protocols.* is a claim: this happened. Almost every claim is made by a single observer — a bridge reading API traffic, a hook intercepting tool calls, an SDK monkey-patch wrapping a library call. Single-observer claims can go wrong in two ways:
To turn each event from a self-report into a provable claim, we adopt a universal verification pattern: any primary event MAY be accompanied by zero or more verify events from independent observers. Each verify event confirms — or by its absence, fails to confirm — that the primary claim is real.
This is the "reported vs. actual" invariant made first-class in the Matrix event model. Correlating intention-layer events (e.g., ai.claude.*) with execution-layer events (e.g., ai.gryph.*) is the foundation of the audit trail; this convention formalises the pattern so any family can adopt it.
For any primary event of type foundation.protocols.<path>.<event>, zero or more verify events MAY be emitted with types of the form:
foundation.protocols.<path>.<event>.verify.<mechanism>.<observation>
<path>.<event> — the full type of the primary event being verified.verify — literal marker distinguishing this as a verification event.<mechanism> — the verifier's identity (gryph, hopsworks_server, downstream_store, etc.).<observation> — what that verifier observed (command_exec, file_write, audit_log, statefile_write).Each verify event MUST reference the primary via Matrix's native m.relates_to:
{
"type": "foundation.protocols.ai.hopsworks.feature_group.create.verify.gryph.command_exec",
"content": {
"m.relates_to": {
"event_id": "$primaryEventId:matrix.org",
"rel_type": "foundation.protocols.verify.v1"
},
"session_id": "2026-04-14T09:00Z",
"observed_at": "2026-04-14T09:00:12.312Z",
"verifier": "gryph-hook",
"verifier_version": "v0.6.0",
"primary_event_id": "$primaryEventId:matrix.org",
"primary_event_type": "foundation.protocols.ai.hopsworks.feature_group.create",
"observed_command": "python3 -c \"hopsworks.login(); fs.create_feature_group(...)\"",
"exit_code": 0,
"duration_ms": 2100,
"stdout_preview": "Feature group 'weather_training_data' v1 created"
}
}
The rel_type value — foundation.protocols.verify.v1 — identifies this specifically as a verification relationship, distinct from Matrix native reactions (m.annotation), replies (m.in_reply_to), edits (m.replace), or threads (m.thread).
Every verify event, regardless of mechanism, includes:
| Field | Type | Required | Description |
|---|---|---|---|
| m.relates_to | object | yes | Matrix native relationship with rel_type: "foundation.protocols.verify.v1" and the primary event's event_id. |
| session_id | string | yes | Copied from the primary event. Enables session-level filtering without following m.relates_to. |
| observed_at | string (ISO 8601) | yes | When the verifying observer saw evidence, UTC. |
| verifier | string | yes | Identifier of the verifying observer (e.g. "gryph-hook", "hopsworks-audit-daemon"). |
| verifier_version | string | recommended | Verifier version, for reproducibility of audit analyses. |
| primary_event_id | string | yes | Duplicated for convenience outside m.relates_to. |
| primary_event_type | string | yes | Duplicated for convenience. |
Mechanism-specific fields follow as defined by each verify subtype's spec (e.g. observed_command + exit_code for .verify.gryph.command_exec).
A well-behaved session satisfies:
session_id.Divergence from the invariant is itself signal:
| Observation | Interpretation |
|---|---|
| Primary with zero verify events (when verify is expected) | Hallucination — the primary observer reported an event that the verifier did not confirm. Or transport failure. Or the verifier is not running (operational). |
| Verify without a matching primary | Silent action — something happened that the primary observer missed or failed to announce. |
| Primary and verify both exist but content disagrees | Race condition, spoofing attempt, observer bug, or two actions close in time misaligned. |
Primary's session_id ≠ verify's session_id | Cross-session misattribution. Almost always a bug. |
| Verify emitted before primary | Clock skew or replay. Investigate. |
This spec does not mandate how audit signals are surfaced. Offline analysis scripts, a correlation daemon, a TUI, or nothing at all — downstream choice.
The pattern is additive and optional. Not every event has a verify counterpart:
ai.claude.text.emitted (Claude's narrative output). No OS-level or SDK-level observer can verify "Claude emitted text" because the only place that text exists is in the Anthropic API response. No verify expected.ai.gryph.file_read_blocked_sensitive — gryph blocked a read without the agent's announcement. The event IS the ground truth. No verify expected.ai.governance.art9_check_determined that represent the agent's internal reasoning about a regulation. No OS or SDK correlate. No verify expected.When an event has no verify by design, its family spec MUST say so. When an event SHOULD have verify but doesn't in a given session, that is audit signal #1 above.
The following <mechanism> identifiers are reserved for consistent semantics across families:
<mechanism> | Meaning |
|---|---|
gryph | Observation via a gryph-based hook implementation (safedep/gryph or any compatible downstream) on the agent runtime. Primary use: OS-level execution verification. |
bridge | Observation via one of the domain bridges (Claude bridge, Hopsworks bridge, Ansvar MCP proxy, etc.). Primary use: SDK-layer execution verification. |
<service>_server | Observation by a remote service's server-side audit (hopsworks_server, ansvar_server, matrix_server). Primary use: ground-truth remote state confirmation. |
downstream | Observation by a downstream system that would have received the effect. |
replay | Observation by re-running the primary's described action in a sandbox. Cryptographic-style verification. |
Novel mechanisms not on this list are allowed but should be documented in the adopting family's spec.
This is version 1 of the correlation protocol. The rel_type string foundation.protocols.verify.v1 is the canonical stable identifier for this version.
If the naming scheme, rel_type, or required fields change in an incompatible way, the protocol bumps to foundation.protocols.verify.v2 and maintains both indefinitely. Consumers handle unknown versions by ignoring them (Matrix clients naturally do this for unknown event types).
High-level index of planned verify mechanisms for each existing event family. Individual family specs own the authoritative detail:
| Family | Primary layer | Planned verify mechanisms | Status |
|---|---|---|---|
ai.claude.tool.bash | Anthropic API | .verify.gryph.command_exec | Planned |
ai.claude.tool.read | Anthropic API | .verify.gryph.file_read | Planned |
ai.claude.tool.{write,edit,multi_edit} | Anthropic API | .verify.gryph.file_write | Planned |
ai.claude.tool.{glob,grep} | Anthropic API | (no gryph hook today) | None |
ai.claude.tool.agent_spawn | Anthropic API | sub-session correlation via spawned session_id | Planned |
ai.claude.session.{start,end} | Anthropic API | ai.gryph.session.{start,end} via linked session_id | Planned |
ai.claude.text.emitted | Anthropic API | (intention-only) | N/A |
ai.claude.cost.summary / .model.usage | Anthropic API (estimated) | .verify.gryph.transcript_cost | Planned |
ai.gryph.* | Gryph hook | (self-verifying execution) | N/A |
ai.hopsworks.feature_group.* / feature_view.* / model.* / deployment.* / job.* / data.* | SDK monkey-patch | .verify.gryph.command_exec, .verify.hopsworks_server.audit_log | Planned |
ai.hopsworks.session.{start,end} | SDK monkey-patch | .verify.gryph.command_exec | Planned |
ai.hopsworks.quota.exceeded | SDK monkey-patch | — | None |
ai.hopsworks.claude.analysis | Bridge (pure reasoning) | (intention-only) | N/A |
ai.ansvar.regulation.queried / .search.result | MCP proxy | .verify.gryph.command_exec, .verify.ansvar_server.log | Planned |
ai.ias.claude.domain.{loaded,unloaded} | Bridge marker parse | .verify.gryph.statefile_write, .verify.gryph.file_read | Planned |
ai.ias.claude.gc.{proposed,accepted,declined} | Bridge marker parse | .verify.gryph.statefile_write | Planned |
ai.ias.claude.session.{start,end} | Bridge marker parse | .verify.gryph.statefile_write | Planned |
ai.ias.claude.pressure.threshold | Bridge computation | (pure introspection) | N/A |
ai.governance.* | Bridge classifier | (pure intention / classification) | N/A |
eudr.* / legal.* / data.* | Orchestrator composition | TBD per-event | TBD |
Status notation:
Planned — verify mechanism is designed at spec level; implementation may or may not yet exist ·
None — no verify mechanism is expected for this primary event (asymmetry) ·
N/A — event is by nature intention-only, execution-only, or pure computation; verify is not applicable ·
TBD — family has not yet been audited against this convention.