# Episodes_ListEpisodes

`GET /v1/accounts/{account}/datasets/{dataset}/episodes`

Lists the episodes of a dataset in recording order (for a mixture: its
pool, source by source). `parent` may be `accounts/a/datasets/-` to read
across every dataset of the account (ExploreLake's successor).

- Base URL: `https://junction-api.qualiastudios.dev`
- Authentication: an API key in the `X-API-Key` header

## Parameters

- `account` (path, string, required): The account id.
- `dataset` (path, string, required): The dataset id.
- `pageSize` (query, integer (int32)): At most this many episodes; 0 means 100, the maximum is 1000.
- `pageToken` (query, string): From a previous response's next_page_token.
- `filter` (query, string): AIP-160 filter. e.g. `state = UNREVIEWED AND open_issue_codes:"jerky"`,
  `note_codes:"graph_outcome"`, `methods:"umi"`, `version = "1.0"`,
  `metrics.duration_seconds < 20`,
  `viewed = false`, `linked_task_inherited = false`, `draft = true`
  (takes with a draft, Episode.draft).
- `orderBy` (query, string): "index" (default: recording order, source by source in a mixture),
  "record_time", "metrics.<field> desc", "open_issue_count desc".
- `view` (query, string (enum)): EPISODE_VIEW_ANALYSIS adds each episode's Episode.analysis, its
  channels' progress only: a channel's curves are GetEpisode's. It signs
  no posters (Episode.posters is empty): a reader of every take's profile
  shows few posters, and reads those with GetEpisode. One of: `EPISODE_VIEW_UNSPECIFIED`, `EPISODE_VIEW_BASIC`, `EPISODE_VIEW_ANALYSIS`.
- `version` (query, string): Read as this version froze it: a tag, `stable`, `v0` or a
  digest prefix; empty or `head` reads the episode as it is now. The list
  holds that version's episodes, each with the fields, trim and subtasks of
  the revision it pinned (task and tags as its snapshot froze them, also
  for an episode never edited); standing, decision, issues and markers are
  current. A version the dataset does not have is NOT_FOUND.

## Responses

- `200` OK: `application/json` `qualia.v1.ListEpisodesResponse`
- `default` Default error response: `application/json` `google.rpc.Status`

## Schemas

```yaml
qualia.v1.ListEpisodesResponse:
  type: object
  properties:
    episodes:
      type: array
      items:
        $ref: "#/components/schemas/qualia.v1.Episode"
      description: One page of episodes.
    nextPageToken:
      type: string
      description: Empty on the last page.
    totalSize:
      type: integer
      description: Episodes matching the filter, across every page.
      format: int32
  description: Response for Episodes.ListEpisodes.
qualia.v1.Episode:
  type: object
  properties:
    name:
      type: string
      description: accounts/{account}/datasets/{dataset}/episodes/{episode}
    upload:
      readOnly: true
      type: string
      description: |-
        accounts/{account}/datasets/{dataset}: the upload it was recorded in.
        The `upload` filter compares it with a dataset name, `=` and `!=`; a
        merged dataset's name matches the episodes of every upload it holds, as
        one comparison.
    index:
      readOnly: true
      type: integer
      description: Its position in the upload, from 0.
      format: int32
    position:
      readOnly: true
      type: integer
      description: |-
        Its place in the dataset it is read through, from 0: what it is numbered
        by there. In a merged dataset, across its uploads, in the order they
        were merged, each upload's episodes in their own order, so no two share
        a number; everywhere else it is `index`.
        Optional for older servers that do not yet report it; clients can
        distinguish an absent position from the valid value zero.
      format: int32
    parentEpisode:
      readOnly: true
      type: string
      description: The episode it was split from, when it is a child.
    childCount:
      readOnly: true
      type: integer
      description: Children it was split into.
      format: int32
    parentWindow:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_Trim"
      description: |-
        Where a split child sits in its parent, in seconds from the
        start of the parent's recording: what `parent_episode` traces it back
        to. It is the child's base window, the stretch the split gave it; a
        later trim of the child narrows the child, not this window.
        Unset for an episode that was not split from another.
    parentIndex:
      readOnly: true
      type: integer
      description: The `index` of the episode it was split from, when it is a split child.
      format: int32
    state:
      readOnly: true
      enum:
        - STATE_UNSPECIFIED
        - UNREVIEWED
        - KEPT
        - REJECTED
      type: string
      description: Where it stands in this scope.
      format: enum
    decision:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_Decision"
      description: The standing ruling in this scope; unset when nobody (and not validation) ruled.
    openIssueCount:
      readOnly: true
      type: integer
      description: Open blocking issues on it, in this scope.
      format: int32
    noteCount:
      readOnly: true
      type: integer
      description: Notes (non-blocking) on it, in this scope.
      format: int32
    openIssueCodes:
      readOnly: true
      type: array
      items:
        type: string
      description: Codes of the open issues, for rail chips without a second call.
    noteCodes:
      readOnly: true
      type: array
      items:
        type: string
      description: |-
        Codes of the open notes (issues that do not block a keep) that carry one: a check's findings, such as a graph check's, and ingest's
        non-blocking ones. A person's note has no code and is not listed.
    viewed:
      readOnly: true
      type: boolean
      description: |-
        Whether the caller has opened it. Per person: always false
        for an API key, which acts as itself, not as the person who made it.
    frameCount:
      readOnly: true
      type: string
      description: Frames in the recording.
    versionFrameCount:
      readOnly: true
      type: string
      description: |-
        Frames the read version holds: the trim window it froze, the rows its
        read plan and a download carry. Set when the read is of a version (the
        request's `version`, or the tag a branch reads); at head, frame_count
        and trim describe the episode.
    fps:
      readOnly: true
      type: number
      description: Frames per second of the data rows.
      format: double
    recordTime:
      readOnly: true
      type: string
      description: When it was recorded.
      format: date-time
    cameras:
      readOnly: true
      type: array
      items:
        type: string
      description: Camera keys it carries.
    posters:
      readOnly: true
      type: array
      items:
        $ref: "#/components/schemas/qualia.v1.Episode_Poster"
      description: First and last frame per camera.
    task:
      type: string
      description: Task label (editable).
    instruction:
      type: string
      description: Language instruction (editable).
    operator:
      readOnly: true
      type: string
      description: Operator label.
    rig:
      readOnly: true
      type: string
      description: Recording rig key, as the recording carries it (see Rig.key).
    sourceRobot:
      readOnly: true
      type: string
      description: "accounts/{account}/robots/{robot}: the fleet robot it was recorded on."
    method:
      type: string
      description: Legacy single-method projection retained for older clients.
    methods:
      type: array
      items:
        type: string
      description: |-
        Canonical collection-method tags (teleop, vr, umi, egocentric,
        policy-rollout, sim). Multiple tags may describe one episode.
    scene:
      type: string
      description: Scene label (editable).
    session:
      readOnly: true
      type: string
      description: Recorder session id.
    tags:
      type: array
      items:
        type: string
      description: Free tags (editable).
    outcome:
      enum:
        - OUTCOME_UNSPECIFIED
        - SUCCESS
        - PARTIAL
        - FAILURE
      type: string
      description: How the attempt went (editable; the operator's own mark by default).
      format: enum
    outcomeActor:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Actor"
      description: Who set the outcome.
    markers:
      readOnly: true
      type: array
      items:
        $ref: "#/components/schemas/qualia.v1.Episode_Marker"
      description: Recorder markers.
    trim:
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_Trim"
      description: The trim window; unset means untrimmed (editable).
    subtasks:
      type: array
      items:
        $ref: "#/components/schemas/qualia.v1.Episode_Subtask"
      description: Subtask spans (editable).
    metrics:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_Metrics"
      description: Health metrics and judgements.
    originalMetrics:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_Metrics"
      description: |-
        The take as recorded, before curation: its measurements
        (speed, jerk, smoothness, pauses, gripper events, corrections, alignment)
        over its whole recording, measured once; a split's piece has its take's.
        duration_seconds is the recording's length. Unset until measured; filter
        as `original.<field>`.
    curatedMetrics:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_Metrics"
      description: |-
        The episode as curated: the same measurements over the window it trains
        on (after its trim; a piece's own window), measured when the trim or
        split is applied, or else within minutes of the publish that made it.
        duration_seconds is after the trim. Unset until measured, and for a
        revision no upload holds now; filter as `curated.<field>`.
    revision:
      readOnly: true
      type: integer
      description: Content revision of the episode edit chain (trim, subtasks, tags, ...).
      format: int32
    etag:
      type: string
      description: Sent back on UpdateEpisodes; equals the revision.
    createTime:
      readOnly: true
      type: string
      description: When it was ingested.
      format: date-time
    updateTime:
      readOnly: true
      type: string
      description: When its content or standing last changed.
      format: date-time
    upstreamState:
      readOnly: true
      enum:
        - STATE_UNSPECIFIED
        - UNREVIEWED
        - KEPT
        - REJECTED
      type: string
      description: |-
        Read through a mixture: where it stands upstream (the least settled of
        its upload and any mixture in between). Unset in its upload's scope.
      format: enum
    analysis:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_Analysis"
      description: How the take moves; set only in the EPISODE_VIEW_ANALYSIS view.
    originalAnalysis:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_Analysis"
      description: |-
        How the take moves as recorded, before curation: the same numbers over
        its whole recording, measured once, with no channels; a split's piece
        has its take's. Where `analysis` follows a trim or a split, this stays,
        so the outliers tab sets the episodes as curated against the takes as
        recorded. Set only in the EPISODE_VIEW_ANALYSIS view, once measured.
    extentSeconds:
      readOnly: true
      type: number
      description: |-
        Length of the recording that edits are checked against, in seconds: a
        subtask or trim may not end after it. It is the stored millisecond
        length, so it can be shorter than frame_count / fps. Unset on the
        response an edit replays.
      format: double
    linkedTask:
      type: string
      description: |-
        accounts/{account}/tasks/{task}: the Task the take is recorded against, or empty when unlinked. A link, not content: `task` stays the
        label and language instruction training reads, and linking changes no
        revision, digest or version. Names a task of the episode's account
        (NOT_FOUND otherwise). Deleting the task unlinks it. Set with AssignTask,
        or UpdateEpisodes with the path on its own in one edit. A take with no link of its own
        reads the Dataset.linked_task of the dataset that holds it (linked_task_inherited): its upload's, or once a merge took the upload,
        the merged dataset's own, wherever the take is read from. Its
        own link overrides that, and clearing it (UpdateEpisodes with "") makes
        the take read the dataset's again. Filters, facets and the VLM check
        read this value.
    linkedTaskInherited:
      readOnly: true
      type: boolean
      description: |-
        Whether linked_task is the dataset's that holds the take (its upload's,
        or its merged dataset's): the take has no link of
        its own. False when nothing links it, or when it links a task itself.
    linkedTaskRevision:
      readOnly: true
      type: integer
      description: |-
        The revision of linked_task the link carries, the one checks
        judge the take against: the dataset's when inherited. 0 when unlinked, or
        when the Task had no published revision when it was linked (its draft is
        judged). Moved only by RelinkTask on the dataset.
      format: int32
    lease:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_Lease"
      description: |-
        Who is editing the take now; unset when nobody holds a live lease.
        ListEpisodes and GetEpisode fill it.
    draft:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_DraftSummary"
      description: |-
        The take's draft (EpisodeDraft), its edit not yet in a version; unset
        when it has none. One per take, so it reads the same from every scope.
        ListEpisodes and GetEpisode fill it.
    cut:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Episode_Cut"
      description: |-
        Set on an episode a version published from a draft that cut a take:
        the take and where in it the episode lies. Unset on a take.
  description: |-
    One take. An episode is recorded in exactly one upload, and can be read
    through any dataset that contains it: the parent in its name is the scope
    it is seen from. `accounts/a/datasets/{upload}/episodes/{e}` is the take as
    its upload stands on it; `accounts/a/datasets/{mixture}/episodes/{e}` is the
    same take as that mixture stands on it. The {episode} id is the same uuid
    in both. Rulings (Keep, Reject, ...) made through a mixture's name belong to
    that mixture. Upstream wins: seen from a mixture, an episode its
    upload (or a mixture in between) does not keep stands as it stands there,
    read-only; only an upstream KEPT episode is the mixture's to rule on.

    A merged dataset (Datasets.MergeDatasets) holds its uploads' episodes where
    they were recorded: `accounts/a/datasets/{merged}/episodes/{e}` is the take
    as its upload stands on it, the same state, decision, issues, notes, tags
    and trim, and `upload` still names the upload it came from. A merge is
    final: the take is the merged dataset's, and everything written
    to it (a ruling, an issue, UpdateEpisodes, AssignTask, splits, suggestions)
    is sent through the merged name and lands in the upload that holds it. The
    upload's own name for it still reads; a write by that name is
    FAILED_PRECONDITION naming the merged dataset. The account-wide list
    (`datasets/-`) names such a take under its merged dataset.

    Served by qds-api.
qualia.v1.Episode_Trim:
  type: object
  properties:
    startSeconds:
      type: number
      description: First second kept.
      format: double
    endSeconds:
      type: number
      description: Last second kept.
      format: double
  description: The trim window, in seconds from the start of the recording.
qualia.v1.Episode_Decision:
  type: object
  properties:
    verdict:
      readOnly: true
      enum:
        - VERDICT_UNSPECIFIED
        - KEEP
        - REJECT
      type: string
      description: Keep or reject.
      format: enum
    actor:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Actor"
      description: "Who ruled: a person, or VALIDATION for an ingest reject."
    decideTime:
      readOnly: true
      type: string
      description: When.
      format: date-time
    reason:
      readOnly: true
      type: string
      description: Why, in the person's words; for validation, the invalid reasons.
    dataset:
      readOnly: true
      type: string
      description: |-
        accounts/{account}/datasets/{dataset}: the dataset the ruling was made
        in. Equals the upload for an upload ruling; a mixture for its own rejects.
    locked:
      readOnly: true
      type: boolean
      description: |-
        True when seen from a mixture and the deciding ruling was made
        upstream: only that dataset can take it back.
  description: The standing ruling in this scope, when there is one.
qualia.v1.Actor:
  type: object
  properties:
    kind:
      readOnly: true
      enum:
        - KIND_UNSPECIFIED
        - PERSON
        - VALIDATION
        - RULE
        - MODEL
        - OPERATOR
        - SYSTEM
      type: string
      description: What kind of actor it is.
      format: enum
    user:
      readOnly: true
      type: string
      description: The person's user id when `kind` is PERSON; empty otherwise.
    displayName:
      readOnly: true
      type: string
      description: The person's display name at the time, for rendering without a lookup.
    agent:
      readOnly: true
      type: string
      description: |-
        The rule code, or for a MODEL the Qualia model tier (e.g. "qualia-vlm";
        "qualia" for any other model), when not a person.
    run:
      readOnly: true
      type: string
      description: The run a model or rule finding came from, when it has one.
    apiKey:
      readOnly: true
      type: string
      description: |-
        The API key's id when a person acted through one; empty for a session.
        Never the key itself.
    attribution:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Attribution"
      description: |-
        Signed identity evidence recorded with the change, kept apart from the
        principal above. Unset on older records and wherever none was signed.
  description: Who did something. Every decision, issue and reply names one.
qualia.v1.Attribution:
  type: object
  properties:
    authentication:
      readOnly: true
      enum:
        - AUTHENTICATION_UNSPECIFIED
        - SESSION
        - API_KEY
        - SERVICE
      type: string
      description: How the principal authenticated.
      format: enum
    initiator:
      readOnly: true
      type: string
      description: |-
        The user id of a person verified as starting the work: the person of a
        session, or the person a trusted service's signed job record names.
        Empty when nobody was verified.
    initiatorDisplayName:
      readOnly: true
      type: string
      description: The initiator's display name at the time, never their email.
    credentialCreator:
      readOnly: true
      type: string
      description: The user id of the key's creator at the time. Not who used the key.
    credentialOwner:
      readOnly: true
      enum:
        - CREDENTIAL_OWNER_UNSPECIFIED
        - PERSON
        - SPACE
      type: string
      description: Who owned the key at the time.
      format: enum
    credentialOwnerSpace:
      readOnly: true
      type: string
      description: |-
        The owning space's id (a workspace or the organization) when
        `credential_owner` is SPACE.
  description: |-
    How a change was authenticated and who verifiably started it.
    Only the trusted mesh signs it. It never authorizes anything, and a key's
    creator or owner is never the person who used the key.
qualia.v1.Episode_Poster:
  type: object
  properties:
    camera:
      readOnly: true
      type: string
      description: Camera key.
    firstFrameUri:
      readOnly: true
      type: string
      description: |-
        Signed URI of the midpoint frame of the window ingest recorded. An edit
        and a split piece keep their take's posters, so after a trim or a split
        this frame may lie outside the episode's own frames. The field name is
        retained for compatibility; ingest publishes a midpoint, not a first frame.
    lastFrameUri:
      readOnly: true
      type: string
      description: |-
        Signed URI of the last frame of the window ingest recorded; like the
        midpoint, it is the take's after a trim or a split.
  description: Midpoint and last-frame posters of one camera.
qualia.v1.Episode_Marker:
  type: object
  properties:
    timeSeconds:
      readOnly: true
      type: number
      description: Seconds from the start of the recording.
      format: double
    label:
      readOnly: true
      type: string
      description: Its label.
    role:
      readOnly: true
      type: string
      description: Its role (start, end, success, event).
  description: A recorder marker, e.g. the operator's success button.
qualia.v1.Episode_Subtask:
  type: object
  properties:
    startSeconds:
      type: number
      description: Start, in seconds from the start of the recording.
      format: double
    endSeconds:
      type: number
      description: End, in seconds.
      format: double
    label:
      type: string
      description: The subtask's one name (also one of the episode's tags).
    review:
      enum:
        - REVIEW_UNSPECIFIED
        - PROPOSED
        - ACCEPTED
        - REJECTED
      type: string
      description: Proposed, accepted or rejected.
      format: enum
    origin:
      enum:
        - ORIGIN_UNSPECIFIED
        - HUMAN
        - MODEL
        - HEURISTIC
      type: string
      description: Who proposed it.
      format: enum
  description: One subtask span.
qualia.v1.Episode_Metrics:
  type: object
  properties:
    durationSeconds:
      type: number
      description: Length, seconds (after trim).
      format: double
    speedVariance:
      type: number
      description: Standard deviation of per-frame speed.
      format: double
    speedMean:
      type: number
      description: Mean joint speed.
      format: double
    sparc:
      type: number
      description: Spectral arc length (smoothness; closer to 0 is smoother).
      format: double
    ldlj:
      type: number
      description: Log dimensionless jerk.
      format: double
    psdHfRatio:
      type: number
      description: Share of power above the high-frequency cut.
      format: double
    idleRatio:
      type: number
      description: Share of time the arm is idle.
      format: double
    startPoseZ:
      type: number
      description: Start pose distance from its robot's median start, in MADs.
      format: double
    endPoseZ:
      type: number
      description: End pose distance from its robot's median end, in MADs.
      format: double
    alignmentLagMs:
      type: number
      description: Lag between action and state, milliseconds.
      format: double
    correctionCount:
      type: integer
      description: Corrections near gripper events.
      format: int32
    gripperEventCount:
      type: integer
      description: Gripper open or close events.
      format: int32
    cameraLagMs:
      type: number
      description: |-
        Camera motion against joint speed offset, milliseconds (camera lag):
        the camera_lags entry the panel opens on (a recorded one, else the
        trusted estimate with the strongest peak).
      format: double
    jerkMean:
      type: number
      description: Mean jerk of the joints (the curation fence's jerk_mean).
      format: double
    gripperFlickerCount:
      type: integer
      description: Gripper open-close flickers.
      format: int32
    jerky:
      type: boolean
      description: psd_hf_ratio or tremor above p90 of its robot's population.
    hasCorrections:
      type: boolean
      description: At least one correction.
    qualityTier:
      readOnly: true
      enum:
        - QUALITY_TIER_UNSPECIFIED
        - A
        - B
        - REJECT
      type: string
      description: Composite grade.
      format: enum
    cameraLags:
      readOnly: true
      type: array
      items:
        $ref: "#/components/schemas/qualia.v1.Episode_CameraLag"
      description: Every camera's offset, by camera key; empty until measured.
  description: |-
    Per-episode health metrics and judgements. Unset
    fields are not computed yet. Each is a filter field and a facet.
qualia.v1.Episode_CameraLag:
  type: object
  properties:
    camera:
      readOnly: true
      type: string
      description: Camera key.
    lagMs:
      readOnly: true
      type: number
      description: |-
        Milliseconds; positive when the video runs behind the robot's
        motion, negative when it runs ahead.
      format: double
    confidence:
      readOnly: true
      type: number
      description: For an estimate, the correlation peak (-1 to 1); 1 when recorded.
      format: double
    method:
      readOnly: true
      type: string
      description: How it was measured, e.g. "motion_xcorr/1" or "sync_event".
    source:
      readOnly: true
      enum:
        - SOURCE_UNSPECIFIED
        - ESTIMATED
        - RECORDED
      type: string
      description: Estimated or recorded.
      format: enum
    trusted:
      readOnly: true
      type: boolean
      description: |-
        An estimate whose peak is strong and whose two halves of the episode
        agree; always true when recorded. Only trusted offsets are judged.
  description: "One camera's time offset against the robot's motion: what the camera lag panel shows per camera."
qualia.v1.Episode_Analysis:
  type: object
  properties:
    version:
      readOnly: true
      type: string
      description: |-
        The definition the numbers follow; a reader treats another one as
        not measured yet.
    unmeasuredReason:
      readOnly: true
      type: string
      description: |-
        Why the take could not be measured: "no_joints" (no state) or
        "channel_never_read". Empty when measured.
    fps:
      readOnly: true
      type: number
      description: Rows per second it was measured at.
      format: double
    frames:
      readOnly: true
      type: integer
      description: Rows read.
      format: int32
    speedVariance:
      readOnly: true
      type: number
      description: Variance of the joint speed over every state channel, (units/s)^2.
      format: double
    speedMean:
      readOnly: true
      type: number
      description: Mean joint speed over every state channel, units/s.
      format: double
    jerkMean:
      readOnly: true
      type: number
      description: Mean norm of the state's third difference, units/s^3.
      format: double
    highFrequencyRatio:
      readOnly: true
      type: number
      description: Share of the speed spectrum's power above 3 Hz.
      format: double
    idleRatio:
      readOnly: true
      type: number
      description: Share of frames under 5% of the top speed.
      format: double
    tremble:
      readOnly: true
      type: number
      description: Mean |v_smooth - v| / (|v_smooth| + |v|) over the arm joints.
      format: double
    gripperEventCount:
      readOnly: true
      type: integer
      description: Commanded gripper moves of at least 30% of their travel.
      format: int32
    gripperFlickerCount:
      readOnly: true
      type: integer
      description: The most events of one gripper inside 0.5 s.
      format: int32
    correctionCount:
      readOnly: true
      type: integer
      description: Regrasps within 3 s, plus events the arm retraces its approach round.
      format: int32
    stateChannels:
      readOnly: true
      type: array
      items:
        type: string
      description: State channel names, in the order of the poses.
    startPose:
      readOnly: true
      type: array
      items:
        type: number
        format: double
      description: First state row, every channel.
    endPose:
      readOnly: true
      type: array
      items:
        type: number
        format: double
      description: Last state row, every channel.
    channels:
      readOnly: true
      type: array
      items:
        $ref: "#/components/schemas/qualia.v1.Analysis_Channel"
      description: Every commanded channel, in recording order.
  description: |-
    How the take moves, as the dataset page's outliers and training tabs
    read it: measured once from its series, within a few
    minutes of a publish, and again only when its data changes (a re-ingest,
    or a trim or a split, measured as it is applied); a ruling or a tag
    measures nothing. The set's fences, embedding and chart averages are
    laid out over these by the reader.
    Read in the EPISODE_VIEW_ANALYSIS view of ListEpisodes (each channel's
    progress only) and of GetEpisode (with the curves); unset when the take
    is not measured yet, or its profile measured another revision of it
    than the one the listed scope reads (before a trim, a re-ingest or a
    split; or through a mixture pinned to an earlier revision, which is
    not measured: only uploads' current members are). The definitions are dataset-ux-proto's
    (scripts/extract.py, src/lib/mock): they differ on purpose from the
    like-named Metrics, which are command-space and feed curation.
qualia.v1.Analysis_Channel:
  type: object
  properties:
    name:
      readOnly: true
      type: string
      description: Channel name, as the recording names it.
    progress:
      readOnly: true
      type: array
      items:
        type: number
        format: double
      description: The value at 50 evenly spaced points of the take, first to last.
    autocorrelation:
      readOnly: true
      type: array
      items:
        type: number
        format: double
      description: |-
        Autocorrelation at lags 1..min(100, frames / 2); empty when the
        channel never moves, and in a list.
    alignment:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Channel_Alignment"
      description: Unset when the state has no channel of this name, and in a list.
  description: One commanded channel's training-chart inputs.
qualia.v1.Channel_Alignment:
  type: object
  properties:
    correlation:
      readOnly: true
      type: array
      items:
        type: number
        format: double
      description: |-
        Correlation at lags -30..30 frames; NaN where a lag has no
        variance. Empty when the take is under 5 frames.
  description: Cross-correlation of the channel's step against its measured twin's.
qualia.v1.Episode_Lease:
  type: object
  properties:
    holder:
      readOnly: true
      type: string
      description: The holder's user id (as Actor.user).
    holderName:
      readOnly: true
      type: string
      description: |-
        The holder's display name at the time they took it; empty when they
        have none.
    expireTime:
      readOnly: true
      type: string
      description: When it lapses unless renewed.
      format: date-time
  description: |-
    Someone editing the take now: the lease AcquireEpisodeLease
    takes. One per take, so it reads the same from every scope.
qualia.v1.Episode_DraftSummary:
  type: object
  properties:
    updateActor:
      readOnly: true
      allOf:
        - $ref: "#/components/schemas/qualia.v1.Actor"
      description: "Who last changed the drawing: a person, or an API key acting for none."
    updateTime:
      readOnly: true
      type: string
      description: When the drawing was last saved.
      format: date-time
    state:
      readOnly: true
      enum:
        - STATE_UNSPECIFIED
        - OPEN
      type: string
      description: "Always OPEN: a draft is never applied."
      format: enum
    baseRevision:
      readOnly: true
      type: integer
      description: The revision it was drawn on (Episode.revision then).
      format: int32
    pieceCount:
      readOnly: true
      type: integer
      description: |-
        The pieces the drawing keeps: 1 for a trim, 2 or more for a split
        (each becomes an episode of the version published from it), 0 when
        it keeps nothing.
      format: int32
    keptSeconds:
      readOnly: true
      type: number
      description: The seconds its kept pieces last, together.
      format: double
  description: |-
    The take's draft, its edit not yet in a version, as its row shows it:
    who last drew it, when, and what it keeps. GetEpisodeDraft reads the
    drawing.
qualia.v1.Episode_Cut:
  type: object
  properties:
    take:
      readOnly: true
      type: string
      description: |-
        accounts/{account}/datasets/{dataset}/episodes/{episode}: the take it
        was cut from.
    takeIndex:
      readOnly: true
      type: integer
      description: The take's index in its upload (Episode.index of the take).
      format: int32
    piece:
      readOnly: true
      type: integer
      description: Its place among the take's pieces, from 1.
      format: int32
    pieceCount:
      readOnly: true
      type: integer
      description: How many pieces the take was cut into.
      format: int32
    startSeconds:
      readOnly: true
      type: number
      description: Where it starts, in seconds of the take's recording.
      format: double
    endSeconds:
      readOnly: true
      type: number
      description: Where it ends, in seconds of the take's recording.
      format: double
  description: |-
    Where a cut piece came from: an episode a version published from a draft
    that split or trimmed a take. It is the take's piece `piece` of
    `piece_count`, kept from `start_seconds` to `end_seconds` of the take's
    recording, and reads as the dashboard numbers it ("12.1": the take's
    index, then the piece's, from 1).
google.rpc.Status:
  oneOf:
    - $ref: "#/components/schemas/ApiError"
    - $ref: "#/components/schemas/GatewayError"
  description: "The body of a failed call: one of the two shapes below."
ApiError:
  title: API error
  type: object
  required:
    - code
    - message
    - retryable
    - details
  properties:
    code:
      type: string
      description: The gRPC code name in upper case, e.g. `NOT_FOUND`.
    message:
      type: string
    retryable:
      type: boolean
      description: Whether the same call may succeed if retried.
    details:
      type: array
      items:
        type: object
      description: "Empty, except when a dataset copy or move is refused: then one `google.rpc.ErrorInfo` with the refusal's `reason` code, its `domain` and, in `metadata`, the datasets it names."
  description: A refusal from the API itself.
GatewayError:
  title: Gateway error
  type: object
  required:
    - detail
  properties:
    detail:
      type: string
      description: What went wrong.
  description: A refusal from the gateway before the call reaches the API, for example `401` bad or missing API key, `403` key lacks the scope or environment closed, `413` body too large.
```
