> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nvisy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Get run detections

> Returns the run's detected findings (the analyzed document) for review.



## OpenAPI

````yaml /api-reference/openapi.json get /workspaces/{workspaceSlug}/runs/{runId}/detections/
openapi: 3.1.0
info:
  title: Nvisy API
  summary: Document processing and annotation platform
  description: >-
    Nvisy provides intelligent document processing, annotation, and analysis
    capabilities. This API enables document upload, OCR processing, embedding
    generation, and semantic search across your document collections.
  termsOfService: https://nvisy.com/legal/terms-of-service
  contact:
    name: Nvisy Support
    url: https://nvisy.com
    email: hello@nvisy.com
  license:
    name: Proprietary
    url: https://nvisy.com/license
  version: 0.1.0
servers: []
security: []
tags:
  - name: Accounts
    description: Account management and profile operations
  - name: Authentication
    description: Login, signup, and token management
  - name: Workspaces
    description: Workspace creation and management
  - name: Files
    description: File upload, download, and management
  - name: Members
    description: Workspace member management
  - name: Invites
    description: Workspace invitation handling
  - name: API Tokens
    description: API token management
  - name: Connections
    description: External provider connections
  - name: Pipelines
    description: Redaction pipeline configuration
  - name: Pipeline Runs
    description: Pipeline run execution and review
  - name: Policies
    description: Redaction policy configuration
  - name: Webhooks
    description: Webhook configuration
  - name: Notifications
    description: Account notification management
  - name: Health
    description: Service health checks
paths:
  /workspaces/{workspaceSlug}/runs/{runId}/detections/:
    get:
      tags:
        - Pipeline Runs
      summary: Get run detections
      description: Returns the run's detected findings (the analyzed document) for review.
      parameters:
        - in: path
          name: workspaceSlug
          description: URL-safe workspace identifier.
          required: true
          schema:
            description: URL-safe workspace identifier.
            type: string
          style: simple
        - in: path
          name: runId
          description: Opaque identifier of the run.
          required: true
          schema:
            $ref: '#/components/schemas/RunId'
            description: Opaque identifier of the run.
          style: simple
      responses:
        '200':
          description: |-
            What detection found in one document.

            The body group plus per-container-part groups (each tagged by
            modality) plus the recognition [`AuditContext`] the entities
            were scored against.

            The context travels with the entities so anonymize can rebuild
            an orchestrator against exactly the vocabulary analyze used.
            Anything a policy predicate compares against beyond the label
            catalog (asserted languages, jurisdictions, document tags) is
            here; labels are re-derived from the policy set on each
            anonymize call.

            No [`Default`] — a well-formed audit must carry a real
            [`AuditContext`] with a real correlation id. Callers building
            an audit outside the analyze path construct it explicitly.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Audit'
        '401':
          description: >-
            HTTP error response representation with security-conscious design.


            This struct contains all the information needed to serialize an
            error

            response, including the error name, message, HTTP status code,
            resource

            information, and user-friendly messages.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: >-
            HTTP error response representation with security-conscious design.


            This struct contains all the information needed to serialize an
            error

            response, including the error name, message, HTTP status code,
            resource

            information, and user-friendly messages.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: >-
            HTTP error response representation with security-conscious design.


            This struct contains all the information needed to serialize an
            error

            response, including the error name, message, HTTP status code,
            resource

            information, and user-friendly messages.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: >-
            HTTP error response representation with security-conscious design.


            This struct contains all the information needed to serialize an
            error

            response, including the error name, message, HTTP status code,
            resource

            information, and user-friendly messages.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - BearerAuth: []
components:
  schemas:
    RunId:
      description: Opaque run identifier (run_<uuid>).
      type: string
      pattern: >-
        ^run_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
    Audit:
      description: |-
        What detection found in one document.

        The body group plus per-container-part groups (each tagged by
        modality) plus the recognition [`AuditContext`] the entities
        were scored against.

        The context travels with the entities so anonymize can rebuild
        an orchestrator against exactly the vocabulary analyze used.
        Anything a policy predicate compares against beyond the label
        catalog (asserted languages, jurisdictions, document tags) is
        here; labels are re-derived from the policy set on each
        anonymize call.

        No [`Default`] — a well-formed audit must carry a real
        [`AuditContext`] with a real correlation id. Callers building
        an audit outside the analyze path construct it explicitly.
      type: object
      properties:
        body:
          $ref: '#/components/schemas/EntityGroup'
          description: |-
            The body group.

            `None` when no body pipeline produced entities (pre-analyze,
            or the codec resolved the doc to a modality with no
            pipeline).
        context:
          description: |-
            Recognition context.

            The asserted languages, countries, document tags, and the
            analyze-side correlation id. Held so
            [`Engine::anonymize`] can compile against the same
            vocabulary analyze used without the caller re-passing an
            `AnalyzerParams`.

            Required on the wire — a missing context on an incoming
            [`Audit`] rejects at deserialize time so the shape
            mismatch surfaces at load, not at apply.

            [`Engine::anonymize`]: super::Engine::anonymize
          allOf:
            - $ref: '#/components/schemas/AuditContext'
        parts:
          description: |-
            One entry per container part the orchestrator surfaced.

            Keyed by the container-private part id (e.g. a DOCX zip
            entry name like `"word/media/image1.png"`); each value
            carries that part's modality + entities.
          type: object
          additionalProperties:
            $ref: '#/components/schemas/EntityGroup'
      required:
        - context
    ErrorResponse:
      description: |-
        HTTP error response representation with security-conscious design.

        This struct contains all the information needed to serialize an error
        response, including the error name, message, HTTP status code, resource
        information, and user-friendly messages.
      type: object
      properties:
        message:
          description: User-friendly error message safe for client display
          type: string
        name:
          description: The error name/type identifier
          type: string
        resource:
          description: The resource that the error relates to (optional, set by handler)
          type: string
        suggestion:
          description: Helpful suggestion for resolving the error (optional)
          type: string
        validation:
          description: Validation error details for field-specific errors
          type: array
          items:
            $ref: '#/components/schemas/ValidationErrorDetail'
      required:
        - name
        - message
    EntityGroup:
      description: |-
        A modality-tagged group of recognised entities.

        The unit [`Audit`] stores in `body` and in every `parts`
        entry.

        Tagged by `modality` (snake_case) so deserialization picks the
        right variant and the entity vec inside is statically typed
        per modality — apply-time we hand each variant back to elide
        as a `Vec<Entity<M>>` for the appropriate `M`.

        [`Audit`]: crate::Audit
      oneOf:
        - description: Text entities, in source-coordinate order.
          type: object
          properties:
            entities:
              type: array
              items:
                $ref: '#/components/schemas/TextEntityRecord'
            modality:
              type: string
              const: text
          required:
            - modality
            - entities
        - description: Tabular entities, in source-coordinate order.
          type: object
          properties:
            entities:
              type: array
              items:
                $ref: '#/components/schemas/TabularEntityRecord'
            modality:
              type: string
              const: tabular
          required:
            - modality
            - entities
        - description: Image entities, in source-coordinate order.
          type: object
          properties:
            entities:
              type: array
              items:
                $ref: '#/components/schemas/ImageEntityRecord'
            modality:
              type: string
              const: image
          required:
            - modality
            - entities
        - description: Audio entities, in source-coordinate order.
          type: object
          properties:
            entities:
              type: array
              items:
                $ref: '#/components/schemas/AudioEntityRecord'
            modality:
              type: string
              const: audio
          required:
            - modality
            - entities
    AuditContext:
      description: |-
        Recognition-side facts that travel from analyze to anonymize.

        Mirrors elide's [`Scope`] shape one-for-one: direct fields
        for `languages` and `countries` (typed, elide-native), a
        [`metadata`] sub-struct for free-form classification strings
        (`tags`, `purpose`, `audience`), and the analyze-time
        [`correlation_id`]. The label catalog is not on here —
        labels are policy-owned, and anonymize re-derives them from
        the policy set it was handed.

        No [`Default`] — `correlation_id` has no meaningful default
        (a nil UUID would silently collapse unrelated audits under
        one bucket in downstream trace aggregators), so callers
        supply one explicitly. Everything else defaults to empty.

        [`Scope`]: elide::recognition::Scope
        [`metadata`]: Self::metadata
        [`correlation_id`]: Self::correlation_id
      type: object
      properties:
        correlationId:
          description: |-
            Analyze-time correlation id.

            Threaded into every tracing span on the recognition path;
            carried over so the anonymize path can link its own spans
            to the same request. The anonymize call supplies a fresh
            id from the passed [`Document`] as the anonymize-side
            correlation id — this one stays as the analyze-side
            pointer.

            Required on the wire.

            [`Document`]: nvisy_schema::file::Document
          type: string
          format: uuid
        countries:
          description: |-
            Caller-asserted jurisdictions.

            Recorded from `AnalyzerParams.scope.countries`.
          type: array
          items:
            $ref: '#/components/schemas/CountryCode'
        languages:
          description: |-
            Caller-asserted languages for the analysis.

            Recorded from `AnalyzerParams.scope.languages` at analyze
            time; anonymize re-uses them verbatim.
          allOf:
            - $ref: '#/components/schemas/Languages'
          default: []
        metadata:
          description: |-
            Free-form request context: document tags, request purpose,
            output audience. See elide's [`ScopeMetadata`].
          allOf:
            - $ref: '#/components/schemas/ScopeMetadata'
        ocrMode:
          description: |-
            OCR mode the analyze call decoded with. Recorded so the
            anonymize call re-decodes the same document under the same
            codec configuration — otherwise entity offsets stored in
            the audit wouldn't line up against a differently-rendered
            second decode. Defaults to [`OcrMode::Auto`] (the codec's
            built-in behaviour) when omitted.
          allOf:
            - $ref: '#/components/schemas/OcrMode'
          default:
            kind: auto
      required:
        - correlationId
    ValidationErrorDetail:
      description: Validation error details for field-specific errors.
      type: object
      properties:
        code:
          description: Error code for the validation failure
          type: string
        field:
          description: Field name that failed validation
          type: string
        message:
          description: Human-readable error message
          type: string
        params:
          description: Additional parameters related to the validation error
          type: object
          additionalProperties: true
      required:
        - field
        - code
        - message
    TextEntityRecord:
      description: |-
        One recognized entity plus the optional reviewer override.

        The bound mirrors elide's [`Entity<M>`]: serialization needs
        `M::Location` and `M::Data` (de)serializable, and JsonSchema
        derivation needs them schema-able. All four modalities elide
        ships satisfy these under the `serde` + `schema` features.
      type: object
      properties:
        entity:
          description: The elide entity, as recognition produced it.
          allOf:
            - $ref: '#/components/schemas/TextEntity'
        review:
          $ref: '#/components/schemas/Review'
          description: |-
            Reviewer-supplied redaction override.

            `None` means "use the matching policy rule's decision";
            `Some(...)` overrides that rule for this specific entity
            at apply time. Reviewer overrides take precedence over
            every policy rule and inherit the authority of the
            [`Review::policy_id`] they name — the audit event's
            attribution stamps that policy so the trail names the
            authority under which the override fired.
      required:
        - entity
    TabularEntityRecord:
      description: |-
        One recognized entity plus the optional reviewer override.

        The bound mirrors elide's [`Entity<M>`]: serialization needs
        `M::Location` and `M::Data` (de)serializable, and JsonSchema
        derivation needs them schema-able. All four modalities elide
        ships satisfy these under the `serde` + `schema` features.
      type: object
      properties:
        entity:
          description: The elide entity, as recognition produced it.
          allOf:
            - $ref: '#/components/schemas/TabularEntity'
        review:
          $ref: '#/components/schemas/Review'
          description: |-
            Reviewer-supplied redaction override.

            `None` means "use the matching policy rule's decision";
            `Some(...)` overrides that rule for this specific entity
            at apply time. Reviewer overrides take precedence over
            every policy rule and inherit the authority of the
            [`Review::policy_id`] they name — the audit event's
            attribution stamps that policy so the trail names the
            authority under which the override fired.
      required:
        - entity
    ImageEntityRecord:
      description: |-
        One recognized entity plus the optional reviewer override.

        The bound mirrors elide's [`Entity<M>`]: serialization needs
        `M::Location` and `M::Data` (de)serializable, and JsonSchema
        derivation needs them schema-able. All four modalities elide
        ships satisfy these under the `serde` + `schema` features.
      type: object
      properties:
        entity:
          description: The elide entity, as recognition produced it.
          allOf:
            - $ref: '#/components/schemas/ImageEntity'
        review:
          $ref: '#/components/schemas/Review'
          description: |-
            Reviewer-supplied redaction override.

            `None` means "use the matching policy rule's decision";
            `Some(...)` overrides that rule for this specific entity
            at apply time. Reviewer overrides take precedence over
            every policy rule and inherit the authority of the
            [`Review::policy_id`] they name — the audit event's
            attribution stamps that policy so the trail names the
            authority under which the override fired.
      required:
        - entity
    AudioEntityRecord:
      description: |-
        One recognized entity plus the optional reviewer override.

        The bound mirrors elide's [`Entity<M>`]: serialization needs
        `M::Location` and `M::Data` (de)serializable, and JsonSchema
        derivation needs them schema-able. All four modalities elide
        ships satisfy these under the `serde` + `schema` features.
      type: object
      properties:
        entity:
          description: The elide entity, as recognition produced it.
          allOf:
            - $ref: '#/components/schemas/AudioEntity'
        review:
          $ref: '#/components/schemas/Review'
          description: |-
            Reviewer-supplied redaction override.

            `None` means "use the matching policy rule's decision";
            `Some(...)` overrides that rule for this specific entity
            at apply time. Reviewer overrides take precedence over
            every policy rule and inherit the authority of the
            [`Review::policy_id`] they name — the audit event's
            attribution stamps that policy so the trail names the
            authority under which the override fired.
      required:
        - entity
    CountryCode:
      description: |-
        [ISO 3166-1] country, identified by its code.

        Wraps [`celes::Country`], a static table entry carrying the numeric,
        alpha-2, and alpha-3 codes together with the country's name. Because
        every value comes from that fixed table, a `CountryCode` is always a
        real, recognised country; there is no way to hold an invalid one.

        Used to scope region-sensitive recognizers (a phone-number or
        national-id pattern, say) to the country whose format they target.

        Serializes as its alpha-2 code (e.g. `"US"`).

        [ISO 3166-1]: https://www.iso.org/iso-3166-country-codes.html
      type: string
    Languages:
      description: |-
        List of [`Language`]s resolved for one text scan.

        Built by a detector (one entry per detected region) or by the caller
        asserting languages. Carried on a [`RecognizerContext`] so every
        recognizer and the context enhancer can consult the call's languages.

        [`RecognizerContext`]: crate::recognition::RecognizerContext
      type: array
      items:
        $ref: '#/components/schemas/Language'
    ScopeMetadata:
      description: >-
        Caller-asserted scope shared across every payload of one analysis.


        Built once with the `with_*` chain and passed by reference to the

        analyzer, which borrows it into a fresh [`RecognizerContext`] per

        payload. It holds only what the *caller* asserts about the analysis as a

        whole — languages, jurisdictions, document labels, the target catalog, a

        correlation id — none of which depends on the medium, so one [`Scope`]

        drives a text, image, or audio analysis alike.


        Per-medium regions (caller-supplied inclusions and exclusions, which are

        `M::Location`-typed) live in [`Annotations`], attached to the analyzer

        of that modality. The per-payload working state (NLP artifacts, detected

        languages) lives on the context, not here.


        [`RecognizerContext`]: super::RecognizerContext

        [`Annotations`]: super::annotation::Annotations

        Free-form, caller-asserted request context: the *document* it is about
        and

        the *request* driving it.


        Three axes of opaque classification strings elide neither ships nor

        interprets — a downstream policy layer chooses what `"medical"` or

        `"fraud_detection"` or `"auditor"` mean. They are read in two places: a

        recognizer may bias its detection on them (the LLM prompt lists them so
        the

        model attends to the right terms), and a scope-aware operator predicate
        may

        branch on them at selection time (redact the same document differently
        per

        [`audience`]).


        - [`tags`] classify the *document* (`"medical"`, `"gdpr-request"`).

        - [`purpose`] is why the request exists (`"fraud_detection"`).

        - [`audience`] is who the redacted output is for (`"support_agent"`,
          `"auditor"`) — the axis PCI-style "same document, two masks" branches on.

        [`tags`]: Self::tags

        [`purpose`]: Self::purpose

        [`audience`]: Self::audience
      type: object
      properties:
        audience:
          description: >-
            Who the redacted output is for (e.g. `"support_agent"`,
            `"auditor"`).

            The axis a per-audience redaction branches on: one detected
            document,

            selected differently per audience. May hold several.
          type: array
          default: []
          items:
            type: string
        purpose:
          description: >-
            The caller-asserted business purpose driving this request (e.g.

            `"fraud_detection"`, `"gdpr_erasure_request"`). A scope-aware
            operator

            predicate may skip or swap a rule based on it; a recognizer may bias

            detection on it. `None` when the caller asserts no purpose.
          type: string
          default: null
        tags:
          description: |-
            Document-level classification tags (e.g. `"medical"`,
            `"gdpr-request"`). Recognizers may use these to bias their behavior
            for domain-specific terms; those that don't ignore the field.

            Named `tags`, not `labels`, to keep "label" reserved for the entity
            taxonomy ([`LabelRef`]/[`LabelCatalog`]): these classify the
            *document*, whereas the scope's catalog names the entity *types* to
            emit.

            [`LabelRef`]: crate::entity::LabelRef
            [`LabelCatalog`]: crate::entity::LabelCatalog
          type: array
          default: []
          items:
            type: string
    OcrMode:
      description: >-
        Policy for turning a document's pages into images for OCR.


        A born-digital PDF has a selectable text layer and needs no OCR; a

        scanned one is image-only and must be rendered to images first. [`Auto`]

        is the right default — extract text, render only what lacks it — but the

        text-layer parser that drives that decision is not in place yet, so
        today

        only [`Force`] actually renders.


        Serializes with an internal `kind` tag (`{"kind": "auto"}`,

        `{"kind": "force", "dpi": 300}`, `{"kind": "never"}`).


        [`Auto`]: OcrMode::Auto

        [`Force`]: OcrMode::Force
      oneOf:
        - description: |-
            Use the text layer where it exists and render pages for OCR only
            where it is absent. The detection lands with the text-layer parser;
            until then this defers to the text path (a no-op for the PDF stub).
          type: object
          properties:
            kind:
              type: string
              const: auto
          required:
            - kind
        - description: |-
            Always render pages to images for OCR at the given [`Dpi`], ignoring
            any text layer. For documents whose text layer is missing, garbled,
            or a watermark.
          type: object
          properties:
            dpi:
              description: Resolution to render pages at; [`Dpi::OCR`] (300) is typical.
              allOf:
                - $ref: '#/components/schemas/Dpi'
            kind:
              type: string
              const: force
          required:
            - kind
            - dpi
        - description: 'Never render: rely on the text layer only, even if it is absent.'
          type: object
          properties:
            kind:
              type: string
              const: never
          required:
            - kind
    TextEntity:
      description: |-
        Detected piece of sensitive information within some medium.

        Generic over the [`Modality`] `M`, which is what makes the model
        multimodal: a text pipeline yields `Entity<Text>`, an audio pipeline
        `Entity<Audio>`, and so on. The entity's location is the modality's
        [`Location`] type, `M::Location`.

        # Birth and fusion

        A recognizer emits an entity directly, carrying a single recognition
        [`AuditEvent`] (its own finding) in the entity's [`audit`] trail. When
        several recognizers find the same thing, a fusion step (in
        `elide`) combines their entities into one: the survivor's
        [`location`] and [`confidence`] are the *fused* values, and every
        contributing recognition event, plus a deduplication event, is
        retained in its audit trail. The entity therefore carries its full
        audit trail with it.

        [`Location`]: Modality::Location
        [`AuditEvent`]: crate::entity::audit::AuditEvent
        [`audit`]: Entity::audit
        [`location`]: Entity::location
        [`confidence`]: Entity::confidence
      type: object
      properties:
        audit:
          description: |-
            Tamper-evident audit trail: every contributing detection, the fusion
            event if any, and the redaction that hid it, as a hash-linked DAG.
          allOf:
            - $ref: '#/components/schemas/TextAuditLog'
        confidence:
          description: Effective confidence in `0.0..=1.0` (fused, if applicable).
          allOf:
            - $ref: '#/components/schemas/Confidence'
        coref:
          $ref: '#/components/schemas/EntityCoRef'
          description: |-
            Coreference identifier, if a recognizer resolved this entity as one
            mention of a cluster. Entities sharing an [`EntityCoRef`] denote the
            same real-world thing.
        id:
          description: |-
            Stable unique identity for this entity (time-ordered UUIDv7), minted
            when the entity is assembled.
          type: string
          format: uuid
        label:
          description: |-
            What kind of sensitive information this is (resolved via a
            [`LabelCatalog`]).
          allOf:
            - $ref: '#/components/schemas/LabelRef'
        language:
          description: |-
            The language of this entity's surrounding text, when a recognizer
            resolved one. `None` when unknown or language-agnostic.
          type: string
        location:
          description: >-
            Location of the entity within the medium (fused, if it came from
            more

            than one detection).
          allOf:
            - $ref: '#/components/schemas/TextLocation'
        recognized_range:
          $ref: '#/components/schemas/Range_of_uint'
          description: >-
            Byte range of the match in the *recognized text* it was found in
            (the

            OCR layout text, the audio transcript, or the text payload itself) —

            the stable key back into that enrichment artifact, where the rich

            context lives (which OCR block, which speaker) that the geometric

            [`location`] cannot hold. `None` for entities not found via text

            recognition (e.g. a VLM box). An audit key, not a coordinate:
            redaction

            uses [`location`]; an audit uses this with the artifact.


            [`location`]: Entity::location
      required:
        - id
        - label
        - location
        - confidence
        - audit
    Review:
      description: |-
        A reviewer-supplied redaction override with the policy
        authority it draws from.

        The `policy_id` isn't just for audit — it also picks which
        per-policy pseudonym vault and per-policy [`KeyProvider`] the
        override's operator resolves against, so an override using
        [`Pseudonymize`] or [`HmacHash`] stays consistent with the
        authoring policy's other rules.

        [`KeyProvider`]: elide::redaction::operators::KeyProvider
        [`Pseudonymize`]: elide::redaction::operators::Pseudonymize
        [`HmacHash`]: elide::redaction::operators::HmacHash
      type: object
      properties:
        action:
          description: |-
            The per-modality redaction operators to run for this
            entity. Overrides whatever the policy set would have
            picked for the same entity.
          allOf:
            - $ref: '#/components/schemas/ModalityRedactions'
        policyId:
          description: |-
            The policy whose authority the reviewer exercises. Must
            match the `id` of a [`PolicyDefinition`] submitted with
            the anonymize request. The audit event stamps this UUID
            as the attribution `name`.

            [`PolicyDefinition`]: nvisy_schema::policy::PolicyDefinition
          type: string
          format: uuid
      required:
        - policyId
        - action
    TabularEntity:
      description: |-
        Detected piece of sensitive information within some medium.

        Generic over the [`Modality`] `M`, which is what makes the model
        multimodal: a text pipeline yields `Entity<Text>`, an audio pipeline
        `Entity<Audio>`, and so on. The entity's location is the modality's
        [`Location`] type, `M::Location`.

        # Birth and fusion

        A recognizer emits an entity directly, carrying a single recognition
        [`AuditEvent`] (its own finding) in the entity's [`audit`] trail. When
        several recognizers find the same thing, a fusion step (in
        `elide`) combines their entities into one: the survivor's
        [`location`] and [`confidence`] are the *fused* values, and every
        contributing recognition event, plus a deduplication event, is
        retained in its audit trail. The entity therefore carries its full
        audit trail with it.

        [`Location`]: Modality::Location
        [`AuditEvent`]: crate::entity::audit::AuditEvent
        [`audit`]: Entity::audit
        [`location`]: Entity::location
        [`confidence`]: Entity::confidence
      type: object
      properties:
        audit:
          description: |-
            Tamper-evident audit trail: every contributing detection, the fusion
            event if any, and the redaction that hid it, as a hash-linked DAG.
          allOf:
            - $ref: '#/components/schemas/TabularAuditLog'
        confidence:
          description: Effective confidence in `0.0..=1.0` (fused, if applicable).
          allOf:
            - $ref: '#/components/schemas/Confidence'
        coref:
          $ref: '#/components/schemas/EntityCoRef'
          description: |-
            Coreference identifier, if a recognizer resolved this entity as one
            mention of a cluster. Entities sharing an [`EntityCoRef`] denote the
            same real-world thing.
        id:
          description: |-
            Stable unique identity for this entity (time-ordered UUIDv7), minted
            when the entity is assembled.
          type: string
          format: uuid
        label:
          description: |-
            What kind of sensitive information this is (resolved via a
            [`LabelCatalog`]).
          allOf:
            - $ref: '#/components/schemas/LabelRef'
        language:
          description: |-
            The language of this entity's surrounding text, when a recognizer
            resolved one. `None` when unknown or language-agnostic.
          type: string
        location:
          description: >-
            Location of the entity within the medium (fused, if it came from
            more

            than one detection).
          allOf:
            - $ref: '#/components/schemas/TabularLocation'
        recognized_range:
          $ref: '#/components/schemas/Range_of_uint'
          description: >-
            Byte range of the match in the *recognized text* it was found in
            (the

            OCR layout text, the audio transcript, or the text payload itself) —

            the stable key back into that enrichment artifact, where the rich

            context lives (which OCR block, which speaker) that the geometric

            [`location`] cannot hold. `None` for entities not found via text

            recognition (e.g. a VLM box). An audit key, not a coordinate:
            redaction

            uses [`location`]; an audit uses this with the artifact.


            [`location`]: Entity::location
      required:
        - id
        - label
        - location
        - confidence
        - audit
    ImageEntity:
      description: |-
        Detected piece of sensitive information within some medium.

        Generic over the [`Modality`] `M`, which is what makes the model
        multimodal: a text pipeline yields `Entity<Text>`, an audio pipeline
        `Entity<Audio>`, and so on. The entity's location is the modality's
        [`Location`] type, `M::Location`.

        # Birth and fusion

        A recognizer emits an entity directly, carrying a single recognition
        [`AuditEvent`] (its own finding) in the entity's [`audit`] trail. When
        several recognizers find the same thing, a fusion step (in
        `elide`) combines their entities into one: the survivor's
        [`location`] and [`confidence`] are the *fused* values, and every
        contributing recognition event, plus a deduplication event, is
        retained in its audit trail. The entity therefore carries its full
        audit trail with it.

        [`Location`]: Modality::Location
        [`AuditEvent`]: crate::entity::audit::AuditEvent
        [`audit`]: Entity::audit
        [`location`]: Entity::location
        [`confidence`]: Entity::confidence
      type: object
      properties:
        audit:
          description: |-
            Tamper-evident audit trail: every contributing detection, the fusion
            event if any, and the redaction that hid it, as a hash-linked DAG.
          allOf:
            - $ref: '#/components/schemas/ImageAuditLog'
        confidence:
          description: Effective confidence in `0.0..=1.0` (fused, if applicable).
          allOf:
            - $ref: '#/components/schemas/Confidence'
        coref:
          $ref: '#/components/schemas/EntityCoRef'
          description: |-
            Coreference identifier, if a recognizer resolved this entity as one
            mention of a cluster. Entities sharing an [`EntityCoRef`] denote the
            same real-world thing.
        id:
          description: |-
            Stable unique identity for this entity (time-ordered UUIDv7), minted
            when the entity is assembled.
          type: string
          format: uuid
        label:
          description: |-
            What kind of sensitive information this is (resolved via a
            [`LabelCatalog`]).
          allOf:
            - $ref: '#/components/schemas/LabelRef'
        language:
          description: |-
            The language of this entity's surrounding text, when a recognizer
            resolved one. `None` when unknown or language-agnostic.
          type: string
        location:
          description: >-
            Location of the entity within the medium (fused, if it came from
            more

            than one detection).
          allOf:
            - $ref: '#/components/schemas/ImageLocation'
        recognized_range:
          $ref: '#/components/schemas/Range_of_uint'
          description: >-
            Byte range of the match in the *recognized text* it was found in
            (the

            OCR layout text, the audio transcript, or the text payload itself) —

            the stable key back into that enrichment artifact, where the rich

            context lives (which OCR block, which speaker) that the geometric

            [`location`] cannot hold. `None` for entities not found via text

            recognition (e.g. a VLM box). An audit key, not a coordinate:
            redaction

            uses [`location`]; an audit uses this with the artifact.


            [`location`]: Entity::location
      required:
        - id
        - label
        - location
        - confidence
        - audit
    AudioEntity:
      description: |-
        Detected piece of sensitive information within some medium.

        Generic over the [`Modality`] `M`, which is what makes the model
        multimodal: a text pipeline yields `Entity<Text>`, an audio pipeline
        `Entity<Audio>`, and so on. The entity's location is the modality's
        [`Location`] type, `M::Location`.

        # Birth and fusion

        A recognizer emits an entity directly, carrying a single recognition
        [`AuditEvent`] (its own finding) in the entity's [`audit`] trail. When
        several recognizers find the same thing, a fusion step (in
        `elide`) combines their entities into one: the survivor's
        [`location`] and [`confidence`] are the *fused* values, and every
        contributing recognition event, plus a deduplication event, is
        retained in its audit trail. The entity therefore carries its full
        audit trail with it.

        [`Location`]: Modality::Location
        [`AuditEvent`]: crate::entity::audit::AuditEvent
        [`audit`]: Entity::audit
        [`location`]: Entity::location
        [`confidence`]: Entity::confidence
      type: object
      properties:
        audit:
          description: |-
            Tamper-evident audit trail: every contributing detection, the fusion
            event if any, and the redaction that hid it, as a hash-linked DAG.
          allOf:
            - $ref: '#/components/schemas/AudioAuditLog'
        confidence:
          description: Effective confidence in `0.0..=1.0` (fused, if applicable).
          allOf:
            - $ref: '#/components/schemas/Confidence'
        coref:
          $ref: '#/components/schemas/EntityCoRef'
          description: |-
            Coreference identifier, if a recognizer resolved this entity as one
            mention of a cluster. Entities sharing an [`EntityCoRef`] denote the
            same real-world thing.
        id:
          description: |-
            Stable unique identity for this entity (time-ordered UUIDv7), minted
            when the entity is assembled.
          type: string
          format: uuid
        label:
          description: |-
            What kind of sensitive information this is (resolved via a
            [`LabelCatalog`]).
          allOf:
            - $ref: '#/components/schemas/LabelRef'
        language:
          description: |-
            The language of this entity's surrounding text, when a recognizer
            resolved one. `None` when unknown or language-agnostic.
          type: string
        location:
          description: >-
            Location of the entity within the medium (fused, if it came from
            more

            than one detection).
          allOf:
            - $ref: '#/components/schemas/AudioLocation'
        recognized_range:
          $ref: '#/components/schemas/Range_of_uint'
          description: >-
            Byte range of the match in the *recognized text* it was found in
            (the

            OCR layout text, the audio transcript, or the text payload itself) —

            the stable key back into that enrichment artifact, where the rich

            context lives (which OCR block, which speaker) that the geometric

            [`location`] cannot hold. `None` for entities not found via text

            recognition (e.g. a VLM box). An audit key, not a coordinate:
            redaction

            uses [`location`]; an audit uses this with the artifact.


            [`location`]: Entity::location
      required:
        - id
        - label
        - location
        - confidence
        - audit
    Language:
      description: |-
        Single language detection result.

        Carries the language plus an optional confidence and an optional
        byte-offset [`LanguageSpan`]. Backends that don't expose confidence
        leave it `None`; single-language detectors that don't track per-region
        information leave `span` as `None`. The `provenance` field records
        whether the answer came from a detector or was asserted by the caller.
      type: object
      properties:
        confidence:
          $ref: '#/components/schemas/Confidence'
          description: Optional confidence score. `None` when not exposed.
        language:
          description: Language.
          allOf:
            - $ref: '#/components/schemas/LanguageTag'
        provenance:
          description: 'How this language was obtained: detected or caller-asserted.'
          allOf:
            - $ref: '#/components/schemas/LanguageProvenance'
        span:
          $ref: '#/components/schemas/LanguageSpan'
          description: |-
            Byte-offset range this detection applies to, when known. `None`
            means the whole text.
      required:
        - language
        - provenance
    Dpi:
      description: |-
        Dots-per-inch resolution for rasterizing vector content.

        Used e.g. for rendering PDF pages to images for OCR.

        PDF coordinates are in points (1 pt = 1/72 in), so
        [`scale_factor`] gives the multiplier from points to
        pixels at this resolution.

        [`scale_factor`]: Self::scale_factor
      type: integer
      format: uint16
      maximum: 65535
      minimum: 0
    TextAuditLog:
      description: >-
        Full audit trail of an [`Entity`]: every [`AuditEvent`] in its life, as
        a

        tamper-evident DAG.


        Where Presidio keeps a shallow, optional, per-stage explanation that is

        stripped by default, an `AuditLog` is always present and records the

        entity's *entire* life: each recognizer that found it, the deduplication

        that fused them, any confidence calibration, and the redaction that hid
        it.

        Nothing is collapsed: every recognizer keeps its own recognition event
        with

        its location and score.


        The events form a **directed acyclic graph**, not a flat list. A
        recognizer

        records a birth event (no parents); each later step links to the event
        it

        follows; and a [fusion](Self::record_fusion) links to *several* parents
        at

        once: the heads of the trails it combines. This is the true shape of a

        deduplicated entity: two recognizers are siblings, then a fusion joins
        them.

        The events are stored in the order they were recorded, which is a

        topological order of the DAG (a parent is always recorded before its

        children).


        Two chains ride the DAG's edges:


        - a **confidence chain**, where each event's [`confidence`] is the
        entity's
          effective score after it; the score flowing *in* is its parents'
          confidence, so [`final_confidence`] and the full history are recoverable;
        - a **hash chain**, where each event's [`hash`] folds its payload
        together
          with its parents' hashes, so any edit, reorder, insertion, or deletion of
          an earlier event breaks every event downstream. [`verify`] walks the DAG
          and reports the first break.

        [`Entity`]: crate::entity::Entity

        [`confidence`]: AuditEvent::confidence

        [`hash`]: AuditEvent::hash

        [`final_confidence`]: Self::final_confidence

        [`verify`]: Self::verify
      type: array
      items:
        $ref: '#/components/schemas/TextAuditEvent'
    Confidence:
      description: |-
        Confidence score in the closed range `0.0..=1.0`.

        Carried by every provenance [`AuditEvent`] (the `before`/`after` of a
        recognition, fusion, or calibration) and by the effective confidence
        of an [`Entity`]. The newtype enforces the range at construction so
        no downstream code has to defend against values outside `[0, 1]`.

        Distinct from [`ConfidenceThreshold`] so the two cannot be confused
        at a call site: a score is *produced* by detection, a threshold is a
        *cutoff* configured to filter scores. Compare the two with
        [`ConfidenceThreshold::passes`].

        [`AuditEvent`]: crate::entity::audit::AuditEvent
        [`Entity`]: crate::entity::Entity
      type: number
      format: float
    EntityCoRef:
      description: |-
        Coreference identifier shared by entities that denote the same
        real-world thing.

        Assigned by a recognizer that performs coreference resolution: an
        NER model or LLM that recognises "Alice", "she", and "Ms. Smith" as
        the same person within one detection call. Two entities carrying the
        same `EntityCoRef` are coreferent: they refer to the same underlying
        entity even though each is a distinct mention with its own span.

        The identifier is opaque and only meaningful *within* a single
        detection call: it is the recognizer's local handle for a cluster of
        mentions, not a global key.
      type: string
    LabelRef:
      description: |-
        Lightweight reference to a [`Label`], carrying only its id.

        This is what detections and entities hold: cloning is cheap (short
        ids inline into the [`HipStr`]), and the full [`Label`], with its
        localized names and descriptions, is resolved on demand from a
        [`LabelCatalog`].

        [`Label`]: crate::entity::Label
        [`LabelCatalog`]: crate::entity::LabelCatalog
      type: string
    TextLocation:
      description: |-
        Half-open `[start, end)` byte range within text content.

        Ordering and overlap consider only `(start, end)`; the optional page
        number is carried for codecs that page their text but does not affect
        comparison.
      type: object
      properties:
        end:
          description: Byte offset where the range ends (exclusive).
          type: integer
          format: uint
          minimum: 0
        page:
          description: 1-based page number, when known.
          type: integer
          format: uint32
          minimum: 0
        start:
          description: Byte offset where the range starts.
          type: integer
          format: uint
          minimum: 0
      required:
        - start
        - end
    Range_of_uint:
      type: object
      properties:
        end:
          type: integer
          format: uint
          minimum: 0
        start:
          type: integer
          format: uint
          minimum: 0
      required:
        - start
        - end
    ModalityRedactions:
      description: |-
        Per-modality operator specs carried by a `redact` rule.

        A single rule can name an operator for every modality the
        workspace supports. At apply time the redaction phase picks the
        operator matching the entity's modality (engine reads the right
        field directly via `redactions.text.as_ref()` etc.); modalities
        the rule didn't cover fall through to the deployment-wide
        default, and entities with no operator from either source are
        skipped.
      type: object
      properties:
        audio:
          $ref: '#/components/schemas/AudioRedaction'
          description: Operator for audio-modality entities.
        image:
          $ref: '#/components/schemas/ImageRedaction'
          description: Operator for image-modality entities.
        tabular:
          $ref: '#/components/schemas/TabularRedaction'
          description: Operator for tabular-modality entities.
        text:
          $ref: '#/components/schemas/TextRedaction'
          description: Operator for text-modality entities.
    TabularAuditLog:
      description: >-
        Full audit trail of an [`Entity`]: every [`AuditEvent`] in its life, as
        a

        tamper-evident DAG.


        Where Presidio keeps a shallow, optional, per-stage explanation that is

        stripped by default, an `AuditLog` is always present and records the

        entity's *entire* life: each recognizer that found it, the deduplication

        that fused them, any confidence calibration, and the redaction that hid
        it.

        Nothing is collapsed: every recognizer keeps its own recognition event
        with

        its location and score.


        The events form a **directed acyclic graph**, not a flat list. A
        recognizer

        records a birth event (no parents); each later step links to the event
        it

        follows; and a [fusion](Self::record_fusion) links to *several* parents
        at

        once: the heads of the trails it combines. This is the true shape of a

        deduplicated entity: two recognizers are siblings, then a fusion joins
        them.

        The events are stored in the order they were recorded, which is a

        topological order of the DAG (a parent is always recorded before its

        children).


        Two chains ride the DAG's edges:


        - a **confidence chain**, where each event's [`confidence`] is the
        entity's
          effective score after it; the score flowing *in* is its parents'
          confidence, so [`final_confidence`] and the full history are recoverable;
        - a **hash chain**, where each event's [`hash`] folds its payload
        together
          with its parents' hashes, so any edit, reorder, insertion, or deletion of
          an earlier event breaks every event downstream. [`verify`] walks the DAG
          and reports the first break.

        [`Entity`]: crate::entity::Entity

        [`confidence`]: AuditEvent::confidence

        [`hash`]: AuditEvent::hash

        [`final_confidence`]: Self::final_confidence

        [`verify`]: Self::verify
      type: array
      items:
        $ref: '#/components/schemas/TabularAuditEvent'
    TabularLocation:
      description: |-
        Cell-addressed location within tabular content.

        Identifies a cell by zero-based [`row_index`] and
        [`column_index`], optionally narrowed to a byte
        range within the cell text for an entity that spans only part of the
        cell. [`sheet_name`] scopes the cell to one sheet of
        a multi-sheet workbook; [`column_name`] is a
        human-readable header carried for provenance.

        Overlap and ordering treat the sheet, cell, and byte range as
        coordinates. The column name is redundant with the column index, so it
        is carried but excluded from comparison.

        [`row_index`]: Self::row_index
        [`column_index`]: Self::column_index
        [`sheet_name`]: Self::sheet_name
        [`column_name`]: Self::column_name
      type: object
      properties:
        column_index:
          description: Zero-based column index of the cell.
          type: integer
          format: uint32
          minimum: 0
        column_name:
          description: Header label of the column, when known.
          type: string
        end_offset:
          description: |-
            Byte offset within the cell text where the entity ends (exclusive).
            Unset means the whole cell.
          type: integer
          format: uint
          minimum: 0
        row_index:
          description: Zero-based row index of the cell.
          type: integer
          format: uint32
          minimum: 0
        sheet_name:
          description: Sheet name within a multi-sheet workbook, when known.
          type: string
        start_offset:
          description: |-
            Byte offset within the cell text where the entity starts. Unset
            means the whole cell.
          type: integer
          format: uint
          minimum: 0
      required:
        - row_index
        - column_index
    ImageAuditLog:
      description: >-
        Full audit trail of an [`Entity`]: every [`AuditEvent`] in its life, as
        a

        tamper-evident DAG.


        Where Presidio keeps a shallow, optional, per-stage explanation that is

        stripped by default, an `AuditLog` is always present and records the

        entity's *entire* life: each recognizer that found it, the deduplication

        that fused them, any confidence calibration, and the redaction that hid
        it.

        Nothing is collapsed: every recognizer keeps its own recognition event
        with

        its location and score.


        The events form a **directed acyclic graph**, not a flat list. A
        recognizer

        records a birth event (no parents); each later step links to the event
        it

        follows; and a [fusion](Self::record_fusion) links to *several* parents
        at

        once: the heads of the trails it combines. This is the true shape of a

        deduplicated entity: two recognizers are siblings, then a fusion joins
        them.

        The events are stored in the order they were recorded, which is a

        topological order of the DAG (a parent is always recorded before its

        children).


        Two chains ride the DAG's edges:


        - a **confidence chain**, where each event's [`confidence`] is the
        entity's
          effective score after it; the score flowing *in* is its parents'
          confidence, so [`final_confidence`] and the full history are recoverable;
        - a **hash chain**, where each event's [`hash`] folds its payload
        together
          with its parents' hashes, so any edit, reorder, insertion, or deletion of
          an earlier event breaks every event downstream. [`verify`] walks the DAG
          and reports the first break.

        [`Entity`]: crate::entity::Entity

        [`confidence`]: AuditEvent::confidence

        [`hash`]: AuditEvent::hash

        [`final_confidence`]: Self::final_confidence

        [`verify`]: Self::verify
      type: array
      items:
        $ref: '#/components/schemas/ImageAuditEvent'
    ImageLocation:
      description: |-
        Region within image content.

        An axis-aligned [`BoundingBox`] in pixel coordinates locates the
        region; an optional [`Polygon`] captures a rotated or quadrilateral
        shape when the source produced one (OCR engines that emit 4-point
        polygons), and an optional page number addresses multi-page documents.
      type: object
      properties:
        bounding_box:
          description: Axis-aligned bounding box of the region, in pixel coordinates.
          allOf:
            - $ref: '#/components/schemas/BoundingBox'
        page:
          description: 1-based page number, for multi-page documents like PDFs.
          type: integer
          format: uint32
          minimum: 0
        polygon:
          $ref: '#/components/schemas/Polygon'
          description: |-
            Polygon vertices when the region is rotated or quadrilateral.
            Axis-aligned-only sources leave this unset.
      required:
        - bounding_box
    AudioAuditLog:
      description: >-
        Full audit trail of an [`Entity`]: every [`AuditEvent`] in its life, as
        a

        tamper-evident DAG.


        Where Presidio keeps a shallow, optional, per-stage explanation that is

        stripped by default, an `AuditLog` is always present and records the

        entity's *entire* life: each recognizer that found it, the deduplication

        that fused them, any confidence calibration, and the redaction that hid
        it.

        Nothing is collapsed: every recognizer keeps its own recognition event
        with

        its location and score.


        The events form a **directed acyclic graph**, not a flat list. A
        recognizer

        records a birth event (no parents); each later step links to the event
        it

        follows; and a [fusion](Self::record_fusion) links to *several* parents
        at

        once: the heads of the trails it combines. This is the true shape of a

        deduplicated entity: two recognizers are siblings, then a fusion joins
        them.

        The events are stored in the order they were recorded, which is a

        topological order of the DAG (a parent is always recorded before its

        children).


        Two chains ride the DAG's edges:


        - a **confidence chain**, where each event's [`confidence`] is the
        entity's
          effective score after it; the score flowing *in* is its parents'
          confidence, so [`final_confidence`] and the full history are recoverable;
        - a **hash chain**, where each event's [`hash`] folds its payload
        together
          with its parents' hashes, so any edit, reorder, insertion, or deletion of
          an earlier event breaks every event downstream. [`verify`] walks the DAG
          and reports the first break.

        [`Entity`]: crate::entity::Entity

        [`confidence`]: AuditEvent::confidence

        [`hash`]: AuditEvent::hash

        [`final_confidence`]: Self::final_confidence

        [`verify`]: Self::verify
      type: array
      items:
        $ref: '#/components/schemas/AudioAuditEvent'
    AudioLocation:
      description: |-
        A [`TimeSpan`] within audio content, with an optional speaker label.

        The time span is the coordinate; ordering and overlap consider only it.
        The optional [`speaker_id`] is a diarization label,
        not a coordinate: two utterances from different speakers at the same
        instant still overlap in time, so the speaker is carried for provenance
        but excluded from comparison.

        [`speaker_id`]: Self::speaker_id
      type: object
      properties:
        span:
          description: Time span the location covers, in the stream's timeline.
          allOf:
            - $ref: '#/components/schemas/TimeSpan'
        speaker_id:
          description: Diarization label of the speaker, when a diarizer assigned one.
          type: string
      required:
        - span
    LanguageTag:
      description: |-
        Well-formed [BCP 47] language tag, such as `en`, `en-US`, or
        `zh-Hant-HK`.

        Wraps [`oxilangtag::LanguageTag`] over a [`HipStr`] backing store, so
        short tags (the overwhelming common case) stay inline without a heap
        allocation. Parsing validates the tag's structure up front; the
        newtype therefore guarantees that any `LanguageTag` value in the
        model is syntactically valid.

        Used to record the language a recognizer is scoped to, or the
        detected language of a span of content.

        [BCP 47]: https://www.rfc-editor.org/info/bcp47
      type: string
    LanguageProvenance:
      description: |-
        How a [`Language`]'s language was obtained.

        Lets consumers distinguish "a detector ran and got this answer" from
        "the caller asserted this language". An assertion may still carry an
        optional confidence, so this is independent of the confidence field.
      oneOf:
        - description: Produced by a language-detection backend.
          type: string
          const: detected
        - description: Asserted by the caller.
          type: string
          const: asserted
    LanguageSpan:
      description: |-
        Byte-offset range within the analyzed text.

        Attached to a [`Language`] when the detector knows the span
        its answer covers (mixed-language input produces multiple detections,
        each with a distinct span). Single-language detections from
        non-segmenting backends, and caller-asserted answers, typically leave
        the span as `None`.
      type: object
      properties:
        end:
          description: Byte offset of the span end in the original text.
          type: integer
          format: uint
          minimum: 0
        start:
          description: Byte offset of the span start in the original text.
          type: integer
          format: uint
          minimum: 0
      required:
        - start
        - end
    TextAuditEvent:
      description: >-
        One node in an entity's audit DAG: a thing that happened, with its

        effect on confidence and its tamper-evident links.


        Events are recorded on an entity's [`AuditLog`], forming the full audit

        trail of its life: each recognizer that found it, the deduplication that

        fused them, any score calibration, and the redaction that hid it. The

        uniform spine (who, resulting score, when) is the same for every event;
        the

        [`kind`] carries the event-specific detail *and* the explanation of why
        the

        event happened.


        Each event links to its [`parents`] by their [`hash`]: a birth event (a

        recognizer's first detection) has no parents, a normal step has one, and
        a

        [fusion](crate::entity::audit::AuditLog::record_fusion) has several. Its
        own

        [`hash`] folds the

        payload together with the parents' hashes, so altering any event breaks

        every event downstream of it: [`AuditLog::verify`] walks the DAG and

        reports the first break.


        `entity.confidence` always equals the [`confidence`] of the most recent

        event. The confidence *flowing in* is not stored: it is the parents'

        [`confidence`], recovered from the DAG.


        [`AuditLog`]: crate::entity::audit::AuditLog

        [`AuditLog::record_fusion`]:
        crate::entity::audit::AuditLog::record_fusion

        [`AuditLog::verify`]: crate::entity::audit::AuditLog::verify

        [`kind`]: AuditEvent::kind

        [`parents`]: AuditEvent::parents

        [`hash`]: AuditEvent::hash

        [`confidence`]: AuditEvent::confidence
      type: object
      properties:
        confidence:
          description: >-
            Confidence after this event: the entity's effective confidence once
            it

            has happened.
          allOf:
            - $ref: '#/components/schemas/Confidence'
        hash:
          description: >-
            This event's hash, over its payload and its parents' hashes.
            Assigned by

            [`AuditLog`] when the event is recorded; read it through

            [`hash`](Self::hash). Recomputing it is how the DAG is verified.


            Not publicly settable: only [`AuditLog`] assigns it, so a caller
            cannot

            forge a self-consistent event outside the recording path.


            [`AuditLog`]: crate::entity::audit::AuditLog
          allOf:
            - $ref: '#/components/schemas/AuditHash'
        kind:
          description: Kind of event, with its event-specific detail and its rationale.
          allOf:
            - $ref: '#/components/schemas/TextAuditKind'
        parents:
          description: >-
            The events this one follows, by their hash. Empty for a birth event,
            one

            entry for a normal step, several for a fusion. Assigned by
            [`AuditLog`]

            when the event is recorded; read it through
            [`parents`](Self::parents).


            Not publicly settable: the links are the tamper-evident structure,
            so

            only [`AuditLog::record`] / [`AuditLog::record_fusion`] assign them.


            [`AuditLog`]: crate::entity::audit::AuditLog

            [`AuditLog::record`]: crate::entity::audit::AuditLog::record

            [`AuditLog::record_fusion`]:
            crate::entity::audit::AuditLog::record_fusion
          type: array
          items:
            $ref: '#/components/schemas/AuditHash'
        source:
          description: >-
            Who produced this event: a recognizer name, a deduplication
            strategy,

            an operator, or whatever acted.
          type: string
        timestamp:
          description: When the event happened (UTC).
          type: string
      required:
        - source
        - confidence
        - timestamp
        - kind
        - parents
        - hash
    AudioRedaction:
      description: Operator spec a `redact` audio rule carries.
      oneOf:
        - description: Cut the matched interval out, shortening the clip.
          type: object
          properties:
            kind:
              type: string
              const: erase
          required:
            - kind
        - description: Pass the interval through unchanged.
          type: object
          properties:
            kind:
              type: string
              const: keep
          required:
            - kind
        - description: |-
            Zero the matched interval in place, preserving the clip
            length and the timing of everything after it.
          type: object
          properties:
            kind:
              type: string
              const: silence
          required:
            - kind
        - description: |-
            Overlay a tone over the matched interval (the broadcast
            "bleep"); preserves duration.
          type: object
          properties:
            amplitude:
              description: |-
                Peak amplitude in `0.0..=1.0` of full scale. Default 0.5:
                audible but not painful, and never clips.
              type: number
              format: float
              default: 0.5
            hz:
              description: |-
                Tone frequency in Hertz. Default 1 kHz, the broadcast
                convention.
              type: number
              format: float
              default: 1000
            kind:
              type: string
              const: beep
            waveform:
              description: Tone shape. Default sine.
              allOf:
                - $ref: '#/components/schemas/Waveform'
              default: sine
          required:
            - kind
    ImageRedaction:
      description: Operator spec a `redact` image rule carries.
      oneOf:
        - description: Clear the matched region.
          type: object
          properties:
            kind:
              type: string
              const: erase
          required:
            - kind
        - description: Pass the region through unchanged.
          type: object
          properties:
            kind:
              type: string
              const: keep
          required:
            - kind
        - description: Gaussian-blur the region.
          type: object
          properties:
            kind:
              type: string
              const: blur
            sigma:
              description: |-
                Standard deviation of the Gaussian kernel, in pixels.
                Larger is blurrier (and harder to reverse).
              type: number
              format: float
              default: 16
          required:
            - kind
        - description: Mosaic-pixelate the region.
          type: object
          properties:
            block_size:
              description: |-
                Side length of each mosaic block, in pixels. Larger
                blocks are coarser (and harder to reverse).
              type: integer
              format: uint32
              default: 16
              minimum: 0
            kind:
              type: string
              const: pixelate
          required:
            - kind
        - description: Cover the region with a solid color fill (black by default).
          type: object
          properties:
            color:
              description: Fill color the codec rasterises over the region.
              allOf:
                - $ref: '#/components/schemas/Color'
              default:
                b: 0
                g: 0
                r: 0
            kind:
              type: string
              const: blackbox
          required:
            - kind
    TabularRedaction:
      description: Operator spec a `redact` tabular rule carries.
      oneOf:
        - description: |-
            Run a text-modality operator on the matched cell's
            content. Cells are `TextBacked` in elide, so any
            [`TextRedaction`] applies unchanged.
          type: object
          properties:
            kind:
              type: string
              const: cell
            spec:
              description: |-
                The text operator to apply. Reuses the full text
                vocabulary (Erase, Keep, Mask, Replace, Hash,
                Pseudonymize, Encrypt).
              allOf:
                - $ref: '#/components/schemas/TextRedaction'
          required:
            - kind
            - spec
        - description: Drop the entire row a matched cell sits in.
          type: object
          properties:
            kind:
              type: string
              const: drop_row
          required:
            - kind
        - description: |-
            Drop the entire column a matched cell sits in (header
            included).
          type: object
          properties:
            kind:
              type: string
              const: drop_column
          required:
            - kind
    TextRedaction:
      description: Operator spec a `redact` text rule carries.
      oneOf:
        - description: Delete the matched span entirely.
          type: object
          properties:
            kind:
              type: string
              const: erase
          required:
            - kind
        - description: Pass the value through unchanged.
          type: object
          properties:
            kind:
              type: string
              const: keep
          required:
            - kind
        - description: |-
            Character-replacement masking. Leaves `keep_prefix` leading
            and `keep_suffix` trailing characters visible; masks the
            rest with `mask_char`.
          type: object
          properties:
            keep_prefix:
              description: |-
                Characters to leave unmasked at the start of the value.
                `0` (the default) masks from the start.
              type: integer
              format: uint
              minimum: 0
            keep_suffix:
              description: |-
                Characters to leave unmasked at the end of the value.
                `0` (the default) masks through to the end.
              type: integer
              format: uint
              minimum: 0
            kind:
              type: string
              const: mask
            mask_char:
              description: The character that replaces masked positions.
              type: string
              default: '*'
              maxLength: 1
              minLength: 1
          required:
            - kind
        - description: |-
            Substitute the span with a fixed template. Supports
            `{label}` / `{value}` / `{coref}` placeholders.
          type: object
          properties:
            kind:
              type: string
              const: replace
            template:
              description: Template string. Default `[{label}]`.
              type: string
              default: '[{label}]'
          required:
            - kind
        - description: One-way SHA-2 hash with optional salt.
          type: object
          properties:
            algorithm:
              description: SHA-256 (default) or SHA-512.
              allOf:
                - $ref: '#/components/schemas/Sha2Algorithm'
              default: sha256
            kind:
              type: string
              const: hash
            salt:
              description: Salt prepended to the value before hashing.
              type: string
          required:
            - kind
        - description: |-
            Swap the matched span for a locale-aware fake value. Picks
            the locale from the entity's BCP-47 `language` tag, falling
            back to `default_language` (English unless overridden) when
            the entity carries none. Coreferent mentions of the same
            real-world entity collapse to the same surrogate within a
            run. Labels outside the built-in PII catalogue fall through
            to [`Replace`] with `fallback_template`.

            [`Replace`]: TextRedaction::Replace
          type: object
          properties:
            default_language:
              $ref: '#/components/schemas/LanguageTag'
              description: |-
                BCP-47 tag used when the entity carries no language of
                its own. Defaults to English (`"en"`).
            fallback_template:
              description: |-
                Template used for entity labels outside the built-in
                PII catalogue (which `Fake` can't generate for).
                Supports the same `{label}` / `{value}` / `{coref}`
                placeholders as [`Replace`]. Defaults to `[{label}]`.

                [`Replace`]: TextRedaction::Replace
              type: string
              default: '[{label}]'
            kind:
              type: string
              const: fake
            seed:
              description: |-
                Seed mixed into per-entity RNG state. Two runs with the
                same seed and the same input entities produce the same
                surrogates. Defaults to `0`.
              type: integer
              format: uint64
              minimum: 0
          required:
            - kind
        - description: >-
            Vault-backed pseudonym: every mention of the same entity

            reads the same surrogate. The engine wires a per-request

            vault + the default [`RandomToken`] generator.


            [`RandomToken`]:
            https://docs.rs/elide/latest/elide/redaction/generator/struct.RandomToken.html
          type: object
          properties:
            kind:
              type: string
              const: pseudonymize
          required:
            - kind
        - description: |-
            Reversible AES-256-GCM ciphertext. The engine supplies the
            per-tenant AES key at construction so raw key material never
            lives in serialised policy. Requires the engine to have a
            key provider wired via `Engine::with_key_provider`.
          type: object
          properties:
            kind:
              type: string
              const: encrypt
          required:
            - kind
        - description: |-
            Keyed HMAC-SHA-2 digest. The key stays secret, so an
            attacker who obtains the redacted output cannot enumerate
            a small input space without the key — the PCI DSS v4.0.1
            §3.5.1 "keyed hash" posture. Distinct from [`Hash`], whose
            salt is public. Requires the engine to have a key provider
            wired via `Engine::with_key_provider`.

            [`Hash`]: TextRedaction::Hash
          type: object
          properties:
            algorithm:
              description: HMAC-SHA-256 (default) or HMAC-SHA-512.
              allOf:
                - $ref: '#/components/schemas/Sha2Algorithm'
              default: sha256
            kind:
              type: string
              const: hmac_hash
          required:
            - kind
        - description: |-
            Physically remove the middle of the value, keeping a
            leading and/or trailing run of characters. Unlike [`Mask`]
            this *shortens* the string — the dropped characters leave
            no placeholder. The PCI DSS §3.5.1 truncation posture for
            stored PAN: `Truncate { keep_prefix: 6, keep_suffix: 4 }`
            on `"4111111111111234"` yields `"4111111234"` (10 chars),
            where the analogous [`Mask`] would yield `"411111******1234"`
            (16 chars, length preserved).

            A configuration whose kept regions cover (or overlap) the
            whole value is rejected at apply time; the operator errors
            rather than silently pass through.

            [`Mask`]: TextRedaction::Mask
          type: object
          properties:
            keep_prefix:
              description: Characters to keep at the start of the value.
              type: integer
              format: uint
              minimum: 0
            keep_suffix:
              description: Characters to keep at the end of the value.
              type: integer
              format: uint
              minimum: 0
            kind:
              type: string
              const: truncate
          required:
            - kind
        - description: |-
            Collapse a numeric value at or above `ceiling` (or at or
            below `floor`) into a bucket label; values in the middle
            pass through unchanged. The HIPAA §164.514(b)(2)(i)(C) age
            posture: everyone ≥90 aggregates into `"90 or older"`,
            while a 73-year-old stays `"73"`.

            Values that don't parse as finite numbers are *declined*.
            `fallback` names what runs on a declined value; when
            absent, elide's baked-in default is [`Erase`] (the safe
            posture — a non-numeric age never survives redaction).

            [`Erase`]: TextRedaction::Erase
          type: object
          properties:
            ceiling:
              description: |-
                Threshold at or above which values collapse to
                `ceiling_bucket`. `None` disables the ceiling.
              type: number
              format: double
            ceiling_bucket:
              $ref: '#/components/schemas/ClampBucket'
              description: |-
                Bucket label for values at or above `ceiling`. Required
                when `ceiling` is set; ignored otherwise.
            fallback:
              $ref: '#/components/schemas/TerminalFallback'
              description: |-
                Operator that runs when the entity value isn't a
                finite number. `None` erases (elide's default).
            floor:
              description: |-
                Threshold at or below which values collapse to
                `floor_bucket`. `None` disables the floor.
              type: number
              format: double
            floor_bucket:
              $ref: '#/components/schemas/ClampBucket'
              description: |-
                Bucket label for values at or below `floor`. Required
                when `floor` is set; ignored otherwise.
            kind:
              type: string
              const: clamp
          required:
            - kind
        - description: |-
            Reduce a date/timestamp to a coarser granularity. The
            HIPAA §164.514(b)(2)(i)(C) date-generalization posture:
            dates directly related to an individual reduced to the
            year, preserving cohort-level analytics.

            Values that don't parse as dates are *declined*. `fallback`
            names what runs on a declined value; when absent, elide's
            baked-in default is [`Erase`].

            [`Erase`]: TextRedaction::Erase
          type: object
          properties:
            fallback:
              $ref: '#/components/schemas/TerminalFallback'
              description: |-
                Operator that runs when the entity value isn't a
                parseable date. `None` erases (elide's default).
            granularity:
              description: Coarseness of the output. Default `Year`.
              allOf:
                - $ref: '#/components/schemas/DateGranularity'
              default: year
            kind:
              type: string
              const: generalize_date
            style:
              description: Which input convention to accept. Default `Iso`.
              allOf:
                - $ref: '#/components/schemas/DateStyle'
              default: iso
          required:
            - kind
    TabularAuditEvent:
      description: >-
        One node in an entity's audit DAG: a thing that happened, with its

        effect on confidence and its tamper-evident links.


        Events are recorded on an entity's [`AuditLog`], forming the full audit

        trail of its life: each recognizer that found it, the deduplication that

        fused them, any score calibration, and the redaction that hid it. The

        uniform spine (who, resulting score, when) is the same for every event;
        the

        [`kind`] carries the event-specific detail *and* the explanation of why
        the

        event happened.


        Each event links to its [`parents`] by their [`hash`]: a birth event (a

        recognizer's first detection) has no parents, a normal step has one, and
        a

        [fusion](crate::entity::audit::AuditLog::record_fusion) has several. Its
        own

        [`hash`] folds the

        payload together with the parents' hashes, so altering any event breaks

        every event downstream of it: [`AuditLog::verify`] walks the DAG and

        reports the first break.


        `entity.confidence` always equals the [`confidence`] of the most recent

        event. The confidence *flowing in* is not stored: it is the parents'

        [`confidence`], recovered from the DAG.


        [`AuditLog`]: crate::entity::audit::AuditLog

        [`AuditLog::record_fusion`]:
        crate::entity::audit::AuditLog::record_fusion

        [`AuditLog::verify`]: crate::entity::audit::AuditLog::verify

        [`kind`]: AuditEvent::kind

        [`parents`]: AuditEvent::parents

        [`hash`]: AuditEvent::hash

        [`confidence`]: AuditEvent::confidence
      type: object
      properties:
        confidence:
          description: >-
            Confidence after this event: the entity's effective confidence once
            it

            has happened.
          allOf:
            - $ref: '#/components/schemas/Confidence'
        hash:
          description: >-
            This event's hash, over its payload and its parents' hashes.
            Assigned by

            [`AuditLog`] when the event is recorded; read it through

            [`hash`](Self::hash). Recomputing it is how the DAG is verified.


            Not publicly settable: only [`AuditLog`] assigns it, so a caller
            cannot

            forge a self-consistent event outside the recording path.


            [`AuditLog`]: crate::entity::audit::AuditLog
          allOf:
            - $ref: '#/components/schemas/AuditHash'
        kind:
          description: Kind of event, with its event-specific detail and its rationale.
          allOf:
            - $ref: '#/components/schemas/TabularAuditKind'
        parents:
          description: >-
            The events this one follows, by their hash. Empty for a birth event,
            one

            entry for a normal step, several for a fusion. Assigned by
            [`AuditLog`]

            when the event is recorded; read it through
            [`parents`](Self::parents).


            Not publicly settable: the links are the tamper-evident structure,
            so

            only [`AuditLog::record`] / [`AuditLog::record_fusion`] assign them.


            [`AuditLog`]: crate::entity::audit::AuditLog

            [`AuditLog::record`]: crate::entity::audit::AuditLog::record

            [`AuditLog::record_fusion`]:
            crate::entity::audit::AuditLog::record_fusion
          type: array
          items:
            $ref: '#/components/schemas/AuditHash'
        source:
          description: >-
            Who produced this event: a recognizer name, a deduplication
            strategy,

            an operator, or whatever acted.
          type: string
        timestamp:
          description: When the event happened (UTC).
          type: string
      required:
        - source
        - confidence
        - timestamp
        - kind
        - parents
        - hash
    ImageAuditEvent:
      description: >-
        One node in an entity's audit DAG: a thing that happened, with its

        effect on confidence and its tamper-evident links.


        Events are recorded on an entity's [`AuditLog`], forming the full audit

        trail of its life: each recognizer that found it, the deduplication that

        fused them, any score calibration, and the redaction that hid it. The

        uniform spine (who, resulting score, when) is the same for every event;
        the

        [`kind`] carries the event-specific detail *and* the explanation of why
        the

        event happened.


        Each event links to its [`parents`] by their [`hash`]: a birth event (a

        recognizer's first detection) has no parents, a normal step has one, and
        a

        [fusion](crate::entity::audit::AuditLog::record_fusion) has several. Its
        own

        [`hash`] folds the

        payload together with the parents' hashes, so altering any event breaks

        every event downstream of it: [`AuditLog::verify`] walks the DAG and

        reports the first break.


        `entity.confidence` always equals the [`confidence`] of the most recent

        event. The confidence *flowing in* is not stored: it is the parents'

        [`confidence`], recovered from the DAG.


        [`AuditLog`]: crate::entity::audit::AuditLog

        [`AuditLog::record_fusion`]:
        crate::entity::audit::AuditLog::record_fusion

        [`AuditLog::verify`]: crate::entity::audit::AuditLog::verify

        [`kind`]: AuditEvent::kind

        [`parents`]: AuditEvent::parents

        [`hash`]: AuditEvent::hash

        [`confidence`]: AuditEvent::confidence
      type: object
      properties:
        confidence:
          description: >-
            Confidence after this event: the entity's effective confidence once
            it

            has happened.
          allOf:
            - $ref: '#/components/schemas/Confidence'
        hash:
          description: >-
            This event's hash, over its payload and its parents' hashes.
            Assigned by

            [`AuditLog`] when the event is recorded; read it through

            [`hash`](Self::hash). Recomputing it is how the DAG is verified.


            Not publicly settable: only [`AuditLog`] assigns it, so a caller
            cannot

            forge a self-consistent event outside the recording path.


            [`AuditLog`]: crate::entity::audit::AuditLog
          allOf:
            - $ref: '#/components/schemas/AuditHash'
        kind:
          description: Kind of event, with its event-specific detail and its rationale.
          allOf:
            - $ref: '#/components/schemas/ImageAuditKind'
        parents:
          description: >-
            The events this one follows, by their hash. Empty for a birth event,
            one

            entry for a normal step, several for a fusion. Assigned by
            [`AuditLog`]

            when the event is recorded; read it through
            [`parents`](Self::parents).


            Not publicly settable: the links are the tamper-evident structure,
            so

            only [`AuditLog::record`] / [`AuditLog::record_fusion`] assign them.


            [`AuditLog`]: crate::entity::audit::AuditLog

            [`AuditLog::record`]: crate::entity::audit::AuditLog::record

            [`AuditLog::record_fusion`]:
            crate::entity::audit::AuditLog::record_fusion
          type: array
          items:
            $ref: '#/components/schemas/AuditHash'
        source:
          description: >-
            Who produced this event: a recognizer name, a deduplication
            strategy,

            an operator, or whatever acted.
          type: string
        timestamp:
          description: When the event happened (UTC).
          type: string
      required:
        - source
        - confidence
        - timestamp
        - kind
        - parents
        - hash
    BoundingBox:
      description: |-
        Axis-aligned rectangle, given by its minimum and maximum corners.

        The location type for the image and document modalities: where a
        detected entity sits within a rendered page. [`min`] is the top-left
        corner and [`max`] the bottom-right under the usual screen convention
        (y grows downward), though the box itself is agnostic to coordinate
        orientation.

        [`min`]: Self::min
        [`max`]: Self::max
      type: object
      properties:
        max:
          description: Maximum corner (bottom-right, conventionally).
          allOf:
            - $ref: '#/components/schemas/Point'
        min:
          description: Minimum corner (top-left, conventionally).
          allOf:
            - $ref: '#/components/schemas/Point'
      required:
        - min
        - max
    Polygon:
      description: |-
        Closed polygon, given by its ordered vertices.

        A richer location than a [`BoundingBox`] for detections whose extent
        is not rectangular: rotated text, a region traced by a vision model, a
        signature. The boundary is implicitly closed, so the last vertex
        connects back to the first.

        [`BoundingBox`]: super::BoundingBox
      type: array
      items:
        $ref: '#/components/schemas/Point'
    AudioAuditEvent:
      description: >-
        One node in an entity's audit DAG: a thing that happened, with its

        effect on confidence and its tamper-evident links.


        Events are recorded on an entity's [`AuditLog`], forming the full audit

        trail of its life: each recognizer that found it, the deduplication that

        fused them, any score calibration, and the redaction that hid it. The

        uniform spine (who, resulting score, when) is the same for every event;
        the

        [`kind`] carries the event-specific detail *and* the explanation of why
        the

        event happened.


        Each event links to its [`parents`] by their [`hash`]: a birth event (a

        recognizer's first detection) has no parents, a normal step has one, and
        a

        [fusion](crate::entity::audit::AuditLog::record_fusion) has several. Its
        own

        [`hash`] folds the

        payload together with the parents' hashes, so altering any event breaks

        every event downstream of it: [`AuditLog::verify`] walks the DAG and

        reports the first break.


        `entity.confidence` always equals the [`confidence`] of the most recent

        event. The confidence *flowing in* is not stored: it is the parents'

        [`confidence`], recovered from the DAG.


        [`AuditLog`]: crate::entity::audit::AuditLog

        [`AuditLog::record_fusion`]:
        crate::entity::audit::AuditLog::record_fusion

        [`AuditLog::verify`]: crate::entity::audit::AuditLog::verify

        [`kind`]: AuditEvent::kind

        [`parents`]: AuditEvent::parents

        [`hash`]: AuditEvent::hash

        [`confidence`]: AuditEvent::confidence
      type: object
      properties:
        confidence:
          description: >-
            Confidence after this event: the entity's effective confidence once
            it

            has happened.
          allOf:
            - $ref: '#/components/schemas/Confidence'
        hash:
          description: >-
            This event's hash, over its payload and its parents' hashes.
            Assigned by

            [`AuditLog`] when the event is recorded; read it through

            [`hash`](Self::hash). Recomputing it is how the DAG is verified.


            Not publicly settable: only [`AuditLog`] assigns it, so a caller
            cannot

            forge a self-consistent event outside the recording path.


            [`AuditLog`]: crate::entity::audit::AuditLog
          allOf:
            - $ref: '#/components/schemas/AuditHash'
        kind:
          description: Kind of event, with its event-specific detail and its rationale.
          allOf:
            - $ref: '#/components/schemas/AudioAuditKind'
        parents:
          description: >-
            The events this one follows, by their hash. Empty for a birth event,
            one

            entry for a normal step, several for a fusion. Assigned by
            [`AuditLog`]

            when the event is recorded; read it through
            [`parents`](Self::parents).


            Not publicly settable: the links are the tamper-evident structure,
            so

            only [`AuditLog::record`] / [`AuditLog::record_fusion`] assign them.


            [`AuditLog`]: crate::entity::audit::AuditLog

            [`AuditLog::record`]: crate::entity::audit::AuditLog::record

            [`AuditLog::record_fusion`]:
            crate::entity::audit::AuditLog::record_fusion
          type: array
          items:
            $ref: '#/components/schemas/AuditHash'
        source:
          description: >-
            Who produced this event: a recognizer name, a deduplication
            strategy,

            an operator, or whatever acted.
          type: string
        timestamp:
          description: When the event happened (UTC).
          type: string
      required:
        - source
        - confidence
        - timestamp
        - kind
        - parents
        - hash
    TimeSpan:
      description: |-
        Half-open `[start, end)` stream interval, measured in microseconds.

        The coordinate a time-addressed medium (audio, video) uses to locate a
        region: a transcribed segment, a redacted span. Microsecond precision
        is finer than both word-level speech timings and per-sample audio
        resolution, so a span never loses precision being carried as a
        `TimeSpan`; the endpoints are non-negative offsets by construction.

        Half-open like a byte range: `[start, end)`, so two intervals that
        merely touch (`a.end == b.start`) do not [`overlap`].

        [`from_millis`] and [`as_millis`] bridge the millisecond-based APIs
        that surround it (audio durations, provider timings reported in ms).

        [`overlap`]: Self::overlaps
        [`from_millis`]: Self::from_millis
        [`as_millis`]: Self::start_millis
      type: object
      properties:
        end_us:
          description: |-
            Microseconds from the start of the stream where the interval ends
            (exclusive).
          type: integer
          format: uint64
          minimum: 0
        start_us:
          description: Microseconds from the start of the stream where the interval begins.
          type: integer
          format: uint64
          minimum: 0
      required:
        - start_us
        - end_us
    AuditHash:
      description: >-
        A 32-byte BLAKE3 digest.


        The tamper-evident link in an [`AuditLog`] DAG: each [`AuditEvent`]
        hashes

        its payload together with its parents' hashes, so altering any event
        breaks

        every event downstream of it. Displays and (with the `serde` feature)

        (de)serializes as lowercase hex.


        The all-zero hash is [`GENESIS`](AuditHash::GENESIS), the link a birth
        event

        (one with no parents) chains from.


        [`AuditLog`]: crate::entity::audit::AuditLog

        [`AuditEvent`]: crate::entity::audit::AuditEvent
      type: string
    TextAuditKind:
      description: |-
        Kind of an [`AuditEvent`], carrying its event-specific detail and the
        rationale for why it happened.

        `#[non_exhaustive]`: new event kinds (verification, annotation, …)
        can be added compatibly. The recognition kinds ([`Pattern`],
        [`Model`]) carry the matched [`Location`]; the rest carry their own
        data.

        [`Pattern`]: AuditKind::Pattern
        [`Model`]: AuditKind::Model
        [`Location`]: Modality::Location
      oneOf:
        - description: A pattern or dictionary recognizer matched here.
          type: object
          properties:
            kind:
              type: string
              const: pattern
            location:
              description: Where the recognizer matched.
              allOf:
                - $ref: '#/components/schemas/TextLocation'
            pattern:
              description: Pattern detail.
              allOf:
                - $ref: '#/components/schemas/PatternEvent'
          required:
            - kind
            - location
            - pattern
        - description: A model / NER recognizer matched here.
          type: object
          properties:
            kind:
              type: string
              const: model
            location:
              description: Where the recognizer matched.
              allOf:
                - $ref: '#/components/schemas/TextLocation'
            model:
              description: Model detail.
              allOf:
                - $ref: '#/components/schemas/ModelEvent'
          required:
            - kind
            - location
            - model
        - description: Several detections were fused into one entity.
          type: object
          properties:
            kind:
              type: string
              const: deduplication
            strategy:
              description: Name of the fusion strategy that combined them.
              type: string
          required:
            - kind
            - strategy
        - description: |-
            A competing detection of a different label over the same span was
            resolved against this (winning) entity.
          type: object
          properties:
            competing_confidence:
              description: The loser's confidence at resolution time.
              allOf:
                - $ref: '#/components/schemas/Confidence'
            competing_label:
              description: The label of the detection that lost arbitration.
              allOf:
                - $ref: '#/components/schemas/LabelRef'
            kind:
              type: string
              const: conflict
            resolved_by:
              description: Name of the conflict policy that chose the winner.
              type: string
          required:
            - kind
            - competing_label
            - competing_confidence
            - resolved_by
        - description: >-
            A competing detection of a different label over the same span was
            left

            *unresolved*: both entities survive, flagged for a human to settle.

            Recorded on each entity of the contested pair, naming the other.
          type: object
          properties:
            competing_confidence:
              description: The competing detection's confidence.
              allOf:
                - $ref: '#/components/schemas/Confidence'
            competing_label:
              description: The label of the competing detection.
              allOf:
                - $ref: '#/components/schemas/LabelRef'
            flagged_by:
              description: Name of the policy that flagged the contest.
              type: string
            kind:
              type: string
              const: contested
          required:
            - kind
            - competing_label
            - competing_confidence
            - flagged_by
        - description: The entity's confidence was rescaled by a per-recognizer factor.
          type: object
          properties:
            factor:
              description: Multiplier applied.
              type: number
              format: double
            kind:
              type: string
              const: calibration
          required:
            - kind
            - factor
        - description: A context keyword near the entity lifted its confidence.
          type: object
          properties:
            hint:
              $ref: '#/components/schemas/TextHint'
              description: |-
                The located [`Hint`] the keyword fired from, when the match came
                from an out-of-band hint (a column header, a key) rather than
                the in-text word window. `None` for an in-text-window match.

                [`Hint`]: crate::modality::Hint
            keyword:
              description: Keyword that fired the boost.
              type: string
            kind:
              type: string
              const: refinement
            location:
              $ref: '#/components/schemas/TextLocation'
              description: >-
                Where the boosting keyword sits in the medium. For a hint match

                this mirrors the hint's own location; for an in-text-window
                match

                it is the keyword resolved through the modality's [`locate`] (a

                pixel box for image, a time span for audio, the byte range for

                text/tabular). `None` when the keyword's stream range could not
                be

                placed, symmetric with a match the recognizer itself drops.


                [`locate`]: crate::modality::TextRecognizable::locate
          required:
            - kind
            - keyword
        - description: An operator hid the entity.
          type: object
          properties:
            attribution:
              $ref: '#/components/schemas/Attribution'
              description: >-
                The author-supplied policy rationale, when the operator carried
                an

                [`Attribution`]; `None` otherwise.
            key_id:
              description: Identifier of the key needed to reverse it, if reversible.
              type: string
            kind:
              type: string
              const: redaction
            leak_profile:
              description: How much the output leaks about the original.
              allOf:
                - $ref: '#/components/schemas/LeakProfile'
            matched_by:
              description: |-
                Which selection rule chose this operator: the automatic "why"
                (matched a label, a tag, a predicate, or the fallback).
              allOf:
                - $ref: '#/components/schemas/RuleMatch'
            operator:
              description: Which operator (name + version) ran.
              allOf:
                - $ref: '#/components/schemas/OperatorId'
            span_hash:
              $ref: '#/components/schemas/AuditHash'
              description: >-
                BLAKE3 digest of the original text the operator hid, when the

                redaction layer recorded it. Proves *what* was redacted without

                storing the plaintext; `None` when the operator did not capture
                it.
            span_length:
              description: >-
                Byte length of the original text the operator hid, paired with

                [`span_hash`](Self::Redaction::span_hash). `None` when not
                captured.
              type: integer
              format: uint32
              minimum: 0
          required:
            - kind
            - operator
            - leak_profile
            - matched_by
    Waveform:
      description: Shape of a synthesized tone.
      oneOf:
        - description: |-
            Pure sine. The broadcast censor-beep convention: audible but smooth,
            with no harmonics to alias on resampling.
          type: string
          const: sine
        - description: Square wave. Harsher and richer in harmonics — the "retro" bleep.
          type: string
          const: square
    Color:
      description: |-
        Color as 8-bit RGB.

        Used by visual redaction (a solid-fill block over an image region) and
        any other rendering instruction that needs a color.
      type: object
      properties:
        b:
          description: Blue channel.
          type: integer
          format: uint8
          maximum: 255
          minimum: 0
        g:
          description: Green channel.
          type: integer
          format: uint8
          maximum: 255
          minimum: 0
        r:
          description: Red channel.
          type: integer
          format: uint8
          maximum: 255
          minimum: 0
      required:
        - r
        - g
        - b
    Sha2Algorithm:
      description: |-
        Which SHA-2 variant a hashing operator uses.

        Shared by [`Sha2Hash`] (unkeyed digest) and [`HmacHash`] (keyed HMAC):
        both pick the same underlying width, so the choice lives in one enum
        rather than one per operator.

        [`Sha2Hash`]: super::Sha2Hash
        [`HmacHash`]: super::HmacHash
      oneOf:
        - description: SHA-256 — 32-byte digest, 64-char hex.
          type: string
          const: sha256
        - description: SHA-512 — 64-byte digest, 128-char hex.
          type: string
          const: sha512
    ClampBucket:
      description: |-
        Text a [`TextRedaction::Clamp`] emits for out-of-range values.

        Three forms, deserialized untagged so callers can pick the
        terser one for the case at hand:

        - **Plain string** (`"90 or older"`) — English-only shorthand.
        - **Localized map** (`{"en": "90 or older", "fr": "90 ou plus"}`)
          — one entry per language the deployment ships; missing
          locales fall back to English at render time.
        - **Format template** (`{"format": "{n} or older"}`) — the
          engine substitutes `{n}` for the threshold, so a ceiling of
          `90` renders `"90 or older"` without the caller repeating the
          number. Same rendering in every language.

        Round-trips through serde as whichever form the caller wrote.
      anyOf:
        - description: Plain English-only string.
          type: string
        - description: |-
            Format template — the engine substitutes `{n}` for the
            threshold. Same rendering in every language.
          type: object
          properties:
            format:
              description: |-
                The template string. `{n}` is substituted; other text
                is literal.
              type: string
          required:
            - format
        - description: Localized map, keyed by BCP-47 language tag.
          type: object
          additionalProperties:
            type: string
    TerminalFallback:
      description: |-
        Fallback operator that runs when a declinable primary
        ([`TextRedaction::Clamp`], [`TextRedaction::GeneralizeDate`])
        doesn't apply to the entity value.

        The four operators that always apply and produce a deterministic
        output without needing engine-side infrastructure (no key
        provider, no vault). Enough to satisfy every regulatory
        pattern I know: `Clamp/GeneralizeDate → Erase` (the safe
        default), `→ Replace { template }` (an explicit placeholder),
        or `→ Mask` / `→ Keep` on the rare occasion those fit.

        Absent from the primary's spec, elide's baked-in default is
        [`Erase`] — a bare [`TextRedaction::Clamp`] without a `fallback`
        erases values that aren't numeric.

        [`Erase`]: TerminalFallback::Erase
      oneOf:
        - description: See [`TextRedaction::Erase`].
          type: object
          properties:
            kind:
              type: string
              const: erase
          required:
            - kind
        - description: See [`TextRedaction::Keep`].
          type: object
          properties:
            kind:
              type: string
              const: keep
          required:
            - kind
        - description: See [`TextRedaction::Replace`].
          type: object
          properties:
            kind:
              type: string
              const: replace
            template:
              description: Template string. Default `[{label}]`.
              type: string
              default: '[{label}]'
          required:
            - kind
        - description: See [`TextRedaction::Mask`].
          type: object
          properties:
            keep_prefix:
              description: Characters to leave unmasked at the start of the value.
              type: integer
              format: uint
              minimum: 0
            keep_suffix:
              description: Characters to leave unmasked at the end of the value.
              type: integer
              format: uint
              minimum: 0
            kind:
              type: string
              const: mask
            mask_char:
              description: The character that replaces masked positions.
              type: string
              default: '*'
              maxLength: 1
              minLength: 1
          required:
            - kind
    DateGranularity:
      description: |-
        The coarseness a [`GeneralizeDate`] reduces a date/timestamp to.

        Every rendering is an ISO-8601 form, so the output is locale-independent
        by construction — no localized month names or week markers to configure.
      oneOf:
        - description: |-
            Year only: `1987-03-14` → `1987`. The HIPAA Safe Harbor default —
            §164.514(b)(2)(i)(C) keeps year but drops finer date elements.
          type: string
          const: year
        - description: 'Year and month: `1987-03-14` → `1987-03`.'
          type: string
          const: year_month
        - description: |-
            Date down to the hour: `1987-03-14T09:32:15` → `1987-03-14T09`.
            A value with no time-of-day can't reduce to an hour and is declined.
          type: string
          const: hour
    DateStyle:
      description: |-
        Which written date convention a [`GeneralizeDate`] accepts on *input*.

        This governs only how the entity value is *parsed*; the output mirrors
        each value's own convention (see [`GeneralizeDate::render`]). The choice
        is explicit, never inferred from the entity's language: `03/04/1987` is
        a real date under both conventions (March 4 vs. April 3), so a wrong
        guess would silently emit a plausible-but-wrong month. The policy
        author, who knows the corpus's convention, sets it.
      oneOf:
        - description: |-
            ISO-8601 only: `1987-03-14`, `1987-03-14T09:32:15`. The unambiguous
            default.
          type: string
          const: iso
        - description: >-
            US month-first slashes: `MM/DD/YYYY` (`03/14/1987`), with an
            optional

            space-separated time (`03/14/1987 09:32:15`). ISO input is still

            accepted too, so a mixed corpus degrades gracefully.
          type: string
          const: us
    TabularAuditKind:
      description: |-
        Kind of an [`AuditEvent`], carrying its event-specific detail and the
        rationale for why it happened.

        `#[non_exhaustive]`: new event kinds (verification, annotation, …)
        can be added compatibly. The recognition kinds ([`Pattern`],
        [`Model`]) carry the matched [`Location`]; the rest carry their own
        data.

        [`Pattern`]: AuditKind::Pattern
        [`Model`]: AuditKind::Model
        [`Location`]: Modality::Location
      oneOf:
        - description: A pattern or dictionary recognizer matched here.
          type: object
          properties:
            kind:
              type: string
              const: pattern
            location:
              description: Where the recognizer matched.
              allOf:
                - $ref: '#/components/schemas/TabularLocation'
            pattern:
              description: Pattern detail.
              allOf:
                - $ref: '#/components/schemas/PatternEvent'
          required:
            - kind
            - location
            - pattern
        - description: A model / NER recognizer matched here.
          type: object
          properties:
            kind:
              type: string
              const: model
            location:
              description: Where the recognizer matched.
              allOf:
                - $ref: '#/components/schemas/TabularLocation'
            model:
              description: Model detail.
              allOf:
                - $ref: '#/components/schemas/ModelEvent'
          required:
            - kind
            - location
            - model
        - description: Several detections were fused into one entity.
          type: object
          properties:
            kind:
              type: string
              const: deduplication
            strategy:
              description: Name of the fusion strategy that combined them.
              type: string
          required:
            - kind
            - strategy
        - description: |-
            A competing detection of a different label over the same span was
            resolved against this (winning) entity.
          type: object
          properties:
            competing_confidence:
              description: The loser's confidence at resolution time.
              allOf:
                - $ref: '#/components/schemas/Confidence'
            competing_label:
              description: The label of the detection that lost arbitration.
              allOf:
                - $ref: '#/components/schemas/LabelRef'
            kind:
              type: string
              const: conflict
            resolved_by:
              description: Name of the conflict policy that chose the winner.
              type: string
          required:
            - kind
            - competing_label
            - competing_confidence
            - resolved_by
        - description: >-
            A competing detection of a different label over the same span was
            left

            *unresolved*: both entities survive, flagged for a human to settle.

            Recorded on each entity of the contested pair, naming the other.
          type: object
          properties:
            competing_confidence:
              description: The competing detection's confidence.
              allOf:
                - $ref: '#/components/schemas/Confidence'
            competing_label:
              description: The label of the competing detection.
              allOf:
                - $ref: '#/components/schemas/LabelRef'
            flagged_by:
              description: Name of the policy that flagged the contest.
              type: string
            kind:
              type: string
              const: contested
          required:
            - kind
            - competing_label
            - competing_confidence
            - flagged_by
        - description: The entity's confidence was rescaled by a per-recognizer factor.
          type: object
          properties:
            factor:
              description: Multiplier applied.
              type: number
              format: double
            kind:
              type: string
              const: calibration
          required:
            - kind
            - factor
        - description: A context keyword near the entity lifted its confidence.
          type: object
          properties:
            hint:
              $ref: '#/components/schemas/TabularHint'
              description: |-
                The located [`Hint`] the keyword fired from, when the match came
                from an out-of-band hint (a column header, a key) rather than
                the in-text word window. `None` for an in-text-window match.

                [`Hint`]: crate::modality::Hint
            keyword:
              description: Keyword that fired the boost.
              type: string
            kind:
              type: string
              const: refinement
            location:
              $ref: '#/components/schemas/TabularLocation'
              description: >-
                Where the boosting keyword sits in the medium. For a hint match

                this mirrors the hint's own location; for an in-text-window
                match

                it is the keyword resolved through the modality's [`locate`] (a

                pixel box for image, a time span for audio, the byte range for

                text/tabular). `None` when the keyword's stream range could not
                be

                placed, symmetric with a match the recognizer itself drops.


                [`locate`]: crate::modality::TextRecognizable::locate
          required:
            - kind
            - keyword
        - description: An operator hid the entity.
          type: object
          properties:
            attribution:
              $ref: '#/components/schemas/Attribution'
              description: >-
                The author-supplied policy rationale, when the operator carried
                an

                [`Attribution`]; `None` otherwise.
            key_id:
              description: Identifier of the key needed to reverse it, if reversible.
              type: string
            kind:
              type: string
              const: redaction
            leak_profile:
              description: How much the output leaks about the original.
              allOf:
                - $ref: '#/components/schemas/LeakProfile'
            matched_by:
              description: |-
                Which selection rule chose this operator: the automatic "why"
                (matched a label, a tag, a predicate, or the fallback).
              allOf:
                - $ref: '#/components/schemas/RuleMatch'
            operator:
              description: Which operator (name + version) ran.
              allOf:
                - $ref: '#/components/schemas/OperatorId'
            span_hash:
              $ref: '#/components/schemas/AuditHash'
              description: >-
                BLAKE3 digest of the original text the operator hid, when the

                redaction layer recorded it. Proves *what* was redacted without

                storing the plaintext; `None` when the operator did not capture
                it.
            span_length:
              description: >-
                Byte length of the original text the operator hid, paired with

                [`span_hash`](Self::Redaction::span_hash). `None` when not
                captured.
              type: integer
              format: uint32
              minimum: 0
          required:
            - kind
            - operator
            - leak_profile
            - matched_by
    ImageAuditKind:
      description: |-
        Kind of an [`AuditEvent`], carrying its event-specific detail and the
        rationale for why it happened.

        `#[non_exhaustive]`: new event kinds (verification, annotation, …)
        can be added compatibly. The recognition kinds ([`Pattern`],
        [`Model`]) carry the matched [`Location`]; the rest carry their own
        data.

        [`Pattern`]: AuditKind::Pattern
        [`Model`]: AuditKind::Model
        [`Location`]: Modality::Location
      oneOf:
        - description: A pattern or dictionary recognizer matched here.
          type: object
          properties:
            kind:
              type: string
              const: pattern
            location:
              description: Where the recognizer matched.
              allOf:
                - $ref: '#/components/schemas/ImageLocation'
            pattern:
              description: Pattern detail.
              allOf:
                - $ref: '#/components/schemas/PatternEvent'
          required:
            - kind
            - location
            - pattern
        - description: A model / NER recognizer matched here.
          type: object
          properties:
            kind:
              type: string
              const: model
            location:
              description: Where the recognizer matched.
              allOf:
                - $ref: '#/components/schemas/ImageLocation'
            model:
              description: Model detail.
              allOf:
                - $ref: '#/components/schemas/ModelEvent'
          required:
            - kind
            - location
            - model
        - description: Several detections were fused into one entity.
          type: object
          properties:
            kind:
              type: string
              const: deduplication
            strategy:
              description: Name of the fusion strategy that combined them.
              type: string
          required:
            - kind
            - strategy
        - description: |-
            A competing detection of a different label over the same span was
            resolved against this (winning) entity.
          type: object
          properties:
            competing_confidence:
              description: The loser's confidence at resolution time.
              allOf:
                - $ref: '#/components/schemas/Confidence'
            competing_label:
              description: The label of the detection that lost arbitration.
              allOf:
                - $ref: '#/components/schemas/LabelRef'
            kind:
              type: string
              const: conflict
            resolved_by:
              description: Name of the conflict policy that chose the winner.
              type: string
          required:
            - kind
            - competing_label
            - competing_confidence
            - resolved_by
        - description: >-
            A competing detection of a different label over the same span was
            left

            *unresolved*: both entities survive, flagged for a human to settle.

            Recorded on each entity of the contested pair, naming the other.
          type: object
          properties:
            competing_confidence:
              description: The competing detection's confidence.
              allOf:
                - $ref: '#/components/schemas/Confidence'
            competing_label:
              description: The label of the competing detection.
              allOf:
                - $ref: '#/components/schemas/LabelRef'
            flagged_by:
              description: Name of the policy that flagged the contest.
              type: string
            kind:
              type: string
              const: contested
          required:
            - kind
            - competing_label
            - competing_confidence
            - flagged_by
        - description: The entity's confidence was rescaled by a per-recognizer factor.
          type: object
          properties:
            factor:
              description: Multiplier applied.
              type: number
              format: double
            kind:
              type: string
              const: calibration
          required:
            - kind
            - factor
        - description: A context keyword near the entity lifted its confidence.
          type: object
          properties:
            hint:
              $ref: '#/components/schemas/ImageHint'
              description: |-
                The located [`Hint`] the keyword fired from, when the match came
                from an out-of-band hint (a column header, a key) rather than
                the in-text word window. `None` for an in-text-window match.

                [`Hint`]: crate::modality::Hint
            keyword:
              description: Keyword that fired the boost.
              type: string
            kind:
              type: string
              const: refinement
            location:
              $ref: '#/components/schemas/ImageLocation'
              description: >-
                Where the boosting keyword sits in the medium. For a hint match

                this mirrors the hint's own location; for an in-text-window
                match

                it is the keyword resolved through the modality's [`locate`] (a

                pixel box for image, a time span for audio, the byte range for

                text/tabular). `None` when the keyword's stream range could not
                be

                placed, symmetric with a match the recognizer itself drops.


                [`locate`]: crate::modality::TextRecognizable::locate
          required:
            - kind
            - keyword
        - description: An operator hid the entity.
          type: object
          properties:
            attribution:
              $ref: '#/components/schemas/Attribution'
              description: >-
                The author-supplied policy rationale, when the operator carried
                an

                [`Attribution`]; `None` otherwise.
            key_id:
              description: Identifier of the key needed to reverse it, if reversible.
              type: string
            kind:
              type: string
              const: redaction
            leak_profile:
              description: How much the output leaks about the original.
              allOf:
                - $ref: '#/components/schemas/LeakProfile'
            matched_by:
              description: |-
                Which selection rule chose this operator: the automatic "why"
                (matched a label, a tag, a predicate, or the fallback).
              allOf:
                - $ref: '#/components/schemas/RuleMatch'
            operator:
              description: Which operator (name + version) ran.
              allOf:
                - $ref: '#/components/schemas/OperatorId'
            span_hash:
              $ref: '#/components/schemas/AuditHash'
              description: >-
                BLAKE3 digest of the original text the operator hid, when the

                redaction layer recorded it. Proves *what* was redacted without

                storing the plaintext; `None` when the operator did not capture
                it.
            span_length:
              description: >-
                Byte length of the original text the operator hid, paired with

                [`span_hash`](Self::Redaction::span_hash). `None` when not
                captured.
              type: integer
              format: uint32
              minimum: 0
          required:
            - kind
            - operator
            - leak_profile
            - matched_by
    Point:
      description: |-
        Point in a 2-D coordinate space.

        The coordinate basis is left to the consumer: pixel coordinates for a
        raster image, normalized `0.0..=1.0` coordinates for a
        resolution-independent region, or page units for a document. The
        model only requires the two scalars.
      type: object
      properties:
        x:
          description: Horizontal coordinate.
          type: number
          format: double
        'y':
          description: Vertical coordinate.
          type: number
          format: double
      required:
        - x
        - 'y'
    AudioAuditKind:
      description: |-
        Kind of an [`AuditEvent`], carrying its event-specific detail and the
        rationale for why it happened.

        `#[non_exhaustive]`: new event kinds (verification, annotation, …)
        can be added compatibly. The recognition kinds ([`Pattern`],
        [`Model`]) carry the matched [`Location`]; the rest carry their own
        data.

        [`Pattern`]: AuditKind::Pattern
        [`Model`]: AuditKind::Model
        [`Location`]: Modality::Location
      oneOf:
        - description: A pattern or dictionary recognizer matched here.
          type: object
          properties:
            kind:
              type: string
              const: pattern
            location:
              description: Where the recognizer matched.
              allOf:
                - $ref: '#/components/schemas/AudioLocation'
            pattern:
              description: Pattern detail.
              allOf:
                - $ref: '#/components/schemas/PatternEvent'
          required:
            - kind
            - location
            - pattern
        - description: A model / NER recognizer matched here.
          type: object
          properties:
            kind:
              type: string
              const: model
            location:
              description: Where the recognizer matched.
              allOf:
                - $ref: '#/components/schemas/AudioLocation'
            model:
              description: Model detail.
              allOf:
                - $ref: '#/components/schemas/ModelEvent'
          required:
            - kind
            - location
            - model
        - description: Several detections were fused into one entity.
          type: object
          properties:
            kind:
              type: string
              const: deduplication
            strategy:
              description: Name of the fusion strategy that combined them.
              type: string
          required:
            - kind
            - strategy
        - description: |-
            A competing detection of a different label over the same span was
            resolved against this (winning) entity.
          type: object
          properties:
            competing_confidence:
              description: The loser's confidence at resolution time.
              allOf:
                - $ref: '#/components/schemas/Confidence'
            competing_label:
              description: The label of the detection that lost arbitration.
              allOf:
                - $ref: '#/components/schemas/LabelRef'
            kind:
              type: string
              const: conflict
            resolved_by:
              description: Name of the conflict policy that chose the winner.
              type: string
          required:
            - kind
            - competing_label
            - competing_confidence
            - resolved_by
        - description: >-
            A competing detection of a different label over the same span was
            left

            *unresolved*: both entities survive, flagged for a human to settle.

            Recorded on each entity of the contested pair, naming the other.
          type: object
          properties:
            competing_confidence:
              description: The competing detection's confidence.
              allOf:
                - $ref: '#/components/schemas/Confidence'
            competing_label:
              description: The label of the competing detection.
              allOf:
                - $ref: '#/components/schemas/LabelRef'
            flagged_by:
              description: Name of the policy that flagged the contest.
              type: string
            kind:
              type: string
              const: contested
          required:
            - kind
            - competing_label
            - competing_confidence
            - flagged_by
        - description: The entity's confidence was rescaled by a per-recognizer factor.
          type: object
          properties:
            factor:
              description: Multiplier applied.
              type: number
              format: double
            kind:
              type: string
              const: calibration
          required:
            - kind
            - factor
        - description: A context keyword near the entity lifted its confidence.
          type: object
          properties:
            hint:
              $ref: '#/components/schemas/AudioHint'
              description: |-
                The located [`Hint`] the keyword fired from, when the match came
                from an out-of-band hint (a column header, a key) rather than
                the in-text word window. `None` for an in-text-window match.

                [`Hint`]: crate::modality::Hint
            keyword:
              description: Keyword that fired the boost.
              type: string
            kind:
              type: string
              const: refinement
            location:
              $ref: '#/components/schemas/AudioLocation'
              description: >-
                Where the boosting keyword sits in the medium. For a hint match

                this mirrors the hint's own location; for an in-text-window
                match

                it is the keyword resolved through the modality's [`locate`] (a

                pixel box for image, a time span for audio, the byte range for

                text/tabular). `None` when the keyword's stream range could not
                be

                placed, symmetric with a match the recognizer itself drops.


                [`locate`]: crate::modality::TextRecognizable::locate
          required:
            - kind
            - keyword
        - description: An operator hid the entity.
          type: object
          properties:
            attribution:
              $ref: '#/components/schemas/Attribution'
              description: >-
                The author-supplied policy rationale, when the operator carried
                an

                [`Attribution`]; `None` otherwise.
            key_id:
              description: Identifier of the key needed to reverse it, if reversible.
              type: string
            kind:
              type: string
              const: redaction
            leak_profile:
              description: How much the output leaks about the original.
              allOf:
                - $ref: '#/components/schemas/LeakProfile'
            matched_by:
              description: |-
                Which selection rule chose this operator: the automatic "why"
                (matched a label, a tag, a predicate, or the fallback).
              allOf:
                - $ref: '#/components/schemas/RuleMatch'
            operator:
              description: Which operator (name + version) ran.
              allOf:
                - $ref: '#/components/schemas/OperatorId'
            span_hash:
              $ref: '#/components/schemas/AuditHash'
              description: >-
                BLAKE3 digest of the original text the operator hid, when the

                redaction layer recorded it. Proves *what* was redacted without

                storing the plaintext; `None` when the operator did not capture
                it.
            span_length:
              description: >-
                Byte length of the original text the operator hid, paired with

                [`span_hash`](Self::Redaction::span_hash). `None` when not
                captured.
              type: integer
              format: uint32
              minimum: 0
          required:
            - kind
            - operator
            - leak_profile
            - matched_by
    PatternEvent:
      description: Detail of a pattern/dictionary recognition.
      type: object
      properties:
        contextual:
          description: |-
            Whether contextual analysis (keyword co-occurrence) adjusted the
            score for this match.
          type: boolean
        name:
          description: Name of the pattern that matched (e.g. `"ssn"`, `"email"`).
          type: string
        regex:
          description: Literal regex source that matched, when exposed.
          type: string
        validator:
          description: Name of the validator that confirmed the match (e.g. `"luhn"`).
          type: string
      required:
        - name
        - contextual
    ModelEvent:
      description: Detail of a model/NER recognition.
      type: object
      properties:
        contextual:
          description: Whether contextual analysis adjusted the score for this match.
          type: boolean
        name:
          description: Model name (e.g. `"spacy-en-core-web-lg"`, `"gpt-4"`).
          type: string
        version:
          description: Model version string, when known.
          type: string
      required:
        - name
        - contextual
    TextHint:
      description: |-
        Located, typed piece of context a recognizer may treat as in-context
        for a nearby value.

        Out-of-band by nature: a hint is *not* a sub-span of the value it
        informs — it lives elsewhere in the source (a table's column header, a
        JSON object key, a log field name). So `location` points at where the
        hint text actually sits, and `data` is the hint text itself. Carrying
        the location (rather than a bare string) lets a confidence boost record
        *which* hint lifted a score and *where* it came from — provenance a
        review consumer can resolve back to the document.

        Mirrors [`Entity`]'s `location` + `data` shape, so the same
        serialization and lifting patterns apply.

        [`Entity`]: crate::entity::Entity
      type: object
      properties:
        data:
          description: The hint text itself (a column header, a field name).
          allOf:
            - $ref: '#/components/schemas/TextData'
        location:
          description: Where the hint text sits in the source (the header cell, the key).
          allOf:
            - $ref: '#/components/schemas/TextLocation'
      required:
        - location
        - data
    Attribution:
      description: |-
        Author-supplied rationale for a redaction: a policy name and an optional
        description.

        Where the matched selection rule answers *which rule fired*, an
        `Attribution` answers *under what authority* — a compliance clause, an
        internal policy, a data-handling rule. A policy author attaches it to a
        selection rule (`Rule::because` in `elide-redaction`); the anonymizer
        records it on the entity's [`Redaction`] event so an audit can trace a
        change back to the policy that demanded it.

        The `name` is the author's label for that policy (`"gdpr-art-17"`,
        `"hipaa-safe-harbor"`, `"PII removal"`); an optional `description` adds
        human context. Any stable machine identity a policy layer needs (a rule
        UUID, a jurisdiction) is that layer's concern — it can encode it in the
        name or carry it separately.

        [`Redaction`]: crate::entity::audit::AuditKind::Redaction
      type: object
      properties:
        description:
          description: Human-readable description (e.g. `"right to erasure"`), when given.
          type: string
        name:
          description: The policy's name (e.g. `"gdpr-art-17"`, `"hipaa-safe-harbor"`).
          type: string
      required:
        - name
    LeakProfile:
      description: |-
        What a redacted output leaks about the original it replaced.

        Variants are ordered from most-leaky to least-leaky, so `Recoverable
        < Partial < Irrecoverable`. Surfaced through
        [`Operator::leak_profile`] for policy authoring and audit reporting.

        [`Operator::leak_profile`]: crate::operator::Operator::leak_profile
      oneOf:
        - description: |-
            The original value is recoverable from the output given the right
            metadata (encryption key, token vault, pseudonym map, or the
            candidate entity list against a hash).
          type: string
          const: recoverable
        - description: |-
            The original value is gone, but observable shape leaks: position,
            length, bounding box, cell coordinates, or a known silence on the
            timeline.
          type: string
          const: partial
        - description: No trace of the original value or its shape remains in the output.
          type: string
          const: irrecoverable
    RuleMatch:
      description: >-
        A serializable summary of *which selection rule* bound an operator to an

        entity — the automatic "why" behind a redaction.


        The anonymizer selects an operator by walking an ordered rule list and

        taking the first match. That decision is recorded on the [`Redaction`]

        event as a `RuleMatch` so an audit can see *why* this operator ran

        ("matched label EMAIL_ADDRESS", "carried tag financial", "the
        fallback").


        This is a summary, not the live rule: a predicate rule can't carry its

        closure into provenance, so [`Predicate`] records only that a predicate

        matched, not which one.


        [`Redaction`]: crate::entity::audit::AuditKind::Redaction

        [`Predicate`]: RuleMatch::Predicate
      oneOf:
        - description: Matched an exact label rule.
          type: object
          properties:
            label:
              $ref: '#/components/schemas/LabelRef'
          additionalProperties: false
          required:
            - label
        - description: 'Matched a tag rule: the entity''s label carries this tag.'
          type: object
          properties:
            tag:
              type: string
          additionalProperties: false
          required:
            - tag
        - description: Matched an arbitrary predicate rule (the closure is not captured).
          type: string
          const: predicate
        - description: Matched the catch-all fallback.
          type: string
          const: fallback
    OperatorId:
      description: |-
        Identifies a redaction operator, for the redaction audit a higher
        layer assembles.

        As with [`RecognizerId`], the version is part of the identity so the
        audit trail records which build of the operator ran. The version is
        opaque text; the core attaches no ordering semantics to it.

        [`RecognizerId`]: crate::recognition::RecognizerId
      type: object
      properties:
        name:
          description: Stable operator name (e.g. `"mask"`, `"aes-gcm-encrypt"`).
          type: string
        version:
          description: Operator's version at the time it was applied.
          type: string
      required:
        - name
        - version
    TabularHint:
      description: |-
        Located, typed piece of context a recognizer may treat as in-context
        for a nearby value.

        Out-of-band by nature: a hint is *not* a sub-span of the value it
        informs — it lives elsewhere in the source (a table's column header, a
        JSON object key, a log field name). So `location` points at where the
        hint text actually sits, and `data` is the hint text itself. Carrying
        the location (rather than a bare string) lets a confidence boost record
        *which* hint lifted a score and *where* it came from — provenance a
        review consumer can resolve back to the document.

        Mirrors [`Entity`]'s `location` + `data` shape, so the same
        serialization and lifting patterns apply.

        [`Entity`]: crate::entity::Entity
      type: object
      properties:
        data:
          description: The hint text itself (a column header, a field name).
          allOf:
            - $ref: '#/components/schemas/TextData'
        location:
          description: Where the hint text sits in the source (the header cell, the key).
          allOf:
            - $ref: '#/components/schemas/TabularLocation'
      required:
        - location
        - data
    ImageHint:
      description: |-
        Located, typed piece of context a recognizer may treat as in-context
        for a nearby value.

        Out-of-band by nature: a hint is *not* a sub-span of the value it
        informs — it lives elsewhere in the source (a table's column header, a
        JSON object key, a log field name). So `location` points at where the
        hint text actually sits, and `data` is the hint text itself. Carrying
        the location (rather than a bare string) lets a confidence boost record
        *which* hint lifted a score and *where* it came from — provenance a
        review consumer can resolve back to the document.

        Mirrors [`Entity`]'s `location` + `data` shape, so the same
        serialization and lifting patterns apply.

        [`Entity`]: crate::entity::Entity
      type: object
      properties:
        data:
          description: The hint text itself (a column header, a field name).
          allOf:
            - $ref: '#/components/schemas/ImageData'
        location:
          description: Where the hint text sits in the source (the header cell, the key).
          allOf:
            - $ref: '#/components/schemas/ImageLocation'
      required:
        - location
        - data
    AudioHint:
      description: |-
        Located, typed piece of context a recognizer may treat as in-context
        for a nearby value.

        Out-of-band by nature: a hint is *not* a sub-span of the value it
        informs — it lives elsewhere in the source (a table's column header, a
        JSON object key, a log field name). So `location` points at where the
        hint text actually sits, and `data` is the hint text itself. Carrying
        the location (rather than a bare string) lets a confidence boost record
        *which* hint lifted a score and *where* it came from — provenance a
        review consumer can resolve back to the document.

        Mirrors [`Entity`]'s `location` + `data` shape, so the same
        serialization and lifting patterns apply.

        [`Entity`]: crate::entity::Entity
      type: object
      properties:
        data:
          description: The hint text itself (a column header, a field name).
          allOf:
            - $ref: '#/components/schemas/AudioData'
        location:
          description: Where the hint text sits in the source (the header cell, the key).
          allOf:
            - $ref: '#/components/schemas/AudioLocation'
      required:
        - location
        - data
    TextData:
      description: |-
        Run of text.

        Either the payload a text recognizer inspects, or the value sliced out
        at an entity's location for an operator.

        Held as a [`HipStr`] so short values inline and longer ones share a
        refcounted buffer, making cheap clones when one payload is passed to
        several recognizers.
      type: string
    ImageData:
      description: |-
        Per-call payload a recognizer inspects for the [`Image`] modality.

        Carries the encoded bytes plus the pixel [`Dimensions`], which a
        recognizer that emits unit-square boxes needs to scale them into pixel
        coordinates. An optional filename aids diagnostics and encoding
        inference.

        [`Image`]: super::Image
      type: object
      properties:
        dimensions:
          description: Pixel dimensions of the encoded image.
          allOf:
            - $ref: '#/components/schemas/Dimensions'
        filename:
          description: Original filename, when known.
          type: string
      required:
        - dimensions
    AudioData:
      description: |-
        Per-call payload a recognizer inspects for the [`Audio`] modality.

        Carries the encoded audio bytes; an optional filename aids diagnostics
        and encoding inference (the container format a decoder should expect).
        The recognizable text — a timestamped transcript — is *not* held here;
        a speech-to-text [`Enricher`] stamps it onto the call's
        [`artifacts`], keeping
        `AudioData` the codec's payload alone.

        [`Audio`]: super::Audio
        [`Enricher`]: crate::recognition::Enricher
        [`artifacts`]: crate::recognition::RecognizerContext::artifacts
      type: object
      properties:
        filename:
          description: Original filename, when known.
          type: string
    Dimensions:
      description: |-
        Pixel dimensions of an image or any 2-D canvas.

        Converts between normalized `0.0..=1.0` coordinates (what vision
        models typically emit) and absolute pixel coordinates (what renderers
        consume). See
        [`UnitBoundingBox::denormalize`]
        for the conversion.

        [`UnitBoundingBox::denormalize`]: super::UnitBoundingBox::denormalize
      type: object
      properties:
        height:
          description: Height in pixels.
          type: integer
          format: uint32
          minimum: 0
        width:
          description: Width in pixels.
          type: integer
          format: uint32
          minimum: 0
      required:
        - width
        - height

````