# 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: Farm Versioning API
  version: 1.0.0
  description: 'The one clock of the farm data: write commits and their numbers, the watermark below which the data
    never changes again, and erasure requests. Dataset exports for `ai-model-platform` go through the gRPC service of
    this domain.'
servers:
- url: https://farm.moonitoring.com/versioning/v1
  description: Prod
- url: https://stage-farm.moonitoring.com/versioning/v1
  description: Stage, through IAP
security:
- bearer: []
tags:
- name: Watermark
  description: The readable clock
- name: Write commits
  description: One write, one number
- name: Erasure
  description: A farm that leaves
paths:
  /watermark:
    get:
      summary: Read the watermark
      operationId: getWatermark
      description: Any signed-in caller; a reader that wants a stable snapshot across several requests passes this
        number as `as_of_seq`.
      tags:
      - Watermark
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Watermark'
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: any
      x-moonitoring-capability: null
      x-moonitoring-requirements:
      - '61'
  /write-commits:
    get:
      summary: List write commits
      operationId: listWriteCommits
      description: An Organization sees the writes of its own runs, jobs and edits; staff with `farm.canonical_data.read_all`
        see all.
      tags:
      - Write commits
      parameters:
      - name: kind
        in: query
        required: false
        schema:
          type: string
          enum:
          - parse
          - sync_diff
          - resolution
          - selection
          - computation
          - identity
          - app_edit
          - file_removal
          - erasure
        description: Only this kind.
      - name: sync_run
        in: query
        required: false
        schema:
          type: string
          format: uuid
        description: Only writes of this run.
      - name: parse_job
        in: query
        required: false
        schema:
          type: string
          format: uuid
        description: Only writes of this job.
      - name: status
        in: query
        required: false
        schema:
          type: string
          enum:
          - pending
          - committed
          - void
        description: Only this status.
      - name: from_seq
        in: query
        required: false
        schema:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/ReadSequence
      - name: to_seq
        in: query
        required: false
        schema:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/ReadSequence
      - $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/WriteCommit'
                  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: any
      x-moonitoring-capability:
      - farm.animal_records.read
      - farm.canonical_data.read_all
      x-moonitoring-requirements:
      - '61'
      - '61.3'
  /write-commits/{seq}:
    get:
      summary: Read a write commit
      operationId: getWriteCommit
      tags:
      - Write commits
      parameters:
      - name: seq
        in: path
        required: true
        schema:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/WriteSequence
        description: The write number.
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WriteCommit'
        '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: any
      x-moonitoring-capability:
      - farm.animal_records.read
      - farm.canonical_data.read_all
      x-moonitoring-requirements:
      - '61'
  /organizations/{organization_id}/erasure-requests:
    get:
      summary: List a farm's erasure requests
      operationId: listErasureRequests
      description: 'A read, so it never asks for a sign-in at most five minutes old, although
        `farm.erasure_requests.request` is an admin capability (decided 2026-11-11).'
      tags:
      - Erasure
      parameters:
      - name: organization_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The Farm.
      - $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/ErasureRequest'
                  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: any
      x-moonitoring-capability:
      - farm.erasure_requests.request
      - farm.erasure_requests.manage
      x-moonitoring-requirements:
      - '63'
    post:
      summary: Request erasure
      operationId: createErasureRequest
      description: 'By the Organization''s owner. Scope pending legal confirmation. Publishes `erasure_request.created.v1`.
        `farm.erasure_requests.request` is an admin capability: a person''s sign-in must be at most five minutes
        old, otherwise 403 with the problem type reauthentication-required.'
      tags:
      - Erasure
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: organization_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The Farm.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ErasureRequestInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErasureRequest'
        '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: organization
      x-moonitoring-capability: farm.erasure_requests.request
      x-moonitoring-requirements:
      - '63'
      - '63.3'
  /erasure-requests:
    get:
      summary: List every erasure request
      operationId: listAllErasureRequests
      tags:
      - Erasure
      parameters:
      - name: pending
        in: query
        required: false
        schema:
          type: boolean
        description: Only requests not executed yet.
      - $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/ErasureRequest'
                  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: farm.erasure_requests.manage
      x-moonitoring-requirements:
      - '63'
  /erasure-requests/{request_id}/execute:
    post:
      summary: Execute an erasure
      operationId: executeErasureRequest
      description: One WriteCommit of kind erasure; raw files leave the bucket; kept datasets are rewritten. Publishes
        `erasure_request.executed.v1`.
      tags:
      - Erasure
      parameters:
      - name: request_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '202':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErasureRequest'
        '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: farm.erasure_requests.manage
      x-moonitoring-requirements:
      - '63.4'
      - '63.5'
      - '61.3'
components:
  schemas:
    WriteCommit:
      description: 'One saved change to versioned data, with its write number. The write number is the single clock
        of the model: reading at a number N sees every write up to N and none after it. Numbers come from a sequence,
        so writers never wait for each other; the watermark (the highest N below which nothing is still pending)
        says which N are safe to read.'
      type: object
      properties:
        seq:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/WriteSequence
          description: Key. Reserved in its own short transaction before the write starts, so the pending row is
            visible to everyone while the write is in progress.
        committed_at:
          type: string
          format: date-time
          description: Empty while pending or void.
        kind:
          type: string
          enum:
          - parse
          - sync_diff
          - resolution
          - selection
          - computation
          - identity
          - app_edit
          - file_removal
          - erasure
        parse_job:
          type: string
          format: uuid
          description: ID of the ParseJob.
        sync_run:
          type: string
          format: uuid
          description: ID of the SyncRun.
        rule_set:
          type: string
          format: uuid
          description: ID of the ReconciliationRuleSet.
        user:
          type: string
          format: uuid
          description: ID of the User. For edits made in our app (`farm.animal_records.edit_own`).
        status:
          type: string
          enum:
          - pending
          - committed
          - void
          default: pending
          description: '`committed`: set in the same transaction as the data it makes available. void: the write
            was abandoned, by a rollback or an expired lease; it carries no data and the watermark passes it.'
        lease_until:
          type: string
          format: date-time
          description: A pending write past its lease is set to void by the scheduler; long jobs renew the lease.
            A writer that finds its own write void must roll back, never commit.
        created_at:
          type: string
          format: date-time
      required:
      - seq
      - kind
      - status
      - lease_until
      - created_at
    ErasureRequest:
      description: A farm that leaves, or asks for its data to be removed. Execution anonymizes everything that
        leads back to the farm, while canonical values are kept under new random ids.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        farm:
          type: string
          format: uuid
          description: ID of the Organization that is a Farm.
        requested_at:
          type: string
          format: date-time
        executed_at:
          type: string
          format: date-time
        executed_in:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/WriteSequence
          description: ID of the WriteCommit.
        created_at:
          type: string
          format: date-time
      required:
      - id
      - farm
      - requested_at
      - created_at
    Watermark:
      type: object
      description: 'The highest write number such that no write at or below it is pending: reads at or below it
        are stable forever.'
      properties:
        watermark_seq:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/ReadSequence
        committed_at:
          type: string
          format: date-time
          description: committed_at of the write at the watermark.
      required:
      - watermark_seq
    ErasureRequestInput:
      type: object
      description: 'Asks for a farm''s data to be removed. Execution anonymizes: everything that leads back to the
        farm is removed, canonical values stay under new random ids.'
      properties:
        reason:
          type: string
        requested_at:
          type: string
          format: date-time
          description: 'Default: now.'
  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.'
