# description
Independent-peer-attestation envelope for synthetic media (images, video, audio, voice clones, avatars). Closes SYNTHESIS-acquisition Round 20 P2 [[ai-image-video-generation]] M1 ship-first action. Designed to RIDE ABOVE C2PA Content Credentials (which are always generator-self-signed via the producer's own CA — Adobe → DigiCert, etc.) rather than replace them. Where C2PA carries the generator's claim, ip.synthetic.media.attestation.v1 carries an INDEPENDENT peer attestation of that claim — Ed25519-signed by judges who verify the generator output matches what the C2PA manifest claims it is. EU AI Act Article 50(2) effective 2026-12-02 (DEFERRED from 2026-08-02 by the 7 May 2026 Digital Omnibus; the Art-50(1)/(3)/73 transparency obligations remain 2026-08-02) requires machine-readable AI-generation marking on synthetic content; €15M / 3% global turnover penalties under Article 99. FTC May-2026 endorsement guidance on synthetic influencers + AI testimonials compounds the regulatory pull. Designed for Runway / Pika / Luma / Sora-2 (tiered $0.10-$0.50/sec) / Midjourney v8.1 / FLUX.2 / Veo 3.1 / Imagen 4 / Kling 3.0 (Kuaishou 60M creators) / Adobe Firefly + Photoshop AI (C2PA founder member) / Stability SD3.5 + Stable Video / Civitai (19.21M visits Feb-2026) / HeyGen $100M ARR / Synthesia $146M ARR + $4B val + $200M Series E Jan-2026 / D-ID / SUNO + Udio (post-RIAA settlements). One JSON Schema × every synthetic-media generator + every IPTC digitalSourceType.

# $comment
Discovery: https://ip.tekton.cc/.well-known/ip-knowledge.json (full descriptor) | Badge: https://ip.tekton.cc/api/badge/v1/attestation/synthetic.media.attestation.v1/<subjectSha256> (shields.io endpoint) | Free dry-run: POST https://ip.tekton.cc/api/credentials/dry-run with body {kind:"synthetic.media.attestation.v1", body:<candidate>} (no auth required, validates against this schema) | Verification recipe: https://ip.tekton.cc/docs/verification-recipe.md (3-layer trust model + curl trail) | Revocation: https://ip.tekton.cc/credentials/status/v1 (W3C BitstringStatusList v1.0; check bit at credentialStatus.statusListIndex)

# x-controlMappingRefs.$comment
Cycle 685 (RC-600-P1-6 deferred — per-schema controlMappingRefs[]).

# x-controlMappingRefs.iso42001Aims[].note
System documentation for users — digitalSourceType enum (IPTC-aligned)

# x-controlMappingRefs.nistAiRmf[].note
GenAI Profile — provenance + traceability (C2PA 2.1/2.2 alignment)

# x-controlMappingRefs.euAiAct[].note
AI-generated content disclosure — digitalSourceType enum

# x-controlMappingRefs.euAiAct[].note
Transparency for AI systems — schema description + machine-readable kind identifier

# x-controlMappingRefs.iso42001RiskRegister[].note
Schema is the Article 50 transparency anchor — IPTC + C2PA interop

# properties.schemaVersion.description
Semver of this schema. Bumps to 2.0.0 land at /credentials/synthetic-media/v2 — v1 stays immutable (see /docs/schema-versioning.md for the cycle-726 canonical bump-mechanics + soft-change-detection contract).

# properties.attestationId.description
Unique RFC 4122 UUID v4 or v7 — this attestation's canonical identifier. Lets a consumer dedupe across retries + replays and link this attestation back to a specific ip.attestation.event.v1 wire row via ipAttestationEventId.

# properties.mediaSha256.description
Sha256 of the canonical bytes of the synthetic media artifact. For images: sha256 of the file bytes (PNG/JPEG/WebP/AVIF/etc.). For video: sha256 of the container file (MP4/WebM/MOV). For audio: sha256 of the file (WAV/MP3/FLAC/AAC). For interactive (HeyGen interactive avatar, Synthesia EXPRESS-1): sha256 of the canonical descriptor manifest. The verifier downloads the media + recomputes; without binding consumers cannot pin 'the image at URL X on date Y had bytes Z.'

# properties.mediaType.description
Top-level media class. Coarser than IANA media-type; finer than 'media.' Lets a downstream consumer route the attestation to the right verifier (image → C2PA Content Credentials reader; video → Sora/Veo/Kling-specific verifier; audio → SUNO/Udio/Whisper verifier).

# properties.digitalSourceType.description
IPTC digitalSourceType taxonomy term — the SAME enum the C2PA Content Credentials assertion uses. 'trainedAlgorithmicMedia' = pure AI-generated (Sora, Midjourney, FLUX). 'compositeWithTrainedAlgorithmicMedia' = human-edited + AI-generated mix (Adobe Firefly Generative Fill). 'trainedAlgorithmicCapture' = AI camera applied to a real capture (computational photography). The enum aligns with IPTC Photo Metadata Standard 2024.1 (which C2PA 2.1 + 2.2 reference) so IntelligencePro attestations interoperate with the rest of the synthetic-media ecosystem without re-mapping.

# properties.generatorId.description
Identifier of the model / pipeline that generated the media. Format is ecosystem-conventional. Examples: 'sora-2-2026-04', 'midjourney-v8.1', 'flux.1.2-pro-ultra', 'veo-3.1', 'kling-3.0', 'firefly-image-3', 'stable-diffusion-3.5', 'suno-v5', 'udio-v2', 'heygen-express-1', 'synthesia-express-1'. The generator author chooses canonical naming. Verifier resolves the generatorId via generatorDid → JWKS to confirm the claim's provenance.

# properties.generatorVersionSha256.description
Optional sha256 of the generator's canonical release artifact. For OSS generators (FLUX.1.dev, Stable Diffusion 3.5, LTX): sha256 of the safetensors / GGUF weights. For closed APIs (Sora, Midjourney): the generator vendor may publish a version-binding manifest that resolves to this sha. When omitted, generatorId + generatorDid are the only identity anchors.

# properties.generatorDid.description
DID of the entity that operates the generator. did:web for institutional / vendor (did:web:openai.com, did:web:adobe.com, did:web:runwayml.com, etc.) — resolves to a JWKS that can verify the generator's own signature on the content (if it was C2PA-signed). did:key for individual creator / OSS-self-hosted runs.

# properties.promptSha256.description
Sha256 of the canonical prompt bytes that drove the generation. For text-to-image: sha256 of the prompt string + negative prompt + control parameters (seed, steps, guidance, etc.) in canonical-JSON. For image-to-image / video-to-video: include the source-media sha256 in the canonical-JSON input. For voice cloning: sha256 of the source-voice consent envelope + target-text. The point: a consumer can verify 'this image came from THIS prompt' by re-running the generator (when accessible) or by comparing to the prompt the creator publishes alongside.

# properties.promptDisclosure.description
Disclosure posture for the prompt. 'public' = the actual prompt is published alongside the attestation (creator commitment). 'salted' = a salt was prepended before hashing so the prompt can be revealed later for spot-check verification while remaining private day-to-day. 'withheld' = only the hash is published; creator commits to internal verification. Aligns with C2PA 2.2's 'partial disclosure' patterns + EU AI Act Article 50 Code of Practice draft.

# properties.createdAt.description
Epoch milliseconds when the media was generated. Required because EU AI Act Article 50(2) machine-readable marking implies time-of-generation provenance, and downstream verifiers (regulators, fact-checkers, publishers) need to reason about whether a piece of content existed before a specific date.

# properties.publishedAt.description
Epoch milliseconds when the media was first published / shared. Optional but recommended — distinct from createdAt when the creator generates internally and publishes later (most commercial production workflows). When present, publishedAt >= createdAt.

# properties.c2paManifestSha256.description
Sha256 of the C2PA manifest bytes that accompany this media. CP rides ABOVE C2PA: the C2PA manifest is the GENERATOR's self-signed claim ('I, Adobe Firefly, generated this'); ip.synthetic.media.attestation.v1 is the INDEPENDENT PEER claim ('I, judge X via runnerDid, verified the C2PA manifest matches the media and the prompt'). When this field is present, downstream verifiers can fetch the C2PA manifest separately and confirm sha. C2PA 2.1 Conformance Program is live; v2.2 spec dropped 2025-10; ISO/IEC JTC 1 fast-track underway.

# properties.issuerDid.description
DID of the independent peer judge issuing this attestation (DISTINCT from generatorDid in the non-self-attestation case). did:web for institutional verifier (Truepic, fact-checking org, regulatory body, registered AI auditor); did:key for individual peer-review submission. When issuerDid === generatorDid, the attestation is self-attested and downstream consumers may discount accordingly.

# properties.audit.properties.method.description
What the issuer did to attest. 'forensic-image-analysis' = pixel-level inspection (noise patterns, GAN fingerprints). 'watermark-detection' = vendor watermark extraction (SynthID, Adobe Edit Tag). 'synthid-recovery' = Google SynthID specifically. 'prompt-replay' = re-ran the generator with promptSha256 + generatorVersionSha256 to verify reproducibility. 'perceptual-hash-match' = pHash/dHash match to known-AI-generated database.

# properties.audit.properties.score.description
Confidence the issuer assigns to the digitalSourceType claim. 1.0 = certain. Lower = uncertain. When score < 0.5, downstream consumers should treat as 'unable to confirm.'

# properties.audit.properties.notes.description
Optional human-readable notes about the audit process.

# properties.audit.description
Optional audit metadata. Required when issuerDid !== generatorDid (an independent attestor must say HOW they verified). Optional when the generator self-attests.

# properties.watermark.properties.scheme.description
Cycle 482 (regulatory-compliance RC-480-F4 P1, EU AI Act Art 50(2) + C2PA 2.1 §6): vendor / scheme identifier for the extracted watermark. 'synthid' = Google DeepMind SynthID (text+image+video+audio variants). 'adobe-edit-tag' = Adobe Edit Tag for Firefly outputs. 'c2pa-watermark' = the watermark assertion defined in C2PA 2.1 §6 (vendor-neutral wrapper). 'imatag' = imatag.com forensic watermark. 'steg-hash' = generic steganographic hash. 'digimarc' = Digimarc Barcode (cross-vendor). 'none' = no detectable watermark (the audit method had to fall back to other signals; expected for older / non-watermarked outputs). Aligned with C2PA 2.1 watermark assertion vocab.

# properties.watermark.properties.fingerprintBase64.description
Base64-encoded extracted watermark payload. The scheme determines decoding — SynthID returns a probability vector; Adobe Edit Tag returns a signed binary; c2pa-watermark returns the manifest digest. A regulator opening a flagged image MUST be able to read this value and cross-check against the scheme's verifier without re-running the detector. When scheme === 'none', this field is empty string.

# properties.watermark.properties.extractorVersionSha256.description
Sha256 of the watermark-extractor binary / module the issuer ran. Required because watermark schemes evolve (SynthID v1 → v2 → v3); a downstream re-verifier needs to know WHICH extractor produced the fingerprint to reproduce the verdict. Pins the extractor's version so an Art 50 audit can re-walk the detection chain.

# properties.watermark.properties.extractedAt.description
Epoch milliseconds when the watermark was extracted. Distinct from createdAt (the media generation moment) and audit.* (the broader audit method). Lets a regulator order incidents by detection time.

# properties.watermark.description
Cycle 482 (regulatory-compliance RC-480-F4 P1 fix): EU AI Act Art 50(2) requires synthetic-media disclosure 'in a machine-readable format and detectable as artificially generated or manipulated.' C2PA 2.1 §6 watermark assertions are the de-facto vehicle. Pre-cycle-482 the schema named 'watermark-detection' + 'synthid-recovery' in audit.method.enum but had no fields to CARRY the extracted watermark — an Art 50 regulator opening a flagged image could not (a) confirm a watermark exists and (b) read the extracted-value to cross-check. Now `watermark.{scheme, fingerprintBase64, extractorVersionSha256, extractedAt}` is first-class. Required when digitalSourceType ∈ {trainedAlgorithmicMedia, compositeWithTrainedAlgorithmicMedia, voiceClone, voiceSynthesis} via the allOf branch below; optional otherwise (e.g., for human-captured media with synthetic post-processing where no watermark is expected).

# properties.judgesDigest.description
When this attestation results from a multi-judge peer review (3+ independent verifiers per CP's standard peer-review economy), the canonical digest of the judges manifest. Chains to the same judgesDigest field used in CP's brief/artifact/eval-result/sandbox-run/eval-run manifests (cycle 303 derivationRecipes documentation applies — sorted by judge identifier ascending; projection (id, agentTag, weight, judgeTier|'', judgeIntelligenceScore|0, judgeIpCidr|'', receivedAt)).

# properties.ipAttestationEventId.description
When this attestation was emitted as a ip.attestation.event.v1 row (R11 T1) to the platform's Kafka/Tinybird/ClickHouse pipeline, the eventId of that wire row. Lets a consumer cross-reference a synthetic-media attestation back to the per-event audit log without re-deriving any hash.

# properties.regulatoryReference.properties.euAiActArticle50.description
True when this attestation is intended to satisfy EU AI Act Article 50(2) machine-readable AI-generation marking. Effective 2026-12-02 (the Art-50(2) content-marking obligation was DEFERRED from 2026-08-02 by the 7 May 2026 Digital Omnibus; see /.well-known/control-mapping.json#enforcement.article50ContentMarking — the 50(1)/(3)/73 transparency obligations remain 2026-08-02); penalties €15M / 3% global turnover under Article 99.

# properties.regulatoryReference.properties.ftcEndorsementGuidance2026.description
True when this attestation is intended to satisfy FTC May-2026 endorsement guidance on synthetic influencers + AI testimonials (Air AI FTC settlement Mar-2026 $18M judgment + marketing ban is the load-bearing precedent).

# properties.regulatoryReference.properties.ukOnlineSafetyAct.description
True when this attestation is intended to satisfy UK Online Safety Act 2026-02-15 extension to AI chatbots + character platforms.

# properties.regulatoryReference.properties.caSb243.description
True when this attestation is intended to satisfy CA SB-243 effective 2026-01-01 ($1k/violation private right of action).

# properties.regulatoryReference.description
Optional regulatory-context flags. Signals to a downstream regulator-facing verifier WHICH regulatory regime the issuer intended this attestation to cover. Helps audit-tooling (R14 G1 governance line items) route the attestation to the right compliance framework.

# properties.signature.description
Ed25519 signature (128 hex chars = 64 raw bytes) over the canonical-JSON bytes of (attestationId ⊕ mediaSha256 ⊕ mediaType ⊕ digitalSourceType ⊕ generatorId ⊕ generatorVersionSha256? ⊕ generatorDid ⊕ promptSha256 ⊕ promptDisclosure? ⊕ createdAt ⊕ publishedAt? ⊕ c2paManifestSha256? ⊕ issuerDid ⊕ audit? ⊕ judgesDigest? ⊕ ipAttestationEventId? ⊕ regulatoryReference?). Verify against the publicKey published in the issuerDid's JWKS. RFC 8037 (Ed25519 in JWS) canonicalization rules apply: JCS (RFC 8785) ordering on the inner object. ⚠ INTEGRITY GAP (aa-824-P0-1, cycle 848 honest disclosure): `chain.*` and `extra` are presently OUTSIDE this signature pre-image. A wire-path or post-hoc rewrite of `chain.parentSha256` / `chain.parentKind` / `chain.parentAttestationId` does NOT invalidate this `signature`. Offline verifiers using `signature`+`publicKey` (the documented embedded-verification path) MUST treat `chain.*` as ADVISORY pointer-shape, NOT cryptographically bound to this attestation. For full-integrity verification including chain pointers, fetch the W3C DataIntegrityProof envelope from /credentials/<sha>/v1 and verify against the proof.cryptosuite=eddsa-jcs-2022 signature (which signs the FULL canonical-JSON body including chain). Cycle-484 added the chain block; cycles 778-784 swept it; the signature pre-image was not re-derived. Migration target: v2 schema slug ($id pin per cycle-462). See cycles 825-829 (5/5 wedge-tier ring) + cycle 830 (verification-recipe.md dual-path teaching) for the canonical write-up; cycle 848 fans this disclosure to the 12 remaining chain-bearing leaf schemas in one batch.

# properties.publicKey.description
Ed25519 public key (32 raw bytes = 64 hex) corresponding to the signature above. Verifier MAY prefer to resolve via issuerDid's JWKS — this field exists for offline / embedded verification when network resolution is unavailable.

# properties.extra.description
Open extension slot — generator-specific or media-format-specific payload (e.g., camera-shot metadata for compositeCapture, voice consent envelope for voiceClone, music-rights envelope for SUNO/Udio post-RIAA-settlement workflows). Consumers MUST ignore unknown keys (forward-compat policy mirrors ip.attestation.event.v1 + ip.sandbox.run + ip.eval.run).

# properties.affectsIdentifiableIndividual.description
Cycle 487 (regulatory-compliance RC-480-F9 P2 fix): flag signaling that the synthetic media depicts, voice-clones, or otherwise represents an identifiable real person. When true, the EU AI Act Article 50 + GDPR Article 22 data-subject-rights obligations attach: a regulator + the depicted individual MUST be able to file an appeal, find a human reviewer, and lodge a complaint. Triggers the dataSubjectSafeguards-required allOf branch below. Defaults to absent (treated as false for back-compat with pre-cycle-487 records); issuers MUST set it explicitly to true whenever the media depicts a real person.

# properties.dataSubjectSafeguards.description
Cycle 487 (regulatory-compliance RC-480-F9 P2 fix): GDPR Article 22 + EU AI Act Article 50 data-subject rights coverage. Same shape as ip.governance.compliance.v1.dataSubjectSafeguards (cycle 390); a future cycle hoists this to a shared $defs / $ref. Required only when affectsIdentifiableIndividual=true — synthetic media of objects, scenes, or wholly-fictional characters carries no Article 22 obligation. When the depicted person is identifiable, the operator MUST provide structured access points so the data subject can appeal an automated decision, find a human reviewer, file a complaint with their national DPA, and learn the retention period. Same fields as the governance-compliance schema for cross-attestation consistency.

# properties.dataSubjectSafeguards.properties.appealUrl.description
HTTPS URL where a depicted data subject submits an appeal of the AI-generated media (e.g., to request removal, correction, or non-association). MUST be HTTPS, MUST accept POST. Operator's responsibility to honor GDPR Art 22(3) right-to-human-review within the regulatory timeline.

# properties.dataSubjectSafeguards.properties.humanReviewerDid.description
DID of the human reviewer (or human-review team) responsible for hearing appeals against this synthetic-media attestation. did:web for institutional teams, did:key for individuals. Lets a regulator verify the human is independently identifiable — not the same DID as the issuing AI.

# properties.dataSubjectSafeguards.properties.escalationPath.description
Human-readable description of the escalation hierarchy: first-line review → supervisor → external regulator. Mirrors ip.governance.compliance.v1's escalationPath verbatim.

# properties.dataSubjectSafeguards.properties.complaintIntakeUrl.description
HTTPS URL for filing a formal complaint about the synthetic-media generation policy itself (separate from an appeal against a specific output). GDPR Art 77 right to lodge a complaint with a supervisory authority.

# properties.dataSubjectSafeguards.properties.automatedDecisionScope.description
Honest classification of how the synthetic-media generator's outputs affect data subjects. Same enum as ip.governance.compliance.v1 for cross-attestation comparability. 'fully-automated' = the media was generated without any human review of the depicted person's likeness consent (highest GDPR Art 22 scrutiny).

# properties.dataSubjectSafeguards.properties.retentionPeriodDays.description
How long the operator retains the synthetic-media artifact + provenance chain before deletion. GDPR Art 5(1)(e) storage limitation.

# properties.chain.properties.parentSha256.description
Sha256 of the canonical-JSON bytes of the parent attestation. For a synthetic.media.attestation typically the parent is the ip.experiment.receipt.v1 that minted the generator's weights (most common path — Runway/Pika/Sora-2/Midjourney/FLUX.2 etc. each have an upstream training-run receipt), OR the ip.pipeline.facet.v1 attesting where the training corpus came from (when the generator declares dataset provenance directly), OR the ip.governance.compliance.v1 row when the synthetic is enterprise-issued under an Art-50 compliance program. ⚠ Cycle 493 honest-disclosure (adversarial-auditor AA-485-P2-4): the platform does NOT verify parent-existence at issuance. A syntactically-valid 64-hex sha256 satisfies this pattern but the bytes may not resolve in any attestation store. Consumers walking the chain MUST resolve parentSha256 against their own attestation registry (the platform exposes no by-sha lookup as of cycle 493); see /docs/verification-recipe.md for the canonical walk. A dangling parentSha256 is an UNVERIFIED chain link, NOT a verified absence — distinguishing 'platform issued an unresolvable parent pointer' from 'parent was revoked and evicted' requires consumer-side state.

# properties.chain.properties.parentKind.description
Kind identifier of the parent attestation. synthetic.media.attestation tolerates experiment-receipt (upstream training-run receipt; the dominant path for SaaS generators), pipeline-facet (direct dataset-provenance anchor for self-trained models), or governance-compliance (enterprise-deployed Art-50 program row).

# properties.chain.properties.parentAttestationId.description
Optional UUID of the parent attestation — convenience for consumers that index by id rather than by sha256.

# properties.chain.description
Cycle 778 (sc-772-P0-1 partial close): uniform upward chain link per the cycle-484 substrate. Pre-cycle-778 ip.synthetic.media.attestation.v1 had no chain.parentSha256, so a verifier walking up from a synthetic-media attestation could not mechanically reach the upstream experiment-receipt / pipeline-facet without out-of-band correlation. This is the Article-50-anchor schema (deepfake disclosure obligation, €15M / 3% global turnover penalties under Article 99) — the wedge claim 'cryptographic chain-of-custody for AI artifacts from data to deployment' literally bottoms-out at this schema for synthetic content. Cycle 778 closes the gap for one schema; sc-772-P0-1 follow-up cycles will sweep the remaining 12 leaf kinds. The block is OPTIONAL (not in required[]) so back-compat is preserved — pre-cycle-778 attestations continue to validate.

# allOf[].$comment
Cycle 482 (regulatory-compliance RC-480-F4 P1 fix): EU AI Act Art 50(2) requires machine-readable disclosure on synthetic media. When digitalSourceType ∈ {trainedAlgorithmicMedia, compositeWithTrainedAlgorithmicMedia, voiceClone, voiceSynthesis} the content IS purely or partially AI-generated and a regulator needs the watermark fingerprint to cross-check. Required-when conditional applied via if/then — non-generative digitalSourceTypes (e.g., trainedAlgorithmicCapture, originalDigitalCapture) remain watermark-optional since no extractable watermark is expected.

# allOf[].$comment
Cycle 487 (regulatory-compliance RC-480-F9 P2 fix): when affectsIdentifiableIndividual=true the synthetic media depicts or voice-clones an identifiable real person, attaching GDPR Article 22 + EU AI Act Article 50 obligations. dataSubjectSafeguards becomes REQUIRED so the data subject has structured access points (appeal URL, human reviewer DID, escalation path, complaint intake URL, decision-scope classification, retention-period). When the flag is absent or false, safeguards are optional — synthetic media of objects, fictional characters, or non-identifiable composites doesn't trigger Art 22. Back-compat: pre-cycle-487 records (no affectsIdentifiableIndividual field) continue to validate without safeguards.