# Proposed contract, version 1: endpoints, errors, paging, idempotency, security and the capability of every
# operation. Resource schemas were initialized from the data model (docs/06-data) and are kept aligned with it; input
# schemas (*Input, *Request) and views are specific to this contract. Status: proposal for review, not confirmed design.
# Conventions: docs/05-interfaces/choosing-an-interface.md. Vendor extensions: x-moonitoring-audience (who calls),
# x-moonitoring-capability (the capability checked), x-moonitoring-entitlement (the entitlement feature checked),
# x-moonitoring-requirements (the requirements of 1.requisiti-raffinati.txt the operation serves).
openapi: 3.1.0
info:
  title: AI Model Platform Datasets API
  version: 1.0.0
  description: 'Datasets for model work: a named selection of canonical data, built at a write number into immutable
    versions of Parquet files in the datasets bucket. Data scientists define and build them in the Console, request
    variants, and read versions from notebooks by manifest; nothing is downloaded or uploaded by hand.'
servers:
- url: https://ai-model-platform.moonitoring.com/datasets/v1
  description: Prod
- url: https://stage-ai-model-platform.moonitoring.com/datasets/v1
  description: Stage, through IAP
security:
- bearer: []
tags:
- name: Datasets
  description: Named selections
- name: Versions
  description: Immutable builds
- name: Files
  description: Parquet files by hash
paths:
  /datasets:
    get:
      summary: List datasets
      operationId: listDatasets
      tags:
      - Datasets
      parameters:
      - name: status
        in: query
        required: false
        schema:
          type: string
          enum:
          - draft
          - active
          - archived
        description: Only this status.
      - name: owner
        in: query
        required: false
        schema:
          type: string
          format: uuid
        description: Only this owner's.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/MlDataset'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.read
      x-moonitoring-requirements:
      - '71'
      - '1006.30'
    post:
      summary: Create a dataset
      operationId: createDataset
      tags:
      - Datasets
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MlDatasetInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MlDataset'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.manage
      x-moonitoring-requirements:
      - '71'
      - '71.6'
      - '1006.29'
  /datasets/{dataset_id}:
    get:
      summary: Read a dataset
      operationId: getDataset
      tags:
      - Datasets
      parameters:
      - name: dataset_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MlDataset'
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.read
      x-moonitoring-requirements:
      - '71'
    patch:
      summary: Update a dataset
      operationId: updateDataset
      description: Editing the selection never changes an existing version.
      tags:
      - Datasets
      parameters:
      - name: dataset_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MlDatasetInput'
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MlDataset'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.manage
      x-moonitoring-requirements:
      - '71'
      - '71.11'
      - '1006.29'
  /datasets/{dataset_id}/archive:
    post:
      summary: Archive a dataset
      operationId: archiveDataset
      tags:
      - Datasets
      parameters:
      - name: dataset_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MlDataset'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.manage
      x-moonitoring-requirements:
      - '71.9'
      - '1006.29'
  /datasets/{dataset_id}/versions:
    get:
      summary: List a dataset's versions
      operationId: listDatasetVersions
      tags:
      - Versions
      parameters:
      - name: dataset_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: status
        in: query
        required: false
        schema:
          type: string
          enum:
          - building
          - ready
          - failed
          - deleted
        description: Only this status.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/MlDatasetVersion'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.read
      x-moonitoring-requirements:
      - '72'
      - '1006.30'
    post:
      summary: Build a version
      operationId: buildDatasetVersion
      description: Accepted; the version is `building` until the export from `farm` finishes. Publishes `dataset_version.ready.v1`
        or `dataset_version.failed.v1`.
      tags:
      - Versions
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: dataset_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuildRequest'
      responses:
        '202':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MlDatasetVersion'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.manage
      x-moonitoring-requirements:
      - '72'
      - '72.4'
      - '72.10'
      - '72.11'
      - '61'
      - '1006.29'
  /versions/{version_id}:
    get:
      summary: Read a version
      operationId: getDatasetVersion
      tags:
      - Versions
      parameters:
      - name: version_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MlDatasetVersion'
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.read
      x-moonitoring-requirements:
      - '72'
    delete:
      summary: Delete a version
      operationId: deleteDatasetVersion
      description: Refused while a ModelRun of a model in production references it. Removes the files no other version
        shares.
      tags:
      - Versions
      parameters:
      - name: version_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '204':
          description: Done.
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.manage
      x-moonitoring-requirements:
      - '72.18'
      - '72.19'
      - '73'
      - '1006.29'
  /versions/{version_id}/variants:
    post:
      summary: Build a variant
      operationId: buildDatasetVariant
      tags:
      - Versions
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: version_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VariantRequest'
      responses:
        '202':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MlDatasetVersion'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.manage
      x-moonitoring-requirements:
      - '72.20'
      - '1006.29'
  /versions/{version_id}/manifest-url:
    post:
      summary: Read the manifest location
      operationId: getDatasetManifest
      description: Identified versions are readable only with `farm.canonical_data.read_all`.
      tags:
      - Versions
      parameters:
      - name: version_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ManifestLocation'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.read
      x-moonitoring-requirements:
      - '72.10'
      - '72.11'
      - '1006.30'
  /versions/{version_id}/files:
    get:
      summary: List a version's files
      operationId: listDatasetFiles
      tags:
      - Files
      parameters:
      - name: version_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: table
        in: query
        required: false
        schema:
          type: string
          enum:
          - animals
          - observations
          - events
          - resolved_events
          - periods
          - animal_links
        description: Only this table.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/MlDatasetFile'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: ai-model-platform.datasets.read
      x-moonitoring-requirements:
      - '73'
      - '1006.30'
components:
  schemas:
    MlDataset:
      description: A named, reusable selection of canonical data for model work, created and managed by data scientists
        in the Console. It says what to extract (tables, time ranges, animal types, breeds, origins, nations, Organizations),
        with which export code and at which anonymization level; it holds no data itself. Every build produces an
        immutable MlDatasetVersion, so a definition can be rebuilt as the data grows while every past build stays
        exactly as it was.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        slug:
          type: string
          description: Unique. e.g. mastitis-holstein-2024-2025.
        name:
          type: string
        description:
          type: string
        owner:
          type: string
          format: uuid
          description: ID of the MoonitoringUser.
        selection:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/MlDatasetSelection
          description: What the build extracts; copied into every version, so editing it never changes an existing
            version.
        feature_code_version:
          type: string
          description: 'Version (commit or hash) of the export code: tables, columns, time grid, pseudonymization.
            Same meaning as 62.4.'
        anonymization:
          type: string
          enum:
          - identified
          - pseudonymized
          - anonymized
          default: pseudonymized
          description: '`identified`: farm and animal ids as they are; only for scoring and pricing in production,
            never readable from ml-lab. `pseudonymized`: ids replaced through a keyed hash (key in Secret Manager,
            one per environment); still personal data. `anonymized`: ids replaced by random values with no key,
            locations and dates coarsened; what may leave the company.'
        status:
          type: string
          enum:
          - draft
          - active
          - archived
          default: draft
          description: '`archived`: no new build; existing versions stay readable until their `keep_until`.'
        retention_days:
          type: integer
          description: 'Sets `keep_until` of a version when a newer one becomes ready. Empty: versions are kept
            until deleted by hand.'
        system_version:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/SystemVersion
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
      - id
      - slug
      - name
      - description
      - owner
      - selection
      - feature_code_version
      - anonymization
      - status
      - system_version
      - created_at
      - updated_at
    MlDatasetVersion:
      description: 'One build of a dataset: the selected data as it was at a write number, written to Parquet files
        in the datasets bucket and described by a manifest. A version is never changed after it is ready; a notebook
        or a pipeline opens it by its manifest path and gets the same rows forever, which is what makes a ModelRun
        reproducible. Deleting a version removes only the files no other version shares. Immutable.'
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        dataset:
          type: string
          format: uuid
          description: ID of the MlDataset.
        number:
          type: integer
          description: 1, 2, 3 within the dataset.
        data_seq:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/ReadSequence
          description: The read cutoff at or below the watermark; zero represents the initial state before any writes.
        rule_set:
          type: string
          format: uuid
          description: ID of the ReconciliationRuleSet.
        knowledge_clock:
          type: string
          enum:
          - platform
          - source
          description: As 62.12.
        selection:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/MlDatasetSelection
        feature_code_version:
          type: string
        anonymization:
          type: string
          enum:
          - identified
          - pseudonymized
          - anonymized
        manifest_path:
          type: string
          description: 'Gs://&lt;datasets bucket>/&lt;dataset slug>/v&lt;number>/manifest.json: schema per table,
            the list of files with their hashes and partitions, row counts, the selection, `data_seq`, `rule_set`,
            `feature_code_version`. What a notebook opens.'
        manifest_hash:
          type: string
          description: 'SHA-256 of the manifest: the identity of the version and the `dataset_hash` (`ModelRun.dataset_hash`)
            of every run that reads it.'
        files:
          type: array
          items:
            type: string
            format: uuid
          description: ID of the MlDatasetFile.
        row_count:
          type: integer
        size_bytes:
          type: integer
        status:
          type: string
          enum:
          - building
          - ready
          - failed
          - deleted
          default: building
        built_by:
          type: string
          format: uuid
          description: ID of the MoonitoringUser.
        built_at:
          type: string
          format: date-time
        keep_until:
          type: string
          format: date-time
          description: Set from the dataset's `retention_days`; never set while a ModelRun of a model in production
            references the version.
        deleted_at:
          type: string
          format: date-time
        parent_version:
          type: string
          format: uuid
          description: 'ID of the MlDatasetVersion. Set when this version is a variant derived from another one
            (same `data_seq`, narrower selection): it is built from the parent''s files, never from the database,
            and shares every file the narrower selection keeps whole.'
        created_at:
          type: string
          format: date-time
      required:
      - id
      - dataset
      - number
      - data_seq
      - rule_set
      - knowledge_clock
      - selection
      - feature_code_version
      - anonymization
      - manifest_path
      - manifest_hash
      - row_count
      - size_bytes
      - status
      - built_by
      - created_at
    MlDatasetFile:
      description: One Parquet file of one partition of one table, named by the hash of its content. Because the
        name is the content, two versions, or two datasets, whose builds yield the same partition point at the same
        object and store it once; a new version of a growing dataset adds only the partitions that changed. A file
        is removed when no version references it. Immutable.
      type: object
      properties:
        hash:
          type: string
          description: Key. SHA-256 of the file content; also the object name in the bucket.
        path:
          type: string
          description: Gs://&lt;datasets bucket>/files/&lt;hash>.parquet.
        table:
          type: string
          enum:
          - animals
          - observations
          - events
          - resolved_events
          - periods
          - animal_links
        partition:
          type: string
          description: 'The partition keys of this file, e.g. {"month": "2025-03", "`animal_type`": "bovine"}. Never
            a farm or animal id.'
        anonymization:
          type: string
          enum:
          - identified
          - pseudonymized
          - anonymized
          description: Files of different levels never share content; a rotated pseudonymization key makes new files.
        row_count:
          type: integer
        size_bytes:
          type: integer
        created_at:
          type: string
          format: date-time
      required:
      - hash
      - path
      - table
      - partition
      - anonymization
      - row_count
      - size_bytes
      - created_at
    MlDatasetInput:
      type: object
      description: Defines a dataset. The owner is the caller; a new dataset is a draft until its first build.
      properties:
        slug:
          type: string
          description: Unique. e.g. mastitis-holstein-2024-2025.
        name:
          type: string
        description:
          type: string
        selection:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/MlDatasetSelection
          description: What the build extracts; copied into every version, so editing it never changes an existing
            version.
        feature_code_version:
          type: string
          description: 'Version (commit or hash) of the export code: tables, columns, time grid, pseudonymization.
            Same meaning as 62.4.'
        anonymization:
          type: string
          enum:
          - identified
          - pseudonymized
          - anonymized
          default: pseudonymized
          description: '`identified`: farm and animal ids as they are; only for scoring and pricing in production,
            never readable from ml-lab. `pseudonymized`: ids replaced through a keyed hash (key in Secret Manager,
            one per environment); still personal data. `anonymized`: ids replaced by random values with no key,
            locations and dates coarsened; what may leave the company.'
        retention_days:
          type: integer
          description: 'Sets `keep_until` of a version when a newer one becomes ready. Empty: versions are kept
            until deleted by hand.'
      required:
      - slug
      - name
      - description
      - selection
      - feature_code_version
      - anonymization
      additionalProperties: false
    BuildRequest:
      type: object
      description: 'Builds a version: reads the selection at `data_seq` (default the watermark of `farm`) with the
        dataset''s feature code version, writes the files and the manifest. A build identical to an existing version
        returns that version. Reuse compares the resolved data sequence, selection, feature code version,
        rule set, anonymization and knowledge_clock; platform and source knowledge clocks must not reuse
        each other''s version merely because the other inputs match. The manifest records the clock.'
      properties:
        data_seq:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/ReadSequence
          description: 'Read cutoff; zero selects the initial state before any writes. Omitted: the current watermark.'
        rule_set:
          type: string
          format: uuid
          description: 'Default: the rule set in force at data_seq.'
        knowledge_clock:
          type: string
          enum:
          - platform
          - source
          description: Default platform.
    VariantRequest:
      type: object
      description: A narrower selection of an existing version, built from its files on the server at the same write
        number.
      properties:
        selection:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/MlDatasetSelection
        anonymization:
          type: string
          enum:
          - pseudonymized
          - anonymized
          description: Never wider than the parent's.
      required:
      - selection
    ManifestLocation:
      type: object
      description: Where the manifest is, with a short-lived read URL for a notebook outside the project.
      properties:
        manifest_path:
          type: string
        manifest_hash:
          type: string
        download:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/SignedUrl
      required:
      - manifest_path
      - manifest_hash
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'The short-lived token signed by `access`: an Organization user token, a staff token or a client
        token, as the operation''s audience says.'
