Skip to content

Provenance, Not Identity

attributed_to (on an Event), responsible_party (on a Task), and requested_reviewers (on a ReviewRequest) are descriptive, untrusted project metadata (SPEC §8). They carry no identity, authority, planning, routing, obligation, or authorization — they are free-form opaque labels, and a consumer MUST NOT treat them as authenticated principals, permission grants, or work assignments.

By InterIP Networks · Last updated 2026-07-01.

DCP has exactly three fields that name a person, team, or agent in prose:

FieldEntityWhat it records
attributed_toEventWho or what is associated with a change, in project terms
responsible_partyTaskThe team or role named as responsible for a task
requested_reviewersReviewRequestWho was asked to review, in project terms

All three are strings. None of them carry a scheme:value identity structure — no email:alice@example.com, no github:alice, no key fingerprint. They are opaque labels, and the spec forbids giving them that kind of structured identity shape, precisely so nothing downstream is tempted to parse one as a credential.

It’s tempting to read responsible_party: "backend-team" as an assignment, or requested_reviewers: ["alice"] as a routing instruction that will page Alice. Neither is true. DCP defines no work-assignment semantics and no message routing (see transport-neutral). These fields are the DCP equivalent of a free-text “assignee” column in a spreadsheet: useful for a human reading the record, meaningless as a system-enforced obligation.

Concretely, per SPEC §8, a producer or consumer MUST NOT:

  • Treat any of these three fields as an authenticated principal.
  • Treat them as a permission grant — naming someone a reviewer confers no review authority.
  • Treat them as a work assignment that a workflow engine should enforce.

A ReviewRequest.requested_reviewers list of ["alice", "bob"] says only: the project record claims Alice and Bob were asked. It does not notify them, does not grant them approval rights, and does not guarantee the message reached anyone at all — see the Event reference for the full field, and the protocol SECURITY documentation (summarized in the specification, §12) untrusted-fields list, which places attributed_to, responsible_party, and requested_reviewers alongside correlation_id and message_id as fields that must never back an authorization or audit decision without independent, transport-layer binding.

This mirrors the treatment of identifiers in SPEC §3. A DCP identifier such as task_42 is an opaque string matching ^[a-z]+_[A-Za-z0-9._-]+$; its prefix denotes a category for readability only, never namespace ownership or routing authority, and identifiers are producer-asserted with no referential-integrity guarantee. Provenance labels follow the identical logic one layer up: a string that looks meaningful to a human reader carries no verifiable authority to a machine. Just as a consumer MUST NOT derive meaning from an identifier beyond its prefix category, it MUST NOT derive identity or authorization from a provenance label beyond its literal text.

Authenticating who actually did something — verifying that the agent claiming to be “alice” really is Alice, and deciding whether Alice is allowed to approve a review — is the job of the transport and identity layer, not the semantic layer. That split is the prime directive in miniature: “DCP carries no trust. DCP describes project-state changes only.” DCP’s job stops at recording the project-level claim; whichever transport carries the message (a mesh, a queue, a webhook relay) is the sole authority for identity, authentication, and permissions.

Mapping a label like responsible_party: "alice" to a real, authenticated principal — an OAuth subject, a signed agent key, a directory entry — is explicitly called out in SPEC §8 as a transport-layer responsibility, and one that MUST NOT be performed by consuming DCP alone. A system that wants to notify Alice, or gate an approval on Alice’s real identity, must resolve that mapping itself, using its own identity and access-control infrastructure, before it acts.

Some agent-to-agent protocols bind messages to authenticated sender identities as part of the wire format. DCP deliberately does not — see DCP vs. A2A for how that comparison plays out. A DCP message can travel over any transport, including ones with strong identity guarantees, but the DCP body itself never asserts one. That’s what keeps a DcpMessage portable: moving it between transports is a transport swap, not a rewrite, because none of its fields depend on a particular identity model.

If you’re building a consumer: read attributed_to, responsible_party, and requested_reviewers for display, search, and reporting — they’re genuinely useful project context. But never wire them into an authorization check, a notification dispatch, or an audit log entry without first resolving them through your transport’s real identity layer.