# Verification Semantics

URL: https://docs.nexart.io/docs/verification-semantics

How to read verification results correctly: identity, reseal behavior, signals scope, and common pitfalls.

This page resolves the ambiguities builders most often hit when integrating NexArt verification. Read it once before shipping.

## certificateHash Is the Source of Truth

`certificateHash` is the canonical identity of any Certified Execution Record. Always store and resolve artifacts by `certificateHash`.

- Public verification URL: `https://verify.nexart.io/c/{certificateHash}`
- SDK lookup, deduplication, audit trails: keyed on `certificateHash`
- For Project Bundles: `projectHash` plays the same role at the bundle level

##### executionId is not a unique artifact identifier

`executionId` is a convenience identifier returned by the certify API. It MUST NOT be used as the primary key for storage, deduplication, or public verification URLs. Use `certificateHash`.

## Resealed Artifacts Have a New Hash

The public verifier MAY return a redacted reseal instead of the original CER. A reseal exists so that artifacts containing sensitive metadata can still be publicly verified after redaction.

A reseal is a new bundle:

- bundleType: `signed-redacted-reseal`
- NEW certificateHash: covers the resealed (redacted) content
- Provenance pointer: references the ORIGINAL `certificateHash` (reference only, not validated)
- Fresh node signature: covers the resealed content

Reseal provenance shape (illustrative)

```
{
  "bundleType": "signed-redacted-reseal",
  "certificateHash": "sha256:<NEW resealed hash>",
  "provenance": {
    "originalCertificateHash": "sha256:<ORIGINAL hash>",
    "reason": "public-redaction",
    "resealedAt": "2026-04-19T10:12:00.000Z"
  },
  "snapshot": { "...redacted snapshot...": true },
  "meta": {
    "attestation": {
      "receipt": { "certificateHash": "sha256:<NEW resealed hash>" },
      "signature": "...",
      "kid": "key_..."
    }
  }
}
```

Rules to apply when you receive a reseal:

- The resealed `certificateHash` is what the verifier validates.
- The original `certificateHash` is reference-only in public context. Do not validate against it.
- Both hashes can legitimately coexist. They describe the same execution at different visibility levels.
- If your application stores the original hash, also store the resealed hash returned by the verifier; treat them as a pair.

## Context Signals: Inside vs Outside Hash Scope

Context signals MAY be transported either inside or outside the `certificateHash` scope:

- Inside the hash. Signals are part of the canonical bundle. Any change invalidates the hash. This is the strongest binding.
- Outside the hash. Signals are transported as supplemental metadata. They are recorded and visible, but their absence or modification does NOT invalidate `certificateHash`.

The verification report distinguishes the two. Signals outside the hash scope are reported as supplemental, not as a failure. Do not treat "signals outside hash scope" as a verification failure.

## Verification Result Classes

| Status | Meaning | Action |
| --- | --- | --- |
| VERIFIED | All applicable checks PASS. No supplemental notes. | Trust the artifact. |
| VERIFIED (supplemental) | Core integrity PASS. Supplemental context present but outside hash scope (e.g. unbound signals). | Trust the artifact. Note that supplemental fields are not cryptographically bound. |
| FAILED | One or more applicable checks FAIL. | Do not trust. Inspect the per-pillar report. |
| NOT_FOUND | Artifact not registered on the node. | Register on the node, then re-resolve. |

See Verification Reports for the full per-pillar semantics.

## Common Pitfalls

- Using `executionId` instead of `certificateHash` for lookup. The execution id is API convenience metadata; only certificateHash is the canonical identity.
- Sending `undefined` values inside metadata or signals. Some runtimes drop undefined keys before serialization, others coerce them. Either omit the key or use `null` to keep canonical JSON deterministic.
- Assuming all signals are hash-bound. They MAY be supplemental. Treat the verifier's "supplemental" status as a normal result.
- Confusing the original `certificateHash` with the public resealed hash. Validate against whichever hash the verifier returns. Store both as a pair.
- Treating local `verifyProjectBundle()` as proof of public verifiability. It only proves integrity. See End-to-End Verification.

## Next

- End-to-End Verification: the full pipeline.
- How Verification Works: per-pillar checks.
- Attestation Node: reseal behavior at the node level.
