{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://storyobjectmodel.com/schema/1.0/story-context.schema.json",
  "title": "SOM 1.0 story.context payload",
  "description": "The story.context payload: the complete state of a story at a moment in time, published as a snapshot and never as a delta. Shape settled across the v0.3.1 and v0.3.2 windows and locked at SOM 1.0. Design record: (1) asset_type gains TRANSCRIPT (locked v0.3.1 29 Jun \u2014 carried here because the 30 Jun re-cut omitted it) plus the promoted generative outputs SUMMARY/SOCIAL_POST/ARTICLE/ANALYSIS (AI-outputs refactor, principle ratified 29 Jun; registry direction \u2014 governed-but-extensible); (2) asset.provenance \u2014 authorship-general provenance object (author HUMAN/MODEL, never AI-keyed); (3) assertions[] \u2014 claims-about-content (FACT_CHECK/DETECTION/MATCH) with target on the audit target set plus STORY (audit-set convergence proposed; the assertion set is deliberately the wider of the two until it lands) and a structured review state; ai_enrichments[] is hard-rejected (narrowed to assertions[]; generative outputs are Assets \u2014 SOM-048 migration is breaking, needs the disambiguation rule); (4) story_type gains ORPHAN (Morag 5 Jul asks / John 9 Jul reply \u2014 minimal shell story holding an unmatched UGC clip; trivially filterable via the story_type predicate; ships at 1.0; residual debate is recorded in spec/open-register.md); (5) editorial_gate.blocks[] contract restored ({kind ASSET|PHASE, ref}; bare string DEPRECATED \u2014 element-level-hold reply 1 Jul). som_version carries the pack version (1.0.0). (6) tags[] \u2014 subject-matter tagging: ordered, scheme-qualified (newsroom / iptc-mediatopic / com.{vendor}.{name}), additive and optional. Added because every other axis here carries lifecycle, priority, compliance or provenance and none of them say what a story is about, so a skill trigger policy had no field to resolve on and was falling back to substring matching on headline text.",
  "type": "object",
  "required": [
    "story_id",
    "slug",
    "headline",
    "story_type",
    "sequence_number",
    "updated_at"
  ],
  "properties": {
    "story_id": {
      "type": "string"
    },
    "slug": {
      "type": "string"
    },
    "headline": {
      "type": "string"
    },
    "story_type": {
      "type": "string",
      "enum": [
        "PLANNED",
        "ACTIVE",
        "KILLED",
        "SPIKED",
        "ARCHIVED",
        "ORPHAN"
      ],
      "description": "ORPHAN (v0.3.2): a minimal shell story minted to hold a clip that arrived with no story (UGC / found media) until a proposed match is confirmed. On confirm the clip MOVES to the real story (same asset_id, original timestamps; the association change is recorded on som.system.audit against the asset \u2014 NOTE the locked action vocabulary CLEARED/SUPPRESSED/WITHHELD/OVERRIDDEN cannot yet express an association, so an ASSOCIATED action is proposed to make this record expressible; until it lands the move is recorded by convention, not by a defined action) and the shell ALWAYS retires to ARCHIVED (Morag, accepted 13 Jul) \u2014 the reason it closed (resolved onto a story, or rejected/discarded) lives in the audit trail, so the terminal story_type carries no distinction; never deleted. Consumers exclude orphans with the same single story_type predicate used for KILLED/SPIKED."
    },
    "tags": {
      "type": "array",
      "uniqueItems": true,
      "description": "Subject-matter tags: what the story is about. Order is significant \u2014 the first entry is the primary tag, and a trigger policy whose map matches more than one entry resolves on the earliest match, so a story that is genuinely both sport and politics routes deterministically instead of ambiguously. Optional and additive; an absent array means untagged, never a default desk.",
      "items": {
        "$ref": "#/$defs/story_tag"
      }
    },
    "lifecycle": {
      "$ref": "#/$defs/lifecycle"
    },
    "sequence_number": {
      "type": "integer",
      "minimum": 0
    },
    "updated_at": {
      "type": "string",
      "format": "date-time"
    },
    "newsroom_id": {
      "type": "string",
      "description": "Optional at 1.0 \u2014 derive from skills_config.newsroom if absent (decision #12). Making it required would be a 2.0 change; see spec/compatibility-policy.md."
    },
    "story_owner": {
      "description": "System/entity with authoritative control over the story",
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "object"
        }
      ]
    },
    "priority": {
      "type": "object",
      "required": [
        "level"
      ],
      "properties": {
        "level": {
          "type": "string",
          "enum": [
            "ROUTINE",
            "STANDARD",
            "HIGH",
            "URGENT",
            "FLASH"
          ]
        },
        "reason": {
          "type": "string"
        },
        "escalated_by": {
          "type": "string"
        },
        "escalated_at": {
          "type": "string",
          "format": "date-time"
        }
      },
      "additionalProperties": false
    },
    "premise": {
      "type": "object",
      "properties": {
        "expected_outcome": {
          "type": "string"
        },
        "confidence": {
          "type": "string",
          "enum": [
            "LOW",
            "MEDIUM",
            "HIGH"
          ]
        },
        "premise_changed": {
          "type": "boolean"
        },
        "previous_outcome": {
          "type": "string"
        },
        "actual_outcome": {
          "type": "string"
        },
        "affected_assets": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "change_detected_at": {
          "type": "string",
          "format": "date-time"
        },
        "change_detected_by": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "compliance": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/compliance_flag"
      }
    },
    "editorial_gates": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/editorial_gate"
      }
    },
    "story_meaning": {
      "type": "object",
      "description": "Structured 5W1H kernel (decision #14); fields token-capped \u2264280 chars, summary \u2264600",
      "properties": {
        "who": {
          "type": "string",
          "maxLength": 280
        },
        "what": {
          "type": "string",
          "maxLength": 280
        },
        "when": {
          "type": "string",
          "maxLength": 280
        },
        "where": {
          "type": "string",
          "maxLength": 280
        },
        "why": {
          "type": "string",
          "maxLength": 280
        },
        "how": {
          "type": "string",
          "maxLength": 280
        },
        "summary": {
          "type": "string",
          "maxLength": 600
        },
        "confidence": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "provenance_refs": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "government_approval": {
      "type": "object",
      "description": "Publication gate (decision #15) \u2014 executor MUST NOT publish while status blocks",
      "required": [
        "status"
      ],
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "NOT_REQUIRED",
            "REQUESTED",
            "UNDER_REVIEW",
            "APPROVED",
            "RETURNED_FOR_REVISION",
            "REJECTED"
          ]
        },
        "jurisdiction": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "editorial_source": {
      "type": "array",
      "description": "Renamed from sources[] (second leg of the source disambiguation)",
      "items": {
        "$ref": "#/$defs/editorial_source_entry"
      }
    },
    "assets": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/asset"
      }
    },
    "ai_enrichments": false,
    "skills_config": {
      "$ref": "#/$defs/skills_config"
    },
    "content_refs": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/content_ref"
      }
    },
    "relations": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/relation"
      }
    },
    "collaboration": {
      "type": "object",
      "properties": {
        "editing_version": {
          "type": "integer",
          "description": "Renamed from collaboration.version"
        },
        "active_editors": {
          "type": "array"
        },
        "lock_status": {
          "type": "string"
        }
      }
    },
    "extensions": {
      "type": "object",
      "patternProperties": {
        "^com\\.[a-z0-9-]+\\.": {}
      },
      "additionalProperties": false
    },
    "instances": false,
    "broadcaster_id": false,
    "sources": false,
    "content_ref": false,
    "assertions": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/assertion"
      }
    }
  },
  "additionalProperties": false,
  "allOf": [
    {
      "if": {
        "properties": {
          "story_type": {
            "const": "ACTIVE"
          }
        },
        "required": [
          "story_type"
        ]
      },
      "then": {
        "required": [
          "lifecycle"
        ]
      },
      "else": {
        "not": {
          "required": [
            "lifecycle"
          ]
        }
      }
    }
  ],
  "$defs": {
    "lifecycle": {
      "type": "object",
      "description": "Present ONLY when story_type: ACTIVE (decision #19)",
      "required": [
        "phase",
        "phase_entered_at"
      ],
      "properties": {
        "phase": {
          "type": "string",
          "enum": [
            "DEVELOPING",
            "READY_TO_AIR",
            "BREAKING",
            "PUBLISHED"
          ]
        },
        "phase_entered_at": {
          "type": "string",
          "format": "date-time"
        },
        "previous_phase": {
          "type": "string",
          "enum": [
            "DEVELOPING",
            "READY_TO_AIR",
            "BREAKING",
            "PUBLISHED"
          ]
        },
        "phase_owner": {
          "type": "object",
          "properties": {
            "user_id": {
              "type": "string"
            },
            "display_name": {
              "type": "string"
            },
            "role": {
              "type": "string"
            }
          },
          "additionalProperties": false
        }
      },
      "additionalProperties": false
    },
    "compliance_flag": {
      "type": "object",
      "required": [
        "flag_id",
        "type",
        "severity",
        "detail",
        "raised_by",
        "raised_at",
        "status"
      ],
      "properties": {
        "flag_id": {
          "type": "string"
        },
        "type": {
          "type": "string",
          "examples": [
            "PREMISE_CONTRADICTION",
            "MINOR_INVOLVED",
            "LEGAL_REVIEW",
            "EDITORIAL_REVIEW",
            "LEGAL_HOLD",
            "VOTING_RIGHTS",
            "DEFAMATION_RISK"
          ]
        },
        "severity": {
          "type": "string",
          "enum": [
            "LOW",
            "MEDIUM",
            "HIGH",
            "CRITICAL"
          ]
        },
        "detail": {
          "type": "string"
        },
        "jurisdiction": {
          "type": "string"
        },
        "regulation_ref": {
          "type": "string"
        },
        "raised_by": {
          "type": "string"
        },
        "raised_at": {
          "type": "string",
          "format": "date-time"
        },
        "status": {
          "type": "string",
          "enum": [
            "ACTIVE",
            "RESOLVED",
            "WAIVED"
          ]
        },
        "media_range": {
          "type": "object",
          "anyOf": [
            {
              "required": [
                "source",
                "time_range"
              ]
            },
            {
              "required": [
                "locator",
                "time_range"
              ]
            }
          ],
          "description": "CONFIRMED (v0.3.1, Source re-key 29 Jun): flags a restricted stretch of the asset's media by Source URI + time range (was flow_id). The what/why/type live on the compliance flag. NOTE: a re-edit mints new TAMS media, so this pin does not automatically survive re-editing; the fuller structured-restriction shape is settled after the lock.",
          "properties": {
            "source": {
              "type": "string",
              "pattern": "^tams://[^/]+/.+",
              "description": "Fully-qualified TAMS Source URI \u2014 tams://store/id."
            },
            "locator": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "store",
                "ref"
              ],
              "properties": {
                "store": {
                  "type": "string"
                },
                "ref": {
                  "type": "string"
                }
              }
            },
            "time_range": {
              "description": "TAMS time range (or list) for the restricted stretch.",
              "anyOf": [
                {
                  "$ref": "#/$defs/timerange"
                },
                {
                  "type": "array",
                  "items": {
                    "$ref": "#/$defs/timerange"
                  }
                }
              ]
            }
          },
          "additionalProperties": false
        }
      },
      "additionalProperties": false
    },
    "editorial_gate": {
      "type": "object",
      "required": [
        "gate_id",
        "gate_type",
        "status"
      ],
      "properties": {
        "gate_id": {
          "type": "string"
        },
        "gate_type": {
          "type": "string"
        },
        "status": {
          "type": "string",
          "enum": [
            "PENDING",
            "APPROVED",
            "REJECTED"
          ]
        },
        "required_by_skill": {
          "type": "string"
        },
        "gate_rule_id": {
          "type": "string"
        },
        "resolution_event_type": {
          "type": "string"
        },
        "assigned_to": {
          "type": "string"
        },
        "blocks": {
          "type": "array",
          "description": "Contract restored (v0.3.2; was a bare string array \u2014 dropped wording). Names the things this gate holds: {kind ASSET, ref asset_id} or {kind PHASE, ref lifecycle-phase token}, reusing the UPPER target-kind vocabulary. Bare strings DEPRECATED (accepted for migration only).",
          "items": {
            "anyOf": [
              {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "kind",
                  "ref"
                ],
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "ASSET",
                      "PHASE"
                    ]
                  },
                  "ref": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "string",
                "description": "DEPRECATED \u2014 migrate to {kind, ref}"
              }
            ]
          }
        }
      },
      "additionalProperties": false
    },
    "editorial_source_entry": {
      "type": "object",
      "required": [
        "source_id",
        "source_type",
        "provider",
        "credibility",
        "received_at"
      ],
      "properties": {
        "source_id": {
          "type": "string"
        },
        "source_type": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "WIRE",
                "OFFICIAL",
                "FIELD_CREW",
                "POOL_FEED",
                "GOVERNMENT",
                "INTERNAL",
                "PRESS_RELEASE",
                "SCANNER",
                "USER_GENERATED",
                "SOCIAL",
                "ARCHIVE"
              ]
            },
            {
              "type": "string",
              "pattern": "^x-[a-z0-9_]+$"
            }
          ]
        },
        "provider": {
          "type": "string"
        },
        "credibility": {
          "type": "string",
          "enum": [
            "TRUSTED",
            "VERIFIED",
            "ENDORSED",
            "UNVERIFIED"
          ]
        },
        "received_at": {
          "type": "string",
          "format": "date-time"
        },
        "content_hash": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "asset": {
      "type": "object",
      "required": [
        "asset_id",
        "asset_type",
        "status"
      ],
      "properties": {
        "asset_id": {
          "type": "string"
        },
        "asset_type": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "VIDEO",
                "AUDIO",
                "GRAPHIC",
                "STILL",
                "CG",
                "SCRIPT",
                "PROMPTER",
                "LOWER_THIRD",
                "FULL_FRAME",
                "MAP",
                "SOCIAL_CARD",
                "TRANSCRIPT",
                "SUMMARY",
                "SOCIAL_POST",
                "ARTICLE",
                "ANALYSIS",
                "CUSTOM"
              ]
            },
            {
              "type": "string",
              "pattern": "^x-[a-z0-9_]+$"
            }
          ],
          "description": "TRANSCRIPT locked at v0.3.1 (29 Jun; the 30 Jun re-cut omitted it \u2014 carried here). SUMMARY/SOCIAL_POST/ARTICLE/ANALYSIS promoted from enrichment_type at v0.3.2 (AI-outputs refactor; the Telling test: publishes \u2192 needs a Telling \u2192 is an Asset). PROMPTER duplication resolved \u2014 it now lives here only. Direction: governed-but-extensible registry (same model as Platform / framing_treatment); vendor values keep the x- prefix."
        },
        "status": {
          "type": "string",
          "enum": [
            "READY",
            "IN_PRODUCTION",
            "PREPARED",
            "INVALIDATED"
          ],
          "description": "Editorial-state only (decision #16). LIVE/AIRED are DERIVED from the Telling, never stored here Distinct from acquisition_state, which is primary-assets-only."
        },
        "evidential_position": {
          "type": "string",
          "enum": [
            "PRIMARY",
            "SECONDARY",
            "TERTIARY"
          ],
          "description": "Voice-count criterion (decision #22); single-reporter package defaults TERTIARY"
        },
        "acquisition_state": {
          "type": "string",
          "enum": [
            "CAPTURING",
            "CAPTURED"
          ],
          "description": "Primary assets only; REOPENED is an event, not a stored value (decision #16)"
        },
        "derived_from": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "EDITORIAL lineage only; computational/format relationships belong in delivery_spec"
        },
        "produced_by": {
          "type": "string"
        },
        "usage": {
          "type": "array",
          "description": "Asset-side back-edge index (decision #3); committed-only, fail-closed modify-gate; maintenance semantics per \u00a75",
          "items": {
            "type": "object",
            "required": [
              "link_id",
              "destination_id",
              "state"
            ],
            "properties": {
              "link_id": {
                "type": "string"
              },
              "destination_id": {
                "type": "string"
              },
              "state": {
                "type": "string",
                "const": "committed"
              }
            },
            "additionalProperties": false
          }
        },
        "invalidated_by": {
          "type": "string"
        },
        "standards_clearance": {
          "type": "object",
          "properties": {
            "status": {
              "type": "string",
              "enum": [
                "CLEARED",
                "BLOCKED",
                "PENDING"
              ]
            },
            "blocked_by": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "last_reviewed": {
              "type": "string",
              "format": "date-time"
            }
          },
          "additionalProperties": false
        },
        "delivery_spec": {
          "type": "object",
          "properties": {
            "format": {
              "type": "string"
            },
            "resolution": {
              "type": "string"
            },
            "frame_rate": {
              "type": "number"
            }
          },
          "additionalProperties": true
        },
        "media_refs": {
          "type": "array",
          "description": "CONFIRMED (v0.3.1, Source re-key 29 Jun; lazy-consensus window to 1 Jul): the media_source leg. TAMS media referenced by a fully-qualified Source URI (tams://store/id) + optional time range(s); non-TAMS via locator. One of source/locator required. flow_id removed \u2014 SOM references Source + time, not Flow.",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "anyOf": [
              {
                "required": [
                  "source"
                ]
              },
              {
                "required": [
                  "locator"
                ]
              }
            ],
            "properties": {
              "source": {
                "type": "string",
                "pattern": "^tams://[^/]+/.+",
                "description": "Fully-qualified TAMS Source URI \u2014 tams://store/id; resolves across remote/second-hand stores."
              },
              "locator": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "store",
                  "ref"
                ],
                "properties": {
                  "store": {
                    "type": "string"
                  },
                  "ref": {
                    "type": "string"
                  }
                },
                "description": "Non-TAMS media store reference."
              },
              "label": {
                "type": "string"
              },
              "time_range": {
                "description": "Optional TAMS time range, or list of ranges, onto the Source.",
                "anyOf": [
                  {
                    "$ref": "#/$defs/timerange"
                  },
                  {
                    "type": "array",
                    "items": {
                      "$ref": "#/$defs/timerange"
                    }
                  }
                ]
              }
            }
          }
        },
        "authenticity_credential": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "present"
          ],
          "description": "Media-authenticity axis (C2PA). Distinct from credibility. present:false is recorded, not hidden.",
          "properties": {
            "present": {
              "type": "boolean"
            },
            "standard": {
              "type": "string"
            },
            "claim": {
              "type": "string"
            },
            "validated_by": {
              "type": "string"
            }
          }
        },
        "framing_treatment": {
          "type": "string",
          "description": "Flat governed per-newsroom registry key (UPPER_SNAKE canonical, x-<lowercase> vendor). SECONDARY/TERTIARY assets; single value. The governed registry itself is not yet published \u2014 see spec/open-register.md."
        },
        "provenance": {
          "$ref": "#/$defs/authorship_provenance"
        }
      },
      "additionalProperties": false
    },
    "skills_config": {
      "type": "object",
      "properties": {
        "newsroom": {
          "type": "string",
          "description": "Renamed from skills_config.broadcaster (decision #12)"
        },
        "skills_spec_version": {
          "type": "string"
        },
        "skill_executor_id": {
          "type": "string"
        },
        "scope_context": {
          "type": "string"
        },
        "active_skills": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "skill_id",
              "skill_version",
              "skill_type"
            ],
            "properties": {
              "skill_id": {
                "type": "string"
              },
              "skill_version": {
                "type": "string"
              },
              "skill_type": {
                "type": "string",
                "enum": [
                  "NEWSROOM",
                  "VENDOR",
                  "REFERENCE"
                ]
              },
              "disclosure_level": {
                "type": "string",
                "enum": [
                  "L1",
                  "L2",
                  "L3"
                ]
              },
              "migration_policy": {
                "type": "string",
                "enum": [
                  "HOT",
                  "COLD",
                  "GATED"
                ]
              },
              "skill_priority": {
                "type": "string",
                "enum": [
                  "CRITICAL",
                  "NORMAL",
                  "LOW"
                ]
              }
            },
            "additionalProperties": false
          }
        },
        "broadcaster": false
      },
      "additionalProperties": false
    },
    "story_tag": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "scheme",
        "value"
      ],
      "description": "A tag qualified by the vocabulary it belongs to, so a governed standard and house desk tags sit in one array without colliding. The scheme namespace is governed; the value vocabulary belongs to whoever owns the scheme.",
      "properties": {
        "scheme": {
          "type": "string",
          "pattern": "^(newsroom|iptc-mediatopic|com\\.[a-z0-9-]+\\.[a-z0-9-]+)$",
          "description": "Vocabulary the value belongs to. newsroom is a house-local desk tag. iptc-mediatopic is an IPTC Media Topic identifier, the broadcast-standard taxonomy. com.{vendor}.{name} carries a vendor or newsroom-system vocabulary, following the same vendor carve-out the extensions object uses. Governed-but-extensible: a new first-class scheme is a registry addition, a vendor scheme needs no registry."
        },
        "value": {
          "type": "string",
          "minLength": 1,
          "description": "The tag itself. Lowercase for the newsroom scheme, for example sport or politics; the numeric topic identifier for iptc-mediatopic. Deliberately unconstrained beyond non-empty, because the scheme namespace is what is governed and the value vocabulary belongs to the scheme owner."
        },
        "label": {
          "type": "string",
          "description": "Optional human-readable label for an opaque identifier, since an IPTC topic number means nothing on a dashboard. Display only: never resolve a trigger policy on this."
        }
      }
    },
    "content_ref": {
      "type": "object",
      "required": [
        "uri"
      ],
      "properties": {
        "uri": {
          "type": "string",
          "format": "uri"
        },
        "mime_type": {
          "type": "string"
        },
        "content_format": {
          "type": "string",
          "examples": [
            "ap-som-body-json-v1"
          ]
        },
        "placement": {
          "type": "string"
        },
        "provider": {
          "type": "string"
        },
        "role": {
          "type": "string"
        },
        "source_id": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "relation": {
      "type": "object",
      "description": "Versioned in v0.3 (\u00a74.7); seed data structure for the Ontology Layer",
      "required": [
        "relation_type"
      ],
      "properties": {
        "relation_type": {
          "type": "string"
        },
        "target_story_id": {
          "type": "string"
        },
        "_version": {
          "type": "integer"
        },
        "_created_at": {
          "type": "string",
          "format": "date-time"
        },
        "_created_by": {
          "type": "string"
        },
        "_modified_at": {
          "type": "string",
          "format": "date-time"
        },
        "_modified_by": {
          "type": "string"
        },
        "_history": {
          "type": "array"
        }
      },
      "additionalProperties": true
    },
    "timecode": {
      "type": "string",
      "pattern": "^\\d{2}:\\d{2}:\\d{2}([:;]\\d{2})?$",
      "description": "DEPRECATED for media references (replaced by the TAMS timerange in the 29 Jun Source re-key); retained for any non-media timecode use."
    },
    "timestamp": {
      "type": "string",
      "pattern": "^\\d+:\\d+$",
      "description": "TAMS timestamp \u2014 seconds:nanoseconds (e.g. 0:500000000 = 0.5s)."
    },
    "timerange": {
      "type": "string",
      "pattern": "^[\\[(](\\d+:\\d+)?_(\\d+:\\d+)?[\\])]$",
      "description": "TAMS timerange \u2014 bracketed inclusive/exclusive over seconds:nanoseconds timestamps (e.g. [0:500000000_1:0) ). Open-ended start or end permitted."
    },
    "review_state": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "state"
      ],
      "description": "Shared human-review record (replaces the v0.3.1 ai_enrichments[].human_reviewed boolean, which had no rejected state). REJECTED entries are marked, not deleted \u2014 the trail must show what was declined.",
      "properties": {
        "state": {
          "type": "string",
          "enum": [
            "PENDING",
            "CONFIRMED",
            "REJECTED"
          ]
        },
        "reviewer": {
          "type": "string",
          "description": "Audit actor_id shape"
        },
        "reviewed_at": {
          "type": "string",
          "format": "date-time"
        }
      }
    },
    "authorship_provenance": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "author"
      ],
      "description": "Authorship-general provenance (v0.3.2, principle ratified 29 Jun): who or what authored this output. NOT AI-keyed \u2014 a human-captured TRANSCRIPT carries author HUMAN with no model. confidence is optional and asset-type-specific (meaningful for TRANSCRIPT/classifiers; generative free text has no calibrated confidence \u2014 do not populate a number that means nothing). Shaped as a sibling of the audit / skill-applied record so it can later assert into a C2PA manifest.",
      "properties": {
        "author": {
          "type": "string",
          "enum": [
            "HUMAN",
            "MODEL"
          ]
        },
        "model": {
          "type": "string"
        },
        "model_version": {
          "type": "string"
        },
        "confidence": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "generated_at": {
          "type": "string",
          "format": "date-time"
        },
        "input_sources": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "prompt_hash": {
          "type": "string"
        },
        "review": {
          "$ref": "#/$defs/review_state"
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "author": {
                "const": "HUMAN"
              }
            }
          },
          "then": {
            "not": {
              "anyOf": [
                {
                  "required": [
                    "model"
                  ]
                },
                {
                  "required": [
                    "model_version"
                  ]
                }
              ]
            }
          }
        }
      ]
    },
    "assertion": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "assertion_id",
        "assertion_type",
        "target",
        "claim",
        "asserted_at",
        "provenance"
      ],
      "description": "A claim-about-a-thing (v0.3.2; the record ai_enrichments[] narrows to \u2014 renamed off the ai_ prefix, a human fact-checker produces verdicts too). One record shape with a discriminator, not three bespoke ones. MATCH doubles as the proposed story match for the orphan/discovery beats: a proposal, not a commitment, until review.state is CONFIRMED. Authoritative-home rule (Jon 1 Jul / Janet corrections): assertions[] is the single authoritative home for a confirmed fact value; story_meaning echoes it, extensions may carry a typed copy \u2014 on disagreement the assertion wins.",
      "properties": {
        "assertion_id": {
          "type": "string"
        },
        "assertion_type": {
          "type": "string",
          "enum": [
            "FACT_CHECK",
            "DETECTION",
            "MATCH"
          ]
        },
        "target": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "kind",
            "id"
          ],
          "description": "What the claim is about. Target kinds are the audit target set (LINK/ASSET/TELLING) plus STORY. STORY has no audit counterpart today \u2014 adding it to the audit target set is proposed so the two vocabularies converge; until that lands this set is deliberately the wider of the two.",
          "properties": {
            "kind": {
              "type": "string",
              "enum": [
                "ASSET",
                "LINK",
                "TELLING",
                "STORY"
              ]
            },
            "id": {
              "type": "string"
            }
          }
        },
        "claim": {
          "type": "object",
          "description": "Typed claim payload, per assertion_type: FACT_CHECK {metric, value} \u2014 skills grip on typed fields, not prose; DETECTION {detection_class, verdict, ...} \u2014 what was looked for and the finding, with per-detector fields extending underneath and governed by the registry; MATCH {story_id} \u2014 the proposed story. The assertion envelope already carries the subject (target), the method (provenance), the score (confidence) and the editorial act (review), so the claim seeds only what those cannot say."
        },
        "attributed_to": {
          "type": "string",
          "description": "Who made the underlying claim (e.g. FEMA Director)"
        },
        "asserted_at": {
          "type": "string",
          "format": "date-time"
        },
        "confidence": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "originated_from": {
          "type": "string",
          "description": "Ref to the source transcript/asset the claim came from"
        },
        "review": {
          "$ref": "#/$defs/review_state"
        },
        "provenance": {
          "$ref": "#/$defs/authorship_provenance"
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "assertion_type": {
                "const": "FACT_CHECK"
              }
            },
            "required": [
              "assertion_type"
            ]
          },
          "then": {
            "properties": {
              "claim": {
                "required": [
                  "metric",
                  "value"
                ]
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "assertion_type": {
                "const": "MATCH"
              }
            },
            "required": [
              "assertion_type"
            ]
          },
          "then": {
            "properties": {
              "claim": {
                "required": [
                  "story_id"
                ]
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "assertion_type": {
                "const": "DETECTION"
              }
            },
            "required": [
              "assertion_type"
            ]
          },
          "then": {
            "properties": {
              "claim": {
                "required": [
                  "detection_class",
                  "verdict"
                ]
              }
            }
          }
        }
      ]
    }
  }
}
