# Relationships and assurance

> Explicit edges, the three assurance levels, and exactly where a machine proposal's confidence score and method live in the payload.

Most edges in an OWG graph are never written by hand. They fall out of running the work: a task that declares `used` and `produced` has stated its own lineage. Those are **structural edges**, and they cost nothing.

This page is about the other kind — edges that require judgement to assert, including every edge a machine proposes while federating two systems together. Those need somewhere to live and something to say about how much they should be trusted.

## Structural versus explicit

| | Structural | Explicit |
|---|---|---|
| Where | Implicit in `tasks[]` — `used`, `produced`, `performed_by`, `ran_on`, `depends_on` | The `relationships[]` array |
| Cost | Free. A by-product of describing work | Requires intelligence or a human |
| Assurance | Always `asserted` by the executing system | Any of three levels |
| Examples | This task consumed that plate | This asset is the same as that one in Frame.io |

The rule: **if executing the workflow proves the edge, it is structural. If something had to decide, it is explicit.** Never duplicate a structural edge in `relationships[]`.

## The relationship object

```json
{
  "relationships": [
    {
      "id": "rel_0001",
      "relation": "same_as",
      "from": { "kind": "asset", "id": "plate_0140" },
      "to":   { "kind": "asset", "id": "frameio_b2c8e9f1" },
      "assurance": "inferred",
      "confidence": 0.82,
      "method": "m-corroborated-2",
      "proposed_by": "connector_frameio",
      "proposed_at": "2026-08-20T09:14:00Z"
    }
  ]
}
```

| Field | Type | Notes |
|---|---|---|
| `id` | string | **Required.** Identifies the edge, so a decision about it can be recorded |
| `relation` | string | **Required.** The predicate. See [vocabulary](#relation-vocabulary) |
| `from` | object | **Required.** `{ kind, id }` |
| `to` | object | **Required.** `{ kind, id }` |
| `assurance` | enum | **Required.** `attested` \| `asserted` \| `inferred` |
| `confidence` | number | 0.0–1.0. **Required when `assurance` is `inferred`**; forbidden otherwise |
| `method` | string | **Required when `assurance` is `inferred`**; forbidden otherwise |
| `proposed_by` | string | Participant id — the connector, agent, or person proposing |
| `proposed_at` | string | RFC 3339 timestamp |
| `accepted_by` | string | Participant id of whoever confirmed it. Absent while pending |
| `accepted_at` | string | RFC 3339 timestamp of acceptance |
| `metadata` | object | Freeform |
| `profiles` | object | Profile-contributed extensions, keyed by profile id (v0.92). See [Extensions](/specification#extensions) |

`kind` in an endpoint is one of `asset`, `participant`, `task`, `organization`, `infrastructure`, `context`.

The conditional requirement is enforced by the schema, not merely described: an `inferred` relationship **without** `confidence` and `method` is a validation error, and an `attested` or `asserted` relationship **with** them is also an error. A confidence score on a human assertion is meaningless, and an inference without one is unauditable.

## The three assurance levels

| Level | Meaning | Carries confidence |
|---|---|---|
| `attested` | Backed by a verified content credential — a C2PA manifest, a signed device output | No |
| `asserted` | Declared by a system of record, or confirmed by a human | No |
| `inferred` | Proposed rather than declared, carrying its score and method identifier | **Yes, required** |

These three appear in the same form wherever assurance is expressed — on relationships here, and on [assets](/assets-and-versioning#assurance-and-credentials). One vocabulary, one rule about confidence.

## An inferred edge, end to end

This is the full lifecycle of a machine proposal, which is what makes federation safe rather than merely automatic.

**1. A connector proposes.** It has found a plausible match between an asset in the graph and one in an external system, and scores it by whatever method it used:

```json
{
  "id": "rel_0042",
  "relation": "same_as",
  "from": { "kind": "asset", "id": "plate_0140" },
  "to":   { "kind": "asset", "id": "ext_frameio_b2c8e9f1" },
  "assurance": "inferred",
  "confidence": 0.74,
  "method": "m-probabilistic-1",
  "proposed_by": "connector_frameio",
  "proposed_at": "2026-08-20T09:14:00Z"
}
```

**2. An acceptance policy decides what happens next.** What confidence warrants automatic acceptance, what warrants review, and what is discarded outright is **entirely an implementation decision** — the specification takes no position, because the right policy depends on the content, the systems involved, and the consequences of a wrong match.

What the specification does require is that whatever happens next is recorded.

**3. A human confirms.** Acceptance does not overwrite the proposal — it annotates it:

```json
{
  "id": "rel_0042",
  "relation": "same_as",
  "from": { "kind": "asset", "id": "plate_0140" },
  "to":   { "kind": "asset", "id": "ext_frameio_b2c8e9f1" },
  "assurance": "inferred",
  "confidence": 0.74,
  "method": "m-probabilistic-1",
  "proposed_by": "connector_frameio",
  "proposed_at": "2026-08-20T09:14:00Z",
  "accepted_by": "s.okafor",
  "accepted_at": "2026-08-20T11:03:00Z"
}
```

Note what is preserved. The edge **stays `inferred`** with its original score and method, and gains an acceptance. It does not get promoted to `asserted`, because that would erase the fact that a machine proposed it at 0.74 confidence and a named person waved it through. Six months later, when the match turns out to be wrong, the question "who accepted this and on what evidence" has an answer.

This is the graph's own provenance rules applied to the graph's own construction — the claim is only meaningful if the acceptance is recorded, which is why `accepted_by` exists.

**4. Acceptance may be automatic.** Where an implementation's policy accepts a proposal without human review, the accepting actor is still named:

```json
{
  "id": "rel_0043",
  "relation": "same_as",
  "from": { "kind": "asset", "id": "plate_0141" },
  "to":   { "kind": "asset", "id": "ext_frameio_c9d1f0a2" },
  "assurance": "inferred",
  "confidence": 1.0,
  "method": "m-exact-identifier",
  "proposed_by": "connector_frameio",
  "proposed_at": "2026-08-20T09:14:00Z",
  "accepted_by": "connector_frameio",
  "accepted_at": "2026-08-20T09:14:00Z"
}
```

The connector accepted its own proposal, and says so. An auto-accept is still an accept, with an actor.

## The `method` field

`method` is an opaque identifier naming **which** method produced the inference. The specification requires that it be present and stable; it does not define a vocabulary, and an implementation's methods are its own.

The reason it is required at all is auditability rather than description: when a class of match later proves unreliable, you need to select every edge produced by that method and re-review the set. That is only possible if the method is recorded as a stable, filterable value.

Two rules follow:

- **Keep method identifiers stable.** Renaming one orphans every edge produced under the old name.
- **Make them specific enough to be useful as a filter.** A single value used for every inference tells a future reviewer nothing.

> **Confidence is not accuracy.** `confidence` states how strongly *that* method believes the match, in its own terms. Two different methods' scores are not directly comparable — which is exactly why `method` is required alongside, and why acceptance policy belongs to the implementation that knows what its own scores mean.

## Relation vocabulary

An open set — the specification does not constrain `relation`, because domains will need predicates it has not anticipated. Documented values:

| Relation | Meaning |
|---|---|
| `same_as` | The two endpoints are the same real thing in different systems |
| `derived_from` | The `from` endpoint originates in the `to` endpoint |
| `version_of` | Endpoints are versions of one lineage. Prefer asset `predecessor` where it applies |
| `depicts` | The asset shows the referenced subject |
| `features` | The asset features the referenced participant or character |
| `part_of` | Structural containment |
| `references` | A weaker link than `derived_from` — cites without deriving |

**Direction matters and is easy to get backwards.** For `derived_from`, `from` is the newer thing and `to` is the source: the edge reads *from derived_from to*. Every relation reads in that order — subject, predicate, object. Asserting the reverse silently inverts lineage answers, so it is worth a test.

## Where semantic edges come from

An edge like `features` requires understanding the content. In OWG, whatever produced that understanding is **itself a task** — with an executor, a participant, and a cost:

```json
{
  "tasks": [
    {
      "id": "tag_faces",
      "type": "work",
      "label": "Identify featured performers",
      "executor": { "type": "agent" },
      "ai_role": "assistive",
      "performed_by": "agent_vision",
      "used": ["master_mp4"],
      "produced": ["face_tags"],
      "failure_mode": "CONTINUE"
    }
  ],
  "relationships": [
    {
      "id": "rel_0100",
      "relation": "features",
      "from": { "kind": "asset", "id": "master_mp4" },
      "to":   { "kind": "participant", "id": "perf_lead" },
      "assurance": "inferred",
      "confidence": 0.88,
      "method": "m-subject-recognition",
      "proposed_by": "agent_vision",
      "proposed_at": "2026-08-20T14:02:00Z"
    }
  ]
}
```

So an inferred relationship carries the same provenance as any other piece of work: `proposed_by` names the agent, and the agent's own `operated_by` chain names the human accountable for it. Enrichment is not a special case that escapes accountability.

## Guidance

- **Do not mirror structural edges here.** If a task's `used`/`produced` already states it, adding a relationship is duplication that will drift.
- **Always populate `proposed_by`.** An edge with no proposer cannot be reviewed, revoked as a class, or trusted.
- **Never round confidence to 1.0** unless the match is genuinely deterministic. Overstating confidence is the one agent failure mode that corrupts the graph rather than merely wasting a review.
- **Keep `method` stable.** It is a filter key. Renaming a method orphans every edge produced under the old name.
